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