blob: 85a4813ccef17d5164fc67e44919e63b0add4e9d [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
Paul Cercueilfbdd08f2016-06-30 12:32:23 +020019/* Force the XSI version of strerror_r */
20#undef _GNU_SOURCE
21
Paul Cercueil2814ed12016-08-25 17:08:18 +020022#include "iio-config.h"
Paul Cercueil542cbb42014-10-21 13:00:38 +020023#include "iio-private.h"
24
25#include <errno.h>
26#include <locale.h>
27#include <stdio.h>
28#include <stdlib.h>
Paul Cercueil53ed9432014-11-20 13:46:04 +010029#include <string.h>
Paul Cercueil542cbb42014-10-21 13:00:38 +020030
Dan Nechita4ed3af62019-11-04 16:42:54 +020031#if defined(_WIN32) || \
32 (defined(__APPLE__) && defined(__MACH__)) || \
33 (defined(__USE_XOPEN2K8) && \
Paul Cercueil2812f502014-11-05 14:40:56 +010034 (!defined(__UCLIBC__) || defined(__UCLIBC_HAS_LOCALE__)))
Paul Cercueil24a62122015-02-09 17:53:14 +010035#define LOCALE_SUPPORT
36#endif
Paul Cercueil2812f502014-11-05 14:40:56 +010037
Paul Cercueil24a62122015-02-09 17:53:14 +010038#ifdef LOCALE_SUPPORT
Paul Cercueil7acf18e2017-02-06 14:04:47 +010039#if defined(__MINGW32__) || (!defined(_WIN32) && !defined(HAS_NEWLOCALE))
Paul Cercueil4202e5f2015-03-03 18:14:46 +010040static int read_double_locale(const char *str, double *val)
41{
42 char *end, *old_locale;
43 double value;
44
45 /* XXX: This is not thread-safe, but it's the only way we have to
46 * support locales under MinGW without linking with Visual Studio
47 * libraries. */
Paul Cercueilcaf0e712016-08-25 17:27:02 +020048 old_locale = iio_strdup(setlocale(LC_NUMERIC, NULL));
Paul Cercueil4202e5f2015-03-03 18:14:46 +010049 if (!old_locale)
50 return -ENOMEM;
51
52 setlocale(LC_NUMERIC, "C");
53 value = strtod(str, &end);
54 setlocale(LC_NUMERIC, old_locale);
55 free(old_locale);
56
57 if (end == str)
58 return -EINVAL;
59
60 *val = value;
61 return 0;
62}
63
64static int write_double_locale(char *buf, size_t len, double val)
65{
66 /* XXX: Not thread-safe, see above */
Paul Cercueilcaf0e712016-08-25 17:27:02 +020067 char *old_locale = iio_strdup(setlocale(LC_NUMERIC, NULL));
Paul Cercueil4202e5f2015-03-03 18:14:46 +010068 if (!old_locale)
69 return -ENOMEM;
70
71 setlocale(LC_NUMERIC, "C");
Paul Cercueil9c9a5562017-01-24 10:48:31 +010072 iio_snprintf(buf, len, "%f", val);
Paul Cercueil4202e5f2015-03-03 18:14:46 +010073 setlocale(LC_NUMERIC, old_locale);
74 free(old_locale);
75 return 0;
76}
77#elif defined(_WIN32)
Paul Cercueil24a62122015-02-09 17:53:14 +010078static int read_double_locale(const char *str, double *val)
Paul Cercueil542cbb42014-10-21 13:00:38 +020079{
Paul Cercueil542cbb42014-10-21 13:00:38 +020080 char *end;
Paul Cercueil24a62122015-02-09 17:53:14 +010081 double value;
Paul Cercueil77cbc4b2015-03-03 18:10:37 +010082 _locale_t locale = _create_locale(LC_NUMERIC, "C");
Paul Cercueil225a3e12015-03-03 18:08:41 +010083 if (!locale)
84 return -ENOMEM;
Paul Cercueil542cbb42014-10-21 13:00:38 +020085
Paul Cercueil24a62122015-02-09 17:53:14 +010086 value = _strtod_l(str, &end, locale);
87 _free_locale(locale);
Paul Cercueil542cbb42014-10-21 13:00:38 +020088
89 if (end == str)
90 return -EINVAL;
91
92 *val = value;
93 return 0;
94}
95
Paul Cercueil225a3e12015-03-03 18:08:41 +010096static int write_double_locale(char *buf, size_t len, double val)
Paul Cercueil542cbb42014-10-21 13:00:38 +020097{
Paul Cercueil77cbc4b2015-03-03 18:10:37 +010098 _locale_t locale = _create_locale(LC_NUMERIC, "C");
Paul Cercueil225a3e12015-03-03 18:08:41 +010099 if (!locale)
100 return -ENOMEM;
Paul Cercueil542cbb42014-10-21 13:00:38 +0200101
Paul Cercueil972a4962015-03-26 13:21:01 +0100102 _snprintf_l(buf, len, "%f", locale, val);
Paul Cercueil24a62122015-02-09 17:53:14 +0100103 _free_locale(locale);
Paul Cercueil225a3e12015-03-03 18:08:41 +0100104 return 0;
Paul Cercueil24a62122015-02-09 17:53:14 +0100105}
Paul Cercueil542cbb42014-10-21 13:00:38 +0200106#else
Paul Cercueil24a62122015-02-09 17:53:14 +0100107static int read_double_locale(const char *str, double *val)
108{
109 char *end;
110 double value;
Paul Cercueil542cbb42014-10-21 13:00:38 +0200111 locale_t old_locale, new_locale;
112
Paul Cercueil77cbc4b2015-03-03 18:10:37 +0100113 new_locale = newlocale(LC_NUMERIC_MASK, "C", (locale_t) 0);
Paul Cercueil225a3e12015-03-03 18:08:41 +0100114 if (!new_locale)
115 return -errno;
116
Paul Cercueil542cbb42014-10-21 13:00:38 +0200117 old_locale = uselocale(new_locale);
Paul Cercueil24a62122015-02-09 17:53:14 +0100118
119 value = strtod(str, &end);
120 uselocale(old_locale);
121 freelocale(new_locale);
122
123 if (end == str)
124 return -EINVAL;
125
126 *val = value;
127 return 0;
128}
129
Paul Cercueil225a3e12015-03-03 18:08:41 +0100130static int write_double_locale(char *buf, size_t len, double val)
Paul Cercueil24a62122015-02-09 17:53:14 +0100131{
132 locale_t old_locale, new_locale;
133
Paul Cercueil77cbc4b2015-03-03 18:10:37 +0100134 new_locale = newlocale(LC_NUMERIC_MASK, "C", (locale_t) 0);
Paul Cercueil225a3e12015-03-03 18:08:41 +0100135 if (!new_locale)
136 return -errno;
137
Paul Cercueil24a62122015-02-09 17:53:14 +0100138 old_locale = uselocale(new_locale);
Paul Cercueil542cbb42014-10-21 13:00:38 +0200139
Paul Cercueil9c9a5562017-01-24 10:48:31 +0100140 iio_snprintf(buf, len, "%f", val);
Paul Cercueil542cbb42014-10-21 13:00:38 +0200141
Paul Cercueil542cbb42014-10-21 13:00:38 +0200142 uselocale(old_locale);
143 freelocale(new_locale);
Paul Cercueil225a3e12015-03-03 18:08:41 +0100144 return 0;
Paul Cercueil24a62122015-02-09 17:53:14 +0100145}
Paul Cercueil542cbb42014-10-21 13:00:38 +0200146#endif
Paul Cercueil2812f502014-11-05 14:40:56 +0100147#endif
Paul Cercueil24a62122015-02-09 17:53:14 +0100148
149int read_double(const char *str, double *val)
150{
151#ifdef LOCALE_SUPPORT
152 return read_double_locale(str, val);
153#else
154 char *end;
155 double value = strtod(str, &end);
156
157 if (end == str)
158 return -EINVAL;
159
160 *val = value;
161 return 0;
162#endif
163}
164
Paul Cercueil225a3e12015-03-03 18:08:41 +0100165int write_double(char *buf, size_t len, double val)
Paul Cercueil24a62122015-02-09 17:53:14 +0100166{
167#ifdef LOCALE_SUPPORT
Paul Cercueil225a3e12015-03-03 18:08:41 +0100168 return write_double_locale(buf, len, val);
Paul Cercueil24a62122015-02-09 17:53:14 +0100169#else
Paul Cercueil9c9a5562017-01-24 10:48:31 +0100170 iio_snprintf(buf, len, "%f", val);
Paul Cercueil225a3e12015-03-03 18:08:41 +0100171 return 0;
Paul Cercueil24a62122015-02-09 17:53:14 +0100172#endif
Paul Cercueil542cbb42014-10-21 13:00:38 +0200173}
Paul Cercueil53ed9432014-11-20 13:46:04 +0100174
175void iio_library_get_version(unsigned int *major,
176 unsigned int *minor, char git_tag[8])
177{
178 if (major)
179 *major = LIBIIO_VERSION_MAJOR;
180 if (minor)
181 *minor = LIBIIO_VERSION_MINOR;
182 if (git_tag) {
183 strncpy(git_tag, LIBIIO_VERSION_GIT, 8);
184 git_tag[7] = '\0';
185 }
186}
Paul Cercueil3fa34382015-05-22 10:54:28 +0200187
188void iio_strerror(int err, char *buf, size_t len)
189{
Paul Cercueil105dcb82016-08-25 17:35:46 +0200190#if defined(_WIN32)
Paul Cercueil3fa34382015-05-22 10:54:28 +0200191 int ret = strerror_s(buf, len, err);
Paul Cercueil105dcb82016-08-25 17:35:46 +0200192#elif defined(HAS_STRERROR_R)
Paul Cercueilfbdd08f2016-06-30 12:32:23 +0200193 int ret = strerror_r(err, buf, len);
Paul Cercueil105dcb82016-08-25 17:35:46 +0200194#else
195 /* no strerror_s, no strerror_r... just use the default message */
196 int ret = 0xf7de;
Paul Cercueil3a8fdb32015-06-29 17:44:02 +0200197#endif
Paul Cercueilfbdd08f2016-06-30 12:32:23 +0200198 if (ret != 0)
Paul Cercueil9c9a5562017-01-24 10:48:31 +0100199 iio_snprintf(buf, len, "Unknown error %i", err);
Paul Cercueil3fa34382015-05-22 10:54:28 +0200200}
Paul Cercueilcaf0e712016-08-25 17:27:02 +0200201
202char *iio_strdup(const char *str)
203{
204#if defined(_WIN32)
205 return _strdup(str);
206#elif defined(HAS_STRDUP)
207 return strdup(str);
208#else
209 size_t len = strlen(str);
210 char *buf = malloc(len + 1);
211
212 if (buf)
213 memcpy(buf, str, len + 1);
214 return buf;
215#endif
216}