strutil: Locale independent sprintf() and vsprintf() functions
This commit is contained in:
parent
49a468ed8b
commit
21ef355e50
|
@ -248,6 +248,8 @@ SR_API uint64_t sr_parse_timestring(const char *timestring);
|
|||
SR_API gboolean sr_parse_boolstring(const char *boolstring);
|
||||
SR_API int sr_parse_period(const char *periodstr, uint64_t *p, uint64_t *q);
|
||||
SR_API int sr_parse_voltage(const char *voltstr, uint64_t *p, uint64_t *q);
|
||||
SR_API int sr_sprintf_ascii(char *buf, const char *format, ...);
|
||||
SR_API int sr_vsprintf_ascii(char *buf, const char *format, va_list args);
|
||||
SR_API int sr_snprintf_ascii(char *buf, size_t buf_size,
|
||||
const char *format, ...);
|
||||
SR_API int sr_vsnprintf_ascii(char *buf, size_t buf_size,
|
||||
|
|
164
src/strutil.c
164
src/strutil.c
|
@ -259,6 +259,165 @@ SR_PRIV int sr_atof_ascii(const char *str, float *ret)
|
|||
return SR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compose a string with a format string in the buffer pointed to by buf.
|
||||
*
|
||||
* It is up to the caller to ensure that the allocated buffer is large enough
|
||||
* to hold the formatted result.
|
||||
*
|
||||
* A terminating NUL character is automatically appended after the content
|
||||
* written.
|
||||
*
|
||||
* After the format parameter, the function expects at least as many additional
|
||||
* arguments as needed for format.
|
||||
*
|
||||
* This version ignores the current locale and uses the locale "C" for Linux,
|
||||
* FreeBSD, OSX and Android.
|
||||
*
|
||||
* @param buf Pointer to a buffer where the resulting C string is stored.
|
||||
* @param format C string that contains a format string (see printf).
|
||||
* @param ... A sequence of additional arguments, each containing a value to be
|
||||
* used to replace a format specifier in the format string.
|
||||
*
|
||||
* @return On success, the number of characters that would have been written,
|
||||
* not counting the terminating NUL character.
|
||||
*
|
||||
* @since 0.6.0
|
||||
*/
|
||||
SR_API int sr_sprintf_ascii(char *buf, const char *format, ...)
|
||||
{
|
||||
int ret;
|
||||
va_list args;
|
||||
|
||||
va_start(args, format);
|
||||
ret = sr_vsprintf_ascii(buf, format, args);
|
||||
va_end(args);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compose a string with a format string in the buffer pointed to by buf.
|
||||
*
|
||||
* It is up to the caller to ensure that the allocated buffer is large enough
|
||||
* to hold the formatted result.
|
||||
*
|
||||
* Internally, the function retrieves arguments from the list identified by
|
||||
* args as if va_arg was used on it, and thus the state of args is likely to
|
||||
* be altered by the call.
|
||||
*
|
||||
* In any case, args should have been initialized by va_start at some point
|
||||
* before the call, and it is expected to be released by va_end at some point
|
||||
* after the call.
|
||||
*
|
||||
* This version ignores the current locale and uses the locale "C" for Linux,
|
||||
* FreeBSD, OSX and Android.
|
||||
*
|
||||
* @param buf Pointer to a buffer where the resulting C string is stored.
|
||||
* @param format C string that contains a format string (see printf).
|
||||
* @param args A value identifying a variable arguments list initialized with
|
||||
* va_start.
|
||||
*
|
||||
* @return On success, the number of characters that would have been written,
|
||||
* not counting the terminating NUL character.
|
||||
*
|
||||
* @since 0.6.0
|
||||
*/
|
||||
SR_API int sr_vsprintf_ascii(char *buf, const char *format, va_list args)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
int ret;
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* TODO: This part compiles with mingw-w64 but doesn't run with Win7.
|
||||
* Doesn't start because of "Procedure entry point _create_locale
|
||||
* not found in msvcrt.dll".
|
||||
* mingw-w64 should link to msvcr100.dll not msvcrt.dll!
|
||||
* See: https://msdn.microsoft.com/en-us/en-en/library/1kt27hek.aspx
|
||||
*/
|
||||
_locale_t locale;
|
||||
|
||||
locale = _create_locale(LC_NUMERIC, "C");
|
||||
ret = _vsprintf_l(buf, format, locale, args);
|
||||
_free_locale(locale);
|
||||
#endif
|
||||
|
||||
/* vsprintf() uses the current locale, may not work correctly for floats. */
|
||||
ret = vsprintf(buf, format, args);
|
||||
|
||||
return ret;
|
||||
#elif defined(__APPLE__)
|
||||
/*
|
||||
* See:
|
||||
* https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man3/printf_l.3.html
|
||||
* https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man3/xlocale.3.html
|
||||
*/
|
||||
int ret;
|
||||
locale_t locale;
|
||||
|
||||
locale = newlocale(LC_NUMERIC_MASK, "C", NULL);
|
||||
ret = vsprintf_l(buf, locale, format, args);
|
||||
freelocale(locale);
|
||||
|
||||
return ret;
|
||||
#elif defined(__FreeBSD__) && __FreeBSD_version >= 901000
|
||||
/*
|
||||
* See:
|
||||
* https://www.freebsd.org/cgi/man.cgi?query=printf_l&apropos=0&sektion=3&manpath=FreeBSD+9.1-RELEASE
|
||||
* https://www.freebsd.org/cgi/man.cgi?query=xlocale&apropos=0&sektion=3&manpath=FreeBSD+9.1-RELEASE
|
||||
*/
|
||||
int ret;
|
||||
locale_t locale;
|
||||
|
||||
locale = newlocale(LC_NUMERIC_MASK, "C", NULL);
|
||||
ret = vsprintf_l(buf, locale, format, args);
|
||||
freelocale(locale);
|
||||
|
||||
return ret;
|
||||
#elif defined(__ANDROID__)
|
||||
/*
|
||||
* The Bionic libc only has two locales ("C" aka "POSIX" and "C.UTF-8"
|
||||
* aka "en_US.UTF-8"). The decimal point is hard coded as "."
|
||||
* See: https://android.googlesource.com/platform/bionic/+/master/libc/bionic/locale.cpp
|
||||
*/
|
||||
int ret;
|
||||
|
||||
ret = vsprintf(buf, format, args);
|
||||
|
||||
return ret;
|
||||
#elif defined(__linux__)
|
||||
int ret;
|
||||
locale_t old_locale, temp_locale;
|
||||
|
||||
/* Switch to C locale for proper float/double conversion. */
|
||||
temp_locale = newlocale(LC_NUMERIC, "C", NULL);
|
||||
old_locale = uselocale(temp_locale);
|
||||
|
||||
ret = vsprintf(buf, format, args);
|
||||
|
||||
/* Switch back to original locale. */
|
||||
uselocale(old_locale);
|
||||
freelocale(temp_locale);
|
||||
|
||||
return ret;
|
||||
#elif defined(__unix__) || defined(__unix)
|
||||
/*
|
||||
* This is a fallback for all other BSDs, *nix and FreeBSD <= 9.0, by
|
||||
* using the current locale for snprintf(). This may not work correctly
|
||||
* for floats!
|
||||
*/
|
||||
int ret;
|
||||
|
||||
ret = vsprintf(buf, format, args);
|
||||
|
||||
return ret;
|
||||
#else
|
||||
/* No implementation for unknown systems! */
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Composes a string with a format string (like printf) in the buffer pointed
|
||||
* by buf (taking buf_size as the maximum buffer capacity to fill).
|
||||
|
@ -270,7 +429,7 @@ SR_PRIV int sr_atof_ascii(const char *str, float *ret)
|
|||
* After the format parameter, the function expects at least as many additional
|
||||
* arguments as needed for format.
|
||||
*
|
||||
* This version ignores the actual locale and uses the locale "C" for Linux,
|
||||
* This version ignores the current locale and uses the locale "C" for Linux,
|
||||
* FreeBSD, OSX and Android.
|
||||
*
|
||||
* @param buf Pointer to a buffer where the resulting C string is stored.
|
||||
|
@ -317,7 +476,7 @@ SR_API int sr_snprintf_ascii(char *buf, size_t buf_size,
|
|||
* before the call, and it is expected to be released by va_end at some point
|
||||
* after the call.
|
||||
*
|
||||
* This version ignores the actual locale and uses the locale "C" for Linux,
|
||||
* This version ignores the current locale and uses the locale "C" for Linux,
|
||||
* FreeBSD, OSX and Android.
|
||||
*
|
||||
* @param buf Pointer to a buffer where the resulting C string is stored.
|
||||
|
@ -348,6 +507,7 @@ SR_API int sr_vsnprintf_ascii(char *buf, size_t buf_size,
|
|||
* Doesn't start because of "Procedure entry point _create_locale
|
||||
* not found in msvcrt.dll".
|
||||
* mingw-w64 should link to msvcr100.dll not msvcrt.dll!.
|
||||
* See: https://msdn.microsoft.com/en-us/en-en/library/1kt27hek.aspx
|
||||
*/
|
||||
_locale_t locale;
|
||||
|
||||
|
|
Loading…
Reference in New Issue