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