Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of azure_c_shared_utility by
Revision 7:1af47e3a19b6, committed 2016-07-29
- Comitter:
- AzureIoTClient
- Date:
- Fri Jul 29 16:01:07 2016 -0700
- Parent:
- 6:c55b013dfc2a
- Child:
- 8:3db46d1e5471
- Commit message:
- 1.0.10
Changed in this revision
--- a/azure_c_shared_utility/crt_abstractions.h Fri Jul 01 10:43:23 2016 -0700
+++ b/azure_c_shared_utility/crt_abstractions.h Fri Jul 29 16:01:07 2016 -0700
@@ -9,10 +9,12 @@
#ifdef __cplusplus
#include <cstdio>
#include <cstring>
+#include <cerrno>
extern "C" {
#else
#include <stdio.h>
#include <string.h>
+#include <errno.h>
#endif
#ifdef _MSC_VER
@@ -97,6 +99,9 @@
extern int strncpy_s(char* dst, size_t dstSizeInBytes, const char* src, size_t maxCount);
extern int sprintf_s(char* dst, size_t dstSizeInBytes, const char* format, ...);
#endif
+extern unsigned long long strtoull_s(const char* nptr, char** endPtr, int base);
+extern float strtof_s(const char* nptr, char** endPtr);
+extern long double strtold_s(const char* nptr, char** endPtr);
MOCKABLE_FUNCTION(, int, mallocAndStrcpy_s, char**, destination, const char*, source);
MOCKABLE_FUNCTION(, int, unsignedIntToString, char*, destination, size_t, destinationSize, unsigned int, value);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/azure_c_shared_utility/optionhandler.h Fri Jul 29 16:01:07 2016 -0700
@@ -0,0 +1,47 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+#ifndef OPTIONHANDLER_H
+#define OPTIONHANDLER_H
+
+#include "azure_c_shared_utility/macro_utils.h"
+
+#define OPTIONHANDLER_RESULT_VALUES \
+OPTIONHANDLER_OK, \
+OPTIONHANDLER_ERROR, \
+OPTIONHANDLER_INVALIDARG
+
+DEFINE_ENUM(OPTIONHANDLER_RESULT, OPTIONHANDLER_RESULT_VALUES)
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#include "azure_c_shared_utility/umock_c_prod.h"
+
+typedef struct OPTIONHANDLER_HANDLE_DATA_TAG* OPTIONHANDLER_HANDLE;
+
+/*the following function pointer points to a function that produces a clone of the option specified by name and value (that is, a clone of void* value)*/
+/*returns NULL if it failed to produce a clone, otherwise returns a non-NULL value*/
+/*to be implemented by every module*/
+typedef void* (*pfCloneOption)(const char* name, const void* value);
+
+/*the following function pointer points to a function that frees resources allocated for an option*/
+/*to be implemented by every module*/
+typedef void (*pfDestroyOption)(const char* name, const void* value);
+
+/*the following function pointer points to a function that sets an option for a module*/
+/*to be implemented by every module*/
+/*returns 0 if _SetOption succeeded, any other value is error, if the option is not intended for that module, returns 0*/
+typedef int (*pfSetOption)(void* handle, const char* name, const void* value);
+
+MOCKABLE_FUNCTION(,OPTIONHANDLER_HANDLE, OptionHandler_Create, pfCloneOption, cloneOption, pfDestroyOption, destroyOption, pfSetOption, setOption);
+MOCKABLE_FUNCTION(,OPTIONHANDLER_RESULT, OptionHandler_AddOption, OPTIONHANDLER_HANDLE, handle, const char*, name, const void*, value);
+MOCKABLE_FUNCTION(,OPTIONHANDLER_RESULT, OptionHandler_FeedOptions, OPTIONHANDLER_HANDLE, handle, void*, destinationHandle);
+MOCKABLE_FUNCTION(,void, OptionHandler_Destroy, OPTIONHANDLER_HANDLE, handle);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /*OPTIONHANDLER*/
--- a/azure_c_shared_utility/refcount.h Fri Jul 01 10:43:23 2016 -0700
+++ b/azure_c_shared_utility/refcount.h Fri Jul 29 16:01:07 2016 -0700
@@ -41,11 +41,17 @@
/*the newly allocated memory shall be free'd by free()*/
/*and the ref counting is handled internally by the type in the _Create/ _Clone /_Destroy functions */
+#if defined(WIN32)
+#define COUNT_TYPE LONG
+#else
+#define COUNT_TYPE uint32_t
+#endif
+
#define DEFINE_REFCOUNT_TYPE(type) \
REFCOUNT_TYPE(type) \
{ \
type counted; \
- uint32_t count; \
+ COUNT_TYPE count; \
}; \
static type* REFCOUNT_TYPE_DECLARE_CREATE(type) (void) \
{ \
--- a/azure_c_shared_utility/xio.h Fri Jul 01 10:43:23 2016 -0700
+++ b/azure_c_shared_utility/xio.h Fri Jul 29 16:01:07 2016 -0700
@@ -4,6 +4,8 @@
#ifndef XIO_H
#define XIO_H
+#include "azure_c_shared_utility/optionhandler.h"
+
#include "azure_c_shared_utility/xlogging.h"
#include "azure_c_shared_utility/umock_c_prod.h"
@@ -37,6 +39,7 @@
typedef void(*ON_IO_CLOSE_COMPLETE)(void* context);
typedef void(*ON_IO_ERROR)(void* context);
+typedef OPTIONHANDLER_HANDLE (*IO_RETRIEVEOPTIONS)(CONCRETE_IO_HANDLE concrete_io);
typedef CONCRETE_IO_HANDLE(*IO_CREATE)(void* io_create_parameters);
typedef void(*IO_DESTROY)(CONCRETE_IO_HANDLE concrete_io);
typedef int(*IO_OPEN)(CONCRETE_IO_HANDLE concrete_io, ON_IO_OPEN_COMPLETE on_io_open_complete, void* on_io_open_complete_context, ON_BYTES_RECEIVED on_bytes_received, void* on_bytes_received_context, ON_IO_ERROR on_io_error, void* on_io_error_context);
@@ -45,8 +48,10 @@
typedef void(*IO_DOWORK)(CONCRETE_IO_HANDLE concrete_io);
typedef int(*IO_SETOPTION)(CONCRETE_IO_HANDLE concrete_io, const char* optionName, const void* value);
+
typedef struct IO_INTERFACE_DESCRIPTION_TAG
{
+ IO_RETRIEVEOPTIONS concrete_io_retrieveoptions;
IO_CREATE concrete_io_create;
IO_DESTROY concrete_io_destroy;
IO_OPEN concrete_io_open;
@@ -63,6 +68,7 @@
MOCKABLE_FUNCTION(, int, xio_send, XIO_HANDLE, xio, const void*, buffer, size_t, size, ON_SEND_COMPLETE, on_send_complete, void*, callback_context);
MOCKABLE_FUNCTION(, void, xio_dowork, XIO_HANDLE, xio);
MOCKABLE_FUNCTION(, int, xio_setoption, XIO_HANDLE, xio, const char*, optionName, const void*, value);
+MOCKABLE_FUNCTION(, OPTIONHANDLER_HANDLE, xio_retrieveoptions, XIO_HANDLE, xio);
#ifdef __cplusplus
}
--- a/azure_c_shared_utility/xlogging.h Fri Jul 01 10:43:23 2016 -0700
+++ b/azure_c_shared_utility/xlogging.h Fri Jul 29 16:01:07 2016 -0700
@@ -13,14 +13,6 @@
#include "azure_c_shared_utility/agenttime.h"
-/*no logging is useful when time and fprintf are mocked*/
-#ifdef NO_LOGGING
-#define LOG(...)
-#define LogInfo(...)
-#define LogError(...)
-#define xlogging_get_log_function() NULL
-#else
-
typedef enum LOG_CATEGORY_TAG
{
LOG_ERROR,
@@ -30,29 +22,94 @@
typedef void(*LOGGER_LOG)(LOG_CATEGORY log_category, unsigned int options, const char* format, ...);
+#define LOG_NONE 0x00
#define LOG_LINE 0x01
+/*no logging is useful when time and fprintf are mocked*/
+#ifdef NO_LOGGING
+#define LOG(...)
+#define LogInfo(...)
+#define LogError(...)
+#define xlogging_get_log_function() NULL
+#elif defined(ARDUINO_ARCH_ESP8266)
+/*
+The ESP8266 compiler dont do a good job compiling this code, it do not understand that the format is
+a cont char* and moves it to the RAM as a global variable, increasing a lot the .bss. So, we create a
+specific LogInfo that explicitly pin the format on the PROGMEM (flash) using a _localFORMAT variable
+with the macro PSTR.
+
+#define ICACHE_FLASH_ATTR __attribute__((section(".irom0.text")))
+#define PROGMEM ICACHE_RODATA_ATTR
+#define PSTR(s) (__extension__({static const char __c[] PROGMEM = (s); &__c[0];}))
+const char* __localFORMAT = PSTR(FORMAT);
+
+On the other hand, vsprintf do not support the pinned format and os_printf do not works with va_list,
+so we compacted the log in the macro LogInfo.
+*/
+#include "esp8266/azcpgmspace.h"
+#define LogInfo(FORMAT, ...) { \
+ const char* __localFORMAT = PSTR(FORMAT); \
+ os_printf(__localFORMAT, ##__VA_ARGS__); \
+ os_printf("\r\n"); \
+}
+#define LogError LogInfo
+
+#else /* !ARDUINO_ARCH_ESP8266 */
+
#if defined _MSC_VER
#define LOG(log_category, log_options, format, ...) { LOGGER_LOG l = xlogging_get_log_function(); if (l != NULL) l(log_category, log_options, format, __VA_ARGS__); }
#else
-#define LOG(log_category, log_options, format, ...) { LOGGER_LOG l = xlogging_get_log_function(); if (l != NULL) l(log_category, log_options, format, ##__VA_ARGS__); }
+#define LOG(log_category, log_options, format, ...) { LOGGER_LOG l = xlogging_get_log_function(); if (l != NULL) l(log_category, log_options, format, ##__VA_ARGS__); }
+#endif
+
+#if defined _MSC_VER
+#define LogInfo(FORMAT, ...) do{LOG(LOG_INFO, LOG_LINE, FORMAT, __VA_ARGS__); }while(0)
+#else
+#define LogInfo(FORMAT, ...) do{LOG(LOG_INFO, LOG_LINE, FORMAT, ##__VA_ARGS__); }while(0)
#endif
#if defined _MSC_VER
-#define LogInfo(FORMAT, ...) do{LOG(LOG_INFO, LOG_LINE, "Info: " FORMAT, __VA_ARGS__); }while(0)
+#define LogError(FORMAT, ...) do{ LOG(LOG_ERROR, LOG_LINE, FORMAT, __VA_ARGS__); }while(0)
+#define TEMP_BUFFER_SIZE 1024
+#define MESSAGE_BUFFER_SIZE 260
+#define LogErrorWinHTTPWithGetLastErrorAsString(FORMAT, ...) do { \
+ DWORD errorMessageID = GetLastError(); \
+ LogError(FORMAT, __VA_ARGS__); \
+ CHAR messageBuffer[MESSAGE_BUFFER_SIZE]; \
+ if (errorMessageID == 0) \
+ {\
+ LogError("GetLastError() returned 0. Make sure you are calling this right after the code that failed. "); \
+ } \
+ else\
+ {\
+ int size = FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, \
+ GetModuleHandle("WinHttp"), errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), messageBuffer, MESSAGE_BUFFER_SIZE, NULL); \
+ if (size == 0)\
+ {\
+ size = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), messageBuffer, MESSAGE_BUFFER_SIZE, NULL); \
+ if (size == 0)\
+ {\
+ LogError("GetLastError Code: %d. ", errorMessageID); \
+ }\
+ else\
+ {\
+ LogError("GetLastError: %s.", messageBuffer); \
+ }\
+ }\
+ else\
+ {\
+ LogError("GetLastError: %s.", messageBuffer); \
+ }\
+ }\
+ } while(0)
#else
-#define LogInfo(FORMAT, ...) do{LOG(LOG_INFO, LOG_LINE, "Info: " FORMAT, ##__VA_ARGS__); }while(0)
-#endif
-
-#if defined _MSC_VER
-#define LogError(FORMAT, ...) do{ time_t t = time(NULL); LOG(LOG_ERROR, LOG_LINE, "Error: Time:%.24s File:%s Func:%s Line:%d " FORMAT, ctime(&t), __FILE__, __FUNCDNAME__, __LINE__, __VA_ARGS__); }while(0)
-#else
-#define LogError(FORMAT, ...) do{ time_t t = time(NULL); LOG(LOG_ERROR, LOG_LINE, "Error: Time:%.24s File:%s Func:%s Line:%d " FORMAT, ctime(&t), __FILE__, __func__, __LINE__, ##__VA_ARGS__); }while(0)
+#define LogError(FORMAT, ...) do{ LOG(LOG_ERROR, LOG_LINE, FORMAT, ##__VA_ARGS__); }while(0)
#endif
extern void xlogging_set_log_function(LOGGER_LOG log_function);
extern LOGGER_LOG xlogging_get_log_function(void);
-#endif
+
+#endif /* ARDUINO_ARCH_ESP8266 */
#ifdef __cplusplus
}
--- a/base64.c Fri Jul 01 10:43:23 2016 -0700
+++ b/base64.c Fri Jul 29 16:01:07 2016 -0700
@@ -183,7 +183,6 @@
}
else
{
- size_t lengthOfSource = numberOfBase64Characters(source);
if ((result = BUFFER_new()) == NULL)
{
/*Codes_SRS_BASE64_06_010: [If there is any memory allocation failure during the decode then Base64_Decode shall return NULL.]*/
--- a/consolelogger.c Fri Jul 01 10:43:23 2016 -0700
+++ b/consolelogger.c Fri Jul 29 16:01:07 2016 -0700
@@ -9,10 +9,31 @@
#include <stdio.h>
#include "azure_c_shared_utility/xlogging.h"
+#if defined _MSC_VER
+#define FUNC_NAME __FUNCDNAME__
+#else
+#define FUNC_NAME __func__
+#endif
+
void consolelogger_log(LOG_CATEGORY log_category,unsigned int options, const char* format, ...)
{
va_list args;
va_start(args, format);
+
+ time_t t = time(NULL);
+
+ switch (log_category)
+ {
+ case LOG_INFO:
+ (void)printf("Info: ");
+ break;
+ case LOG_ERROR:
+ (void)printf("Error: Time:%.24s File:%s Func:%s Line:%d ", ctime(&t), __FILE__, FUNC_NAME, __LINE__);
+ break;
+ default:
+ break;
+ }
+
(void)vprintf(format, args);
va_end(args);
--- 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
{
--- a/httpapi_compact.c Fri Jul 01 10:43:23 2016 -0700
+++ b/httpapi_compact.c Fri Jul 29 16:01:07 2016 -0700
@@ -18,6 +18,7 @@
#include "azure_c_shared_utility/tlsio.h"
#include "azure_c_shared_utility/threadapi.h"
#include <string.h>
+#include <limits.h>
#define MAX_HOSTNAME 64
#define TEMP_BUFFER_SIZE 4096
@@ -46,6 +47,68 @@
unsigned int is_connected : 1;
} HTTP_HANDLE_DATA;
+/*the following function does the same as sscanf(pos2, "%d", &sec)*/
+/*this function only exists because some of platforms do not have sscanf. */
+static int ParseStringToDecimal(const char *src, int* dst)
+{
+ char* next;
+ (*dst) = strtol(src, &next, 0);
+ if ((src == next) || ((((*dst) == LONG_MAX) || ((*dst) == LONG_MIN)) && (errno != 0)))
+ {
+ return EOF;
+ }
+ return 1;
+}
+
+/*the following function does the same as sscanf(pos2, "%x", &sec)*/
+/*this function only exists because some of platforms do not have sscanf. This is not a full implementation; it only works with well-defined x numbers. */
+#define HEXA_DIGIT_VAL(c) (((c>='0') && (c<='9')) ? (c-'0') : ((c>='a') && (c<='f')) ? (c-'a'+10) : ((c>='A') && (c<='F')) ? (c-'A'+10) : -1)
+static int ParseStringToHexadecimal(const char *src, int* dst)
+{
+ if (src == NULL)
+ return EOF;
+ if (HEXA_DIGIT_VAL(*src) == -1)
+ return EOF;
+
+ int digitVal;
+ (*dst) = 0;
+ while ((digitVal = HEXA_DIGIT_VAL(*src)) != -1)
+ {
+ (*dst) *= 0x10;
+ (*dst) += digitVal;
+ src++;
+ }
+ return 1;
+}
+
+/*the following function does the same as sscanf(buf, "HTTP/%*d.%*d %d %*[^\r\n]", &ret) */
+/*this function only exists because some of platforms do not have sscanf. This is not a full implementation; it only works with well-defined HTTP response. */
+static int ParseHttpResponse(const char* src, int* dst)
+{
+ const char* prefix = "HTTP/";
+ while ((*prefix) != '\0')
+ {
+ if ((*prefix) != (*src))
+ return EOF;
+ prefix++;
+ src++;
+ }
+
+ while ((*src) != '.')
+ {
+ if ((*src) == '\0')
+ return EOF;
+ }
+
+ while ((*src) != ' ')
+ {
+ if ((*src) == '\0')
+ return EOF;
+ }
+
+ return ParseStringToDecimal(src, dst);
+}
+
HTTPAPI_RESULT HTTPAPI_Init(void)
{
return HTTPAPI_OK;
@@ -529,7 +592,7 @@
}
//Parse HTTP response
- if (sscanf(buf, "HTTP/%*d.%*d %d %*[^\r\n]", &ret) != 1)
+ if (ParseHttpResponse(buf, &ret) != 1)
{
//Cannot match string, error
LogInfo("HTTPAPI_ExecuteRequest::Not a correct HTTP answer=%s", buf);
@@ -555,7 +618,7 @@
if (my_strnicmp(buf, ContentLength, CHAR_COUNT(ContentLength)) == 0)
{
- if (sscanf(buf + CHAR_COUNT(ContentLength), " %d", &bodyLength) != 1)
+ if (ParseStringToDecimal(buf + CHAR_COUNT(ContentLength), &bodyLength) != 1)
{
result = HTTPAPI_READ_DATA_FAILED;
LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
@@ -640,7 +703,7 @@
LogError("(result = %s)", ENUM_TO_STRING(HTTPAPI_RESULT, result));
goto exit;
}
- if (sscanf(buf, "%x", &chunkSize) != 1) // chunkSize is length of next line (/r/n is not counted)
+ if (ParseStringToHexadecimal(buf, &chunkSize) != 1) // chunkSize is length of next line (/r/n is not counted)
{
//Cannot match string, error
result = HTTPAPI_RECEIVE_RESPONSE_FAILED;
--- a/httpapiexsas.c Fri Jul 01 10:43:23 2016 -0700
+++ b/httpapiexsas.c Fri Jul 29 16:01:07 2016 -0700
@@ -47,6 +47,7 @@
}
else
{
+ /*Codes_SRS_HTTPAPIEXSAS_01_001: [ HTTPAPIEX_SAS_Create shall create a new instance of HTTPAPIEX_SAS and return a non-NULL handle to it. ]*/
HTTPAPIEX_SAS_STATE* state = malloc(sizeof(HTTPAPIEX_SAS_STATE));
/*Codes_SRS_HTTPAPIEXSAS_06_004: [If there are any other errors in the instantiation of this handle then HTTPAPIEX_SAS_Create shall return NULL.]*/
if (state != NULL)
--- a/list.c Fri Jul 01 10:43:23 2016 -0700
+++ b/list.c Fri Jul 29 16:01:07 2016 -0700
@@ -46,7 +46,7 @@
while (list_instance->head != NULL)
{
LIST_ITEM_INSTANCE* current_item = list_instance->head;
- list_instance->head = current_item->next;
+ list_instance->head = (LIST_ITEM_INSTANCE*)current_item->next;
free(current_item);
}
@@ -90,7 +90,7 @@
LIST_ITEM_INSTANCE* current = list_instance->head;
while (current->next != NULL)
{
- current = current->next;
+ current = (LIST_ITEM_INSTANCE*)current->next;
}
current->next = result;
@@ -127,7 +127,7 @@
}
else
{
- list_instance->head = current_item->next;
+ list_instance->head = (LIST_ITEM_INSTANCE*)current_item->next;
}
free(current_item);
@@ -135,7 +135,7 @@
break;
}
previous_item = current_item;
- current_item = current_item->next;
+ current_item = (LIST_ITEM_INSTANCE*)current_item->next;
}
if (current_item == NULL)
@@ -186,7 +186,7 @@
else
{
/* Codes_SRS_LIST_01_018: [list_get_next_item shall return the next item in the list following the item item_handle.] */
- result = ((LIST_ITEM_INSTANCE*)item_handle)->next;
+ result = (LIST_ITEM_HANDLE)((LIST_ITEM_INSTANCE*)item_handle)->next;
}
return result;
@@ -237,7 +237,7 @@
}
/* Codes_SRS_LIST_01_016: [If the match function returns false, list_find shall consider that item as not matching.] */
- current = current->next;
+ current = (LIST_ITEM_INSTANCE*)current->next;
}
if (current == NULL)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/optionhandler.c Fri Jul 29 16:01:07 2016 -0700
@@ -0,0 +1,190 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+#include "azure_c_shared_utility/optionhandler.h"
+#include "azure_c_shared_utility/xlogging.h"
+#include "azure_c_shared_utility/gballoc.h"
+#include "azure_c_shared_utility/vector.h"
+
+typedef struct OPTION_TAG
+{
+ const char* name;
+ void* storage;
+}OPTION;
+
+typedef struct OPTIONHANDLER_HANDLE_DATA_TAG
+{
+ pfCloneOption cloneOption;
+ pfDestroyOption destroyOption;
+ pfSetOption setOption;
+ VECTOR_HANDLE storage;
+}OPTIONHANDLER_HANDLE_DATA;
+
+OPTIONHANDLER_HANDLE OptionHandler_Create(pfCloneOption cloneOption, pfDestroyOption destroyOption, pfSetOption setOption)
+{
+ /*Codes_SRS_OPTIONHANDLER_02_001: [ OptionHandler_Create shall fail and retun NULL if any parameters are NULL. ]*/
+ OPTIONHANDLER_HANDLE_DATA* result;
+ if (
+ (cloneOption == NULL) ||
+ (destroyOption == NULL) ||
+ (setOption == NULL)
+ )
+ {
+ LogError("invalid parameter = pfCloneOption cloneOption=%p, pfDestroyOption destroyOption=%p, pfSetOption setOption=%p", cloneOption, destroyOption, setOption);
+ result = NULL;
+ }
+ else
+ {
+ result = (OPTIONHANDLER_HANDLE_DATA*)malloc(sizeof(OPTIONHANDLER_HANDLE_DATA));
+ if (result == NULL)
+ {
+ /*Codes_SRS_OPTIONHANDLER_02_004: [ Otherwise, OptionHandler_Create shall fail and return NULL. ]*/
+ LogError("unable to malloc");
+ /*return as is*/
+ }
+ else
+ {
+ /*Codes_SRS_OPTIONHANDLER_02_002: [ OptionHandler_Create shall create an empty VECTOR that will hold pairs of const char* and void*. ]*/
+ result->storage = VECTOR_create(sizeof(OPTION));
+ if (result->storage == NULL)
+ {
+ /*Codes_SRS_OPTIONHANDLER_02_004: [ Otherwise, OptionHandler_Create shall fail and return NULL. ]*/
+ LogError("unable to VECTOR_create");
+ free(result);
+ result= NULL;
+ }
+ else
+ {
+ /*Codes_SRS_OPTIONHANDLER_02_003: [ If all the operations succeed then OptionHandler_Create shall succeed and return a non-NULL handle. ]*/
+ result->cloneOption = cloneOption;
+ result->destroyOption = destroyOption;
+ result->setOption = setOption;
+ /*return as is*/
+ }
+ }
+ }
+ return result;
+
+}
+
+OPTIONHANDLER_RESULT OptionHandler_AddOption(OPTIONHANDLER_HANDLE handle, const char* name, const void* value)
+{
+ OPTIONHANDLER_RESULT result;
+ /*Codes_SRS_OPTIONHANDLER_02_001: [ OptionHandler_Create shall fail and retun NULL if any parameters are NULL. ]*/
+ if (
+ (handle == NULL) ||
+ (name == NULL) ||
+ (value == NULL)
+ )
+ {
+ LogError("invalid arguments: OPTIONHANDLER_HANDLE handle=%p, const char* name=%p, void* value=%p", handle, name, value);
+ result= OPTIONHANDLER_INVALIDARG;
+ }
+ else
+ {
+ const char* cloneOfName;
+ if (mallocAndStrcpy_s((char**)&cloneOfName, name) != 0)
+ {
+ /*Codes_SRS_OPTIONHANDLER_02_009: [ Otherwise, OptionHandler_AddProperty shall succeed and return OPTIONHANDLER_ERROR. ]*/
+ LogError("unable to clone name");
+ result = OPTIONHANDLER_ERROR;
+ }
+ else
+ {
+ /*Codes_SRS_OPTIONHANDLER_02_006: [ OptionHandler_AddProperty shall call pfCloneOption passing name and value. ]*/
+ void* cloneOfValue = handle->cloneOption(name, value);
+ if (cloneOfValue == NULL)
+ {
+ /*Codes_SRS_OPTIONHANDLER_02_009: [ Otherwise, OptionHandler_AddProperty shall succeed and return OPTIONHANDLER_ERROR. ]*/
+ LogError("unable to clone value");
+ free((void*)cloneOfName);
+ result = OPTIONHANDLER_ERROR;
+ }
+ else
+ {
+ OPTION temp;
+ temp.name = cloneOfName;
+ temp.storage = cloneOfValue;
+ /*Codes_SRS_OPTIONHANDLER_02_007: [ OptionHandler_AddProperty shall use VECTOR APIs to save the name and the newly created clone of value. ]*/
+ if (VECTOR_push_back(handle->storage, &temp, 1) != 0)
+ {
+ /*Codes_SRS_OPTIONHANDLER_02_009: [ Otherwise, OptionHandler_AddProperty shall succeed and return OPTIONHANDLER_ERROR. ]*/
+ LogError("unable to VECTOR_push_back");
+ handle->destroyOption(name, cloneOfValue);
+ free((void*)cloneOfName);
+ result = OPTIONHANDLER_ERROR;
+ }
+ else
+ {
+ /*Codes_SRS_OPTIONHANDLER_02_008: [ If all the operations succed then OptionHandler_AddProperty shall succeed and return OPTIONHANDLER_OK. ]*/
+ result = OPTIONHANDLER_OK;
+ }
+ }
+ }
+ }
+ return result;
+}
+
+OPTIONHANDLER_RESULT OptionHandler_FeedOptions(OPTIONHANDLER_HANDLE handle, void* destinationHandle)
+{
+ OPTIONHANDLER_RESULT result;
+ /*Codes_SRS_OPTIONHANDLER_02_010: [ OptionHandler_FeedOptions shall fail and return OPTIONHANDLER_INVALIDARG if any argument is NULL. ]*/
+ if (
+ (handle == NULL) ||
+ (destinationHandle == NULL)
+ )
+ {
+ LogError("invalid arguments OPTIONHANDLER_HANDLE handle=%p, void* destinationHandle=%p", handle, destinationHandle);
+ result = OPTIONHANDLER_INVALIDARG;
+ }
+ else
+ {
+ /*Codes_SRS_OPTIONHANDLER_02_011: [ Otherwise, OptionHandler_FeedOptions shall use VECTOR's iteration mechanisms to retrieve pairs of name, value (const char* and void*). ]*/
+ size_t nOptions = VECTOR_size(handle->storage), i;
+ for (i = 0;i < nOptions;i++)
+ {
+ OPTION* option = (OPTION*)VECTOR_element(handle->storage, i);
+ /*Codes_SRS_OPTIONHANDLER_02_012: [ OptionHandler_FeedOptions shall call for every pair of name,value setOption passing destinationHandle, name and value. ]*/
+ if (handle->setOption(destinationHandle, option->name, option->storage) != 0)
+ {
+ LogError("failure while trying to _SetOption");
+ break;
+ }
+ }
+
+ if (i == nOptions)
+ {
+ /*Codes_SRS_OPTIONHANDLER_02_014: [ Otherwise, OptionHandler_FeedOptions shall fail and return OPTIONHANDLER_ERROR. ]*/
+ result = OPTIONHANDLER_OK;
+ }
+ else
+ {
+ /*Codes_SRS_OPTIONHANDLER_02_013: [ If all the operations succeed then OptionHandler_FeedOptions shall succeed and return OPTIONHANDLER_OK. ]*/
+ result = OPTIONHANDLER_ERROR;
+ }
+ }
+ return result;
+}
+
+void OptionHandler_Destroy(OPTIONHANDLER_HANDLE handle)
+{
+ /*Codes_SRS_OPTIONHANDLER_02_015: [ OptionHandler_Destroy shall do nothing if parameter handle is NULL. ]*/
+ if (handle == NULL)
+ {
+ LogError("invalid argument OPTIONHANDLER_HANDLE handle=%p", handle);
+ }
+ else
+ {
+ /*Codes_SRS_OPTIONHANDLER_02_016: [ Otherwise, OptionHandler_Destroy shall free all used resources. ]*/
+ size_t nOptions = VECTOR_size(handle->storage), i;
+ for (i = 0;i < nOptions;i++)
+ {
+ OPTION* option = (OPTION*)VECTOR_element(handle->storage, i);
+ handle->destroyOption(option->name, option->storage);
+ free((void*)option->name);
+ }
+
+ VECTOR_destroy(handle->storage);
+ free(handle);
+ }
+}
--- a/string_tokenizer.c Fri Jul 01 10:43:23 2016 -0700
+++ b/string_tokenizer.c Fri Jul 29 16:01:07 2016 -0700
@@ -104,10 +104,11 @@
else
{
size_t i;
- size_t j;
/* Codes_SRS_STRING_04_005: [STRING_TOKENIZER_get_next_token searches the string inside STRING_TOKENIZER_HANDLE for the first character that is NOT contained in the current delimiter] */
for (i = 0; i < remainingInputStringSize; i++)
{
+ size_t j;
+
bool foundDelimitter = false;
for (j = 0; j < delimitterSize; j++)
{
--- a/xio.c Fri Jul 01 10:43:23 2016 -0700
+++ b/xio.c Fri Jul 29 16:01:07 2016 -0700
@@ -9,6 +9,8 @@
#include "azure_c_shared_utility/gballoc.h"
#include "azure_c_shared_utility/xio.h"
+static const char* CONCRETE_OPTIONS = "concreteOptions";
+
typedef struct XIO_INSTANCE_TAG
{
const IO_INTERFACE_DESCRIPTION* io_interface_description;
@@ -21,6 +23,7 @@
/* Codes_SRS_XIO_01_003: [If the argument io_interface_description is NULL, xio_create shall return NULL.] */
if ((io_interface_description == NULL) ||
/* Codes_SRS_XIO_01_004: [If any io_interface_description member is NULL, xio_create shall return NULL.] */
+ (io_interface_description->concrete_io_retrieveoptions == NULL) ||
(io_interface_description->concrete_io_create == NULL) ||
(io_interface_description->concrete_io_destroy == NULL) ||
(io_interface_description->concrete_io_open == NULL) ||
@@ -168,7 +171,7 @@
{
int result;
- /* Codes_SRS_XIO_03_030: [If the xio argumnent or the optionName argument is NULL, xio_setoption shall return a non-zero value.] */
+ /* Codes_SRS_XIO_03_030: [If the xio argument or the optionName argument is NULL, xio_setoption shall return a non-zero value.] */
if (xio == NULL || optionName == NULL)
{
result = __LINE__;
@@ -177,11 +180,125 @@
{
XIO_INSTANCE* xio_instance = (XIO_INSTANCE*)xio;
- /* Codes_SRS_XIO_003_028: [xio_setoption shall pass the optionName and value to the concrete IO implementation specified in xio_create by invoking the concrete_xio_setoption function.] */
- /* Codes_SRS_XIO_03_029: [xio_setoption shall return 0 upon success.] */
- /* Codes_SRS_XIO_03_031: [If the underlying concrete_xio_setoption fails, xio_setOption shall return a non-zero value.] */
- result = xio_instance->io_interface_description->concrete_io_setoption(xio_instance->concrete_xio_handle, optionName, value);
+ if (strcmp(CONCRETE_OPTIONS, optionName) == 0)
+ {
+ /*then value is a pointer to OPTIONHANDLER_HANDLE*/
+ if (OptionHandler_FeedOptions((OPTIONHANDLER_HANDLE)value, xio_instance->concrete_xio_handle) != OPTIONHANDLER_OK)
+ {
+ LogError("unable to OptionHandler_FeedOptions");
+ result = __LINE__;
+ }
+ else
+ {
+ result = 0;
+ }
+ }
+ else /*passthrough*/
+ {
+ /* Codes_SRS_XIO_003_028: [xio_setoption shall pass the optionName and value to the concrete IO implementation specified in xio_create by invoking the concrete_xio_setoption function.] */
+ /* Codes_SRS_XIO_03_029: [xio_setoption shall return 0 upon success.] */
+ /* Codes_SRS_XIO_03_031: [If the underlying concrete_xio_setoption fails, xio_setOption shall return a non-zero value.] */
+ result = xio_instance->io_interface_description->concrete_io_setoption(xio_instance->concrete_xio_handle, optionName, value);
+ }
}
return result;
}
+
+static void* xio_CloneOption(const char* name, const void* value)
+{
+ void *result;
+ if (
+ (name == NULL) ||
+ (value == NULL)
+ )
+ {
+ LogError("invalid argument detected: const char* name=%p, const void* value=%p", name, value);
+ result = NULL;
+ }
+ else
+ {
+ if (strcmp(name, CONCRETE_OPTIONS) == 0)
+ {
+ result = (void*)value;
+ }
+ else
+ {
+ LogError("unknown option: %s", name);
+ result = NULL;
+ }
+ }
+ return result;
+}
+
+
+static void xio_DestroyOption(const char* name, const void* value)
+{
+ if (
+ (name == NULL) ||
+ (value == NULL)
+ )
+ {
+ LogError("invalid argument detected: const char* name=%p, const void* value=%p", name, value);
+ }
+ else
+ {
+ if (strcmp(name, CONCRETE_OPTIONS) == 0)
+ {
+ OptionHandler_Destroy((OPTIONHANDLER_HANDLE)value);
+ }
+ else
+ {
+ LogError("unknown option: %s", name);
+ }
+ }
+}
+
+OPTIONHANDLER_HANDLE xio_retrieveoptions(XIO_HANDLE xio)
+{
+ OPTIONHANDLER_HANDLE result;
+
+ if (xio == NULL)
+ {
+ LogError("invalid argument detected: XIO_HANDLE xio=%p", xio);
+ result = NULL;
+ }
+ else
+ {
+ XIO_INSTANCE* xio_instance = (XIO_INSTANCE*)xio;
+ /*xio_retrieveoptions shall return a OPTIONHANDLER_HANDLE that has 1 option called "underlyingOptions" which is of type OPTIONHANDLER_HANDLE*/
+ result = OptionHandler_Create(xio_CloneOption, xio_DestroyOption, (pfSetOption)xio_setoption);
+ if (result == NULL)
+ {
+ LogError("unable to OptionHandler_Create");
+ /*return as is*/
+ }
+ else
+ {
+ OPTIONHANDLER_HANDLE concreteOptions = xio_instance->io_interface_description->concrete_io_retrieveoptions(xio_instance->concrete_xio_handle);
+ if (concreteOptions == NULL)
+ {
+ LogError("unable to concrete_io_retrieveoptions");
+ OptionHandler_Destroy(result);
+ result = NULL;
+ }
+ else
+ {
+ if (OptionHandler_AddOption(result, CONCRETE_OPTIONS, concreteOptions) != OPTIONHANDLER_OK)
+ {
+ LogError("unable to OptionHandler_AddOption");
+ OptionHandler_Destroy(concreteOptions);
+ OptionHandler_Destroy(result);
+ result = NULL;
+ }
+ else
+ {
+ /*all is fine*/
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
--- a/xlogging.c Fri Jul 01 10:43:23 2016 -0700
+++ b/xlogging.c Fri Jul 29 16:01:07 2016 -0700
@@ -4,7 +4,49 @@
#include "azure_c_shared_utility/xlogging.h"
#include "azure_c_shared_utility/consolelogger.h"
-static LOGGER_LOG global_log_function = consolelogger_log;
+#ifndef NO_LOGGING
+
+
+#ifdef WINCE
+#include <stdarg.h>
+#if defined _MSC_VER
+#define FUNC_NAME __FUNCDNAME__
+#else
+#define FUNC_NAME __func__
+#endif
+
+void consolelogger_log(LOG_CATEGORY log_category, unsigned int options, const char* format, ...)
+{
+ va_list args;
+ va_start(args, format);
+
+ time_t t = time(NULL);
+
+ switch (log_category)
+ {
+ case LOG_INFO:
+ (void)printf("Info: ");
+ break;
+ case LOG_ERROR:
+ (void)printf("Error: Time:%.24s File:%s Func:%s Line:%d ", ctime(&t), __FILE__, FUNC_NAME, __LINE__);
+ break;
+ default:
+ break;
+ }
+
+ (void)vprintf(format, args);
+ va_end(args);
+
+ (void)log_category;
+ if (options & LOG_LINE)
+ {
+ (void)printf("\r\n");
+ }
+}
+#endif
+
+LOGGER_LOG global_log_function = consolelogger_log;
+
void xlogging_set_log_function(LOGGER_LOG log_function)
{
@@ -15,3 +57,5 @@
{
return global_log_function;
}
+
+#endif
