1 /*
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 /* Force the XSI version of strerror_r */
20 #undef _GNU_SOURCE
21
22 #include "iio-config.h"
23 #include "iio-private.h"
24
25 #include <errno.h>
26 #include <locale.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30
31 #if defined(_WIN32) || (defined(__USE_XOPEN2K8) && \
32 (!defined(__UCLIBC__) || defined(__UCLIBC_HAS_LOCALE__)))
33 #define LOCALE_SUPPORT
34 #endif
35
36 #ifdef LOCALE_SUPPORT
37 #if defined(__MINGW32__) || (!defined(_WIN32) && !defined(HAS_NEWLOCALE))
read_double_locale(const char * str,double * val)38 static 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. */
46 old_locale = iio_strdup(setlocale(LC_NUMERIC, NULL));
47 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
write_double_locale(char * buf,size_t len,double val)62 static int write_double_locale(char *buf, size_t len, double val)
63 {
64 /* XXX: Not thread-safe, see above */
65 char *old_locale = iio_strdup(setlocale(LC_NUMERIC, NULL));
66 if (!old_locale)
67 return -ENOMEM;
68
69 setlocale(LC_NUMERIC, "C");
70 iio_snprintf(buf, len, "%f", val);
71 setlocale(LC_NUMERIC, old_locale);
72 free(old_locale);
73 return 0;
74 }
75 #elif defined(_WIN32)
read_double_locale(const char * str,double * val)76 static int read_double_locale(const char *str, double *val)
77 {
78 char *end;
79 double value;
80 _locale_t locale = _create_locale(LC_NUMERIC, "C");
81 if (!locale)
82 return -ENOMEM;
83
84 value = _strtod_l(str, &end, locale);
85 _free_locale(locale);
86
87 if (end == str)
88 return -EINVAL;
89
90 *val = value;
91 return 0;
92 }
93
write_double_locale(char * buf,size_t len,double val)94 static int write_double_locale(char *buf, size_t len, double val)
95 {
96 _locale_t locale = _create_locale(LC_NUMERIC, "C");
97 if (!locale)
98 return -ENOMEM;
99
100 _snprintf_l(buf, len, "%f", locale, val);
101 _free_locale(locale);
102 return 0;
103 }
104 #else
read_double_locale(const char * str,double * val)105 static int read_double_locale(const char *str, double *val)
106 {
107 char *end;
108 double value;
109 locale_t old_locale, new_locale;
110
111 new_locale = newlocale(LC_NUMERIC_MASK, "C", (locale_t) 0);
112 if (!new_locale)
113 return -errno;
114
115 old_locale = uselocale(new_locale);
116
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
write_double_locale(char * buf,size_t len,double val)128 static int write_double_locale(char *buf, size_t len, double val)
129 {
130 locale_t old_locale, new_locale;
131
132 new_locale = newlocale(LC_NUMERIC_MASK, "C", (locale_t) 0);
133 if (!new_locale)
134 return -errno;
135
136 old_locale = uselocale(new_locale);
137
138 iio_snprintf(buf, len, "%f", val);
139
140 uselocale(old_locale);
141 freelocale(new_locale);
142 return 0;
143 }
144 #endif
145 #endif
146
read_double(const char * str,double * val)147 int 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
write_double(char * buf,size_t len,double val)163 int write_double(char *buf, size_t len, double val)
164 {
165 #ifdef LOCALE_SUPPORT
166 return write_double_locale(buf, len, val);
167 #else
168 iio_snprintf(buf, len, "%f", val);
169 return 0;
170 #endif
171 }
172
iio_library_get_version(unsigned int * major,unsigned int * minor,char git_tag[8])173 void 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 }
185
iio_strerror(int err,char * buf,size_t len)186 void iio_strerror(int err, char *buf, size_t len)
187 {
188 #if defined(_WIN32)
189 int ret = strerror_s(buf, len, err);
190 #elif defined(HAS_STRERROR_R)
191 int ret = strerror_r(err, buf, len);
192 #else
193 /* no strerror_s, no strerror_r... just use the default message */
194 int ret = 0xf7de;
195 #endif
196 if (ret != 0)
197 iio_snprintf(buf, len, "Unknown error %i", err);
198 }
199
iio_strdup(const char * str)200 char *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 }
215