Nigel Rantor / azure_c_shared_utility

Fork of azure_c_shared_utility by Azure IoT

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers crt_abstractions.c Source File

crt_abstractions.c

00001 // Copyright (c) Microsoft. All rights reserved.
00002 // Licensed under the MIT license. See LICENSE file in the project root for full license information.
00003 
00004 #define __STDC_WANT_LIB_EXT1__ 1
00005 
00006 #include <stdlib.h>
00007 #include <stddef.h>
00008 #include <stdarg.h>
00009 #include <limits.h>
00010 #include <float.h>
00011 #include <math.h>
00012 #include <errno.h>
00013 #include "azure_c_shared_utility/gballoc.h"
00014 #include "azure_c_shared_utility/optimize_size.h"
00015 #include "azure_c_shared_utility/crt_abstractions.h"
00016 
00017 // VS 2008 does not have INFINITY and all the nice goodies...
00018 #if defined (TIZENRT) || defined (WINCE)
00019 #define DEFINE_INFINITY 1
00020 #else
00021 
00022 #if defined _MSC_VER
00023 #if _MSC_VER <= 1500
00024 #define DEFINE_INFINITY 1
00025 #endif
00026 #endif
00027 #endif
00028 
00029 #if defined DEFINE_INFINITY
00030 
00031 #pragma warning(disable:4756 4056) // warning C4756: overflow in constant arithmetic
00032 
00033 // These defines are missing in math.h for WEC2013 SDK
00034 #ifndef _HUGE_ENUF
00035 #define _HUGE_ENUF  1e+300  // _HUGE_ENUF*_HUGE_ENUF must overflow
00036 #endif
00037 
00038 #define INFINITY   ((float)(_HUGE_ENUF * _HUGE_ENUF))
00039 #define HUGE_VALF  ((float)INFINITY)
00040 #define HUGE_VALL  ((long double)INFINITY)
00041 #define NAN        ((float)(INFINITY * 0.0F))
00042 #endif
00043 
00044 #ifdef _MSC_VER
00045 #else
00046 
00047 /*Codes_SRS_CRT_ABSTRACTIONS_99_008: [strcat_s shall append the src to dst and terminates the resulting string with a null character.]*/
00048 int strcat_s(char* dst, size_t dstSizeInBytes, const char* src)
00049 {
00050     int result;
00051     /*Codes_SRS_CRT_ABSTRACTIONS_99_004: [If dst is NULL or unterminated, the error code returned shall be EINVAL & dst shall not be modified.]*/
00052     if (dst == NULL)
00053     {
00054         result = EINVAL;
00055     }
00056     /*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.]*/
00057     else if (src == NULL)
00058     {
00059         dst[0] = '\0';
00060         result = EINVAL;
00061     }
00062     else
00063     {
00064         /*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.]*/
00065         if (dstSizeInBytes == 0)
00066         {
00067             result = ERANGE;
00068             dst[0] = '\0';
00069         }
00070         else
00071         {
00072             size_t dstStrLen = 0;
00073 #ifdef __STDC_LIB_EXT1__
00074             dstStrLen = strnlen_s(dst, dstSizeInBytes);
00075 #else
00076             size_t i;
00077             for(i=0; (i < dstSizeInBytes) && (dst[i]!= '\0'); i++)
00078             {
00079             }
00080             dstStrLen = i;
00081 #endif
00082             /*Codes_SRS_CRT_ABSTRACTIONS_99_004: [If dst is NULL or unterminated, the error code returned shall be EINVAL & dst shall not be modified.]*/
00083             if (dstSizeInBytes == dstStrLen) /* this means the dst string is not terminated*/
00084             {
00085                 result = EINVAL;
00086             }
00087             else
00088             {
00089                 /*Codes_SRS_CRT_ABSTRACTIONS_99_009: [The initial character of src shall overwrite the terminating null character of dst.]*/
00090                 (void)strncpy(&dst[dstStrLen], src, dstSizeInBytes - dstStrLen);
00091                 /*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.]*/
00092                 if (dst[dstSizeInBytes-1] != '\0')
00093                 {
00094                     dst[0] = '\0';
00095                     result = ERANGE;
00096                 }
00097                 else
00098                 {
00099                     /*Codes_SRS_CRT_ABSTRACTIONS_99_003: [strcat_s shall return Zero upon success.]*/
00100                     result = 0;
00101                 }
00102             }
00103         }
00104     }
00105 
00106     return result;
00107 }
00108 
00109 /*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.]*/
00110 int strncpy_s(char* dst, size_t dstSizeInBytes, const char* src, size_t maxCount)
00111 {
00112     int result;
00113     int truncationFlag = 0;
00114     /*Codes_SRS_CRT_ABSTRACTIONS_99_020: [If dst is NULL, the error code returned shall be EINVAL and dst shall not be modified.]*/
00115     if (dst == NULL)
00116     {
00117         result = EINVAL;
00118     }
00119     /*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.]*/
00120     else if (src == NULL)
00121     {
00122         dst[0] = '\0';
00123         result = EINVAL;
00124     }
00125     /*Codes_SRS_CRT_ABSTRACTIONS_99_022: [If the dstSizeInBytes is 0, the error code returned shall be EINVAL and dst shall not be modified.]*/
00126     else if (dstSizeInBytes == 0)
00127     {
00128         result = EINVAL;
00129     }
00130     else 
00131     {
00132         size_t srcLength = strlen(src);
00133         if (maxCount != _TRUNCATE)
00134         {
00135             /*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.]*/
00136             if (srcLength > maxCount)
00137             {
00138                 srcLength = maxCount;
00139             }
00140 
00141             /*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.]*/
00142             if (srcLength + 1 > dstSizeInBytes)
00143             {
00144                 dst[0] = '\0';
00145                 result = ERANGE;
00146             }
00147             else
00148             {
00149                 (void)strncpy(dst, src, srcLength);
00150                 dst[srcLength] = '\0';
00151                 /*Codes_SRS_CRT_ABSTRACTIONS_99_018: [strncpy_s shall return Zero upon success]*/
00152                 result = 0;
00153             }
00154         }
00155         /*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.]*/
00156         else
00157         {
00158             if (srcLength + 1 > dstSizeInBytes )
00159             {
00160                 srcLength = dstSizeInBytes - 1;
00161                 truncationFlag = 1;
00162             }
00163             (void)strncpy(dst, src, srcLength);
00164             dst[srcLength] = '\0';
00165             result = 0;
00166         }
00167     }
00168 
00169     /*Codes_SRS_CRT_ABSTRACTIONS_99_019: [If truncation occurred as a result of the copy, the error code returned shall be STRUNCATE.]*/
00170     if (truncationFlag == 1)
00171     {
00172         result = STRUNCATE;
00173     }
00174 
00175     return result;
00176 }
00177 
00178 /* 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.]*/
00179 int strcpy_s(char* dst, size_t dstSizeInBytes, const char* src)
00180 {
00181     int result;
00182 
00183     /* Codes_SRS_CRT_ABSTRACTIONS_99_012: [If dst is NULL, the error code returned shall be EINVAL & dst shall not be modified.]*/
00184     if (dst == NULL)
00185     {
00186         result = EINVAL;
00187     }
00188     /* 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.]*/
00189     else if (src == NULL)
00190     {
00191         dst[0] = '\0';
00192         result = EINVAL;
00193     }
00194     /* 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.]*/
00195     else if (dstSizeInBytes == 0)
00196     {
00197         dst[0] = '\0';
00198         result = ERANGE;
00199     }
00200     else
00201     {
00202         size_t neededBuffer = strlen(src);
00203         /* 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.]*/
00204         if (neededBuffer + 1 > dstSizeInBytes)
00205         {
00206             dst[0] = '\0';
00207             result = ERANGE;
00208         }
00209         else
00210         {
00211             (void)memcpy(dst, src, neededBuffer + 1);
00212             /*Codes_SRS_CRT_ABSTRACTIONS_99_011: [strcpy_s shall return Zero upon success]*/
00213             result = 0;
00214         }
00215     }
00216 
00217     return result;
00218 }
00219 
00220 /*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.]*/
00221 /*Codes_SRS_CRT_ABSTRACTIONS_99_031: [A null character is appended after the last character written.]*/
00222 int sprintf_s(char* dst, size_t dstSizeInBytes, const char* format, ...)
00223 {
00224     int result;
00225     /*Codes_SRS_CRT_ABSTRACTIONS_99_028: [If dst or format is a null pointer, sprintf_s shall return -1 and set errno to EINVAL]*/
00226     if ((dst == NULL) ||
00227         (format == NULL))
00228     {
00229         errno = EINVAL;
00230         result = -1;
00231     }
00232     else
00233     {
00234         /*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.]*/
00235 
00236 #if defined _MSC_VER 
00237 #error crt_abstractions is not provided for Microsoft Compilers
00238 #else
00239         /*not Microsoft compiler... */
00240 #if defined (__STDC_VERSION__) || (__cplusplus)
00241 #if ( \
00242         ((__STDC_VERSION__  == 199901L) || (__STDC_VERSION__ == 201000L) || (__STDC_VERSION__ == 201112L)) || \
00243         (defined __cplusplus) \
00244     )
00245         /*C99 compiler*/
00246         va_list args;
00247         va_start(args, format);
00248         /*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.]*/
00249         result = vsnprintf(dst, dstSizeInBytes, format, args);
00250         va_end(args);
00251 
00252         /*C99: Thus, the null-terminated output has been completely written if and only if the returned value is nonnegative and less than n*/
00253         if (result < 0)
00254         {
00255             result = -1;
00256         }
00257         else if ((size_t)result >= dstSizeInBytes)
00258         {
00259             /*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.]*/
00260             dst[0] = '\0';
00261             result = -1;
00262         }
00263         else
00264         {
00265             /*do nothing, all is fine*/
00266         }
00267 #else
00268 #error STDC_VERSION defined, but of unknown value; unable to sprinf_s, or provide own implementation
00269 #endif
00270 #else
00271 #error for STDC_VERSION undefined (assumed C89), provide own implementation of sprintf_s
00272 #endif
00273 #endif
00274     }
00275     return result;
00276 }
00277 #endif /* _MSC_VER */
00278 
00279 /*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.]*/
00280 /* returns the integer value that correspond to the character 'c'. If the character is invalid, it returns -1. */
00281 #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)
00282 #define IN_BASE_RANGE(d, b)  ((d >= 0) && (d < b))
00283 
00284 /*Codes_SRS_CRT_ABSTRACTIONS_21_010: [The white-space must be one of the characters ' ', '\f', '\n', '\r', '\t', '\v'.]*/
00285 #define IS_SPACE(c)           (c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v')
00286 
00287 /*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.]*/
00288 /*Codes_SRS_CRT_ABSTRACTIONS_21_002: [The strtoull_s must resembling an integer represented in some radix determined by the value of base.]*/
00289 /*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.]*/
00290 unsigned long long strtoull_s(const char* nptr, char** endptr, int base)
00291 {
00292     unsigned long long result = 0ULL;
00293     bool validStr = true;
00294     char* runner = (char*)nptr;
00295     bool isNegative = false;
00296     int digitVal;
00297 
00298     /*Codes_SRS_CRT_ABSTRACTIONS_21_005: [The strtoull_s must convert number using base 2 to 36.]*/
00299     /*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.]*/
00300     /*Codes_SRS_CRT_ABSTRACTIONS_21_013: [If no conversion could be performed, the strtoull_s returns the value 0L.]*/
00301     /*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.]*/
00302         if (((base >= 2) || (base == 0)) && (base <= 36) && (runner != NULL))
00303     {
00304         /*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).]*/
00305         /*Codes_SRS_CRT_ABSTRACTIONS_21_010: [The white-space must be one of the characters ' ', '\f', '\n', '\r', '\t', '\v'.]*/
00306         while (IS_SPACE(*runner))
00307         {
00308             runner++;
00309         }
00310         if ((*runner) == '+')
00311         {
00312             runner++;
00313         }
00314         else if ((*runner) == '-')
00315         {
00316             /*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.]*/
00317             isNegative = true;
00318             runner++;
00319         }
00320 
00321         if ((*runner) == '0')
00322         {
00323             if ((*(runner+1) == 'x') || (*(runner+1) == 'X'))
00324             {
00325                 /*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).]*/
00326                 /* hexadecimal... */
00327                 if ((base == 0) || (base == 16))
00328                 {
00329                     base = 16;
00330                     runner += 2;
00331                 }
00332             }
00333             else if((base == 0) || (base == 8))
00334             {
00335                 /*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).]*/
00336                 /* octal... */
00337                 base = 8;
00338                 runner++;
00339             }
00340         }
00341         
00342         if(base == 0)
00343         {
00344             /*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).]*/
00345             /* decimal... */
00346             base = 10;
00347         }
00348 
00349         digitVal = DIGIT_VAL(*runner);
00350         if (validStr && IN_BASE_RANGE(digitVal, base))
00351         {
00352             errno = 0;
00353             do
00354             {
00355                 if (((ULLONG_MAX - digitVal) / base) < result)
00356                 {
00357                     /*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.]*/
00358                     /* overflow... */
00359                     result = ULLONG_MAX;
00360                     errno = ERANGE;
00361                 }
00362                 else
00363                 {
00364                     result = result * base + digitVal;
00365                 }
00366                 runner++;
00367                 digitVal = DIGIT_VAL(*runner);
00368             } while (IN_BASE_RANGE(digitVal, base));
00369         }
00370         else
00371         {
00372             runner = (char*)nptr;
00373         }
00374     }
00375 
00376     /*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.]*/
00377     if (endptr != NULL)
00378     {
00379         (*endptr) = (char*)runner;
00380     }
00381 
00382     /*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.]*/
00383     if (isNegative)
00384     {
00385         result = ULLONG_MAX - result + 1;
00386     }
00387 
00388     return result;
00389 }
00390 
00391 /*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.]*/
00392 /*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.]*/
00393 /*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.]*/
00394 /*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.]*/
00395 static int substricmp(const char* nptr, const char* subsrt)
00396 {
00397     int result = 0;
00398     while (((*subsrt) != '\0') && (result == 0))
00399     {
00400         result = TOUPPER(*nptr) - TOUPPER(*subsrt);
00401         nptr++;
00402         subsrt++;
00403     }
00404     return result;
00405 }
00406 
00407 /*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.]*/
00408 /*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.]*/
00409 static bool isInfinity(const char** endptr)
00410 {
00411     bool result = false;
00412     if (substricmp((*endptr), "INF") == 0)
00413     {
00414         (*endptr) += 3;
00415         result = true;
00416         if (substricmp((*endptr), "INITY") == 0)
00417         {
00418             (*endptr) += 5;
00419         }
00420     }
00421     return result;
00422 }
00423 
00424 /*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.]*/
00425 /*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.]*/
00426 static bool isNaN(const char** endptr)
00427 {
00428     const char* runner = (*endptr);
00429     bool result = false;
00430     if (substricmp(runner, "NAN") == 0)
00431     {
00432         runner += 3;
00433         result = true;
00434         if ((*runner) == '(')
00435         {
00436             do
00437             {
00438                 runner++;
00439             } while (((*runner) != '\0') && ((*runner) != ')'));
00440             if ((*runner) == ')')
00441                 runner++;
00442             else
00443                 result = false;
00444         }
00445     }
00446     if (result)
00447         (*endptr) = runner;
00448     return result;
00449 }
00450 
00451 #define FLOAT_STRING_TYPE_VALUES    \
00452             FST_INFINITY,           \
00453             FST_NAN,                \
00454             FST_NUMBER,             \
00455             FST_OVERFLOW,           \
00456             FST_ERROR
00457 
00458 DEFINE_ENUM(FLOAT_STRING_TYPE, FLOAT_STRING_TYPE_VALUES);
00459 
00460 static FLOAT_STRING_TYPE splitFloatString(const char* nptr, char** endptr, int *signal, double *fraction, int *exponential)
00461 {
00462     FLOAT_STRING_TYPE result = FST_ERROR;
00463 
00464     unsigned long long ullInteger = 0;
00465     unsigned long long ullFraction = 0;
00466     int integerSize = 0;
00467     int fractionSize = 0;
00468     char* startptr;
00469 
00470     (*endptr) = (char*)nptr;
00471 
00472     /*Codes_SRS_CRT_ABSTRACTIONS_21_018: [The white-space for strtof_s must be one of the characters ' ', '\f', '\n', '\r', '\t', '\v'.]*/
00473     /*Codes_SRS_CRT_ABSTRACTIONS_21_028: [The white-space for strtold_s must be one of the characters ' ', '\f', '\n', '\r', '\t', '\v'.]*/
00474     while (IS_SPACE(**endptr))
00475     {
00476         (*endptr)++;
00477     }
00478 
00479     /*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).]*/
00480     /*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).]*/
00481     (*signal) = +1;
00482     if ((**endptr) == '+')
00483     {
00484         (*endptr)++;
00485     }
00486     else if ((**endptr) == '-')
00487     {
00488         (*signal) = -1;
00489         (*endptr)++;
00490     }
00491 
00492     /*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.]*/
00493     /*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.]*/
00494     if (isInfinity((const char**)endptr))
00495     {
00496         result = FST_INFINITY;
00497     }
00498     /*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.]*/
00499     /*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.]*/
00500     else if (isNaN((const char**)endptr))
00501     {
00502         result = FST_NAN;
00503     }
00504     else if (IN_BASE_RANGE(DIGIT_VAL(**endptr), 10))
00505     {
00506         result = FST_NUMBER;
00507         startptr = *endptr;
00508         /* integers will go to the fraction and exponential. */
00509         ullInteger = strtoull_s(startptr, endptr, 10);
00510         integerSize = (int)((*endptr) - startptr);
00511         if ((ullInteger == ULLONG_MAX) && (errno != 0))
00512         {
00513             result = FST_OVERFLOW;
00514         }
00515 
00516         /* get the real fraction part, if exist. */
00517         if ((**endptr) == '.')
00518         {
00519             startptr = (*endptr) + 1;
00520             ullFraction = strtoull_s(startptr, endptr, 10);
00521             fractionSize = (int)((*endptr) - startptr);
00522             if ((ullFraction == ULLONG_MAX) && (errno != 0))
00523             {
00524                 result = FST_OVERFLOW;
00525             }
00526         }
00527         
00528         if (((**endptr) == 'e') || ((**endptr) == 'E'))
00529         {
00530             startptr = (*endptr) + 1;
00531             (*exponential) = strtol(startptr, endptr, 10);
00532             if (((*exponential) < (DBL_MAX_10_EXP * (-1))) || ((*exponential) > DBL_MAX_10_EXP))
00533             {
00534                 result = FST_OVERFLOW;
00535             }
00536         }
00537         else
00538         {
00539             (*exponential) = 0;
00540         }
00541 
00542         if (result == FST_NUMBER)
00543         {
00544             /* Add ullInteger to ullFraction. */
00545             ullFraction += (ullInteger * (unsigned long long)(pow(10, (double)fractionSize)));
00546             (*fraction) = ((double)ullFraction / (pow(10.0f, (double)(fractionSize + integerSize - 1))));
00547 
00548             /* Unify rest of integerSize and fractionSize in the exponential. */
00549             (*exponential) += integerSize - 1;
00550         }
00551     }
00552 
00553     return result;
00554 }
00555 
00556 /*Codes_SRS_CRT_ABSTRACTIONS_21_015: [The strtof_s must convert the initial portion of the string pointed to by nptr to float representation.]*/
00557 /*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.]*/
00558 float strtof_s(const char* nptr, char** endptr)
00559 {
00560     int signal = 1;
00561     double fraction;
00562     int exponential;
00563     char* runner = (char*)nptr;
00564     double val;
00565 
00566     /*Codes_SRS_CRT_ABSTRACTIONS_21_021: [If no conversion could be performed, the strtof_s returns the value 0.0.]*/
00567     float result = 0.0;
00568 
00569     /*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.]*/
00570     if (nptr != NULL)
00571     {
00572         switch (splitFloatString(nptr, &runner, &signal, &fraction, &exponential))
00573         {
00574         case FST_INFINITY:
00575             /*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.]*/
00576             result = INFINITY * (signal);
00577             errno = 0;
00578             break;
00579         case FST_NAN:
00580             /*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.]*/
00581             result = NAN;
00582             break;
00583         case FST_NUMBER:
00584             val = fraction * pow(10.0, (double)exponential) * (double)signal;
00585             if ((val >= (FLT_MAX * (-1))) && (val <= FLT_MAX))
00586             {
00587                 /*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.]*/
00588                 result = (float)val;
00589             }
00590             else
00591             {
00592                 /*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.]*/
00593                 result = HUGE_VALF * (signal);
00594                 errno = ERANGE;
00595             }
00596             break;
00597         case FST_OVERFLOW:
00598             /*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.]*/
00599             result = HUGE_VALF * (signal);
00600             errno = ERANGE;
00601             break;
00602         default:
00603             /*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.]*/
00604             runner = (char*)nptr;
00605             break;
00606         }
00607     }
00608 
00609     /*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.]*/
00610     if (endptr != NULL)
00611     {
00612         (*endptr) = runner;
00613     }
00614 
00615     return result;
00616 }
00617 
00618 /*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.]*/
00619 /*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.]*/
00620 long double strtold_s(const char* nptr, char** endptr)
00621 {
00622     int signal = 1;
00623     double fraction;
00624     int exponential;
00625     char* runner = (char*)nptr;
00626 
00627     /*Codes_SRS_CRT_ABSTRACTIONS_21_031: [If no conversion could be performed, the strtold_s returns the value 0.0.]*/
00628     long double result = 0.0;
00629 
00630     /*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.]*/
00631     if (nptr != NULL)
00632     {
00633         switch (splitFloatString(nptr, &runner, &signal, &fraction, &exponential))
00634         {
00635         case FST_INFINITY:
00636             /*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.]*/
00637             result = INFINITY * (signal);
00638             errno = 0;
00639             break;
00640         case FST_NAN:
00641             /*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.]*/
00642             result = NAN;
00643             break;
00644         case FST_NUMBER:
00645             if ((exponential != DBL_MAX_10_EXP || (fraction <= 1.7976931348623158)) &&
00646                 (exponential != (DBL_MAX_10_EXP * (-1)) || (fraction <= 2.2250738585072014)))
00647             {
00648                 /*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.]*/
00649                 result = fraction * pow(10.0, (double)exponential) * (double)signal;
00650             }
00651             else
00652             {
00653                 /*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.]*/
00654                 result = HUGE_VALF * (signal);
00655                 errno = ERANGE;
00656             }
00657             break;
00658         case FST_OVERFLOW:
00659             /*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.]*/
00660             result = HUGE_VALF * (signal);
00661             errno = ERANGE;
00662             break;
00663         default:
00664             /*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.]*/
00665             runner = (char*)nptr;
00666             break;
00667         }
00668     }
00669 
00670     /*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.]*/
00671     if (endptr != NULL)
00672     {
00673         (*endptr) = runner;
00674     }
00675 
00676     return result;
00677 }
00678 
00679 
00680 /*Codes_SRS_CRT_ABSTRACTIONS_99_038: [mallocAndstrcpy_s shall allocate memory for destination buffer to fit the string in the source parameter.]*/
00681 int mallocAndStrcpy_s(char** destination, const char* source)
00682 {
00683     int result;
00684     int copied_result;
00685     /*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.]*/
00686     if ((destination == NULL) || (source == NULL))
00687     {
00688         /*If strDestination or strSource is a NULL pointer[...]these functions return EINVAL */
00689         result = EINVAL;
00690     }
00691     else
00692     {
00693         size_t l = strlen(source);
00694         char* temp = (char*)malloc(l + 1);
00695         
00696         /*Codes_SRS_CRT_ABSTRACTIONS_99_037: [Upon failure to allocate memory for the destination, the function will return ENOMEM.]*/
00697         if (temp == NULL)
00698         {
00699             result = ENOMEM;
00700         }
00701         else
00702         {
00703             *destination = temp;
00704             /*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.]*/
00705             copied_result = strcpy_s(*destination, l + 1, source);
00706             if (copied_result < 0) /*strcpy_s error*/
00707             {
00708                 free(*destination);
00709                 *destination = NULL;
00710                 result = copied_result;
00711             }
00712             else
00713             {
00714                 /*Codes_SRS_CRT_ABSTRACTIONS_99_035: [mallocAndstrcpy_s shall return Zero upon success]*/
00715                 result = 0;
00716             }
00717         }
00718     }
00719     return result;
00720 }
00721 
00722 /*takes "value" and transforms it into a decimal string*/
00723 /*10 => "10"*/
00724 /*return 0 when everything went ok*/
00725 /*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.] */
00726 int unsignedIntToString(char* destination, size_t destinationSize, unsigned int value)
00727 {
00728     int result;
00729     size_t pos;
00730     /*the below loop gets the number in reverse order*/
00731     /*Codes_SRS_CRT_ABSTRACTIONS_02_003: [If destination is NULL then unsignedIntToString shall fail.] */
00732     /*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.] */
00733     if (
00734         (destination == NULL) ||
00735         (destinationSize < 2) /*because the smallest number is '0\0' which requires 2 characters*/
00736         )
00737     {
00738         result = __FAILURE__;
00739     }
00740     else
00741     {
00742         pos = 0;
00743         do
00744         {
00745             destination[pos++] = '0' + (value % 10);
00746             value /= 10;
00747         } while ((value > 0) && (pos < (destinationSize-1)));
00748 
00749         if (value == 0)
00750         {
00751             size_t w;
00752             destination[pos] = '\0';
00753             /*all converted and they fit*/
00754             for (w = 0; w <= (pos-1) >> 1; w++)
00755             {
00756                 char temp;
00757                 temp = destination[w];
00758                 destination[w] = destination[pos - 1 - w];
00759                 destination[pos -1 - w] = temp;
00760             }
00761             /*Codes_SRS_CRT_ABSTRACTIONS_02_004: [If the conversion has been successfull then unsignedIntToString shall return 0.] */
00762             result = 0;
00763         }
00764         else
00765         {
00766             /*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.] */
00767             result = __FAILURE__;
00768         }
00769     }
00770     return result;
00771 }
00772 
00773 /*takes "value" and transforms it into a decimal string*/
00774 /*10 => "10"*/
00775 /*return 0 when everything went ok*/
00776 /*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.] */
00777 int size_tToString(char* destination, size_t destinationSize, size_t value)
00778 {
00779     int result;
00780     size_t pos;
00781     /*the below loop gets the number in reverse order*/
00782     /*Codes_SRS_CRT_ABSTRACTIONS_02_003: [If destination is NULL then unsignedIntToString shall fail.] */
00783     /*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.] */
00784     if (
00785         (destination == NULL) ||
00786         (destinationSize < 2) /*because the smallest number is '0\0' which requires 2 characters*/
00787         )
00788     {
00789         result = __FAILURE__;
00790     }
00791     else
00792     {
00793         pos = 0;
00794         do
00795         {
00796             destination[pos++] = '0' + (value % 10);
00797             value /= 10;
00798         } while ((value > 0) && (pos < (destinationSize - 1)));
00799 
00800         if (value == 0)
00801         {
00802             size_t w;
00803             destination[pos] = '\0';
00804             /*all converted and they fit*/
00805             for (w = 0; w <= (pos - 1) >> 1; w++)
00806             {
00807                 char temp;
00808                 temp = destination[w];
00809                 destination[w] = destination[pos - 1 - w];
00810                 destination[pos - 1 - w] = temp;
00811             }
00812             /*Codes_SRS_CRT_ABSTRACTIONS_02_004: [If the conversion has been successfull then unsignedIntToString shall return 0.] */
00813             result = 0;
00814         }
00815         else
00816         {
00817             /*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.] */
00818             result = __FAILURE__;
00819         }
00820     }
00821     return result;
00822 }