diff --git a/CMakeLists.txt b/CMakeLists.txt index de60ce8..82027fe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -135,6 +135,11 @@ if(NOT GMIO_BUILD_STRICT_C90) if(WIN32 AND NOT GMIO_HAVE_SNPRINTF_FUNC) check_function_exists(_snprintf GMIO_HAVE_WIN__SNPRINTF_FUNC) endif() + + check_function_exists(vsnprintf GMIO_HAVE_VSNPRINTF_FUNC) + if(WIN32 AND NOT GMIO_HAVE_VSNPRINTF_FUNC) + check_function_exists(_vsnprintf GMIO_HAVE_WIN__VSNPRINTF_FUNC) + endif() endif() # Check POSIX features diff --git a/benchmarks/commons/benchmark_tools.c b/benchmarks/commons/benchmark_tools.c index 73fca65..8df8010 100644 --- a/benchmarks/commons/benchmark_tools.c +++ b/benchmarks/commons/benchmark_tools.c @@ -28,6 +28,9 @@ # define BENCHMARK_TIMER_LIBC #endif +#include "../../src/gmio_core/internal/c99_stdio_compat.h" +#include "../../src/gmio_core/internal/string.h" + /* Benchmark timers */ struct benchmark_timer @@ -78,26 +81,27 @@ static gmio_time_ms_t benchmark_timer_elapsed_ms(const struct benchmark_timer* t /* Wraps around formatted printing functions */ -/*! Wrap around sprintf() to be used with gprintf_func_exec_time() */ -static void sprintf_wrap(void* cookie, const char* fmt, ...) +/*! Wrap around snprintf() to be used with gprintf_func_exec_time() */ +static void snprintf_wrap(void* cookie, const char* fmt, ...) { + struct gmio_string* str = (struct gmio_string*)cookie; va_list args; va_start(args, fmt); - vsprintf((char*)cookie, fmt, args); + gmio_vsnprintf(str->ptr, str->max_len, fmt, args); va_end(args); } -/*! Wrap around printf() to be used with gprintf_func_exec_time() */ -static void printf_wrap(void* cookie, const char* fmt, ...) +/*! Wrap around fprintf() to be used with gprintf_func_exec_time() */ +static void fprintf_wrap(void* cookie, const char* fmt, ...) { + FILE* file = (FILE*)cookie; va_list args; - GMIO_UNUSED(cookie); va_start(args, fmt); - vprintf(fmt, args); + vfprintf(file, fmt, args); va_end(args); } -/*! Typedef on pointer to printf-wrap functions(eg. sprintf_wrap()) */ +/*! Typedef on pointer to printf-wrap functions(eg. snprintf_wrap()) */ typedef void (*func_gprintf_t)(void*, const char*, ...); @@ -133,7 +137,7 @@ static const char n_a[] = "N/A"; static void gprintf_func_string( /* Annex data for func_gprintf (ex: char* for sprintf()) */ void* cookie, - /* Function ptr on a printf wrap (ex: sprintf_wrap()) */ + /* Function ptr on a printf wrap (ex: snprintf_wrap()) */ func_gprintf_t func_gprintf, /* Width of the print column, if any (can be == 0) */ size_t width_column, @@ -157,7 +161,11 @@ static void gprintf_func_exec_time( if (has_time) { char str_time[128] = {0}; /* TODO: %ull is not accepted by mingw, find a fix(maybe %ul64) */ - sprintf(str_time, "%u%s", (unsigned)time, unit_time_str); + gmio_snprintf(str_time, + sizeof(str_time), + "%u%s", + (unsigned)time, + unit_time_str); gprintf_func_string(cookie, func_gprintf, width_column, str_time); } else { @@ -174,7 +182,7 @@ static void gprintf_func_exec_ratio( { if (!(ratio < 0)) { /* Valid ratio */ char str_ratio[128] = {0}; - sprintf(str_ratio, "%.2f", ratio); + gmio_snprintf(str_ratio, sizeof(str_ratio), "%.2f", ratio); gprintf_func_string(cookie, func_gprintf, width_column, str_ratio); } else { @@ -189,7 +197,7 @@ static void printf_func_exec_time( bool has_time) { gprintf_func_exec_time( - NULL, &printf_wrap, width_column, time_ms, has_time); + stdout, &fprintf_wrap, width_column, time_ms, has_time); } /*! Returns the strlen of the longest tag string */ @@ -234,13 +242,14 @@ static size_t find_maxlen_cmp_result_func_exec_time( func_select_cmp_result_func_exec_infos_t func_select_exec_infos) { char strbuff[1024] = {0}; + struct gmio_string str = gmio_string(strbuff, 0, sizeof(strbuff)); size_t max_len = 0; size_t i; for (i = 0; i < res_array.count; ++i) { gmio_time_ms_t time = 0; bool has_time = false; func_select_exec_infos(&res_array.ptr[i], &time, &has_time); - gprintf_func_exec_time(strbuff, &sprintf_wrap, 0, time, has_time); + gprintf_func_exec_time(&str, &snprintf_wrap, 0, time, has_time); max_len = size_t_max(safe_strlen(strbuff), max_len); } return max_len; @@ -251,11 +260,12 @@ static size_t find_maxlen_cmp_result_ratio( struct benchmark_cmp_result_array res_array) { char strbuff[1024] = {0}; + struct gmio_string str = gmio_string(strbuff, 0, sizeof(strbuff)); size_t max_len = 0; size_t i; for (i = 0; i < res_array.count; ++i) { const float ratio = res_array.ptr[i].func2_func1_ratio; - gprintf_func_exec_ratio(strbuff, &sprintf_wrap, 0, ratio); + gprintf_func_exec_ratio(&str, &snprintf_wrap, 0, ratio); max_len = size_t_max(safe_strlen(strbuff), max_len); } return max_len; @@ -404,7 +414,7 @@ void benchmark_print_results( result.has_func2_exec_time); printf(" | "); gprintf_func_exec_ratio( - NULL, printf_wrap, + stdout, fprintf_wrap, width_ratio_col, result.func2_func1_ratio); printf("\n"); } diff --git a/src/gmio_core/config.h.cmake b/src/gmio_core/config.h.cmake index 0a34baa..8ccc905 100644 --- a/src/gmio_core/config.h.cmake +++ b/src/gmio_core/config.h.cmake @@ -44,6 +44,8 @@ #cmakedefine GMIO_HAVE_POWF_FUNC #cmakedefine GMIO_HAVE_SNPRINTF_FUNC #cmakedefine GMIO_HAVE_WIN__SNPRINTF_FUNC +#cmakedefine GMIO_HAVE_VSNPRINTF_FUNC +#cmakedefine GMIO_HAVE_WIN__VSNPRINTF_FUNC /* POSIX */ #cmakedefine GMIO_HAVE_SYS_TYPES_H diff --git a/src/gmio_core/internal/c99_stdio_compat.h b/src/gmio_core/internal/c99_stdio_compat.h index 3ed47e4..5df965f 100644 --- a/src/gmio_core/internal/c99_stdio_compat.h +++ b/src/gmio_core/internal/c99_stdio_compat.h @@ -18,29 +18,47 @@ #include "../global.h" +#include #include #include /* Note: - * Visual C++ provides snprintf() since version 2015, before that it was - * used to provide only equivalent _snprintf() + * Visual C++ provides vsnprintf() since version 2005, before it used to + * provide only _vsnprintf() * - * snprintf() appears in C99 + * vsnprintf() appeared in C99 */ +#ifdef GMIO_HAVE_VSNPRINTF_FUNC +# define gmio_vsnprintf vsnprintf +#elif defined(GMIO_HAVE_WIN__VSNPRINTF_FUNC) +# define gmio_vsnprintf _vsnprintf +#else +/* No existing vsnprintf()-like function, call unsafe vsprintf() as fallback */ +GMIO_INLINE int gmio_vsnprintf( + char* buf, size_t bufn, const char* fmt, va_list args) +{ + return vsprintf(buf, fmt, args); +} +#endif +/* Note: + * Visual C++ provides snprintf() since version 2015, before it used to + * provide only _snprintf() + * + * snprintf() appeared in C99 + */ #ifdef GMIO_HAVE_SNPRINTF_FUNC # define gmio_snprintf snprintf #elif defined(GMIO_HAVE_WIN__SNPRINTF_FUNC) # define gmio_snprintf _snprintf #else -# include -/* No existing snprintf()-like function, call unsafe vsprintf() as fallback */ +/* No existing snprintf()-like function, translate to gmio_vsnprintf() call */ GMIO_INLINE int gmio_snprintf(char* buf, size_t bufn, const char* fmt, ...) { int ret = 0; va_list args; va_start(args, fmt); - ret = vsprintf(buf, fmt, args); + ret = gmio_vsnprintf(buf, bufn, fmt, args); va_end(args); return ret; } diff --git a/tests/test_core_benchmark_fast_atof.c b/tests/test_core_benchmark_fast_atof.c index 4fedb6b..194b03e 100644 --- a/tests/test_core_benchmark_fast_atof.c +++ b/tests/test_core_benchmark_fast_atof.c @@ -16,6 +16,7 @@ #include "utest_assert.h" #include "../benchmarks/commons/benchmark_tools.h" +#include "../src/gmio_core/internal/c99_stdio_compat.h" #include "../src/gmio_core/internal/fast_atof.h" #include @@ -49,9 +50,9 @@ static void test_internal__run_atof(float (*func_atof)(const char*)) for (i = 0; i < GMIO_ARRAY_SIZE(float_array); ++i) { const float f = float_array[i]; float fres = 0.f; - sprintf(strbuff, "%f", f); + gmio_snprintf(strbuff, sizeof(strbuff), "%f", f); fres = func_atof(strbuff); - sprintf(strbuff, "%E", f); + gmio_snprintf(strbuff, sizeof(strbuff), "%E", f); fres = func_atof(strbuff); } }