Demo using MBED TLS

Dependencies:   EthernetInterface NTPClient iothub_amqp_transport iothub_client mbed-rtos mbed

Fork of iothub_client_sample_amqp by Azure IoT

Committer:
markrad
Date:
Thu Jan 05 00:20:03 2017 +0000
Revision:
58:f50b97b08851
Sample using MBED TLS

Who changed what in which revision?

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