]> git.sur5r.net Git - freertos/blob - FreeRTOS-Plus/Source/Reliance-Edge/tests/util/atoi.c
Update version numbers in preparation for new release.
[freertos] / FreeRTOS-Plus / Source / Reliance-Edge / tests / util / atoi.c
1 /*             ----> DO NOT REMOVE THE FOLLOWING NOTICE <----\r
2 \r
3                    Copyright (c) 2014-2015 Datalight, Inc.\r
4                        All Rights Reserved Worldwide.\r
5 \r
6     This program is free software; you can redistribute it and/or modify\r
7     it under the terms of the GNU General Public License as published by\r
8     the Free Software Foundation; use version 2 of the License.\r
9 \r
10     This program is distributed in the hope that it will be useful,\r
11     but "AS-IS," WITHOUT ANY WARRANTY; without even the implied warranty\r
12     of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
13     GNU General Public License for more details.\r
14 \r
15     You should have received a copy of the GNU General Public License along\r
16     with this program; if not, write to the Free Software Foundation, Inc.,\r
17     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
18 */\r
19 /*  Businesses and individuals that for commercial or other reasons cannot\r
20     comply with the terms of the GPLv2 license may obtain a commercial license\r
21     before incorporating Reliance Edge into proprietary software for\r
22     distribution in any form.  Visit http://www.datalight.com/reliance-edge for\r
23     more information.\r
24 */\r
25 /** @file\r
26     @brief Implements utilities that convert strings to numbers.\r
27 */\r
28 #include <redfs.h>\r
29 #include <redtestutils.h>\r
30 \r
31 \r
32 #define ISHEXDIGITU(c)  (((c) >= 'A') && ((c) <= 'F'))\r
33 #define ISHEXDIGITL(c)  (((c) >= 'a') && ((c) <= 'f'))\r
34 #define ISHEXDIGIT(c)   (ISHEXDIGITL(c) || ISHEXDIGITU(c))\r
35 \r
36 \r
37 /** @brief Converts an ASCII number into an int32_t.\r
38 \r
39     Converts all decimal digit numbers up to the end of the string or to the\r
40     first non-numerical character.\r
41 \r
42     @note This function does *not* ignore leading white space.\r
43 \r
44     @param pszNum   Pointer to a constant array of characters.\r
45 \r
46     @return The integer represented in the string.\r
47 */\r
48 int32_t RedAtoI(\r
49     const char *pszNum)\r
50 {\r
51     int32_t     lValue = 0;\r
52     int32_t     lNegative = 1;\r
53     uint32_t    ulIdx = 0U;\r
54 \r
55     if(pszNum[ulIdx] == '+')\r
56     {\r
57         ulIdx++;\r
58     }\r
59     else if(pszNum[ulIdx] == '-')\r
60     {\r
61         ulIdx++;\r
62         lNegative = -1;\r
63     }\r
64     else\r
65     {\r
66         /*  No sign, implicitly positive.\r
67         */\r
68     }\r
69 \r
70     while(ISDIGIT(pszNum[ulIdx]))\r
71     {\r
72         lValue *= 10;\r
73         lValue += pszNum[ulIdx] - '0';\r
74         ulIdx++;\r
75     }\r
76 \r
77     lValue *= lNegative;\r
78 \r
79     return lValue;\r
80 }\r
81 \r
82 \r
83 /** @brief Convert a hexadecimal ASCII number into a uint32_t value.\r
84 \r
85     The function processes all hex digits up to a NUL-terminator, or to the\r
86     first non-hex character.  Only hexadecimal digits are processed, so leading\r
87     white space, or a leading "0x" prefix are not allowed.\r
88 \r
89     If pachNum points to an empty string (points to a NUL), this function will\r
90     return NULL, and the value at *pulNum will not be modified.\r
91 \r
92     @note This function does not check for overflow.  If there are more\r
93           significant digits than can be represented in a uint32_t variable, the\r
94           output is unspecified.\r
95 \r
96     @param pachNum  A pointer to a constant array of hex characters.\r
97     @param pulNum   A pointer to the location in which to store the uint32_t\r
98                     result.  Upon return, this value will be modified ONLY if\r
99                     the function succeeds and the returned pointer is valid (not\r
100                     NULL).\r
101 \r
102     @return A pointer to the byte following the converted number or NULL to\r
103             indicate failure.\r
104 */\r
105 const char *RedHtoUL(\r
106     const char *pszNum,\r
107     uint32_t   *pulNum)\r
108 {\r
109     uint64_t    ullValue;\r
110     const char *pszReturn;\r
111 \r
112     pszReturn = RedHtoULL(pszNum, &ullValue);\r
113     if(pszReturn != NULL)\r
114     {\r
115         if(ullValue < UINT32_MAX)\r
116         {\r
117             *pulNum = (uint32_t)ullValue;\r
118         }\r
119         else\r
120         {\r
121             pszReturn = NULL;\r
122         }\r
123     }\r
124 \r
125     return pszReturn;\r
126 }\r
127 \r
128 \r
129 /** @brief Convert a hexadecimal ASCII number into a D_UINT64 value.\r
130 \r
131     The function processes all hex digits up to a NUL-terminator, or to the\r
132     first non-hex character.  Only hexadecimal digits are processed, so leading\r
133     white space, or a leading "0x" prefix are not allowed.\r
134 \r
135     If pachNum points to an empty string (points to a NUL), this function will\r
136     return NULL, and the value at *pulNum will not be modified.\r
137 \r
138     @note This function does not check for overflow.  If there are more\r
139           significant digits than can be represented in a uint64_t variable, the\r
140           output is unspecified.\r
141 \r
142     @param pszNum   A pointer to a constant array of hex characters.\r
143     @param pullNum  A pointer to the location in which to store the uint64_t\r
144                     result.  Upon return, this value will be modified ONLY if\r
145                     the function succeeds and the returned pointer is valid (not\r
146                     NULL).\r
147 \r
148     @return A pointer to the byte following the converted number, or NULL to\r
149             indicate failure.\r
150 */\r
151 const char *RedHtoULL(\r
152     const char *pszNum,\r
153     uint64_t   *pullNum)\r
154 {\r
155     uint64_t    ullValue = 0U;\r
156     const char *pszReturn = NULL;\r
157     uint32_t    ulIdx = 0U;\r
158 \r
159     REDASSERT(pszNum != NULL);\r
160     REDASSERT(pullNum != NULL);\r
161 \r
162     while(pszNum[ulIdx] != '\0')\r
163     {\r
164         char cDigit = pszNum[ulIdx];\r
165 \r
166         if(ISDIGIT(cDigit))\r
167         {\r
168             cDigit -= '0';\r
169         }\r
170         else if(ISHEXDIGITU(cDigit))\r
171         {\r
172             cDigit -= ('A' - 10);\r
173         }\r
174         else if(ISHEXDIGITL(cDigit))\r
175         {\r
176             cDigit -= ('a' - 10);\r
177         }\r
178         else\r
179         {\r
180             break;\r
181         }\r
182 \r
183         REDASSERT((ullValue & UINT64_SUFFIX(0xF000000000000000)) == 0U);\r
184 \r
185         ullValue <<= 4U;\r
186         ullValue += cDigit;\r
187 \r
188         ulIdx++;\r
189         pszReturn = &pszNum[ulIdx];\r
190     }\r
191 \r
192     /*  Modify the number returned only if we found one or more valid hex\r
193         digits.\r
194     */\r
195     if(pszReturn != NULL)\r
196     {\r
197         *pullNum = ullValue;\r
198     }\r
199 \r
200     return pszReturn;\r
201 }\r
202 \r
203 \r
204 /** @brief Convert the ASCII number to a uint32_t  value.\r
205 \r
206     The number may be hex or decimal.  Hex numbers must be prefixed by '0x', and\r
207     they may be upper or lower case.  The conversion process will stop with the\r
208     first non hex or decimal digit.\r
209 \r
210     If the number is negative (the first character is a '-' sign), the value\r
211     will be range checked and returned as the equivalent unsigned value.\r
212 \r
213     @note   This function will NOT fail for numbers which exceed the size of a\r
214             uint32_t value.\r
215 \r
216     @param pszNum   A pointer to the ASCII number to convert\r
217     @param pulNum   A pointer to the uint32_t location to store the result.\r
218                     This value will be modified on return only if the function\r
219                     succeeds and the returned pointer is valid (not NULL).\r
220 \r
221     @return A pointer to the byte following the converted number, or NULL to\r
222             indicate failure.\r
223 */\r
224 const char *RedNtoUL(\r
225     const char *pszNum,\r
226     uint32_t   *pulNum)\r
227 {\r
228     bool        fNegative = false;\r
229     uint32_t    ulIdx = 0U;\r
230     const char *pszReturn;\r
231 \r
232     REDASSERT(pszNum != NULL);\r
233     REDASSERT(pulNum != NULL);\r
234 \r
235     if(pszNum[ulIdx] == '-')\r
236     {\r
237         fNegative = true;\r
238         ulIdx++;\r
239     }\r
240 \r
241     /*  Hex numbers must be prefixed with '0x'.\r
242     */\r
243     if((pszNum[ulIdx] == '0') && ((pszNum[ulIdx + 1U] == 'x') || (pszNum[ulIdx + 1U] == 'X')))\r
244     {\r
245         ulIdx += 2U;\r
246 \r
247         if(ISDIGIT(pszNum[ulIdx]) || ISHEXDIGIT(pszNum[ulIdx]))\r
248         {\r
249             pszReturn = RedHtoUL(&pszNum[ulIdx], pulNum);\r
250         }\r
251         else\r
252         {\r
253             pszReturn = NULL;\r
254         }\r
255     }\r
256     else if(ISDIGIT(pszNum[ulIdx]))\r
257     {\r
258         uint32_t ulTemp;\r
259 \r
260         ulTemp = RedAtoI(&pszNum[ulIdx]);\r
261 \r
262         while(ISDIGIT(pszNum[ulIdx]))\r
263         {\r
264             ulIdx++;\r
265         }\r
266 \r
267         if(fNegative)\r
268         {\r
269             /*  Fail if the number is out of range.\r
270             */\r
271             if(ulTemp > INT32_MAX)\r
272             {\r
273                 pszReturn = NULL;\r
274             }\r
275             else\r
276             {\r
277                 *pulNum = -((int32_t)ulTemp);\r
278                 pszReturn = &pszNum[ulIdx];\r
279             }\r
280         }\r
281         else\r
282         {\r
283             *pulNum = ulTemp;\r
284             pszReturn = &pszNum[ulIdx];\r
285         }\r
286     }\r
287     else\r
288     {\r
289         /*  Return an error if there is not at least one hex or decimal digit.\r
290         */\r
291         pszReturn = NULL;\r
292     }\r
293 \r
294     return pszReturn;\r
295 }\r
296 \r
297 \r
298 /** @brief Convert the ASCII number pointed to by pachNum to a uint64_t value.\r
299 \r
300     The number may be hex or decimal.  Hex numbers must be prefixed by '0x', and\r
301     they may be upper or lower case.  The conversion process will stop with the\r
302     first non hex or decimal digit.\r
303 \r
304     If the number is negative (the first character is a '-' sign), the value\r
305     will be range checked and returned as the equivalent unsigned value.\r
306 \r
307     @param pszNum   A pointer to the ASCII number to convert.\r
308     @param pullNum  A pointer to the uint64_t location to store the result.\r
309                     This value will be modified on return only if the function\r
310                     succeeds and the returned pointer is valid (not NULL).\r
311 \r
312     @return A pointer to the byte following the converted number, or NULL to\r
313             indicate failure.\r
314 */\r
315 const char *RedNtoULL(\r
316     const char *pszNum,\r
317     uint64_t   *pullNum)\r
318 {\r
319     bool        fNegative = false;\r
320     uint32_t    ulIdx = 0U;\r
321     const char *pszReturn;\r
322 \r
323     REDASSERT(pszNum != NULL);\r
324     REDASSERT(pullNum != NULL);\r
325 \r
326     if(pszNum[ulIdx] == '-')\r
327     {\r
328         fNegative = true;\r
329         ulIdx++;\r
330     }\r
331 \r
332     /*  Hex numbers must be prefixed with '0x'.\r
333     */\r
334     if((pszNum[ulIdx] == '0') && ((pszNum[ulIdx + 1U] == 'x') || (pszNum[ulIdx + 1U] == 'X')))\r
335     {\r
336         ulIdx += 2U;\r
337 \r
338         if(ISDIGIT(pszNum[ulIdx]) || ISHEXDIGIT(pszNum[ulIdx]))\r
339         {\r
340             pszReturn = RedHtoULL(&pszNum[ulIdx], pullNum);\r
341         }\r
342         else\r
343         {\r
344             pszReturn = NULL;\r
345         }\r
346     }\r
347     else if(ISDIGIT(pszNum[ulIdx]))\r
348     {\r
349         uint64_t ullTemp = 0U;\r
350 \r
351         while(ISDIGIT(pszNum[ulIdx]))\r
352         {\r
353             ullTemp *= 10U;\r
354             ullTemp += pszNum[ulIdx] - '0';\r
355             ulIdx++;\r
356         }\r
357 \r
358         if(fNegative)\r
359         {\r
360             /*  Fail if the number is out of range.\r
361             */\r
362             if(ullTemp > INT64_MAX)\r
363             {\r
364                 pszReturn = NULL;\r
365             }\r
366             else\r
367             {\r
368                 *pullNum = (uint64_t)(-((int64_t)ullTemp));\r
369                 pszReturn = &pszNum[ulIdx];\r
370             }\r
371         }\r
372         else\r
373         {\r
374             *pullNum = ullTemp;\r
375             pszReturn = &pszNum[ulIdx];\r
376         }\r
377     }\r
378     else\r
379     {\r
380         /*  Return an error if there is not at least one hex or decimal digit.\r
381         */\r
382         pszReturn = NULL;\r
383     }\r
384 \r
385     return pszReturn;\r
386 }\r
387 \r
388 \r
389 /** @brief Convert an ASCII hex or decimal number, which may may have a "B",\r
390            "KB", or "MB" suffix (case insensitive), to a binary value.\r
391 \r
392     Hex numbers must be prefixed with "0x".\r
393 \r
394     @note If there is no postfix, KB is assumed!\r
395 \r
396     May fail due to bad formatting or overflow.\r
397 \r
398     @param pszNum       A pointer to the ASCII number to convert.\r
399     @param pulResult    A pointer to a uint32_t in which to place the result.\r
400 \r
401     @return A pointer to the byte following the string, or NULL to indicate an\r
402             error.  In the event of an error, *pulResult will not be modified.\r
403 */\r
404 const char *RedSizeToUL(\r
405     const char *pszNum,\r
406     uint32_t   *pulResult)\r
407 {\r
408     uint32_t    ulResult;\r
409     const char *pszSuffix;\r
410     const char *pszReturn;\r
411     uint32_t    ulIdx = 0U;\r
412 \r
413     REDASSERT(pszNum != NULL);\r
414     REDASSERT(pulResult != NULL);\r
415 \r
416     /*  Do the basic hex/decimal conversion\r
417     */\r
418     pszSuffix = RedNtoUL(pszNum, &ulResult);\r
419     if(pszSuffix != NULL)\r
420     {\r
421         if((pszSuffix[ulIdx] == 'B') || (pszSuffix[ulIdx] == 'b'))\r
422         {\r
423             ulIdx++;\r
424             pszReturn = &pszSuffix[ulIdx];\r
425         }\r
426         else if(    ((pszSuffix[ulIdx] == 'M') || (pszSuffix[ulIdx] == 'm'))\r
427                  && ((pszSuffix[ulIdx + 1U] == 'B') || (pszSuffix[ulIdx + 1U] == 'b')))\r
428         {\r
429             ulIdx += 2U;\r
430 \r
431             if(ulResult > (UINT32_MAX / (1024U * 1024U)))\r
432             {\r
433                 pszReturn = NULL;\r
434             }\r
435             else\r
436             {\r
437                 ulResult *= 1024U * 1024U;\r
438                 pszReturn = &pszSuffix[ulIdx];\r
439             }\r
440         }\r
441         else\r
442         {\r
443             /*  The number is either postfixed with "KB" or something\r
444                 else (we don't care), but we must increment the pointer\r
445                 if it is something recognize.\r
446             */\r
447             if(    ((pszSuffix[ulIdx] == 'K') || (pszSuffix[ulIdx] == 'k'))\r
448                 && ((pszSuffix[ulIdx + 1U] == 'B') || (pszSuffix[ulIdx + 1U] == 'b')))\r
449             {\r
450                 ulIdx += 2U;\r
451             }\r
452 \r
453             /*  "B" or "MB" were not specified, so it must be "KB"\r
454             */\r
455             if(ulResult > (UINT32_MAX / 1024U))\r
456             {\r
457                 pszReturn = NULL;\r
458             }\r
459             else\r
460             {\r
461                 ulResult *= 1024UL;\r
462                 pszReturn = &pszSuffix[ulIdx];\r
463             }\r
464         }\r
465 \r
466         if(pszReturn != NULL)\r
467         {\r
468             *pulResult = ulResult;\r
469         }\r
470     }\r
471     else\r
472     {\r
473         pszReturn = NULL;\r
474     }\r
475 \r
476     return pszReturn;\r
477 }\r
478 \r