source: azure_iot_hub_f767zi/trunk/azure_iot_sdk/c-utility/src/crt_abstractions.c@ 457

Last change on this file since 457 was 457, checked in by coas-nagasima, 4 years ago

ファイルを追加

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc;charset=UTF-8
File size: 34.7 KB
Line 
1// Copyright (c) Microsoft. All rights reserved.
2// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
4#define __STDC_WANT_LIB_EXT1__ 1
5
6#include <stdlib.h>
7#include <stdarg.h>
8#include <string.h>
9#include <limits.h>
10#include <float.h>
11#include <math.h>
12#include <errno.h>
13#include "azure_c_shared_utility/gballoc.h"
14#include "azure_c_shared_utility/optimize_size.h"
15#include "azure_c_shared_utility/crt_abstractions.h"
16
17// VS 2008 does not have INFINITY and all the nice goodies...
18#if defined (TIZENRT)
19#define DEFINE_INFINITY 1
20#else
21
22#if defined _MSC_VER
23#if _MSC_VER <= 1500
24#define DEFINE_INFINITY 1
25#endif
26#endif
27#endif
28
29#if defined DEFINE_INFINITY
30
31#pragma warning(disable:4756 4056) // warning C4756: overflow in constant arithmetic
32
33// These defines are missing in math.h for WEC2013 SDK
34#ifndef _HUGE_ENUF
35#define _HUGE_ENUF 1e+300 // _HUGE_ENUF*_HUGE_ENUF must overflow
36#endif
37
38#define INFINITY ((float)(_HUGE_ENUF * _HUGE_ENUF))
39#define HUGE_VALF ((float)INFINITY)
40#define HUGE_VALL ((long double)INFINITY)
41#define NAN ((float)(INFINITY * 0.0F))
42#endif
43
44#if defined (_MSC_VER) || defined (MINGW_HAS_SECURE_API)
45#else
46
47/*Codes_SRS_CRT_ABSTRACTIONS_99_008: [strcat_s shall append the src to dst and terminates the resulting string with a null character.]*/
48int strcat_s(char* dst, size_t dstSizeInBytes, const char* src)
49{
50 int result;
51 /*Codes_SRS_CRT_ABSTRACTIONS_99_004: [If dst is NULL or unterminated, the error code returned shall be EINVAL & dst shall not be modified.]*/
52 if (dst == NULL)
53 {
54 result = EINVAL;
55 }
56 /*Codes_SRS_CRT_ABSTRACTIONS_99_005: [If src is NULL, the error code returned shall be EINVAL and dst[0] shall be set to 0.]*/
57 else if (src == NULL)
58 {
59 dst[0] = '\0';
60 result = EINVAL;
61 }
62 else
63 {
64 /*Codes_SRS_CRT_ABSTRACTIONS_99_006: [If the dstSizeInBytes is 0 or smaller than the required size for dst & src, the error code returned shall be ERANGE & dst[0] set to 0.]*/
65 if (dstSizeInBytes == 0)
66 {
67 result = ERANGE;
68 dst[0] = '\0';
69 }
70 else
71 {
72 size_t dstStrLen = 0;
73 size_t src_len = strlen(src);
74#ifdef __STDC_LIB_EXT1__
75 dstStrLen = strnlen_s(dst, dstSizeInBytes);
76#else
77 size_t i;
78 for(i=0; (i < dstSizeInBytes) && (dst[i]!= '\0'); i++)
79 {
80 }
81 dstStrLen = i;
82#endif
83 /*Codes_SRS_CRT_ABSTRACTIONS_99_004: [If dst is NULL or unterminated, the error code returned shall be EINVAL & dst shall not be modified.]*/
84 if (dstSizeInBytes == dstStrLen) /* this means the dst string is not terminated*/
85 {
86 result = EINVAL;
87 }
88 // If we are instructed to write too much data to the buffer
89 // return ERANGE
90 else if ((src_len + dstStrLen) >= dstSizeInBytes)
91 {
92 dst[0] = '\0';
93 result = ERANGE;
94 }
95 else
96 {
97 // memcpy should at most copy the result of strlen(src) or there may be
98 // some issues with copying unwanted memory
99 size_t bytes_to_cpy = dstSizeInBytes - dstStrLen;
100 if (bytes_to_cpy > src_len)
101 {
102 bytes_to_cpy = src_len;
103 }
104
105 /*Codes_SRS_CRT_ABSTRACTIONS_99_009: [The initial character of src shall overwrite the terminating null character of dst.]*/
106 if (memcpy(&dst[dstStrLen], src, bytes_to_cpy) == NULL)
107 /*Codes_SRS_CRT_ABSTRACTIONS_99_006: [If the dstSizeInBytes is 0 or smaller than the required size for dst & src, the error code returned shall be ERANGE & dst[0] set to 0.]*/
108 {
109 dst[0] = '\0';
110 result = ERANGE;
111 }
112 else
113 {
114 /*Codes_SRS_CRT_ABSTRACTIONS_99_003: [strcat_s shall return Zero upon success.]*/
115 dst[dstStrLen+bytes_to_cpy] = '\0';
116 result = 0;
117 }
118 }
119 }
120 }
121 return result;
122}
123
124/*Codes_SRS_CRT_ABSTRACTIONS_99_025: [strncpy_s shall copy the first N characters of src to dst, where N is the lesser of MaxCount and the length of src.]*/
125int strncpy_s(char* dst, size_t dstSizeInBytes, const char* src, size_t maxCount)
126{
127 int result;
128 int truncationFlag = 0;
129 /*Codes_SRS_CRT_ABSTRACTIONS_99_020: [If dst is NULL, the error code returned shall be EINVAL and dst shall not be modified.]*/
130 if (dst == NULL)
131 {
132 result = EINVAL;
133 }
134 /*Codes_SRS_CRT_ABSTRACTIONS_99_021: [If src is NULL, the error code returned shall be EINVAL and dst[0] shall be set to 0.]*/
135 else if (src == NULL)
136 {
137 dst[0] = '\0';
138 result = EINVAL;
139 }
140 /*Codes_SRS_CRT_ABSTRACTIONS_99_022: [If the dstSizeInBytes is 0, the error code returned shall be EINVAL and dst shall not be modified.]*/
141 else if (dstSizeInBytes == 0)
142 {
143 result = EINVAL;
144 }
145 else
146 {
147 size_t srcLength = strlen(src);
148 if (maxCount != _TRUNCATE)
149 {
150 /*Codes_SRS_CRT_ABSTRACTIONS_99_041: [If those N characters will fit within dst (whose size is given as dstSizeInBytes) and still leave room for a null terminator, then those characters shall be copied and a terminating null is appended; otherwise, strDest[0] is set to the null character and ERANGE error code returned.]*/
151 if (srcLength > maxCount)
152 {
153 srcLength = maxCount;
154 }
155
156 /*Codes_SRS_CRT_ABSTRACTIONS_99_023: [If dst is not NULL & dstSizeInBytes is smaller than the required size for the src string, the error code returned shall be ERANGE and dst[0] shall be set to 0.]*/
157 if (srcLength + 1 > dstSizeInBytes)
158 {
159 dst[0] = '\0';
160 result = ERANGE;
161 }
162 else
163 {
164 (void)memcpy(dst, src, srcLength);
165 dst[srcLength] = '\0';
166 /*Codes_SRS_CRT_ABSTRACTIONS_99_018: [strncpy_s shall return Zero upon success]*/
167 result = 0;
168 }
169 }
170 /*Codes_SRS_CRT_ABSTRACTIONS_99_026: [If MaxCount is _TRUNCATE (defined as -1), then as much of src as will fit into dst shall be copied while still leaving room for the terminating null to be appended.]*/
171 else
172 {
173 if (srcLength + 1 > dstSizeInBytes )
174 {
175 srcLength = dstSizeInBytes - 1;
176 truncationFlag = 1;
177 }
178 (void)memcpy(dst, src, srcLength);
179 dst[srcLength] = '\0';
180 result = 0;
181 }
182 }
183
184 /*Codes_SRS_CRT_ABSTRACTIONS_99_019: [If truncation occurred as a result of the copy, the error code returned shall be STRUNCATE.]*/
185 if (truncationFlag == 1)
186 {
187 result = STRUNCATE;
188 }
189
190 return result;
191}
192
193/* Codes_SRS_CRT_ABSTRACTIONS_99_016: [strcpy_s shall copy the contents in the address of src, including the terminating null character, to the location that's specified by dst.]*/
194int strcpy_s(char* dst, size_t dstSizeInBytes, const char* src)
195{
196 int result;
197
198 /* Codes_SRS_CRT_ABSTRACTIONS_99_012: [If dst is NULL, the error code returned shall be EINVAL & dst shall not be modified.]*/
199 if (dst == NULL)
200 {
201 result = EINVAL;
202 }
203 /* Codes_SRS_CRT_ABSTRACTIONS_99_013: [If src is NULL, the error code returned shall be EINVAL and dst[0] shall be set to 0.]*/
204 else if (src == NULL)
205 {
206 dst[0] = '\0';
207 result = EINVAL;
208 }
209 /* Codes_SRS_CRT_ABSTRACTIONS_99_014: [If the dstSizeInBytes is 0 or smaller than the required size for the src string, the error code returned shall be ERANGE & dst[0] set to 0.]*/
210 else if (dstSizeInBytes == 0)
211 {
212 dst[0] = '\0';
213 result = ERANGE;
214 }
215 else
216 {
217 size_t neededBuffer = strlen(src);
218 /* Codes_SRS_CRT_ABSTRACTIONS_99_014: [If the dstSizeInBytes is 0 or smaller than the required size for the src string, the error code returned shall be ERANGE & dst[0] set to 0.]*/
219 if (neededBuffer + 1 > dstSizeInBytes)
220 {
221 dst[0] = '\0';
222 result = ERANGE;
223 }
224 else
225 {
226 (void)memcpy(dst, src, neededBuffer + 1);
227 /*Codes_SRS_CRT_ABSTRACTIONS_99_011: [strcpy_s shall return Zero upon success]*/
228 result = 0;
229 }
230 }
231
232 return result;
233}
234
235/*Codes_SRS_CRT_ABSTRACTIONS_99_029: [The sprintf_s function shall format and store series of characters and values in dst. Each argument (if any) is converted and output according to the corresponding Format Specification in the format variable.]*/
236/*Codes_SRS_CRT_ABSTRACTIONS_99_031: [A null character is appended after the last character written.]*/
237int sprintf_s(char* dst, size_t dstSizeInBytes, const char* format, ...)
238{
239 int result;
240 /*Codes_SRS_CRT_ABSTRACTIONS_99_028: [If dst or format is a null pointer, sprintf_s shall return -1 and set errno to EINVAL]*/
241 if ((dst == NULL) ||
242 (format == NULL))
243 {
244 errno = EINVAL;
245 result = -1;
246 }
247 else
248 {
249 /*Codes_SRS_CRT_ABSTRACTIONS_99_033: [sprintf_s shall check the format string for valid formatting characters. If the check fails, the function returns -1.]*/
250
251#if defined _MSC_VER
252#error crt_abstractions is not provided for Microsoft Compilers
253#else
254 /*not Microsoft compiler... */
255#if defined (__STDC_VERSION__) || (__cplusplus)
256#if ( \
257 ((__STDC_VERSION__ == 199901L) || (__STDC_VERSION__ == 201000L) || (__STDC_VERSION__ == 201112L) || (__STDC_VERSION__ == 201710L)) || \
258 (defined __cplusplus) \
259 )
260 /*C99 compiler*/
261 va_list args;
262 va_start(args, format);
263 /*Codes_SRS_CRT_ABSTRACTIONS_99_027: [sprintf_s shall return the number of characters stored in dst upon success. This number shall not include the terminating null character.]*/
264 result = vsnprintf(dst, dstSizeInBytes, format, args);
265 va_end(args);
266
267 /*C99: Thus, the null-terminated output has been completely written if and only if the returned value is nonnegative and less than n*/
268 if (result < 0)
269 {
270 result = -1;
271 }
272 else if ((size_t)result >= dstSizeInBytes)
273 {
274 /*Codes_SRS_CRT_ABSTRACTIONS_99_034: [If the dst buffer is too small for the text being printed, then dst is set to an empty string and the function shall return -1.]*/
275 dst[0] = '\0';
276 result = -1;
277 }
278 else
279 {
280 /*do nothing, all is fine*/
281 }
282#else
283#error STDC_VERSION defined, but of unknown value; unable to sprinf_s, or provide own implementation
284#endif
285#else
286#error for STDC_VERSION undefined (assumed C89), provide own implementation of sprintf_s
287#endif
288#endif
289 }
290 return result;
291}
292#endif /* _MSC_VER || MINGW_HAS_SECURE_API */
293
294/*Codes_SRS_CRT_ABSTRACTIONS_21_006: [The strtoull_s must use the letters from a(or A) through z(or Z) to represent the numbers between 10 to 35.]*/
295/* returns the integer value that correspond to the character 'c'. If the character is invalid, it returns -1. */
296#define DIGIT_VAL(c) (((c>='0') && (c<='9')) ? (c-'0') : ((c>='a') && (c<='z')) ? (c-'a'+10) : ((c>='A') && (c<='Z')) ? (c-'A'+10) : -1)
297#define IN_BASE_RANGE(d, b) ((d >= 0) && (d < b))
298
299/*Codes_SRS_CRT_ABSTRACTIONS_21_010: [The white-space must be one of the characters ' ', '\f', '\n', '\r', '\t', '\v'.]*/
300#define IS_SPACE(c) (c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v')
301
302/*Codes_SRS_CRT_ABSTRACTIONS_21_001: [The strtoull_s must convert the initial portion of the string pointed to by nptr to unsigned long long int representation.]*/
303/*Codes_SRS_CRT_ABSTRACTIONS_21_002: [The strtoull_s must resembling an integer represented in some radix determined by the value of base.]*/
304/*Codes_SRS_CRT_ABSTRACTIONS_21_003: [The strtoull_s must return the integer that represents the value in the initial part of the string. If any.]*/
305unsigned long long strtoull_s(const char* nptr, char** endptr, int base)
306{
307 unsigned long long result = 0ULL;
308 bool validStr = true;
309 char* runner = (char*)nptr;
310 bool isNegative = false;
311 int digitVal;
312
313 /*Codes_SRS_CRT_ABSTRACTIONS_21_005: [The strtoull_s must convert number using base 2 to 36.]*/
314 /*Codes_SRS_CRT_ABSTRACTIONS_21_012: [If the subject sequence is empty or does not have the expected form, the strtoull_s must not perform any conversion; the value of nptr is stored in the object pointed to by endptr, provided that endptr is not a NULL pointer.]*/
315 /*Codes_SRS_CRT_ABSTRACTIONS_21_013: [If no conversion could be performed, the strtoull_s returns the value 0L.]*/
316 /*Codes_SRS_CRT_ABSTRACTIONS_21_035: [If the nptr is NULL, the strtoull_s must **not** perform any conversion and must returns 0L; endptr must receive NULL, provided that endptr is not a NULL pointer.]*/
317 if (((base >= 2) || (base == 0)) && (base <= 36) && (runner != NULL))
318 {
319 /*Codes_SRS_CRT_ABSTRACTIONS_21_011: [The valid sequence starts after the first non-white-space character, followed by an optional positive or negative sign, a number or a letter(depending of the base).]*/
320 /*Codes_SRS_CRT_ABSTRACTIONS_21_010: [The white-space must be one of the characters ' ', '\f', '\n', '\r', '\t', '\v'.]*/
321 while (IS_SPACE(*runner))
322 {
323 runner++;
324 }
325 if ((*runner) == '+')
326 {
327 runner++;
328 }
329 else if ((*runner) == '-')
330 {
331 /*Codes_SRS_CRT_ABSTRACTIONS_21_038: [If the subject sequence starts with a negative sign, the strtoull_s will convert it to the posive representation of the negative value.]*/
332 isNegative = true;
333 runner++;
334 }
335
336 if ((*runner) == '0')
337 {
338 if ((*(runner+1) == 'x') || (*(runner+1) == 'X'))
339 {
340 /*Codes_SRS_CRT_ABSTRACTIONS_21_008: [If the base is 0 and '0x' or '0X' precedes the number, strtoull_s must convert to a hexadecimal (base 16).]*/
341 /* hexadecimal... */
342 if ((base == 0) || (base == 16))
343 {
344 base = 16;
345 runner += 2;
346 }
347 }
348 else if((base == 0) || (base == 8))
349 {
350 /*Codes_SRS_CRT_ABSTRACTIONS_21_009: [If the base is 0 and '0' precedes the number, strtoull_s must convert to an octal (base 8).]*/
351 /* octal... */
352 base = 8;
353 runner++;
354 }
355 }
356
357 if(base == 0)
358 {
359 /*Codes_SRS_CRT_ABSTRACTIONS_21_007: [If the base is 0 and no special chars precedes the number, strtoull_s must convert to a decimal (base 10).]*/
360 /* decimal... */
361 base = 10;
362 }
363
364 digitVal = DIGIT_VAL(*runner);
365 if (validStr && IN_BASE_RANGE(digitVal, base))
366 {
367 errno = 0;
368 do
369 {
370 if (((ULLONG_MAX - digitVal) / base) < result)
371 {
372 /*Codes_SRS_CRT_ABSTRACTIONS_21_014: [If the correct value is outside the range, the strtoull_s returns the value ULLONG_MAX, and errno will receive the value ERANGE.]*/
373 /* overflow... */
374 result = ULLONG_MAX;
375 errno = ERANGE;
376 }
377 else
378 {
379 result = result * base + digitVal;
380 }
381 runner++;
382 digitVal = DIGIT_VAL(*runner);
383 } while (IN_BASE_RANGE(digitVal, base));
384 }
385 else
386 {
387 runner = (char*)nptr;
388 }
389 }
390
391 /*Codes_SRS_CRT_ABSTRACTIONS_21_004: [The strtoull_s must return in endptr a final string of one or more unrecognized characters, including the terminating null character of the input string.]*/
392 if (endptr != NULL)
393 {
394 (*endptr) = (char*)runner;
395 }
396
397 /*Codes_SRS_CRT_ABSTRACTIONS_21_038: [If the subject sequence starts with a negative sign, the strtoull_s will convert it to the posive representation of the negative value.]*/
398 if (isNegative)
399 {
400 result = ULLONG_MAX - result + 1;
401 }
402
403 return result;
404}
405
406/*Codes_SRS_CRT_ABSTRACTIONS_21_023: [If the string is 'INF' of 'INFINITY' (ignoring case), the strtof_s must return the INFINITY value for float.]*/
407/*Codes_SRS_CRT_ABSTRACTIONS_21_024: [If the string is 'NAN' or 'NAN(...)' (ignoring case), the strtof_s must return 0.0f and points endptr to the first character after the 'NAN' sequence.]*/
408/*Codes_SRS_CRT_ABSTRACTIONS_21_033: [If the string is 'INF' of 'INFINITY' (ignoring case), the strtold_s must return the INFINITY value for long double.]*/
409/*Codes_SRS_CRT_ABSTRACTIONS_21_034: [If the string is 'NAN' or 'NAN(...)' (ignoring case), the strtold_s must return 0.0 and points endptr to the first character after the 'NAN' sequence.]*/
410static int substricmp(const char* nptr, const char* subsrt)
411{
412 int result = 0;
413 while (((*subsrt) != '\0') && (result == 0))
414 {
415 result = TOUPPER(*nptr) - TOUPPER(*subsrt);
416 nptr++;
417 subsrt++;
418 }
419 return result;
420}
421
422/*Codes_SRS_CRT_ABSTRACTIONS_21_023: [If the string is 'INF' of 'INFINITY' (ignoring case), the strtof_s must return the INFINITY value for float.]*/
423/*Codes_SRS_CRT_ABSTRACTIONS_21_033: [If the string is 'INF' of 'INFINITY' (ignoring case), the strtold_s must return the INFINITY value for long double.]*/
424static bool isInfinity(const char** endptr)
425{
426 bool result = false;
427 if (substricmp((*endptr), "INF") == 0)
428 {
429 (*endptr) += 3;
430 result = true;
431 if (substricmp((*endptr), "INITY") == 0)
432 {
433 (*endptr) += 5;
434 }
435 }
436 return result;
437}
438
439/*Codes_SRS_CRT_ABSTRACTIONS_21_024: [If the string is 'NAN' or 'NAN(...)' (ignoring case), the strtof_s must return 0.0f and points endptr to the first character after the 'NAN' sequence.]*/
440/*Codes_SRS_CRT_ABSTRACTIONS_21_034: [If the string is 'NAN' or 'NAN(...)' (ignoring case), the strtold_s must return 0.0 and points endptr to the first character after the 'NAN' sequence.]*/
441static bool isNaN(const char** endptr)
442{
443 const char* runner = (*endptr);
444 bool result = false;
445 if (substricmp(runner, "NAN") == 0)
446 {
447 runner += 3;
448 result = true;
449 if ((*runner) == '(')
450 {
451 do
452 {
453 runner++;
454 } while (((*runner) != '\0') && ((*runner) != ')'));
455 if ((*runner) == ')')
456 runner++;
457 else
458 result = false;
459 }
460 }
461 if (result)
462 (*endptr) = runner;
463 return result;
464}
465
466#define FLOAT_STRING_TYPE_VALUES \
467 FST_INFINITY, \
468 FST_NAN, \
469 FST_NUMBER, \
470 FST_OVERFLOW, \
471 FST_ERROR
472
473MU_DEFINE_ENUM(FLOAT_STRING_TYPE, FLOAT_STRING_TYPE_VALUES);
474
475static FLOAT_STRING_TYPE splitFloatString(const char* nptr, char** endptr, int *signal, double *fraction, int *exponential)
476{
477 FLOAT_STRING_TYPE result = FST_ERROR;
478
479 unsigned long long ullInteger = 0;
480 unsigned long long ullFraction = 0;
481 int integerSize = 0;
482 int fractionSize = 0;
483 char* startptr;
484
485 (*endptr) = (char*)nptr;
486
487 /*Codes_SRS_CRT_ABSTRACTIONS_21_018: [The white-space for strtof_s must be one of the characters ' ', '\f', '\n', '\r', '\t', '\v'.]*/
488 /*Codes_SRS_CRT_ABSTRACTIONS_21_028: [The white-space for strtold_s must be one of the characters ' ', '\f', '\n', '\r', '\t', '\v'.]*/
489 while (IS_SPACE(**endptr))
490 {
491 (*endptr)++;
492 }
493
494 /*Codes_SRS_CRT_ABSTRACTIONS_21_019: [The valid sequence for strtof_s starts after the first non-white - space character, followed by an optional positive or negative sign, a number, 'INF', or 'NAN' (ignoring case).]*/
495 /*Codes_SRS_CRT_ABSTRACTIONS_21_029: [The valid sequence for strtold_s starts after the first non-white - space character, followed by an optional positive or negative sign, a number, 'INF', or 'NAN' (ignoring case).]*/
496 (*signal) = +1;
497 if ((**endptr) == '+')
498 {
499 (*endptr)++;
500 }
501 else if ((**endptr) == '-')
502 {
503 (*signal) = -1;
504 (*endptr)++;
505 }
506
507 /*Codes_SRS_CRT_ABSTRACTIONS_21_023: [If the string is 'INF' of 'INFINITY' (ignoring case), the strtof_s must return the INFINITY value for float.]*/
508 /*Codes_SRS_CRT_ABSTRACTIONS_21_033: [If the string is 'INF' of 'INFINITY' (ignoring case), the strtold_s must return the INFINITY value for long double.]*/
509 if (isInfinity((const char**)endptr))
510 {
511 result = FST_INFINITY;
512 }
513 /*Codes_SRS_CRT_ABSTRACTIONS_21_034: [If the string is 'NAN' or 'NAN(...)' (ignoring case), the strtold_s must return 0.0 and points endptr to the first character after the 'NAN' sequence.]*/
514 /*Codes_SRS_CRT_ABSTRACTIONS_21_024: [If the string is 'NAN' or 'NAN(...)' (ignoring case), the strtof_s must return 0.0f and points endptr to the first character after the 'NAN' sequence.]*/
515 else if (isNaN((const char**)endptr))
516 {
517 result = FST_NAN;
518 }
519 else if (IN_BASE_RANGE(DIGIT_VAL(**endptr), 10))
520 {
521 result = FST_NUMBER;
522 startptr = *endptr;
523 /* integers will go to the fraction and exponential. */
524 ullInteger = strtoull_s(startptr, endptr, 10);
525 integerSize = (int)((*endptr) - startptr);
526 if ((ullInteger == ULLONG_MAX) && (errno != 0))
527 {
528 result = FST_OVERFLOW;
529 }
530
531 /* get the real fraction part, if exist. */
532 if ((**endptr) == '.')
533 {
534 startptr = (*endptr) + 1;
535 ullFraction = strtoull_s(startptr, endptr, 10);
536 fractionSize = (int)((*endptr) - startptr);
537 if ((ullFraction == ULLONG_MAX) && (errno != 0))
538 {
539 result = FST_OVERFLOW;
540 }
541 }
542
543 if (((**endptr) == 'e') || ((**endptr) == 'E'))
544 {
545 startptr = (*endptr) + 1;
546 (*exponential) = (int)strtol(startptr, endptr, 10);
547 if (((*exponential) < (DBL_MAX_10_EXP * (-1))) || ((*exponential) > DBL_MAX_10_EXP))
548 {
549 result = FST_OVERFLOW;
550 }
551 }
552 else
553 {
554 (*exponential) = 0;
555 }
556
557 if (result == FST_NUMBER)
558 {
559 /* Add ullInteger to ullFraction. */
560 ullFraction += (ullInteger * (unsigned long long)(pow(10, (double)fractionSize)));
561 (*fraction) = ((double)ullFraction / (pow(10.0f, ((double)fractionSize + (double)integerSize - 1.00))));
562
563 /* Unify rest of integerSize and fractionSize in the exponential. */
564 (*exponential) += integerSize - 1;
565 }
566 }
567
568 return result;
569}
570
571/*Codes_SRS_CRT_ABSTRACTIONS_21_015: [The strtof_s must convert the initial portion of the string pointed to by nptr to float representation.]*/
572/*Codes_SRS_CRT_ABSTRACTIONS_21_016: [The strtof_s must return the float that represents the value in the initial part of the string. If any.]*/
573float strtof_s(const char* nptr, char** endptr)
574{
575 int signal = 1;
576 double fraction;
577 int exponential;
578 char* runner = (char*)nptr;
579 double val;
580
581 /*Codes_SRS_CRT_ABSTRACTIONS_21_021: [If no conversion could be performed, the strtof_s returns the value 0.0.]*/
582 float result = 0.0;
583
584 /*Codes_SRS_CRT_ABSTRACTIONS_21_036: [**If the nptr is NULL, the strtof_s must not perform any conversion and must returns 0.0f; endptr must receive NULL, provided that endptr is not a NULL pointer.]*/
585 if (nptr != NULL)
586 {
587 switch (splitFloatString(nptr, &runner, &signal, &fraction, &exponential))
588 {
589 case FST_INFINITY:
590 /*Codes_SRS_CRT_ABSTRACTIONS_21_023: [If the string is 'INF' of 'INFINITY' (ignoring case), the strtof_s must return the INFINITY value for float.]*/
591 result = INFINITY * (signal);
592 errno = 0;
593 break;
594 case FST_NAN:
595 /*Codes_SRS_CRT_ABSTRACTIONS_21_024: [If the string is 'NAN' or 'NAN(...)' (ignoring case), the strtof_s must return 0.0f and points endptr to the first character after the 'NAN' sequence.]*/
596 result = NAN;
597 break;
598 case FST_NUMBER:
599 val = fraction * pow(10.0, (double)exponential) * (double)signal;
600 if ((val >= (FLT_MAX * (-1.0f))) && (val <= FLT_MAX))
601 {
602 /*Codes_SRS_CRT_ABSTRACTIONS_21_016: [The strtof_s must return the float that represents the value in the initial part of the string. If any.]*/
603 result = (float)val;
604 }
605 else
606 {
607 /*Codes_SRS_CRT_ABSTRACTIONS_21_022: [If the correct value is outside the range, the strtof_s returns the value plus or minus HUGE_VALF, and errno will receive the value ERANGE.]*/
608 result = HUGE_VALF * (signal);
609 errno = ERANGE;
610 }
611 break;
612 case FST_OVERFLOW:
613 /*Codes_SRS_CRT_ABSTRACTIONS_21_022: [If the correct value is outside the range, the strtof_s returns the value plus or minus HUGE_VALF, and errno will receive the value ERANGE.]*/
614 result = HUGE_VALF * (signal);
615 errno = ERANGE;
616 break;
617 default:
618 /*Codes_SRS_CRT_ABSTRACTIONS_21_020: [If the subject sequence is empty or does not have the expected form, the strtof_s must not perform any conversion and must returns 0.0f; the value of nptr is stored in the object pointed to by endptr, provided that endptr is not a NULL pointer.]*/
619 runner = (char*)nptr;
620 break;
621 }
622 }
623
624 /*Codes_SRS_CRT_ABSTRACTIONS_21_017: [The strtof_s must return in endptr a final string of one or more unrecognized characters, including the terminating null character of the input string.]*/
625 if (endptr != NULL)
626 {
627 (*endptr) = runner;
628 }
629
630 return result;
631}
632
633/*Codes_SRS_CRT_ABSTRACTIONS_21_025: [The strtold_s must convert the initial portion of the string pointed to by nptr to long double representation.]*/
634/*Codes_SRS_CRT_ABSTRACTIONS_21_026: [The strtold_s must return the long double that represents the value in the initial part of the string. If any.]*/
635long double strtold_s(const char* nptr, char** endptr)
636{
637 int signal = 1;
638 double fraction;
639 int exponential;
640 char* runner = (char*)nptr;
641
642 /*Codes_SRS_CRT_ABSTRACTIONS_21_031: [If no conversion could be performed, the strtold_s returns the value 0.0.]*/
643 long double result = 0.0;
644
645 /*Codes_SRS_CRT_ABSTRACTIONS_21_037: [If the nptr is NULL, the strtold_s must not perform any conversion and must returns 0.0; endptr must receive NULL, provided that endptr is not a NULL pointer.]*/
646 if (nptr != NULL)
647 {
648 switch (splitFloatString(nptr, &runner, &signal, &fraction, &exponential))
649 {
650 case FST_INFINITY:
651 /*Codes_SRS_CRT_ABSTRACTIONS_21_033: [If the string is 'INF' of 'INFINITY' (ignoring case), the strtold_s must return the INFINITY value for long double.]*/
652 result = (long double)INFINITY * (long double)(signal);
653 errno = 0;
654 break;
655 case FST_NAN:
656 /*Codes_SRS_CRT_ABSTRACTIONS_21_034: [If the string is 'NAN' or 'NAN(...)' (ignoring case), the strtold_s must return 0.0 and points endptr to the first character after the 'NAN' sequence.]*/
657 result = (long double)NAN;
658 break;
659 case FST_NUMBER:
660 if ((exponential != DBL_MAX_10_EXP || (fraction <= 1.7976931348623158)) &&
661 (exponential != (DBL_MAX_10_EXP * (-1)) || (fraction <= 2.2250738585072014)))
662 {
663 /*Codes_SRS_CRT_ABSTRACTIONS_21_026: [The strtold_s must return the long double that represents the value in the initial part of the string. If any.]*/
664 result = fraction * pow(10.0, (double)exponential) * (double)signal;
665 }
666 else
667 {
668 /*Codes_SRS_CRT_ABSTRACTIONS_21_032: [If the correct value is outside the range, the strtold_s returns the value plus or minus HUGE_VALL, and errno will receive the value ERANGE.]*/
669 result = (long double)HUGE_VALF * (long double)(signal);
670 errno = ERANGE;
671 }
672 break;
673 case FST_OVERFLOW:
674 /*Codes_SRS_CRT_ABSTRACTIONS_21_032: [If the correct value is outside the range, the strtold_s returns the value plus or minus HUGE_VALL, and errno will receive the value ERANGE.]*/
675 result = (long double)HUGE_VALF * (long double)(signal);
676 errno = ERANGE;
677 break;
678 default:
679 /*Codes_SRS_CRT_ABSTRACTIONS_21_030: [If the subject sequence is empty or does not have the expected form, the strtold_s must not perform any conversion and must returns 0.0; the value of nptr is stored in the object pointed to by endptr, provided that endptr is not a NULL pointer.]*/
680 runner = (char*)nptr;
681 break;
682 }
683 }
684
685 /*Codes_SRS_CRT_ABSTRACTIONS_21_027: [The strtold_s must return in endptr a final string of one or more unrecognized characters, including the terminating null character of the input string.]*/
686 if (endptr != NULL)
687 {
688 (*endptr) = runner;
689 }
690
691 return result;
692}
693
694
695/*Codes_SRS_CRT_ABSTRACTIONS_99_038: [mallocAndstrcpy_s shall allocate memory for destination buffer to fit the string in the source parameter.]*/
696int mallocAndStrcpy_s(char** destination, const char* source)
697{
698 int result;
699 int copied_result;
700 /*Codes_SRS_CRT_ABSTRACTIONS_99_036: [destination parameter or source parameter is NULL, the error code returned shall be EINVAL and destination shall not be modified.]*/
701 if ((destination == NULL) || (source == NULL))
702 {
703 /*If strDestination or strSource is a NULL pointer[...]these functions return EINVAL */
704 result = EINVAL;
705 }
706 else
707 {
708 size_t l = strlen(source);
709 char* temp = (char*)malloc(l + 1);
710
711 /*Codes_SRS_CRT_ABSTRACTIONS_99_037: [Upon failure to allocate memory for the destination, the function will return ENOMEM.]*/
712 if (temp == NULL)
713 {
714 result = ENOMEM;
715 }
716 else
717 {
718 *destination = temp;
719 /*Codes_SRS_CRT_ABSTRACTIONS_99_039: [mallocAndstrcpy_s shall copy the contents in the address source, including the terminating null character into location specified by the destination pointer after the memory allocation.]*/
720 copied_result = strcpy_s(*destination, l + 1, source);
721 if (copied_result < 0) /*strcpy_s error*/
722 {
723 free(*destination);
724 *destination = NULL;
725 result = copied_result;
726 }
727 else
728 {
729 /*Codes_SRS_CRT_ABSTRACTIONS_99_035: [mallocAndstrcpy_s shall return Zero upon success]*/
730 result = 0;
731 }
732 }
733 }
734 return result;
735}
736
737/*takes "value" and transforms it into a decimal string*/
738/*10 => "10"*/
739/*return 0 when everything went ok*/
740/*Codes_SRS_CRT_ABSTRACTIONS_02_001: [unsignedIntToString shall convert the parameter value to its decimal representation as a string in the buffer indicated by parameter destination having the size indicated by parameter destinationSize.] */
741int unsignedIntToString(char* destination, size_t destinationSize, unsigned int value)
742{
743 int result;
744 size_t pos;
745 /*the below loop gets the number in reverse order*/
746 /*Codes_SRS_CRT_ABSTRACTIONS_02_003: [If destination is NULL then unsignedIntToString shall fail.] */
747 /*Codes_SRS_CRT_ABSTRACTIONS_02_002: [If the conversion fails for any reason (for example, insufficient buffer space), a non-zero return value shall be supplied and unsignedIntToString shall fail.] */
748 if (
749 (destination == NULL) ||
750 (destinationSize < 2) /*because the smallest number is '0\0' which requires 2 characters*/
751 )
752 {
753 result = MU_FAILURE;
754 }
755 else
756 {
757 pos = 0;
758 do
759 {
760 destination[pos++] = '0' + (value % 10);
761 value /= 10;
762 } while ((value > 0) && (pos < (destinationSize-1)));
763
764 if (value == 0)
765 {
766 size_t w;
767 destination[pos] = '\0';
768 /*all converted and they fit*/
769 for (w = 0; w <= (pos-1) >> 1; w++)
770 {
771 char temp;
772 temp = destination[w];
773 destination[w] = destination[pos - 1 - w];
774 destination[pos -1 - w] = temp;
775 }
776 /*Codes_SRS_CRT_ABSTRACTIONS_02_004: [If the conversion has been successfull then unsignedIntToString shall return 0.] */
777 result = 0;
778 }
779 else
780 {
781 /*Codes_SRS_CRT_ABSTRACTIONS_02_002: [If the conversion fails for any reason (for example, insufficient buffer space), a non-zero return value shall be supplied and unsignedIntToString shall fail.] */
782 result = MU_FAILURE;
783 }
784 }
785 return result;
786}
787
788/*takes "value" and transforms it into a decimal string*/
789/*10 => "10"*/
790/*return 0 when everything went ok*/
791/*Codes_SRS_CRT_ABSTRACTIONS_02_001: [unsignedIntToString shall convert the parameter value to its decimal representation as a string in the buffer indicated by parameter destination having the size indicated by parameter destinationSize.] */
792int size_tToString(char* destination, size_t destinationSize, size_t value)
793{
794 int result;
795 size_t pos;
796 /*the below loop gets the number in reverse order*/
797 /*Codes_SRS_CRT_ABSTRACTIONS_02_003: [If destination is NULL then unsignedIntToString shall fail.] */
798 /*Codes_SRS_CRT_ABSTRACTIONS_02_002: [If the conversion fails for any reason (for example, insufficient buffer space), a non-zero return value shall be supplied and unsignedIntToString shall fail.] */
799 if (
800 (destination == NULL) ||
801 (destinationSize < 2) /*because the smallest number is '0\0' which requires 2 characters*/
802 )
803 {
804 result = MU_FAILURE;
805 }
806 else
807 {
808 pos = 0;
809 do
810 {
811 destination[pos++] = '0' + (value % 10);
812 value /= 10;
813 } while ((value > 0) && (pos < (destinationSize - 1)));
814
815 if (value == 0)
816 {
817 size_t w;
818 destination[pos] = '\0';
819 /*all converted and they fit*/
820 for (w = 0; w <= (pos - 1) >> 1; w++)
821 {
822 char temp;
823 temp = destination[w];
824 destination[w] = destination[pos - 1 - w];
825 destination[pos - 1 - w] = temp;
826 }
827 /*Codes_SRS_CRT_ABSTRACTIONS_02_004: [If the conversion has been successfull then unsignedIntToString shall return 0.] */
828 result = 0;
829 }
830 else
831 {
832 /*Codes_SRS_CRT_ABSTRACTIONS_02_002: [If the conversion fails for any reason (for example, insufficient buffer space), a non-zero return value shall be supplied and unsignedIntToString shall fail.] */
833 result = MU_FAILURE;
834 }
835 }
836 return result;
837}
Note: See TracBrowser for help on using the repository browser.