blob: 21dbd104919d20422026c948ce037bc2a408e160 [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
Paul Cercueil24a62122015-02-09 17:53:14 +010031#if defined(_WIN32) || (defined(__USE_XOPEN2K8) && \
Paul Cercueil2812f502014-11-05 14:40:56 +010032 (!defined(__UCLIBC__) || defined(__UCLIBC_HAS_LOCALE__)))
Paul Cercueil24a62122015-02-09 17:53:14 +010033#define LOCALE_SUPPORT
34#endif
Paul Cercueil2812f502014-11-05 14:40:56 +010035
Paul Cercueil24a62122015-02-09 17:53:14 +010036#ifdef LOCALE_SUPPORT
Paul Cercueil7acf18e2017-02-06 14:04:47 +010037#if defined(__MINGW32__) || (!defined(_WIN32) && !defined(HAS_NEWLOCALE))
Paul Cercueil4202e5f2015-03-03 18:14:46 +010038static int read_double_locale(const char *str, double *val)
39{
40 char *end, *old_locale;
41 double value;
42
43 /* XXX: This is not thread-safe, but it's the only way we have to
44 * support locales under MinGW without linking with Visual Studio
45 * libraries. */
Paul Cercueilcaf0e712016-08-25 17:27:02 +020046 old_locale = iio_strdup(setlocale(LC_NUMERIC, NULL));
Paul Cercueil4202e5f2015-03-03 18:14:46 +010047 if (!old_locale)
48 return -ENOMEM;
49
50 setlocale(LC_NUMERIC, "C");
51 value = strtod(str, &end);
52 setlocale(LC_NUMERIC, old_locale);
53 free(old_locale);
54
55 if (end == str)
56 return -EINVAL;
57
58 *val = value;
59 return 0;
60}
61
62static int write_double_locale(char *buf, size_t len, double val)
63{
64 /* XXX: Not thread-safe, see above */
Paul Cercueilcaf0e712016-08-25 17:27:02 +020065 char *old_locale = iio_strdup(setlocale(LC_NUMERIC, NULL));
Paul Cercueil4202e5f2015-03-03 18:14:46 +010066 if (!old_locale)
67 return -ENOMEM;
68
69 setlocale(LC_NUMERIC, "C");
Paul Cercueil9c9a5562017-01-24 10:48:31 +010070 iio_snprintf(buf, len, "%f", val);
Paul Cercueil4202e5f2015-03-03 18:14:46 +010071 setlocale(LC_NUMERIC, old_locale);
72 free(old_locale);
73 return 0;
74}
75#elif defined(_WIN32)
Paul Cercueil24a62122015-02-09 17:53:14 +010076static int read_double_locale(const char *str, double *val)
Paul Cercueil542cbb42014-10-21 13:00:38 +020077{
Paul Cercueil542cbb42014-10-21 13:00:38 +020078 char *end;
Paul Cercueil24a62122015-02-09 17:53:14 +010079 double value;
Paul Cercueil77cbc4b2015-03-03 18:10:37 +010080 _locale_t locale = _create_locale(LC_NUMERIC, "C");
Paul Cercueil225a3e12015-03-03 18:08:41 +010081 if (!locale)
82 return -ENOMEM;
Paul Cercueil542cbb42014-10-21 13:00:38 +020083
Paul Cercueil24a62122015-02-09 17:53:14 +010084 value = _strtod_l(str, &end, locale);
85 _free_locale(locale);
Paul Cercueil542cbb42014-10-21 13:00:38 +020086
87 if (end == str)
88 return -EINVAL;
89
90 *val = value;
91 return 0;
92}
93
Paul Cercueil225a3e12015-03-03 18:08:41 +010094static int write_double_locale(char *buf, size_t len, double val)
Paul Cercueil542cbb42014-10-21 13:00:38 +020095{
Paul Cercueil77cbc4b2015-03-03 18:10:37 +010096 _locale_t locale = _create_locale(LC_NUMERIC, "C");
Paul Cercueil225a3e12015-03-03 18:08:41 +010097 if (!locale)
98 return -ENOMEM;
Paul Cercueil542cbb42014-10-21 13:00:38 +020099
Paul Cercueil972a4962015-03-26 13:21:01 +0100100 _snprintf_l(buf, len, "%f", locale, val);
Paul Cercueil24a62122015-02-09 17:53:14 +0100101 _free_locale(locale);
Paul Cercueil225a3e12015-03-03 18:08:41 +0100102 return 0;
Paul Cercueil24a62122015-02-09 17:53:14 +0100103}
Paul Cercueil542cbb42014-10-21 13:00:38 +0200104#else
Paul Cercueil24a62122015-02-09 17:53:14 +0100105static int read_double_locale(const char *str, double *val)
106{
107 char *end;
108 double value;
Paul Cercueil542cbb42014-10-21 13:00:38 +0200109 locale_t old_locale, new_locale;
110
Paul Cercueil77cbc4b2015-03-03 18:10:37 +0100111 new_locale = newlocale(LC_NUMERIC_MASK, "C", (locale_t) 0);
Paul Cercueil225a3e12015-03-03 18:08:41 +0100112 if (!new_locale)
113 return -errno;
114
Paul Cercueil542cbb42014-10-21 13:00:38 +0200115 old_locale = uselocale(new_locale);
Paul Cercueil24a62122015-02-09 17:53:14 +0100116
117 value = strtod(str, &end);
118 uselocale(old_locale);
119 freelocale(new_locale);
120
121 if (end == str)
122 return -EINVAL;
123
124 *val = value;
125 return 0;
126}
127
Paul Cercueil225a3e12015-03-03 18:08:41 +0100128static int write_double_locale(char *buf, size_t len, double val)
Paul Cercueil24a62122015-02-09 17:53:14 +0100129{
130 locale_t old_locale, new_locale;
131
Paul Cercueil77cbc4b2015-03-03 18:10:37 +0100132 new_locale = newlocale(LC_NUMERIC_MASK, "C", (locale_t) 0);
Paul Cercueil225a3e12015-03-03 18:08:41 +0100133 if (!new_locale)
134 return -errno;
135
Paul Cercueil24a62122015-02-09 17:53:14 +0100136 old_locale = uselocale(new_locale);
Paul Cercueil542cbb42014-10-21 13:00:38 +0200137
Paul Cercueil9c9a5562017-01-24 10:48:31 +0100138 iio_snprintf(buf, len, "%f", val);
Paul Cercueil542cbb42014-10-21 13:00:38 +0200139
Paul Cercueil542cbb42014-10-21 13:00:38 +0200140 uselocale(old_locale);
141 freelocale(new_locale);
Paul Cercueil225a3e12015-03-03 18:08:41 +0100142 return 0;
Paul Cercueil24a62122015-02-09 17:53:14 +0100143}
Paul Cercueil542cbb42014-10-21 13:00:38 +0200144#endif
Paul Cercueil2812f502014-11-05 14:40:56 +0100145#endif
Paul Cercueil24a62122015-02-09 17:53:14 +0100146
147int read_double(const char *str, double *val)
148{
149#ifdef LOCALE_SUPPORT
150 return read_double_locale(str, val);
151#else
152 char *end;
153 double value = strtod(str, &end);
154
155 if (end == str)
156 return -EINVAL;
157
158 *val = value;
159 return 0;
160#endif
161}
162
Paul Cercueil225a3e12015-03-03 18:08:41 +0100163int write_double(char *buf, size_t len, double val)
Paul Cercueil24a62122015-02-09 17:53:14 +0100164{
165#ifdef LOCALE_SUPPORT
Paul Cercueil225a3e12015-03-03 18:08:41 +0100166 return write_double_locale(buf, len, val);
Paul Cercueil24a62122015-02-09 17:53:14 +0100167#else
Paul Cercueil9c9a5562017-01-24 10:48:31 +0100168 iio_snprintf(buf, len, "%f", val);
Paul Cercueil225a3e12015-03-03 18:08:41 +0100169 return 0;
Paul Cercueil24a62122015-02-09 17:53:14 +0100170#endif
Paul Cercueil542cbb42014-10-21 13:00:38 +0200171}
Paul Cercueil53ed9432014-11-20 13:46:04 +0100172
173void iio_library_get_version(unsigned int *major,
174 unsigned int *minor, char git_tag[8])
175{
176 if (major)
177 *major = LIBIIO_VERSION_MAJOR;
178 if (minor)
179 *minor = LIBIIO_VERSION_MINOR;
180 if (git_tag) {
181 strncpy(git_tag, LIBIIO_VERSION_GIT, 8);
182 git_tag[7] = '\0';
183 }
184}
Paul Cercueil3fa34382015-05-22 10:54:28 +0200185
186void iio_strerror(int err, char *buf, size_t len)
187{
Paul Cercueil105dcb82016-08-25 17:35:46 +0200188#if defined(_WIN32)
Paul Cercueil3fa34382015-05-22 10:54:28 +0200189 int ret = strerror_s(buf, len, err);
Paul Cercueil105dcb82016-08-25 17:35:46 +0200190#elif defined(HAS_STRERROR_R)
Paul Cercueilfbdd08f2016-06-30 12:32:23 +0200191 int ret = strerror_r(err, buf, len);
Paul Cercueil105dcb82016-08-25 17:35:46 +0200192#else
193 /* no strerror_s, no strerror_r... just use the default message */
194 int ret = 0xf7de;
Paul Cercueil3a8fdb32015-06-29 17:44:02 +0200195#endif
Paul Cercueilfbdd08f2016-06-30 12:32:23 +0200196 if (ret != 0)
Paul Cercueil9c9a5562017-01-24 10:48:31 +0100197 iio_snprintf(buf, len, "Unknown error %i", err);
Paul Cercueil3fa34382015-05-22 10:54:28 +0200198}
Paul Cercueilcaf0e712016-08-25 17:27:02 +0200199
200char *iio_strdup(const char *str)
201{
202#if defined(_WIN32)
203 return _strdup(str);
204#elif defined(HAS_STRDUP)
205 return strdup(str);
206#else
207 size_t len = strlen(str);
208 char *buf = malloc(len + 1);
209
210 if (buf)
211 memcpy(buf, str, len + 1);
212 return buf;
213#endif
214}