You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
215 lines
4.5 KiB
215 lines
4.5 KiB
/*
|
|
* 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
|
|
}
|