diff options
Diffstat (limited to 'src/utilities.c')
-rw-r--r-- | src/utilities.c | 214 |
1 files changed, 214 insertions, 0 deletions
diff --git a/src/utilities.c b/src/utilities.c new file mode 100644 index 0000000..21dbd10 --- /dev/null +++ b/src/utilities.c @@ -0,0 +1,214 @@ +/* + * libiio - Library for interfacing industrial I/O (IIO) devices + * + * Copyright (C) 2014 Analog Devices, Inc. + * Author: Paul Cercueil <paul.cercueil@analog.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * */ + +/* Force the XSI version of strerror_r */ +#undef _GNU_SOURCE + +#include "iio-config.h" +#include "iio-private.h" + +#include <errno.h> +#include <locale.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#if defined(_WIN32) || (defined(__USE_XOPEN2K8) && \ + (!defined(__UCLIBC__) || defined(__UCLIBC_HAS_LOCALE__))) +#define LOCALE_SUPPORT +#endif + +#ifdef LOCALE_SUPPORT +#if defined(__MINGW32__) || (!defined(_WIN32) && !defined(HAS_NEWLOCALE)) +static int read_double_locale(const char *str, double *val) +{ + char *end, *old_locale; + double value; + + /* XXX: This is not thread-safe, but it's the only way we have to + * support locales under MinGW without linking with Visual Studio + * libraries. */ + old_locale = iio_strdup(setlocale(LC_NUMERIC, NULL)); + if (!old_locale) + return -ENOMEM; + + setlocale(LC_NUMERIC, "C"); + value = strtod(str, &end); + setlocale(LC_NUMERIC, old_locale); + free(old_locale); + + if (end == str) + return -EINVAL; + + *val = value; + return 0; +} + +static int write_double_locale(char *buf, size_t len, double val) +{ + /* XXX: Not thread-safe, see above */ + char *old_locale = iio_strdup(setlocale(LC_NUMERIC, NULL)); + if (!old_locale) + return -ENOMEM; + + setlocale(LC_NUMERIC, "C"); + iio_snprintf(buf, len, "%f", val); + setlocale(LC_NUMERIC, old_locale); + free(old_locale); + return 0; +} +#elif defined(_WIN32) +static int read_double_locale(const char *str, double *val) +{ + char *end; + double value; + _locale_t locale = _create_locale(LC_NUMERIC, "C"); + if (!locale) + return -ENOMEM; + + value = _strtod_l(str, &end, locale); + _free_locale(locale); + + if (end == str) + return -EINVAL; + + *val = value; + return 0; +} + +static int write_double_locale(char *buf, size_t len, double val) +{ + _locale_t locale = _create_locale(LC_NUMERIC, "C"); + if (!locale) + return -ENOMEM; + + _snprintf_l(buf, len, "%f", locale, val); + _free_locale(locale); + return 0; +} +#else +static int read_double_locale(const char *str, double *val) +{ + char *end; + double value; + locale_t old_locale, new_locale; + + new_locale = newlocale(LC_NUMERIC_MASK, "C", (locale_t) 0); + if (!new_locale) + return -errno; + + old_locale = uselocale(new_locale); + + value = strtod(str, &end); + uselocale(old_locale); + freelocale(new_locale); + + if (end == str) + return -EINVAL; + + *val = value; + return 0; +} + +static int write_double_locale(char *buf, size_t len, double val) +{ + locale_t old_locale, new_locale; + + new_locale = newlocale(LC_NUMERIC_MASK, "C", (locale_t) 0); + if (!new_locale) + return -errno; + + old_locale = uselocale(new_locale); + + iio_snprintf(buf, len, "%f", val); + + uselocale(old_locale); + freelocale(new_locale); + return 0; +} +#endif +#endif + +int read_double(const char *str, double *val) +{ +#ifdef LOCALE_SUPPORT + return read_double_locale(str, val); +#else + char *end; + double value = strtod(str, &end); + + if (end == str) + return -EINVAL; + + *val = value; + return 0; +#endif +} + +int write_double(char *buf, size_t len, double val) +{ +#ifdef LOCALE_SUPPORT + return write_double_locale(buf, len, val); +#else + iio_snprintf(buf, len, "%f", val); + return 0; +#endif +} + +void iio_library_get_version(unsigned int *major, + unsigned int *minor, char git_tag[8]) +{ + if (major) + *major = LIBIIO_VERSION_MAJOR; + if (minor) + *minor = LIBIIO_VERSION_MINOR; + if (git_tag) { + strncpy(git_tag, LIBIIO_VERSION_GIT, 8); + git_tag[7] = '\0'; + } +} + +void iio_strerror(int err, char *buf, size_t len) +{ +#if defined(_WIN32) + int ret = strerror_s(buf, len, err); +#elif defined(HAS_STRERROR_R) + int ret = strerror_r(err, buf, len); +#else + /* no strerror_s, no strerror_r... just use the default message */ + int ret = 0xf7de; +#endif + if (ret != 0) + iio_snprintf(buf, len, "Unknown error %i", err); +} + +char *iio_strdup(const char *str) +{ +#if defined(_WIN32) + return _strdup(str); +#elif defined(HAS_STRDUP) + return strdup(str); +#else + size_t len = strlen(str); + char *buf = malloc(len + 1); + + if (buf) + memcpy(buf, str, len + 1); + return buf; +#endif +} |