Azure IoT common library

Dependents:   STM32F746_iothub_client_sample_mqtt f767zi_mqtt iothub_client_sample_amqp iothub_client_sample_http ... more

Revision:
7:1af47e3a19b6
Parent:
6:c55b013dfc2a
Child:
11:77df6d7e65ae
--- a/crt_abstractions.c	Fri Jul 01 10:43:23 2016 -0700
+++ b/crt_abstractions.c	Fri Jul 29 16:01:07 2016 -0700
@@ -13,6 +13,25 @@
 #include "errno.h"
 #include <stddef.h>
 #include <limits.h>
+#include <float.h>
+#include <math.h>
+
+
+#ifdef WINCE
+#pragma warning(disable:4756) // warning C4756: overflow in constant arithmetic
+
+// These defines are missing in math.h for WEC2013 SDK
+#ifndef _HUGE_ENUF
+#define _HUGE_ENUF  1e+300  // _HUGE_ENUF*_HUGE_ENUF must overflow
+#endif
+
+#define INFINITY   ((float)(_HUGE_ENUF * _HUGE_ENUF))
+#define HUGE_VALF  ((float)INFINITY)
+#define HUGE_VALL  ((long double)INFINITY)
+#define NAN        ((float)(INFINITY * 0.0F))
+#endif
+
+
 
 #ifdef _MSC_VER
 #else
@@ -251,14 +270,417 @@
 }
 #endif /* _MSC_VER */
 
+/*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.]*/
+/* returns the integer value that correspond to the character 'c'. If the character is invalid, it returns -1. */
+#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)
+#define IN_BASE_RANGE(d, b)  ((d >= 0) && (d < b))
+
+/*Codes_SRS_CRT_ABSTRACTIONS_21_010: [The white-space must be one of the characters ' ', '\f', '\n', '\r', '\t', '\v'.]*/
+#define IS_SPACE(c)           (c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v')
+
+/*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.]*/
+/*Codes_SRS_CRT_ABSTRACTIONS_21_002: [The strtoull_s must resembling an integer represented in some radix determined by the value of base.]*/
+/*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.]*/
+unsigned long long strtoull_s(const char* nptr, char** endptr, int base)
+{
+    unsigned long long result = 0ULL;
+    bool validStr = true;
+    char* runner = (char*)nptr;
+    bool isNegative = false;
+	int digitVal;
+
+    /*Codes_SRS_CRT_ABSTRACTIONS_21_005: [The strtoull_s must convert number using base 2 to 36.]*/
+    /*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.]*/
+    /*Codes_SRS_CRT_ABSTRACTIONS_21_013: [If no conversion could be performed, the strtoull_s returns the value 0L.]*/
+    /*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.]*/
+        if (((base >= 2) || (base == 0)) && (base <= 36) && (runner != NULL))
+    {
+        /*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).]*/
+        /*Codes_SRS_CRT_ABSTRACTIONS_21_010: [The white-space must be one of the characters ' ', '\f', '\n', '\r', '\t', '\v'.]*/
+        while (IS_SPACE(*runner))
+        {
+            runner++;
+        }
+        if ((*runner) == '+')
+        {
+            runner++;
+        }
+        else if ((*runner) == '-')
+        {
+            /*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.]*/
+            isNegative = true;
+            runner++;
+        }
+
+        if ((*runner) == '0')
+        {
+            if ((*(runner+1) == 'x') || (*(runner+1) == 'X'))
+            {
+                /*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).]*/
+                /* hexadecimal... */
+                if ((base == 0) || (base == 16))
+                {
+                    base = 16;
+                    runner += 2;
+                }
+            }
+            else if((base == 0) || (base == 8))
+            {
+                /*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).]*/
+                /* octal... */
+                base = 8;
+                runner++;
+            }
+        }
+        
+        if(base == 0)
+        {
+            /*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).]*/
+            /* decimal... */
+            base = 10;
+        }
+
+        digitVal = DIGIT_VAL(*runner);
+        if (validStr && IN_BASE_RANGE(digitVal, base))
+        {
+            errno = 0;
+            do
+            {
+                if (((ULLONG_MAX - digitVal) / base) < result)
+                {
+                    /*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.]*/
+                    /* overflow... */
+                    result = ULLONG_MAX;
+                    errno = ERANGE;
+                }
+                else
+                {
+                    result = result * base + digitVal;
+                }
+                runner++;
+                digitVal = DIGIT_VAL(*runner);
+            } while (IN_BASE_RANGE(digitVal, base));
+        }
+        else
+        {
+            runner = (char*)nptr;
+        }
+    }
+
+    /*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.]*/
+    if (endptr != NULL)
+    {
+        (*endptr) = (char*)runner;
+    }
+
+    /*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.]*/
+    if (isNegative)
+    {
+        result = ULLONG_MAX - result + 1;
+    }
+
+    return result;
+}
+
+/*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.]*/
+/*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.]*/
+/*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.]*/
+/*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.]*/
+#define TOUPPER(c)      (((c>='a') && (c<='z'))?c-'a'+'A':c)
+static int substricmp(const char* nptr, char* subsrt)
+{
+    int result = 0;
+    while (((*subsrt) != '\0') && (result == 0))
+    {
+        result = TOUPPER(*nptr) - TOUPPER(*subsrt);
+        nptr++;
+        subsrt++;
+    }
+    return result;
+}
+
+/*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.]*/
+/*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.]*/
+static bool isInfinity(const char** endptr)
+{
+    bool result = false;
+    if (substricmp((*endptr), "INF") == 0)
+    {
+        (*endptr) += 3;
+        result = true;
+        if (substricmp((*endptr), "INITY") == 0)
+        {
+            (*endptr) += 5;
+        }
+    }
+    return result;
+}
+
+/*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.]*/
+/*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.]*/
+static bool isNaN(const char** endptr)
+{
+    const char* runner = (*endptr);
+    bool result = false;
+    if (substricmp(runner, "NAN") == 0)
+    {
+        runner += 3;
+        result = true;
+        if ((*runner) == '(')
+        {
+            do
+            {
+                runner++;
+            } while (((*runner) != '\0') && ((*runner) != ')'));
+            if ((*runner) == ')')
+                runner++;
+            else
+                result = false;
+        }
+    }
+    if (result)
+        (*endptr) = runner;
+    return result;
+}
+
+typedef enum
+{
+    FST_INFINITY,
+    FST_NAN,
+    FST_NUMBER,
+    FST_OVERFLOW,
+    FST_ERROR
+} FLOAT_STRING_TYPE;
+
+static FLOAT_STRING_TYPE splitFloatString(const char* nptr, char** endptr, int *signal, double *fraction, int *exponential)
+{
+    FLOAT_STRING_TYPE result = FST_ERROR;
+
+    unsigned long long ullInteger = 0;
+    unsigned long long ullFraction = 0;
+    int integerSize = 0;
+    int fractionSize = 0;
+	char* startptr;
+
+    (*endptr) = (char*)nptr;
+
+    /*Codes_SRS_CRT_ABSTRACTIONS_21_018: [The white-space for strtof_s must be one of the characters ' ', '\f', '\n', '\r', '\t', '\v'.]*/
+    /*Codes_SRS_CRT_ABSTRACTIONS_21_028: [The white-space for strtold_s must be one of the characters ' ', '\f', '\n', '\r', '\t', '\v'.]*/
+    while (IS_SPACE(**endptr))
+    {
+        (*endptr)++;
+    }
+
+    /*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).]*/
+    /*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).]*/
+    (*signal) = +1;
+    if ((**endptr) == '+')
+    {
+        (*endptr)++;
+    }
+    else if ((**endptr) == '-')
+    {
+        (*signal) = -1;
+        (*endptr)++;
+    }
+
+    /*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.]*/
+    /*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.]*/
+    if (isInfinity((const char**)endptr))
+    {
+        result = FST_INFINITY;
+    }
+    /*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.]*/
+    /*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.]*/
+    else if (isNaN((const char**)endptr))
+    {
+        result = FST_NAN;
+    }
+    else if (IN_BASE_RANGE(DIGIT_VAL(**endptr), 10))
+    {
+        result = FST_NUMBER;
+        startptr = *endptr;
+        /* integers will go to the fraction and exponential. */
+        ullInteger = strtoull_s(startptr, endptr, 10);
+        integerSize = (int)((*endptr) - startptr);
+        if ((ullInteger == ULLONG_MAX) && (errno != 0))
+        {
+            result = FST_OVERFLOW;
+        }
+
+        /* get the real fraction part, if exist. */
+        if ((**endptr) == '.')
+        {
+            startptr = (*endptr) + 1;
+            ullFraction = strtoull_s(startptr, endptr, 10);
+            fractionSize = (int)((*endptr) - startptr);
+            if ((ullFraction == ULLONG_MAX) && (errno != 0))
+            {
+                result = FST_OVERFLOW;
+            }
+        }
+        
+        if (((**endptr) == 'e') || ((**endptr) == 'E'))
+        {
+            startptr = (*endptr) + 1;
+            (*exponential) = strtol(startptr, endptr, 10);
+            if (((*exponential) < (DBL_MAX_10_EXP * (-1))) || ((*exponential) > DBL_MAX_10_EXP))
+            {
+                result = FST_OVERFLOW;
+            }
+        }
+        else
+        {
+            (*exponential) = 0;
+        }
+
+        if (result == FST_NUMBER)
+        {
+            /* Add ullInteger to ullFraction. */
+            ullFraction += (ullInteger * (unsigned long long)(pow(10, (double)fractionSize)));
+            (*fraction) = ((double)ullFraction / (pow(10.0f, (double)(fractionSize + integerSize - 1))));
+
+            /* Unify rest of integerSize and fractionSize in the exponential. */
+            (*exponential) += integerSize - 1;
+        }
+    }
+
+    return result;
+}
+
+/*Codes_SRS_CRT_ABSTRACTIONS_21_015: [The strtof_s must convert the initial portion of the string pointed to by nptr to float representation.]*/
+/*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.]*/
+float strtof_s(const char* nptr, char** endptr)
+{
+    int signal = 1;
+    double fraction;
+    int exponential;
+    char* runner = (char*)nptr;
+    double val;
+
+    /*Codes_SRS_CRT_ABSTRACTIONS_21_021: [If no conversion could be performed, the strtof_s returns the value 0.0.]*/
+    float result = 0.0;
+
+    /*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.]*/
+    if (nptr != NULL)
+    {
+        switch (splitFloatString(nptr, &runner, &signal, &fraction, &exponential))
+        {
+        case FST_INFINITY:
+            /*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.]*/
+            result = INFINITY * (signal);
+            errno = 0;
+            break;
+        case FST_NAN:
+            /*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.]*/
+            result = NAN;
+            break;
+        case FST_NUMBER:
+            val = fraction * pow(10.0, (double)exponential) * (double)signal;
+            if ((val >= (FLT_MAX * (-1))) && (val <= FLT_MAX))
+            {
+                /*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.]*/
+                result = (float)val;
+            }
+            else
+            {
+                /*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.]*/
+                result = HUGE_VALF * (signal);
+                errno = ERANGE;
+            }
+            break;
+        case FST_OVERFLOW:
+            /*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.]*/
+            result = HUGE_VALF * (signal);
+            errno = ERANGE;
+            break;
+        default:
+            /*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.]*/
+            runner = (char*)nptr;
+            break;
+        }
+    }
+
+    /*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.]*/
+    if (endptr != NULL)
+    {
+        (*endptr) = runner;
+    }
+
+    return result;
+}
+
+/*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.]*/
+/*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.]*/
+long double strtold_s(const char* nptr, char** endptr)
+{
+    int signal = 1;
+    double fraction;
+    int exponential;
+    char* runner = (char*)nptr;
+
+    /*Codes_SRS_CRT_ABSTRACTIONS_21_031: [If no conversion could be performed, the strtold_s returns the value 0.0.]*/
+    long double result = 0.0;
+
+    /*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.]*/
+    if (nptr != NULL)
+    {
+        switch (splitFloatString(nptr, &runner, &signal, &fraction, &exponential))
+        {
+        case FST_INFINITY:
+            /*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.]*/
+            result = INFINITY * (signal);
+            errno = 0;
+            break;
+        case FST_NAN:
+            /*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.]*/
+            result = NAN;
+            break;
+        case FST_NUMBER:
+            if ((exponential != DBL_MAX_10_EXP || (fraction <= 1.7976931348623158)) &&
+                (exponential != (DBL_MAX_10_EXP * (-1)) || (fraction <= 2.2250738585072014)))
+            {
+                /*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.]*/
+                result = fraction * pow(10.0, (double)exponential) * (double)signal;
+            }
+            else
+            {
+                /*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.]*/
+                result = HUGE_VALF * (signal);
+                errno = ERANGE;
+            }
+            break;
+        case FST_OVERFLOW:
+            /*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.]*/
+            result = HUGE_VALF * (signal);
+            errno = ERANGE;
+            break;
+        default:
+            /*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.]*/
+            runner = (char*)nptr;
+            break;
+        }
+    }
+
+    /*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.]*/
+    if (endptr != NULL)
+    {
+        (*endptr) = runner;
+    }
+
+    return result;
+}
+
+
 /*Codes_SRS_CRT_ABSTRACTIONS_99_038: [mallocAndstrcpy_s shall allocate memory for destination buffer to fit the string in the source parameter.]*/
 int mallocAndStrcpy_s(char** destination, const char* source)
 {
     int result;
+	int copied_result;
     /*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.]*/
     if ((destination == NULL) || (source == NULL))
     {
-        /*If strDestination or strSource is a null pointer[...]these functions return EINVAL */
+        /*If strDestination or strSource is a NULL pointer[...]these functions return EINVAL */
         result = EINVAL;
     }
     else
@@ -275,12 +697,12 @@
         {
             *destination = temp;
             /*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.]*/
-            int temp = strcpy_s(*destination, l + 1, source);
-            if (temp < 0) /*strcpy_s error*/
+            copied_result = strcpy_s(*destination, l + 1, source);
+            if (copied_result < 0) /*strcpy_s error*/
             {
                 free(*destination);
                 *destination = NULL;
-                result = temp;
+                result = copied_result;
             }
             else
             {