blob: bee913c61151ae8a81d7c2fc01da9756a90d1bf6 [file] [log] [blame]
Paul Cercueil542cbb42014-10-21 13:00:38 +02001/*
2 * libiio - Library for interfacing industrial I/O (IIO) devices
3 *
4 * Copyright (C) 2014 Analog Devices, Inc.
5 * Author: Paul Cercueil <paul.cercueil@analog.com>
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * */
18
19#include "iio-private.h"
20
21#include <errno.h>
22#include <locale.h>
23#include <stdio.h>
24#include <stdlib.h>
Paul Cercueil53ed9432014-11-20 13:46:04 +010025#include <string.h>
Paul Cercueil542cbb42014-10-21 13:00:38 +020026
Paul Cercueil24a62122015-02-09 17:53:14 +010027#if defined(_WIN32) || (defined(__USE_XOPEN2K8) && \
Paul Cercueil2812f502014-11-05 14:40:56 +010028 (!defined(__UCLIBC__) || defined(__UCLIBC_HAS_LOCALE__)))
Paul Cercueil24a62122015-02-09 17:53:14 +010029#define LOCALE_SUPPORT
30#endif
Paul Cercueil2812f502014-11-05 14:40:56 +010031
Paul Cercueil24a62122015-02-09 17:53:14 +010032#ifdef LOCALE_SUPPORT
Paul Cercueil4202e5f2015-03-03 18:14:46 +010033#if defined(__MINGW32__)
34static int read_double_locale(const char *str, double *val)
35{
36 char *end, *old_locale;
37 double value;
38
39 /* XXX: This is not thread-safe, but it's the only way we have to
40 * support locales under MinGW without linking with Visual Studio
41 * libraries. */
42 old_locale = strdup(setlocale(LC_NUMERIC, NULL));
43 if (!old_locale)
44 return -ENOMEM;
45
46 setlocale(LC_NUMERIC, "C");
47 value = strtod(str, &end);
48 setlocale(LC_NUMERIC, old_locale);
49 free(old_locale);
50
51 if (end == str)
52 return -EINVAL;
53
54 *val = value;
55 return 0;
56}
57
58static int write_double_locale(char *buf, size_t len, double val)
59{
60 /* XXX: Not thread-safe, see above */
61 char *old_locale = strdup(setlocale(LC_NUMERIC, NULL));
62 if (!old_locale)
63 return -ENOMEM;
64
65 setlocale(LC_NUMERIC, "C");
Paul Cercueil972a4962015-03-26 13:21:01 +010066 snprintf(buf, len, "%f", val);
Paul Cercueil4202e5f2015-03-03 18:14:46 +010067 setlocale(LC_NUMERIC, old_locale);
68 free(old_locale);
69 return 0;
70}
71#elif defined(_WIN32)
Paul Cercueil24a62122015-02-09 17:53:14 +010072static int read_double_locale(const char *str, double *val)
Paul Cercueil542cbb42014-10-21 13:00:38 +020073{
Paul Cercueil542cbb42014-10-21 13:00:38 +020074 char *end;
Paul Cercueil24a62122015-02-09 17:53:14 +010075 double value;
Paul Cercueil77cbc4b2015-03-03 18:10:37 +010076 _locale_t locale = _create_locale(LC_NUMERIC, "C");
Paul Cercueil225a3e12015-03-03 18:08:41 +010077 if (!locale)
78 return -ENOMEM;
Paul Cercueil542cbb42014-10-21 13:00:38 +020079
Paul Cercueil24a62122015-02-09 17:53:14 +010080 value = _strtod_l(str, &end, locale);
81 _free_locale(locale);
Paul Cercueil542cbb42014-10-21 13:00:38 +020082
83 if (end == str)
84 return -EINVAL;
85
86 *val = value;
87 return 0;
88}
89
Paul Cercueil225a3e12015-03-03 18:08:41 +010090static int write_double_locale(char *buf, size_t len, double val)
Paul Cercueil542cbb42014-10-21 13:00:38 +020091{
Paul Cercueil77cbc4b2015-03-03 18:10:37 +010092 _locale_t locale = _create_locale(LC_NUMERIC, "C");
Paul Cercueil225a3e12015-03-03 18:08:41 +010093 if (!locale)
94 return -ENOMEM;
Paul Cercueil542cbb42014-10-21 13:00:38 +020095
Paul Cercueil972a4962015-03-26 13:21:01 +010096 _snprintf_l(buf, len, "%f", locale, val);
Paul Cercueil24a62122015-02-09 17:53:14 +010097 _free_locale(locale);
Paul Cercueil225a3e12015-03-03 18:08:41 +010098 return 0;
Paul Cercueil24a62122015-02-09 17:53:14 +010099}
Paul Cercueil542cbb42014-10-21 13:00:38 +0200100#else
Paul Cercueil24a62122015-02-09 17:53:14 +0100101static int read_double_locale(const char *str, double *val)
102{
103 char *end;
104 double value;
Paul Cercueil542cbb42014-10-21 13:00:38 +0200105 locale_t old_locale, new_locale;
106
Paul Cercueil77cbc4b2015-03-03 18:10:37 +0100107 new_locale = newlocale(LC_NUMERIC_MASK, "C", (locale_t) 0);
Paul Cercueil225a3e12015-03-03 18:08:41 +0100108 if (!new_locale)
109 return -errno;
110
Paul Cercueil542cbb42014-10-21 13:00:38 +0200111 old_locale = uselocale(new_locale);
Paul Cercueil24a62122015-02-09 17:53:14 +0100112
113 value = strtod(str, &end);
114 uselocale(old_locale);
115 freelocale(new_locale);
116
117 if (end == str)
118 return -EINVAL;
119
120 *val = value;
121 return 0;
122}
123
Paul Cercueil225a3e12015-03-03 18:08:41 +0100124static int write_double_locale(char *buf, size_t len, double val)
Paul Cercueil24a62122015-02-09 17:53:14 +0100125{
126 locale_t old_locale, new_locale;
127
Paul Cercueil77cbc4b2015-03-03 18:10:37 +0100128 new_locale = newlocale(LC_NUMERIC_MASK, "C", (locale_t) 0);
Paul Cercueil225a3e12015-03-03 18:08:41 +0100129 if (!new_locale)
130 return -errno;
131
Paul Cercueil24a62122015-02-09 17:53:14 +0100132 old_locale = uselocale(new_locale);
Paul Cercueil542cbb42014-10-21 13:00:38 +0200133
Paul Cercueil972a4962015-03-26 13:21:01 +0100134 snprintf(buf, len, "%f", val);
Paul Cercueil542cbb42014-10-21 13:00:38 +0200135
Paul Cercueil542cbb42014-10-21 13:00:38 +0200136 uselocale(old_locale);
137 freelocale(new_locale);
Paul Cercueil225a3e12015-03-03 18:08:41 +0100138 return 0;
Paul Cercueil24a62122015-02-09 17:53:14 +0100139}
Paul Cercueil542cbb42014-10-21 13:00:38 +0200140#endif
Paul Cercueil2812f502014-11-05 14:40:56 +0100141#endif
Paul Cercueil24a62122015-02-09 17:53:14 +0100142
143int read_double(const char *str, double *val)
144{
145#ifdef LOCALE_SUPPORT
146 return read_double_locale(str, val);
147#else
148 char *end;
149 double value = strtod(str, &end);
150
151 if (end == str)
152 return -EINVAL;
153
154 *val = value;
155 return 0;
156#endif
157}
158
Paul Cercueil225a3e12015-03-03 18:08:41 +0100159int write_double(char *buf, size_t len, double val)
Paul Cercueil24a62122015-02-09 17:53:14 +0100160{
161#ifdef LOCALE_SUPPORT
Paul Cercueil225a3e12015-03-03 18:08:41 +0100162 return write_double_locale(buf, len, val);
Paul Cercueil24a62122015-02-09 17:53:14 +0100163#else
Paul Cercueil972a4962015-03-26 13:21:01 +0100164 snprintf(buf, len, "%f", val);
Paul Cercueil225a3e12015-03-03 18:08:41 +0100165 return 0;
Paul Cercueil24a62122015-02-09 17:53:14 +0100166#endif
Paul Cercueil542cbb42014-10-21 13:00:38 +0200167}
Paul Cercueil53ed9432014-11-20 13:46:04 +0100168
169void iio_library_get_version(unsigned int *major,
170 unsigned int *minor, char git_tag[8])
171{
172 if (major)
173 *major = LIBIIO_VERSION_MAJOR;
174 if (minor)
175 *minor = LIBIIO_VERSION_MINOR;
176 if (git_tag) {
177 strncpy(git_tag, LIBIIO_VERSION_GIT, 8);
178 git_tag[7] = '\0';
179 }
180}
Paul Cercueil3fa34382015-05-22 10:54:28 +0200181
182void iio_strerror(int err, char *buf, size_t len)
183{
184#ifdef _WIN32
185 int ret = strerror_s(buf, len, err);
Paul Cercueil3fa34382015-05-22 10:54:28 +0200186 if (ret != 0)
187 snprintf(buf, len, "Unknown error %i", err);
Paul Cercueil3a8fdb32015-06-29 17:44:02 +0200188#elif (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && ! _GNU_SOURCE
189 int ret = strerror_r(err, buf, len);
190 if (ret != 0)
191 snprintf(buf, len, "Unknown error %i", err);
192#else
193 char *str = strerror_r(err, buf, len);
194 if (str != buf)
195 strncpy(buf, str, len);
196#endif
Paul Cercueil3fa34382015-05-22 10:54:28 +0200197}