blob: 96c3bcaeb3844a225121fa6b151290faea31d7da [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>
Romain Roffécead1da2015-06-30 13:35:51 +020022#include <fcntl.h>
Paul Cercueil542cbb42014-10-21 13:00:38 +020023#include <locale.h>
24#include <stdio.h>
25#include <stdlib.h>
Paul Cercueil53ed9432014-11-20 13:46:04 +010026#include <string.h>
Paul Cercueil542cbb42014-10-21 13:00:38 +020027
Paul Cercueil24a62122015-02-09 17:53:14 +010028#if defined(_WIN32) || (defined(__USE_XOPEN2K8) && \
Paul Cercueil2812f502014-11-05 14:40:56 +010029 (!defined(__UCLIBC__) || defined(__UCLIBC_HAS_LOCALE__)))
Paul Cercueil24a62122015-02-09 17:53:14 +010030#define LOCALE_SUPPORT
31#endif
Paul Cercueil2812f502014-11-05 14:40:56 +010032
Paul Cercueil24a62122015-02-09 17:53:14 +010033#ifdef LOCALE_SUPPORT
Paul Cercueil4202e5f2015-03-03 18:14:46 +010034#if defined(__MINGW32__)
35static int read_double_locale(const char *str, double *val)
36{
37 char *end, *old_locale;
38 double value;
39
40 /* XXX: This is not thread-safe, but it's the only way we have to
41 * support locales under MinGW without linking with Visual Studio
42 * libraries. */
43 old_locale = strdup(setlocale(LC_NUMERIC, NULL));
44 if (!old_locale)
45 return -ENOMEM;
46
47 setlocale(LC_NUMERIC, "C");
48 value = strtod(str, &end);
49 setlocale(LC_NUMERIC, old_locale);
50 free(old_locale);
51
52 if (end == str)
53 return -EINVAL;
54
55 *val = value;
56 return 0;
57}
58
59static int write_double_locale(char *buf, size_t len, double val)
60{
61 /* XXX: Not thread-safe, see above */
62 char *old_locale = strdup(setlocale(LC_NUMERIC, NULL));
63 if (!old_locale)
64 return -ENOMEM;
65
66 setlocale(LC_NUMERIC, "C");
Paul Cercueil972a4962015-03-26 13:21:01 +010067 snprintf(buf, len, "%f", val);
Paul Cercueil4202e5f2015-03-03 18:14:46 +010068 setlocale(LC_NUMERIC, old_locale);
69 free(old_locale);
70 return 0;
71}
72#elif defined(_WIN32)
Paul Cercueil24a62122015-02-09 17:53:14 +010073static int read_double_locale(const char *str, double *val)
Paul Cercueil542cbb42014-10-21 13:00:38 +020074{
Paul Cercueil542cbb42014-10-21 13:00:38 +020075 char *end;
Paul Cercueil24a62122015-02-09 17:53:14 +010076 double value;
Paul Cercueil77cbc4b2015-03-03 18:10:37 +010077 _locale_t locale = _create_locale(LC_NUMERIC, "C");
Paul Cercueil225a3e12015-03-03 18:08:41 +010078 if (!locale)
79 return -ENOMEM;
Paul Cercueil542cbb42014-10-21 13:00:38 +020080
Paul Cercueil24a62122015-02-09 17:53:14 +010081 value = _strtod_l(str, &end, locale);
82 _free_locale(locale);
Paul Cercueil542cbb42014-10-21 13:00:38 +020083
84 if (end == str)
85 return -EINVAL;
86
87 *val = value;
88 return 0;
89}
90
Paul Cercueil225a3e12015-03-03 18:08:41 +010091static int write_double_locale(char *buf, size_t len, double val)
Paul Cercueil542cbb42014-10-21 13:00:38 +020092{
Paul Cercueil77cbc4b2015-03-03 18:10:37 +010093 _locale_t locale = _create_locale(LC_NUMERIC, "C");
Paul Cercueil225a3e12015-03-03 18:08:41 +010094 if (!locale)
95 return -ENOMEM;
Paul Cercueil542cbb42014-10-21 13:00:38 +020096
Paul Cercueil972a4962015-03-26 13:21:01 +010097 _snprintf_l(buf, len, "%f", locale, val);
Paul Cercueil24a62122015-02-09 17:53:14 +010098 _free_locale(locale);
Paul Cercueil225a3e12015-03-03 18:08:41 +010099 return 0;
Paul Cercueil24a62122015-02-09 17:53:14 +0100100}
Paul Cercueil542cbb42014-10-21 13:00:38 +0200101#else
Paul Cercueil24a62122015-02-09 17:53:14 +0100102static int read_double_locale(const char *str, double *val)
103{
104 char *end;
105 double value;
Paul Cercueil542cbb42014-10-21 13:00:38 +0200106 locale_t old_locale, new_locale;
107
Paul Cercueil77cbc4b2015-03-03 18:10:37 +0100108 new_locale = newlocale(LC_NUMERIC_MASK, "C", (locale_t) 0);
Paul Cercueil225a3e12015-03-03 18:08:41 +0100109 if (!new_locale)
110 return -errno;
111
Paul Cercueil542cbb42014-10-21 13:00:38 +0200112 old_locale = uselocale(new_locale);
Paul Cercueil24a62122015-02-09 17:53:14 +0100113
114 value = strtod(str, &end);
115 uselocale(old_locale);
116 freelocale(new_locale);
117
118 if (end == str)
119 return -EINVAL;
120
121 *val = value;
122 return 0;
123}
124
Paul Cercueil225a3e12015-03-03 18:08:41 +0100125static int write_double_locale(char *buf, size_t len, double val)
Paul Cercueil24a62122015-02-09 17:53:14 +0100126{
127 locale_t old_locale, new_locale;
128
Paul Cercueil77cbc4b2015-03-03 18:10:37 +0100129 new_locale = newlocale(LC_NUMERIC_MASK, "C", (locale_t) 0);
Paul Cercueil225a3e12015-03-03 18:08:41 +0100130 if (!new_locale)
131 return -errno;
132
Paul Cercueil24a62122015-02-09 17:53:14 +0100133 old_locale = uselocale(new_locale);
Paul Cercueil542cbb42014-10-21 13:00:38 +0200134
Paul Cercueil972a4962015-03-26 13:21:01 +0100135 snprintf(buf, len, "%f", val);
Paul Cercueil542cbb42014-10-21 13:00:38 +0200136
Paul Cercueil542cbb42014-10-21 13:00:38 +0200137 uselocale(old_locale);
138 freelocale(new_locale);
Paul Cercueil225a3e12015-03-03 18:08:41 +0100139 return 0;
Paul Cercueil24a62122015-02-09 17:53:14 +0100140}
Paul Cercueil542cbb42014-10-21 13:00:38 +0200141#endif
Paul Cercueil2812f502014-11-05 14:40:56 +0100142#endif
Paul Cercueil24a62122015-02-09 17:53:14 +0100143
144int read_double(const char *str, double *val)
145{
146#ifdef LOCALE_SUPPORT
147 return read_double_locale(str, val);
148#else
149 char *end;
150 double value = strtod(str, &end);
151
152 if (end == str)
153 return -EINVAL;
154
155 *val = value;
156 return 0;
157#endif
158}
159
Paul Cercueil225a3e12015-03-03 18:08:41 +0100160int write_double(char *buf, size_t len, double val)
Paul Cercueil24a62122015-02-09 17:53:14 +0100161{
162#ifdef LOCALE_SUPPORT
Paul Cercueil225a3e12015-03-03 18:08:41 +0100163 return write_double_locale(buf, len, val);
Paul Cercueil24a62122015-02-09 17:53:14 +0100164#else
Paul Cercueil972a4962015-03-26 13:21:01 +0100165 snprintf(buf, len, "%f", val);
Paul Cercueil225a3e12015-03-03 18:08:41 +0100166 return 0;
Paul Cercueil24a62122015-02-09 17:53:14 +0100167#endif
Paul Cercueil542cbb42014-10-21 13:00:38 +0200168}
Paul Cercueil53ed9432014-11-20 13:46:04 +0100169
170void iio_library_get_version(unsigned int *major,
171 unsigned int *minor, char git_tag[8])
172{
173 if (major)
174 *major = LIBIIO_VERSION_MAJOR;
175 if (minor)
176 *minor = LIBIIO_VERSION_MINOR;
177 if (git_tag) {
178 strncpy(git_tag, LIBIIO_VERSION_GIT, 8);
179 git_tag[7] = '\0';
180 }
181}
Paul Cercueil3fa34382015-05-22 10:54:28 +0200182
183void iio_strerror(int err, char *buf, size_t len)
184{
185#ifdef _WIN32
186 int ret = strerror_s(buf, len, err);
Paul Cercueil3fa34382015-05-22 10:54:28 +0200187 if (ret != 0)
188 snprintf(buf, len, "Unknown error %i", err);
Paul Cercueil3a8fdb32015-06-29 17:44:02 +0200189#elif (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && ! _GNU_SOURCE
190 int ret = strerror_r(err, buf, len);
191 if (ret != 0)
192 snprintf(buf, len, "Unknown error %i", err);
193#else
194 char *str = strerror_r(err, buf, len);
195 if (str != buf)
196 strncpy(buf, str, len);
197#endif
Paul Cercueil3fa34382015-05-22 10:54:28 +0200198}
Romain Roffécead1da2015-06-30 13:35:51 +0200199
200int set_blocking_mode(int fd, bool blocking)
201{
202#ifndef _WIN32
203 int ret = fcntl(fd, F_GETFL, 0);
204 if (ret < 0)
205 return -errno;
206
207 if (blocking)
208 ret &= ~O_NONBLOCK;
209 else
210 ret |= O_NONBLOCK;
211
212 ret = fcntl(fd, F_SETFL, ret);
213 return ret < 0 ? -errno : 0;
214#else
215 return -ENOSYS;
216#endif
217}