]> sigrok.org Git - libsigrok.git/blob - src/strutil.c
drivers: Fix locale dependent string to float conversion
[libsigrok.git] / src / strutil.c
1 /*
2  * This file is part of the libsigrok project.
3  *
4  * Copyright (C) 2010 Uwe Hermann <uwe@hermann-uwe.de>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <config.h>
21 #include <stdint.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <strings.h>
25 #include <errno.h>
26 #include <stdbool.h>
27 #include <libsigrok/libsigrok.h>
28 #include "libsigrok-internal.h"
29
30 /** @cond PRIVATE */
31 #define LOG_PREFIX "strutil"
32 /** @endcond */
33
34 /**
35  * @file
36  *
37  * Helper functions for handling or converting libsigrok-related strings.
38  */
39
40 /**
41  * @defgroup grp_strutil String utilities
42  *
43  * Helper functions for handling or converting libsigrok-related strings.
44  *
45  * @{
46  */
47
48 /**
49  * @private
50  *
51  * Convert a string representation of a numeric value (base 10) to a long integer. The
52  * conversion is strict and will fail if the complete string does not represent
53  * a valid long integer. The function sets errno according to the details of the
54  * failure.
55  *
56  * @param str The string representation to convert.
57  * @param ret Pointer to long where the result of the conversion will be stored.
58  *
59  * @retval SR_OK Conversion successful.
60  * @retval SR_ERR Failure.
61  */
62 SR_PRIV int sr_atol(const char *str, long *ret)
63 {
64         long tmp;
65         char *endptr = NULL;
66
67         errno = 0;
68         tmp = strtol(str, &endptr, 10);
69
70         if (!endptr || *endptr || errno) {
71                 if (!errno)
72                         errno = EINVAL;
73                 return SR_ERR;
74         }
75
76         *ret = tmp;
77         return SR_OK;
78 }
79
80 /**
81  * @private
82  *
83  * Convert a string representation of a numeric value (base 10) to an integer. The
84  * conversion is strict and will fail if the complete string does not represent
85  * a valid integer. The function sets errno according to the details of the
86  * failure.
87  *
88  * @param str The string representation to convert.
89  * @param ret Pointer to int where the result of the conversion will be stored.
90  *
91  * @retval SR_OK Conversion successful.
92  * @retval SR_ERR Failure.
93  */
94 SR_PRIV int sr_atoi(const char *str, int *ret)
95 {
96         long tmp;
97
98         if (sr_atol(str, &tmp) != SR_OK)
99                 return SR_ERR;
100
101         if ((int) tmp != tmp) {
102                 errno = ERANGE;
103                 return SR_ERR;
104         }
105
106         *ret = (int) tmp;
107         return SR_OK;
108 }
109
110 /**
111  * @private
112  *
113  * Convert a string representation of a numeric value to a double. The
114  * conversion is strict and will fail if the complete string does not represent
115  * a valid double. The function sets errno according to the details of the
116  * failure.
117  *
118  * @param str The string representation to convert.
119  * @param ret Pointer to double where the result of the conversion will be stored.
120  *
121  * @retval SR_OK Conversion successful.
122  * @retval SR_ERR Failure.
123  */
124 SR_PRIV int sr_atod(const char *str, double *ret)
125 {
126         double tmp;
127         char *endptr = NULL;
128
129         errno = 0;
130         tmp = strtof(str, &endptr);
131
132         if (!endptr || *endptr || errno) {
133                 if (!errno)
134                         errno = EINVAL;
135                 return SR_ERR;
136         }
137
138         *ret = tmp;
139         return SR_OK;
140 }
141
142 /**
143  * @private
144  *
145  * Convert a string representation of a numeric value to a float. The
146  * conversion is strict and will fail if the complete string does not represent
147  * a valid float. The function sets errno according to the details of the
148  * failure.
149  *
150  * @param str The string representation to convert.
151  * @param ret Pointer to float where the result of the conversion will be stored.
152  *
153  * @retval SR_OK Conversion successful.
154  * @retval SR_ERR Failure.
155  */
156 SR_PRIV int sr_atof(const char *str, float *ret)
157 {
158         double tmp;
159
160         if (sr_atod(str, &tmp) != SR_OK)
161                 return SR_ERR;
162
163         if ((float) tmp != tmp) {
164                 errno = ERANGE;
165                 return SR_ERR;
166         }
167
168         *ret = (float) tmp;
169         return SR_OK;
170 }
171
172 /**
173  * @private
174  *
175  * Convert a string representation of a numeric value to a double. The
176  * conversion is strict and will fail if the complete string does not represent
177  * a valid double. The function sets errno according to the details of the
178  * failure. This version ignores the locale.
179  *
180  * @param str The string representation to convert.
181  * @param ret Pointer to double where the result of the conversion will be stored.
182  *
183  * @retval SR_OK Conversion successful.
184  * @retval SR_ERR Failure.
185  */
186 SR_PRIV int sr_atod_ascii(const char *str, double *ret)
187 {
188         double tmp;
189         char *endptr = NULL;
190
191         errno = 0;
192         tmp = g_ascii_strtod(str, &endptr);
193
194         if (!endptr || *endptr || errno) {
195                 if (!errno)
196                         errno = EINVAL;
197                 return SR_ERR;
198         }
199
200         *ret = tmp;
201         return SR_OK;
202 }
203
204 /**
205  * @private
206  *
207  * Convert a string representation of a numeric value to a float. The
208  * conversion is strict and will fail if the complete string does not represent
209  * a valid float. The function sets errno according to the details of the
210  * failure. This version ignores the locale.
211  *
212  * @param str The string representation to convert.
213  * @param ret Pointer to float where the result of the conversion will be stored.
214  *
215  * @retval SR_OK Conversion successful.
216  * @retval SR_ERR Failure.
217  */
218 SR_PRIV int sr_atof_ascii(const char *str, float *ret)
219 {
220         double tmp;
221         char *endptr = NULL;
222
223         errno = 0;
224         tmp = g_ascii_strtod(str, &endptr);
225
226         if (!endptr || *endptr || errno) {
227                 if (!errno)
228                         errno = EINVAL;
229                 return SR_ERR;
230         }
231
232         /* FIXME This fails unexpectedly. Some other method to safel downcast
233          * needs to be found. Checking against FLT_MAX doesn't work as well. */
234         /*
235         if ((float) tmp != tmp) {
236                 errno = ERANGE;
237                 sr_dbg("ERANGEEEE %e != %e", (float) tmp, tmp);
238                 return SR_ERR;
239         }
240         */
241
242         *ret = (float) tmp;
243         return SR_OK;
244 }
245
246 /**
247  * Convert a string representation of a numeric value to a sr_rational.
248  *
249  * The conversion is strict and will fail if the complete string does not
250  * represent a valid number. The function sets errno according to the details
251  * of the failure. This version ignores the locale.
252  *
253  * @param str The string representation to convert.
254  * @param ret Pointer to sr_rational where the result of the conversion will be stored.
255  *
256  * @retval SR_OK Conversion successful.
257  * @retval SR_ERR Failure.
258  *
259  * @since 0.5.0
260  */
261 SR_API int sr_parse_rational(const char *str, struct sr_rational *ret)
262 {
263         char *endptr = NULL;
264         int64_t integral;
265         int64_t fractional = 0;
266         int64_t denominator = 1;
267         int32_t fractional_len = 0;
268         int32_t exponent = 0;
269         bool is_negative = false;
270
271         errno = 0;
272         integral = g_ascii_strtoll(str, &endptr, 10);
273
274         if (str == endptr && (str[0] == '-' || str[0] == '+') && str[1] == '.')
275                 endptr += 1;
276         else if (errno)
277                 return SR_ERR;
278
279         if (integral < 0 || str[0] == '-')
280                 is_negative = true;
281
282         if (*endptr == '.') {
283                 const char* start = endptr + 1;
284                 fractional = g_ascii_strtoll(start, &endptr, 10);
285                 if (errno)
286                         return SR_ERR;
287                 fractional_len = endptr - start;
288         }
289
290         if ((*endptr == 'E') || (*endptr == 'e')) {
291                 exponent = g_ascii_strtoll(endptr + 1, &endptr, 10);
292                 if (errno)
293                         return SR_ERR;
294         }
295
296         if (*endptr != '\0')
297                 return SR_ERR;
298
299         for (int i = 0; i < fractional_len; i++)
300                 integral *= 10;
301         exponent -= fractional_len;
302
303         if (!is_negative)
304                 integral += fractional;
305         else
306                 integral -= fractional;
307
308         while (exponent > 0) {
309                 integral *= 10;
310                 exponent--;
311         }
312
313         while (exponent < 0) {
314                 denominator *= 10;
315                 exponent++;
316         }
317
318         ret->p = integral;
319         ret->q = denominator;
320
321         return SR_OK;
322 }
323
324 /**
325  * Convert a numeric value value to its "natural" string representation
326  * in SI units.
327  *
328  * E.g. a value of 3000000, with units set to "W", would be converted
329  * to "3 MW", 20000 to "20 kW", 31500 would become "31.5 kW".
330  *
331  * @param x The value to convert.
332  * @param unit The unit to append to the string, or NULL if the string
333  *             has no units.
334  *
335  * @return A newly allocated string representation of the samplerate value,
336  *         or NULL upon errors. The caller is responsible to g_free() the
337  *         memory.
338  *
339  * @since 0.2.0
340  */
341 SR_API char *sr_si_string_u64(uint64_t x, const char *unit)
342 {
343         uint8_t i;
344         uint64_t quot, divisor[] = {
345                 SR_HZ(1), SR_KHZ(1), SR_MHZ(1), SR_GHZ(1),
346                 SR_GHZ(1000), SR_GHZ(1000 * 1000), SR_GHZ(1000 * 1000 * 1000),
347         };
348         const char *p, prefix[] = "\0kMGTPE";
349         char fmt[16], fract[20] = "", *f;
350
351         if (!unit)
352                 unit = "";
353
354         for (i = 0; (quot = x / divisor[i]) >= 1000; i++);
355
356         if (i) {
357                 sprintf(fmt, ".%%0%d"PRIu64, i * 3);
358                 f = fract + sprintf(fract, fmt, x % divisor[i]) - 1;
359
360                 while (f >= fract && strchr("0.", *f))
361                         *f-- = 0;
362         }
363
364         p = prefix + i;
365
366         return g_strdup_printf("%" PRIu64 "%s %.1s%s", quot, fract, p, unit);
367 }
368
369 /**
370  * Convert a numeric samplerate value to its "natural" string representation.
371  *
372  * E.g. a value of 3000000 would be converted to "3 MHz", 20000 to "20 kHz",
373  * 31500 would become "31.5 kHz".
374  *
375  * @param samplerate The samplerate in Hz.
376  *
377  * @return A newly allocated string representation of the samplerate value,
378  *         or NULL upon errors. The caller is responsible to g_free() the
379  *         memory.
380  *
381  * @since 0.1.0
382  */
383 SR_API char *sr_samplerate_string(uint64_t samplerate)
384 {
385         return sr_si_string_u64(samplerate, "Hz");
386 }
387
388 /**
389  * Convert a numeric period value to the "natural" string representation
390  * of its period value.
391  *
392  * The period is specified as a rational number's numerator and denominator.
393  *
394  * E.g. a pair of (1, 5) would be converted to "200 ms", (10, 100) to "100 ms".
395  *
396  * @param v_p The period numerator.
397  * @param v_q The period denominator.
398  *
399  * @return A newly allocated string representation of the period value,
400  *         or NULL upon errors. The caller is responsible to g_free() the
401  *         memory.
402  *
403  * @since 0.5.0
404  */
405 SR_API char *sr_period_string(uint64_t v_p, uint64_t v_q)
406 {
407         double freq, v;
408         int prec;
409
410         freq = 1 / ((double)v_p / v_q);
411
412         if (freq > SR_GHZ(1)) {
413                 v = (double)v_p / v_q * 1000000000000.0;
414                 prec = ((v - (uint64_t)v) < FLT_MIN) ? 0 : 3;
415                 return g_strdup_printf("%.*f ps", prec, v);
416         } else if (freq > SR_MHZ(1)) {
417                 v = (double)v_p / v_q * 1000000000.0;
418                 prec = ((v - (uint64_t)v) < FLT_MIN) ? 0 : 3;
419                 return g_strdup_printf("%.*f ns", prec, v);
420         } else if (freq > SR_KHZ(1)) {
421                 v = (double)v_p / v_q * 1000000.0;
422                 prec = ((v - (uint64_t)v) < FLT_MIN) ? 0 : 3;
423                 return g_strdup_printf("%.*f us", prec, v);
424         } else if (freq > 1) {
425                 v = (double)v_p / v_q * 1000.0;
426                 prec = ((v - (uint64_t)v) < FLT_MIN) ? 0 : 3;
427                 return g_strdup_printf("%.*f ms", prec, v);
428         } else {
429                 v = (double)v_p / v_q;
430                 prec = ((v - (uint64_t)v) < FLT_MIN) ? 0 : 3;
431                 return g_strdup_printf("%.*f s", prec, v);
432         }
433 }
434
435 /**
436  * Convert a numeric voltage value to the "natural" string representation
437  * of its voltage value. The voltage is specified as a rational number's
438  * numerator and denominator.
439  *
440  * E.g. a value of 300000 would be converted to "300mV", 2 to "2V".
441  *
442  * @param v_p The voltage numerator.
443  * @param v_q The voltage denominator.
444  *
445  * @return A newly allocated string representation of the voltage value,
446  *         or NULL upon errors. The caller is responsible to g_free() the
447  *         memory.
448  *
449  * @since 0.2.0
450  */
451 SR_API char *sr_voltage_string(uint64_t v_p, uint64_t v_q)
452 {
453         if (v_q == 1000)
454                 return g_strdup_printf("%" PRIu64 " mV", v_p);
455         else if (v_q == 1)
456                 return g_strdup_printf("%" PRIu64 " V", v_p);
457         else
458                 return g_strdup_printf("%g V", (float)v_p / (float)v_q);
459 }
460
461 /**
462  * Convert a "natural" string representation of a size value to uint64_t.
463  *
464  * E.g. a value of "3k" or "3 K" would be converted to 3000, a value
465  * of "15M" would be converted to 15000000.
466  *
467  * Value representations other than decimal (such as hex or octal) are not
468  * supported. Only 'k' (kilo), 'm' (mega), 'g' (giga) suffixes are supported.
469  * Spaces (but not other whitespace) between value and suffix are allowed.
470  *
471  * @param sizestring A string containing a (decimal) size value.
472  * @param size Pointer to uint64_t which will contain the string's size value.
473  *
474  * @return SR_OK upon success, SR_ERR upon errors.
475  *
476  * @since 0.1.0
477  */
478 SR_API int sr_parse_sizestring(const char *sizestring, uint64_t *size)
479 {
480         int multiplier, done;
481         double frac_part;
482         char *s;
483
484         *size = strtoull(sizestring, &s, 10);
485         multiplier = 0;
486         frac_part = 0;
487         done = FALSE;
488         while (s && *s && multiplier == 0 && !done) {
489                 switch (*s) {
490                 case ' ':
491                         break;
492                 case '.':
493                         frac_part = g_ascii_strtod(s, &s);
494                         break;
495                 case 'k':
496                 case 'K':
497                         multiplier = SR_KHZ(1);
498                         break;
499                 case 'm':
500                 case 'M':
501                         multiplier = SR_MHZ(1);
502                         break;
503                 case 'g':
504                 case 'G':
505                         multiplier = SR_GHZ(1);
506                         break;
507                 default:
508                         done = TRUE;
509                         s--;
510                 }
511                 s++;
512         }
513         if (multiplier > 0) {
514                 *size *= multiplier;
515                 *size += frac_part * multiplier;
516         } else
517                 *size += frac_part;
518
519         if (s && *s && g_ascii_strcasecmp(s, "Hz"))
520                 return SR_ERR;
521
522         return SR_OK;
523 }
524
525 /**
526  * Convert a "natural" string representation of a time value to an
527  * uint64_t value in milliseconds.
528  *
529  * E.g. a value of "3s" or "3 s" would be converted to 3000, a value
530  * of "15ms" would be converted to 15.
531  *
532  * Value representations other than decimal (such as hex or octal) are not
533  * supported. Only lower-case "s" and "ms" time suffixes are supported.
534  * Spaces (but not other whitespace) between value and suffix are allowed.
535  *
536  * @param timestring A string containing a (decimal) time value.
537  * @return The string's time value as uint64_t, in milliseconds.
538  *
539  * @todo Add support for "m" (minutes) and others.
540  * @todo Add support for picoseconds?
541  * @todo Allow both lower-case and upper-case? If no, document it.
542  *
543  * @since 0.1.0
544  */
545 SR_API uint64_t sr_parse_timestring(const char *timestring)
546 {
547         uint64_t time_msec;
548         char *s;
549
550         /* TODO: Error handling, logging. */
551
552         time_msec = strtoull(timestring, &s, 10);
553         if (time_msec == 0 && s == timestring)
554                 return 0;
555
556         if (s && *s) {
557                 while (*s == ' ')
558                         s++;
559                 if (!strcmp(s, "s"))
560                         time_msec *= 1000;
561                 else if (!strcmp(s, "ms"))
562                         ; /* redundant */
563                 else
564                         return 0;
565         }
566
567         return time_msec;
568 }
569
570 /** @since 0.1.0 */
571 SR_API gboolean sr_parse_boolstring(const char *boolstr)
572 {
573         /*
574          * Complete absence of an input spec is assumed to mean TRUE,
575          * as in command line option strings like this:
576          *   ...:samplerate=100k:header:numchannels=4:...
577          */
578         if (!boolstr || !*boolstr)
579                 return TRUE;
580
581         if (!g_ascii_strncasecmp(boolstr, "true", 4) ||
582             !g_ascii_strncasecmp(boolstr, "yes", 3) ||
583             !g_ascii_strncasecmp(boolstr, "on", 2) ||
584             !g_ascii_strncasecmp(boolstr, "1", 1))
585                 return TRUE;
586
587         return FALSE;
588 }
589
590 /** @since 0.2.0 */
591 SR_API int sr_parse_period(const char *periodstr, uint64_t *p, uint64_t *q)
592 {
593         char *s;
594
595         *p = strtoull(periodstr, &s, 10);
596         if (*p == 0 && s == periodstr)
597                 /* No digits found. */
598                 return SR_ERR_ARG;
599
600         if (s && *s) {
601                 while (*s == ' ')
602                         s++;
603                 if (!strcmp(s, "fs"))
604                         *q = 1000000000000000ULL;
605                 else if (!strcmp(s, "ps"))
606                         *q = 1000000000000ULL;
607                 else if (!strcmp(s, "ns"))
608                         *q = 1000000000ULL;
609                 else if (!strcmp(s, "us"))
610                         *q = 1000000;
611                 else if (!strcmp(s, "ms"))
612                         *q = 1000;
613                 else if (!strcmp(s, "s"))
614                         *q = 1;
615                 else
616                         /* Must have a time suffix. */
617                         return SR_ERR_ARG;
618         }
619
620         return SR_OK;
621 }
622
623 /** @since 0.2.0 */
624 SR_API int sr_parse_voltage(const char *voltstr, uint64_t *p, uint64_t *q)
625 {
626         char *s;
627
628         *p = strtoull(voltstr, &s, 10);
629         if (*p == 0 && s == voltstr)
630                 /* No digits found. */
631                 return SR_ERR_ARG;
632
633         if (s && *s) {
634                 while (*s == ' ')
635                         s++;
636                 if (!g_ascii_strcasecmp(s, "mv"))
637                         *q = 1000L;
638                 else if (!g_ascii_strcasecmp(s, "v"))
639                         *q = 1;
640                 else
641                         /* Must have a base suffix. */
642                         return SR_ERR_ARG;
643         }
644
645         return SR_OK;
646 }
647
648 /** @} */