]> sigrok.org Git - libsigrok.git/blame - src/strutil.c
output/csv: use intermediate time_t var, silence compiler warning
[libsigrok.git] / src / strutil.c
CommitLineData
25e7d9b1 1/*
50985c20 2 * This file is part of the libsigrok project.
25e7d9b1
UH
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
2ea1fdf1 17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
25e7d9b1
UH
18 */
19
79034d4f 20/* Needed for POSIX.1-2008 locale functions */
82b9f3d1 21/** @cond PRIVATE */
79034d4f 22#define _XOPEN_SOURCE 700
82b9f3d1 23/** @endcond */
6ec6c43b 24#include <config.h>
b8278e09 25#include <ctype.h>
79034d4f
FS
26#include <locale.h>
27#if defined(__FreeBSD__) || defined(__APPLE__)
28#include <xlocale.h>
29#endif
30#if defined(__FreeBSD__)
31#include <sys/param.h>
32#endif
25e7d9b1
UH
33#include <stdint.h>
34#include <stdlib.h>
35#include <string.h>
ba464a12 36#include <strings.h>
9e4f8cf9 37#include <errno.h>
c1aae900 38#include <libsigrok/libsigrok.h>
45c59c8b 39#include "libsigrok-internal.h"
25e7d9b1 40
2ad1deb8 41/** @cond PRIVATE */
3544f848 42#define LOG_PREFIX "strutil"
2ad1deb8 43/** @endcond */
a885ce3e 44
393fb9cb
UH
45/**
46 * @file
47 *
48 * Helper functions for handling or converting libsigrok-related strings.
49 */
50
7b870c38
UH
51/**
52 * @defgroup grp_strutil String utilities
53 *
54 * Helper functions for handling or converting libsigrok-related strings.
55 *
56 * @{
57 */
58
9e4f8cf9 59/**
1ba4a1cf 60 * Convert a string representation of a numeric value (base 10) to a long integer. The
9e4f8cf9
DJ
61 * conversion is strict and will fail if the complete string does not represent
62 * a valid long integer. The function sets errno according to the details of the
63 * failure.
64 *
65 * @param str The string representation to convert.
66 * @param ret Pointer to long where the result of the conversion will be stored.
67 *
1ba4a1cf
MH
68 * @retval SR_OK Conversion successful.
69 * @retval SR_ERR Failure.
82b9f3d1
UH
70 *
71 * @private
9e4f8cf9 72 */
8d558c7a 73SR_PRIV int sr_atol(const char *str, long *ret)
9e4f8cf9
DJ
74{
75 long tmp;
76 char *endptr = NULL;
77
78 errno = 0;
1ba4a1cf 79 tmp = strtol(str, &endptr, 10);
9e4f8cf9 80
b8278e09
GS
81 while (endptr && isspace(*endptr))
82 endptr++;
83
9e4f8cf9
DJ
84 if (!endptr || *endptr || errno) {
85 if (!errno)
86 errno = EINVAL;
87 return SR_ERR;
88 }
89
90 *ret = tmp;
91 return SR_OK;
92}
93
97aa41e9
GS
94/**
95 * Convert a text to a number including support for non-decimal bases.
96 * Also optionally returns the position after the number, where callers
97 * can either error out, or support application specific suffixes.
98 *
99 * @param[in] str The input text to convert.
100 * @param[out] ret The conversion result.
101 * @param[out] end The position after the number.
102 * @param[in] base The number format's base, can be 0.
103 *
104 * @retval SR_OK Conversion successful.
105 * @retval SR_ERR Conversion failed.
106 *
107 * @private
108 *
109 * This routine is more general than @ref sr_atol(), which strictly
110 * expects the input text to contain just a decimal number, and nothing
111 * else in addition. The @ref sr_atol_base() routine accepts trailing
112 * text after the number, and supports non-decimal numbers (bin, hex),
113 * including automatic detection from prefix text.
114 */
115SR_PRIV int sr_atol_base(const char *str, long *ret, char **end, int base)
116{
117 long num;
118 char *endptr;
119
120 /* Add "0b" prefix support which strtol(3) may be missing. */
121 while (str && isspace(*str))
122 str++;
123 if (!base && strncmp(str, "0b", strlen("0b")) == 0) {
124 str += strlen("0b");
125 base = 2;
126 }
127
128 /* Run the number conversion. Quick bail out if that fails. */
129 errno = 0;
130 endptr = NULL;
131 num = strtol(str, &endptr, base);
132 if (!endptr || errno) {
133 if (!errno)
134 errno = EINVAL;
135 return SR_ERR;
136 }
137 *ret = num;
138
139 /* Advance to optional non-space trailing suffix. */
140 while (endptr && isspace(*endptr))
141 endptr++;
142 if (end)
143 *end = endptr;
144
145 return SR_OK;
146}
147
30903c40
NT
148/**
149 * Convert a text to a number including support for non-decimal bases.
150 * Also optionally returns the position after the number, where callers
151 * can either error out, or support application specific suffixes.
152 *
153 * @param[in] str The input text to convert.
154 * @param[out] ret The conversion result.
155 * @param[out] end The position after the number.
156 * @param[in] base The number format's base, can be 0.
157 *
158 * @retval SR_OK Conversion successful.
159 * @retval SR_ERR Conversion failed.
160 *
161 * @private
162 *
163 * This routine is more general than @ref sr_atol(), which strictly
164 * expects the input text to contain just a decimal number, and nothing
165 * else in addition. The @ref sr_atoul_base() routine accepts trailing
166 * text after the number, and supports non-decimal numbers (bin, hex),
167 * including automatic detection from prefix text.
168 */
169SR_PRIV int sr_atoul_base(const char *str, unsigned long *ret, char **end, int base)
170{
171 unsigned long num;
172 char *endptr;
173
174 /* Add "0b" prefix support which strtol(3) may be missing. */
175 while (str && isspace(*str))
176 str++;
5c462eb3 177 if ((!base || base == 2) && strncmp(str, "0b", strlen("0b")) == 0) {
30903c40
NT
178 str += strlen("0b");
179 base = 2;
180 }
181
182 /* Run the number conversion. Quick bail out if that fails. */
183 errno = 0;
184 endptr = NULL;
185 num = strtoul(str, &endptr, base);
186 if (!endptr || errno) {
187 if (!errno)
188 errno = EINVAL;
189 return SR_ERR;
190 }
191 *ret = num;
192
193 /* Advance to optional non-space trailing suffix. */
194 while (endptr && isspace(*endptr))
195 endptr++;
196 if (end)
197 *end = endptr;
198
199 return SR_OK;
200}
201
9e4f8cf9 202/**
1ba4a1cf 203 * Convert a string representation of a numeric value (base 10) to an integer. The
9e4f8cf9
DJ
204 * conversion is strict and will fail if the complete string does not represent
205 * a valid integer. The function sets errno according to the details of the
206 * failure.
207 *
208 * @param str The string representation to convert.
209 * @param ret Pointer to int where the result of the conversion will be stored.
210 *
1ba4a1cf
MH
211 * @retval SR_OK Conversion successful.
212 * @retval SR_ERR Failure.
82b9f3d1
UH
213 *
214 * @private
9e4f8cf9 215 */
8d558c7a 216SR_PRIV int sr_atoi(const char *str, int *ret)
9e4f8cf9
DJ
217{
218 long tmp;
219
220 if (sr_atol(str, &tmp) != SR_OK)
221 return SR_ERR;
222
223 if ((int) tmp != tmp) {
224 errno = ERANGE;
225 return SR_ERR;
226 }
227
228 *ret = (int) tmp;
229 return SR_OK;
230}
231
232/**
233 * Convert a string representation of a numeric value to a double. The
234 * conversion is strict and will fail if the complete string does not represent
235 * a valid double. The function sets errno according to the details of the
236 * failure.
237 *
238 * @param str The string representation to convert.
239 * @param ret Pointer to double where the result of the conversion will be stored.
240 *
1ba4a1cf
MH
241 * @retval SR_OK Conversion successful.
242 * @retval SR_ERR Failure.
82b9f3d1
UH
243 *
244 * @private
9e4f8cf9 245 */
8d558c7a 246SR_PRIV int sr_atod(const char *str, double *ret)
9e4f8cf9
DJ
247{
248 double tmp;
249 char *endptr = NULL;
250
251 errno = 0;
252 tmp = strtof(str, &endptr);
253
b8278e09
GS
254 while (endptr && isspace(*endptr))
255 endptr++;
256
9e4f8cf9
DJ
257 if (!endptr || *endptr || errno) {
258 if (!errno)
259 errno = EINVAL;
260 return SR_ERR;
261 }
262
263 *ret = tmp;
264 return SR_OK;
265}
266
267/**
268 * Convert a string representation of a numeric value to a float. The
269 * conversion is strict and will fail if the complete string does not represent
270 * a valid float. The function sets errno according to the details of the
271 * failure.
272 *
273 * @param str The string representation to convert.
274 * @param ret Pointer to float where the result of the conversion will be stored.
275 *
1ba4a1cf
MH
276 * @retval SR_OK Conversion successful.
277 * @retval SR_ERR Failure.
82b9f3d1
UH
278 *
279 * @private
9e4f8cf9 280 */
8d558c7a 281SR_PRIV int sr_atof(const char *str, float *ret)
9e4f8cf9
DJ
282{
283 double tmp;
284
285 if (sr_atod(str, &tmp) != SR_OK)
286 return SR_ERR;
287
288 if ((float) tmp != tmp) {
289 errno = ERANGE;
290 return SR_ERR;
291 }
292
293 *ret = (float) tmp;
294 return SR_OK;
295}
296
4f0463a0 297/**
4f0463a0
FS
298 * Convert a string representation of a numeric value to a double. The
299 * conversion is strict and will fail if the complete string does not represent
300 * a valid double. The function sets errno according to the details of the
301 * failure. This version ignores the locale.
302 *
303 * @param str The string representation to convert.
304 * @param ret Pointer to double where the result of the conversion will be stored.
305 *
306 * @retval SR_OK Conversion successful.
307 * @retval SR_ERR Failure.
82b9f3d1
UH
308 *
309 * @private
4f0463a0
FS
310 */
311SR_PRIV int sr_atod_ascii(const char *str, double *ret)
312{
313 double tmp;
314 char *endptr = NULL;
315
316 errno = 0;
317 tmp = g_ascii_strtod(str, &endptr);
318
319 if (!endptr || *endptr || errno) {
320 if (!errno)
321 errno = EINVAL;
322 return SR_ERR;
323 }
324
325 *ret = tmp;
326 return SR_OK;
327}
328
91ab2f64
GS
329/**
330 * Convert text to a floating point value, and get its precision.
331 *
332 * @param[in] str The input text to convert.
333 * @param[out] ret The conversion result, a double precision float number.
334 * @param[out] digits The number of significant decimals.
335 *
336 * @returns SR_OK in case of successful text to number conversion.
337 * @returns SR_ERR when conversion fails.
338 *
339 * @since 0.6.0
340 */
341SR_PRIV int sr_atod_ascii_digits(const char *str, double *ret, int *digits)
342{
343 const char *p;
344 int *dig_ref, m_dig, exp;
345 char c;
346 double f;
347
348 /*
349 * Convert floating point text to the number value, _and_ get
350 * the value's precision in the process. Steps taken to do it:
351 * - Skip leading whitespace.
352 * - Count the number of decimals after the mantissa's period.
353 * - Get the exponent's signed value.
354 *
355 * This implementation still uses common code for the actual
356 * conversion, but "violates API layers" by duplicating the
357 * text scan, to get the number of significant digits.
358 */
359 p = str;
360 while (*p && isspace(*p))
361 p++;
362 if (*p == '-' || *p == '+')
363 p++;
364 m_dig = 0;
365 exp = 0;
366 dig_ref = NULL;
367 while (*p) {
368 c = *p++;
369 if (toupper(c) == 'E') {
370 exp = strtol(p, NULL, 10);
371 break;
372 }
373 if (c == '.') {
374 m_dig = 0;
375 dig_ref = &m_dig;
376 continue;
377 }
378 if (isdigit(c)) {
379 if (dig_ref)
380 (*dig_ref)++;
381 continue;
382 }
383 /* Need not warn, conversion will fail. */
384 break;
385 }
386 sr_spew("atod digits: txt \"%s\" -> m %d, e %d -> digits %d",
387 str, m_dig, exp, m_dig + -exp);
388 m_dig += -exp;
389
390 if (sr_atod_ascii(str, &f) != SR_OK)
391 return SR_ERR;
392 if (ret)
393 *ret = f;
394 if (digits)
395 *digits = m_dig;
396
397 return SR_OK;
398}
399
9806c2d5 400/**
9806c2d5
DJ
401 * Convert a string representation of a numeric value to a float. The
402 * conversion is strict and will fail if the complete string does not represent
403 * a valid float. The function sets errno according to the details of the
404 * failure. This version ignores the locale.
405 *
406 * @param str The string representation to convert.
407 * @param ret Pointer to float where the result of the conversion will be stored.
408 *
1ba4a1cf
MH
409 * @retval SR_OK Conversion successful.
410 * @retval SR_ERR Failure.
82b9f3d1
UH
411 *
412 * @private
9806c2d5
DJ
413 */
414SR_PRIV int sr_atof_ascii(const char *str, float *ret)
415{
416 double tmp;
417 char *endptr = NULL;
418
419 errno = 0;
420 tmp = g_ascii_strtod(str, &endptr);
421
422 if (!endptr || *endptr || errno) {
423 if (!errno)
424 errno = EINVAL;
425 return SR_ERR;
426 }
427
428 /* FIXME This fails unexpectedly. Some other method to safel downcast
429 * needs to be found. Checking against FLT_MAX doesn't work as well. */
430 /*
431 if ((float) tmp != tmp) {
432 errno = ERANGE;
433 sr_dbg("ERANGEEEE %e != %e", (float) tmp, tmp);
434 return SR_ERR;
435 }
436 */
437
438 *ret = (float) tmp;
439 return SR_OK;
440}
441
21ef355e
FS
442/**
443 * Compose a string with a format string in the buffer pointed to by buf.
444 *
445 * It is up to the caller to ensure that the allocated buffer is large enough
446 * to hold the formatted result.
447 *
448 * A terminating NUL character is automatically appended after the content
449 * written.
450 *
451 * After the format parameter, the function expects at least as many additional
452 * arguments as needed for format.
453 *
454 * This version ignores the current locale and uses the locale "C" for Linux,
455 * FreeBSD, OSX and Android.
456 *
457 * @param buf Pointer to a buffer where the resulting C string is stored.
458 * @param format C string that contains a format string (see printf).
459 * @param ... A sequence of additional arguments, each containing a value to be
460 * used to replace a format specifier in the format string.
461 *
462 * @return On success, the number of characters that would have been written,
463 * not counting the terminating NUL character.
464 *
465 * @since 0.6.0
466 */
467SR_API int sr_sprintf_ascii(char *buf, const char *format, ...)
468{
469 int ret;
470 va_list args;
471
472 va_start(args, format);
473 ret = sr_vsprintf_ascii(buf, format, args);
474 va_end(args);
475
476 return ret;
477}
478
479/**
480 * Compose a string with a format string in the buffer pointed to by buf.
481 *
482 * It is up to the caller to ensure that the allocated buffer is large enough
483 * to hold the formatted result.
484 *
485 * Internally, the function retrieves arguments from the list identified by
486 * args as if va_arg was used on it, and thus the state of args is likely to
487 * be altered by the call.
488 *
489 * In any case, args should have been initialized by va_start at some point
490 * before the call, and it is expected to be released by va_end at some point
491 * after the call.
492 *
493 * This version ignores the current locale and uses the locale "C" for Linux,
494 * FreeBSD, OSX and Android.
495 *
496 * @param buf Pointer to a buffer where the resulting C string is stored.
497 * @param format C string that contains a format string (see printf).
498 * @param args A value identifying a variable arguments list initialized with
499 * va_start.
500 *
501 * @return On success, the number of characters that would have been written,
502 * not counting the terminating NUL character.
503 *
504 * @since 0.6.0
505 */
506SR_API int sr_vsprintf_ascii(char *buf, const char *format, va_list args)
507{
508#if defined(_WIN32)
509 int ret;
510
511#if 0
512 /*
513 * TODO: This part compiles with mingw-w64 but doesn't run with Win7.
514 * Doesn't start because of "Procedure entry point _create_locale
515 * not found in msvcrt.dll".
516 * mingw-w64 should link to msvcr100.dll not msvcrt.dll!
517 * See: https://msdn.microsoft.com/en-us/en-en/library/1kt27hek.aspx
518 */
519 _locale_t locale;
520
521 locale = _create_locale(LC_NUMERIC, "C");
522 ret = _vsprintf_l(buf, format, locale, args);
523 _free_locale(locale);
524#endif
525
526 /* vsprintf() uses the current locale, may not work correctly for floats. */
527 ret = vsprintf(buf, format, args);
528
529 return ret;
530#elif defined(__APPLE__)
531 /*
532 * See:
533 * https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man3/printf_l.3.html
534 * https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man3/xlocale.3.html
535 */
536 int ret;
537 locale_t locale;
538
539 locale = newlocale(LC_NUMERIC_MASK, "C", NULL);
540 ret = vsprintf_l(buf, locale, format, args);
541 freelocale(locale);
542
543 return ret;
544#elif defined(__FreeBSD__) && __FreeBSD_version >= 901000
545 /*
546 * See:
547 * https://www.freebsd.org/cgi/man.cgi?query=printf_l&apropos=0&sektion=3&manpath=FreeBSD+9.1-RELEASE
548 * https://www.freebsd.org/cgi/man.cgi?query=xlocale&apropos=0&sektion=3&manpath=FreeBSD+9.1-RELEASE
549 */
550 int ret;
551 locale_t locale;
552
553 locale = newlocale(LC_NUMERIC_MASK, "C", NULL);
554 ret = vsprintf_l(buf, locale, format, args);
555 freelocale(locale);
556
557 return ret;
558#elif defined(__ANDROID__)
559 /*
560 * The Bionic libc only has two locales ("C" aka "POSIX" and "C.UTF-8"
561 * aka "en_US.UTF-8"). The decimal point is hard coded as "."
562 * See: https://android.googlesource.com/platform/bionic/+/master/libc/bionic/locale.cpp
563 */
564 int ret;
565
566 ret = vsprintf(buf, format, args);
567
568 return ret;
569#elif defined(__linux__)
570 int ret;
571 locale_t old_locale, temp_locale;
572
573 /* Switch to C locale for proper float/double conversion. */
574 temp_locale = newlocale(LC_NUMERIC, "C", NULL);
575 old_locale = uselocale(temp_locale);
576
577 ret = vsprintf(buf, format, args);
578
579 /* Switch back to original locale. */
580 uselocale(old_locale);
581 freelocale(temp_locale);
582
583 return ret;
584#elif defined(__unix__) || defined(__unix)
585 /*
586 * This is a fallback for all other BSDs, *nix and FreeBSD <= 9.0, by
587 * using the current locale for snprintf(). This may not work correctly
588 * for floats!
589 */
590 int ret;
591
592 ret = vsprintf(buf, format, args);
593
594 return ret;
595#else
596 /* No implementation for unknown systems! */
597 return -1;
598#endif
599}
600
79034d4f
FS
601/**
602 * Composes a string with a format string (like printf) in the buffer pointed
603 * by buf (taking buf_size as the maximum buffer capacity to fill).
604 * If the resulting string would be longer than n - 1 characters, the remaining
605 * characters are discarded and not stored, but counted for the value returned
606 * by the function.
607 * A terminating NUL character is automatically appended after the content
608 * written.
609 * After the format parameter, the function expects at least as many additional
610 * arguments as needed for format.
611 *
21ef355e 612 * This version ignores the current locale and uses the locale "C" for Linux,
79034d4f
FS
613 * FreeBSD, OSX and Android.
614 *
615 * @param buf Pointer to a buffer where the resulting C string is stored.
616 * @param buf_size Maximum number of bytes to be used in the buffer. The
617 * generated string has a length of at most buf_size - 1, leaving space
618 * for the additional terminating NUL character.
619 * @param format C string that contains a format string (see printf).
620 * @param ... A sequence of additional arguments, each containing a value to be
621 * used to replace a format specifier in the format string.
622 *
623 * @return On success, the number of characters that would have been written if
624 * buf_size had been sufficiently large, not counting the terminating
625 * NUL character. On failure, a negative number is returned.
626 * Notice that only when this returned value is non-negative and less
627 * than buf_size, the string has been completely written.
628 *
629 * @since 0.6.0
630 */
631SR_API int sr_snprintf_ascii(char *buf, size_t buf_size,
632 const char *format, ...)
633{
634 int ret;
635 va_list args;
636
637 va_start(args, format);
638 ret = sr_vsnprintf_ascii(buf, buf_size, format, args);
639 va_end(args);
640
641 return ret;
642}
643
644/**
645 * Composes a string with a format string (like printf) in the buffer pointed
646 * by buf (taking buf_size as the maximum buffer capacity to fill).
647 * If the resulting string would be longer than n - 1 characters, the remaining
648 * characters are discarded and not stored, but counted for the value returned
649 * by the function.
650 * A terminating NUL character is automatically appended after the content
651 * written.
652 * Internally, the function retrieves arguments from the list identified by
653 * args as if va_arg was used on it, and thus the state of args is likely to
654 * be altered by the call.
655 * In any case, arg should have been initialized by va_start at some point
656 * before the call, and it is expected to be released by va_end at some point
657 * after the call.
658 *
21ef355e 659 * This version ignores the current locale and uses the locale "C" for Linux,
79034d4f
FS
660 * FreeBSD, OSX and Android.
661 *
662 * @param buf Pointer to a buffer where the resulting C string is stored.
663 * @param buf_size Maximum number of bytes to be used in the buffer. The
664 * generated string has a length of at most buf_size - 1, leaving space
665 * for the additional terminating NUL character.
666 * @param format C string that contains a format string (see printf).
667 * @param args A value identifying a variable arguments list initialized with
668 * va_start.
669 *
670 * @return On success, the number of characters that would have been written if
671 * buf_size had been sufficiently large, not counting the terminating
672 * NUL character. On failure, a negative number is returned.
673 * Notice that only when this returned value is non-negative and less
674 * than buf_size, the string has been completely written.
675 *
676 * @since 0.6.0
677 */
678SR_API int sr_vsnprintf_ascii(char *buf, size_t buf_size,
679 const char *format, va_list args)
680{
681#if defined(_WIN32)
682 int ret;
683
684#if 0
685 /*
686 * TODO: This part compiles with mingw-w64 but doesn't run with Win7.
687 * Doesn't start because of "Procedure entry point _create_locale
688 * not found in msvcrt.dll".
689 * mingw-w64 should link to msvcr100.dll not msvcrt.dll!.
21ef355e 690 * See: https://msdn.microsoft.com/en-us/en-en/library/1kt27hek.aspx
79034d4f
FS
691 */
692 _locale_t locale;
693
694 locale = _create_locale(LC_NUMERIC, "C");
695 ret = _vsnprintf_l(buf, buf_size, format, locale, args);
696 _free_locale(locale);
697#endif
698
699 /* vsprintf uses the current locale, may cause issues for floats. */
700 ret = vsnprintf(buf, buf_size, format, args);
701
702 return ret;
703#elif defined(__APPLE__)
704 /*
705 * See:
706 * https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man3/printf_l.3.html
707 * https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man3/xlocale.3.html
708 */
709 int ret;
710 locale_t locale;
711
712 locale = newlocale(LC_NUMERIC_MASK, "C", NULL);
713 ret = vsnprintf_l(buf, buf_size, locale, format, args);
714 freelocale(locale);
715
716 return ret;
717#elif defined(__FreeBSD__) && __FreeBSD_version >= 901000
718 /*
719 * See:
720 * https://www.freebsd.org/cgi/man.cgi?query=printf_l&apropos=0&sektion=3&manpath=FreeBSD+9.1-RELEASE
721 * https://www.freebsd.org/cgi/man.cgi?query=xlocale&apropos=0&sektion=3&manpath=FreeBSD+9.1-RELEASE
722 */
723 int ret;
724 locale_t locale;
725
726 locale = newlocale(LC_NUMERIC_MASK, "C", NULL);
727 ret = vsnprintf_l(buf, buf_size, locale, format, args);
728 freelocale(locale);
729
730 return ret;
731#elif defined(__ANDROID__)
732 /*
733 * The Bionic libc only has two locales ("C" aka "POSIX" and "C.UTF-8"
734 * aka "en_US.UTF-8"). The decimal point is hard coded as ".".
735 * See: https://android.googlesource.com/platform/bionic/+/master/libc/bionic/locale.cpp
736 */
737 int ret;
738
739 ret = vsnprintf(buf, buf_size, format, args);
740
741 return ret;
742#elif defined(__linux__)
743 int ret;
744 locale_t old_locale, temp_locale;
745
746 /* Switch to C locale for proper float/double conversion. */
747 temp_locale = newlocale(LC_NUMERIC, "C", NULL);
748 old_locale = uselocale(temp_locale);
749
750 ret = vsnprintf(buf, buf_size, format, args);
751
752 /* Switch back to original locale. */
753 uselocale(old_locale);
754 freelocale(temp_locale);
755
756 return ret;
757#elif defined(__unix__) || defined(__unix)
758 /*
759 * This is a fallback for all other BSDs, *nix and FreeBSD <= 9.0, by
760 * using the current locale for snprintf(). This may not work correctly
761 * for floats!
762 */
763 int ret;
764
765 ret = vsnprintf(buf, buf_size, format, args);
766
767 return ret;
768#else
769 /* No implementation for unknown systems! */
770 return -1;
771#endif
772}
773
d8bc7ca3
GS
774/**
775 * Convert a sequence of bytes to its textual representation ("hex dump").
776 *
6762401d 777 * Callers should free the allocated GString. See sr_hexdump_free().
d8bc7ca3
GS
778 *
779 * @param[in] data Pointer to the byte sequence to print.
780 * @param[in] len Number of bytes to print.
781 *
6762401d 782 * @return NULL upon error, newly allocated GString pointer otherwise.
82b9f3d1
UH
783 *
784 * @private
d8bc7ca3
GS
785 */
786SR_PRIV GString *sr_hexdump_new(const uint8_t *data, const size_t len)
787{
788 GString *s;
789 size_t i;
790
a1d7443b
GS
791 i = 3 * len;
792 i += len / 8;
793 i += len / 16;
794 s = g_string_sized_new(i);
d8bc7ca3
GS
795 for (i = 0; i < len; i++) {
796 if (i)
797 g_string_append_c(s, ' ');
a1d7443b
GS
798 if (i && (i % 8) == 0)
799 g_string_append_c(s, ' ');
800 if (i && (i % 16) == 0)
801 g_string_append_c(s, ' ');
d8bc7ca3
GS
802 g_string_append_printf(s, "%02x", data[i]);
803 }
804
805 return s;
806}
807
808/**
6762401d 809 * Free a hex dump text that was created by sr_hexdump_new().
d8bc7ca3
GS
810 *
811 * @param[in] s Pointer to the GString to release.
82b9f3d1
UH
812 *
813 * @private
d8bc7ca3
GS
814 */
815SR_PRIV void sr_hexdump_free(GString *s)
816{
817 if (s)
818 g_string_free(s, TRUE);
819}
820
5ec172d7 821/**
5c436a3b
UH
822 * Convert a string representation of a numeric value to a sr_rational.
823 *
824 * The conversion is strict and will fail if the complete string does not
825 * represent a valid number. The function sets errno according to the details
826 * of the failure. This version ignores the locale.
5ec172d7
SB
827 *
828 * @param str The string representation to convert.
829 * @param ret Pointer to sr_rational where the result of the conversion will be stored.
830 *
831 * @retval SR_OK Conversion successful.
832 * @retval SR_ERR Failure.
833 *
834 * @since 0.5.0
835 */
836SR_API int sr_parse_rational(const char *str, struct sr_rational *ret)
837{
ca994998
GS
838 const char *readptr;
839 char *endptr;
840 gboolean is_negative, empty_integral, empty_fractional, exp_negative;
5ec172d7 841 int64_t integral;
ca994998
GS
842 int64_t fractional;
843 int64_t denominator;
844 uint32_t fractional_len;
845 int32_t exponent;
7f5bfd61 846
ca994998
GS
847 /*
848 * Implementor's note: This routine tries hard to avoid calling
849 * glib's or the platform's conversion routines with input that
850 * cannot get converted *at all* (see bug #1093). It also takes
851 * care to return with non-zero errno values for any failed
852 * conversion attempt. It's assumed that correctness and robustness
853 * are more important than performance, which is why code paths
854 * are not optimized at all. Maintainability took priority.
855 */
856
857 readptr = str;
5ec172d7 858
ca994998
GS
859 /* Skip leading whitespace. */
860 while (isspace(*readptr))
861 readptr++;
862
863 /* Determine the sign, default to non-negative. */
864 is_negative = FALSE;
865 if (*readptr == '-') {
0f5bba96 866 is_negative = TRUE;
ca994998
GS
867 readptr++;
868 } else if (*readptr == '+') {
869 is_negative = FALSE;
870 readptr++;
871 }
41c47f2c 872
ca994998
GS
873 /* Get the (optional) integral part. */
874 empty_integral = TRUE;
875 integral = 0;
876 endptr = (char *)readptr;
51bf39a1 877 errno = 0;
ca994998
GS
878 if (isdigit(*readptr)) {
879 empty_integral = FALSE;
880 integral = g_ascii_strtoll(readptr, &endptr, 10);
5ec172d7
SB
881 if (errno)
882 return SR_ERR;
ca994998
GS
883 if (endptr == str) {
884 errno = -EINVAL;
d8754963 885 return SR_ERR;
ca994998
GS
886 }
887 readptr = endptr;
5ec172d7
SB
888 }
889
ca994998
GS
890 /* Get the optional fractional part. */
891 empty_fractional = TRUE;
892 fractional = 0;
893 fractional_len = 0;
894 if (*readptr == '.') {
895 readptr++;
896 endptr++;
897 errno = 0;
898 if (isdigit(*readptr)) {
899 empty_fractional = FALSE;
900 fractional = g_ascii_strtoll(readptr, &endptr, 10);
901 if (errno)
902 return SR_ERR;
903 if (endptr == readptr) {
904 errno = -EINVAL;
905 return SR_ERR;
906 }
907 fractional_len = endptr - readptr;
908 readptr = endptr;
909 }
910 }
911
912 /* At least one of integral or fractional is required. */
913 if (empty_integral && empty_fractional) {
914 errno = -EINVAL;
915 return SR_ERR;
916 }
917
918 /* Get the (optional) exponent. */
919 exponent = 0;
920 if ((*readptr == 'E') || (*readptr == 'e')) {
921 readptr++;
922 endptr++;
923 exp_negative = FALSE;
924 if (*readptr == '+') {
925 exp_negative = FALSE;
926 readptr++;
927 endptr++;
928 } else if (*readptr == '-') {
929 exp_negative = TRUE;
930 readptr++;
931 endptr++;
932 }
933 if (!isdigit(*readptr)) {
934 errno = -EINVAL;
935 return SR_ERR;
936 }
937 errno = 0;
938 exponent = g_ascii_strtoll(readptr, &endptr, 10);
5ec172d7
SB
939 if (errno)
940 return SR_ERR;
ca994998
GS
941 if (endptr == readptr) {
942 errno = -EINVAL;
943 return SR_ERR;
944 }
945 readptr = endptr;
946 if (exp_negative)
947 exponent = -exponent;
5ec172d7
SB
948 }
949
ca994998
GS
950 /* Input must be exhausted. Unconverted remaining input is fatal. */
951 if (*endptr != '\0') {
952 errno = -EINVAL;
5ec172d7 953 return SR_ERR;
ca994998 954 }
5ec172d7 955
ca994998
GS
956 /*
957 * Apply the sign to the integral (and fractional) part(s).
958 * Adjust exponent (decimal position) such that the above integral
959 * and fractional parts both fit into the (new) integral part.
960 */
961 if (is_negative)
962 integral = -integral;
963 while (fractional_len-- > 0) {
5ec172d7 964 integral *= 10;
ca994998
GS
965 exponent--;
966 }
41c47f2c 967 if (!is_negative)
5ec172d7
SB
968 integral += fractional;
969 else
970 integral -= fractional;
5ec172d7
SB
971 while (exponent > 0) {
972 integral *= 10;
973 exponent--;
974 }
975
ca994998
GS
976 /*
977 * When significant digits remain after the decimal, scale up the
978 * denominator such that we end up with two integer p/q numbers.
979 */
980 denominator = 1;
5ec172d7
SB
981 while (exponent < 0) {
982 denominator *= 10;
983 exponent++;
984 }
985
986 ret->p = integral;
987 ret->q = denominator;
988
989 return SR_OK;
990}
991
25e7d9b1 992/**
b07b42f3
UH
993 * Convert a numeric value value to its "natural" string representation
994 * in SI units.
25e7d9b1 995 *
4cc9aea1
JH
996 * E.g. a value of 3000000, with units set to "W", would be converted
997 * to "3 MW", 20000 to "20 kW", 31500 would become "31.5 kW".
25e7d9b1 998 *
4cc9aea1
JH
999 * @param x The value to convert.
1000 * @param unit The unit to append to the string, or NULL if the string
1001 * has no units.
44dae539 1002 *
91219afc 1003 * @return A newly allocated string representation of the samplerate value,
133a37bf
UH
1004 * or NULL upon errors. The caller is responsible to g_free() the
1005 * memory.
47117241
UH
1006 *
1007 * @since 0.2.0
25e7d9b1 1008 */
4cc9aea1 1009SR_API char *sr_si_string_u64(uint64_t x, const char *unit)
25e7d9b1 1010{
094e6b81
PS
1011 uint8_t i;
1012 uint64_t quot, divisor[] = {
b07b42f3
UH
1013 SR_HZ(1), SR_KHZ(1), SR_MHZ(1), SR_GHZ(1),
1014 SR_GHZ(1000), SR_GHZ(1000 * 1000), SR_GHZ(1000 * 1000 * 1000),
094e6b81
PS
1015 };
1016 const char *p, prefix[] = "\0kMGTPE";
69d83be9 1017 char fmt[16], fract[20] = "", *f;
094e6b81 1018
98fec29e 1019 if (!unit)
4cc9aea1 1020 unit = "";
25e7d9b1 1021
094e6b81
PS
1022 for (i = 0; (quot = x / divisor[i]) >= 1000; i++);
1023
1024 if (i) {
69d83be9 1025 sprintf(fmt, ".%%0%d"PRIu64, i * 3);
094e6b81
PS
1026 f = fract + sprintf(fract, fmt, x % divisor[i]) - 1;
1027
1028 while (f >= fract && strchr("0.", *f))
1029 *f-- = 0;
133a37bf 1030 }
25e7d9b1 1031
094e6b81
PS
1032 p = prefix + i;
1033
1034 return g_strdup_printf("%" PRIu64 "%s %.1s%s", quot, fract, p, unit);
4cc9aea1 1035}
25e7d9b1 1036
4cc9aea1
JH
1037/**
1038 * Convert a numeric samplerate value to its "natural" string representation.
1039 *
1040 * E.g. a value of 3000000 would be converted to "3 MHz", 20000 to "20 kHz",
1041 * 31500 would become "31.5 kHz".
1042 *
1043 * @param samplerate The samplerate in Hz.
1044 *
91219afc 1045 * @return A newly allocated string representation of the samplerate value,
4cc9aea1
JH
1046 * or NULL upon errors. The caller is responsible to g_free() the
1047 * memory.
47117241
UH
1048 *
1049 * @since 0.1.0
4cc9aea1
JH
1050 */
1051SR_API char *sr_samplerate_string(uint64_t samplerate)
1052{
1053 return sr_si_string_u64(samplerate, "Hz");
25e7d9b1 1054}
2a3f9541 1055
2a3f9541 1056/**
9a17c23b
UH
1057 * Convert a numeric period value to the "natural" string representation
1058 * of its period value.
2a3f9541 1059 *
9a17c23b 1060 * The period is specified as a rational number's numerator and denominator.
2a3f9541 1061 *
9a17c23b 1062 * E.g. a pair of (1, 5) would be converted to "200 ms", (10, 100) to "100 ms".
44dae539 1063 *
9a17c23b
UH
1064 * @param v_p The period numerator.
1065 * @param v_q The period denominator.
1066 *
1067 * @return A newly allocated string representation of the period value,
133a37bf
UH
1068 * or NULL upon errors. The caller is responsible to g_free() the
1069 * memory.
47117241 1070 *
9a17c23b 1071 * @since 0.5.0
2a3f9541 1072 */
6984cfb2 1073SR_API char *sr_period_string(uint64_t v_p, uint64_t v_q)
2a3f9541 1074{
6984cfb2 1075 double freq, v;
d2391b54 1076 int prec;
6984cfb2
SA
1077
1078 freq = 1 / ((double)v_p / v_q);
2a3f9541 1079
6984cfb2
SA
1080 if (freq > SR_GHZ(1)) {
1081 v = (double)v_p / v_q * 1000000000000.0;
1082 prec = ((v - (uint64_t)v) < FLT_MIN) ? 0 : 3;
d2391b54 1083 return g_strdup_printf("%.*f ps", prec, v);
6984cfb2
SA
1084 } else if (freq > SR_MHZ(1)) {
1085 v = (double)v_p / v_q * 1000000000.0;
1086 prec = ((v - (uint64_t)v) < FLT_MIN) ? 0 : 3;
d2391b54 1087 return g_strdup_printf("%.*f ns", prec, v);
6984cfb2
SA
1088 } else if (freq > SR_KHZ(1)) {
1089 v = (double)v_p / v_q * 1000000.0;
1090 prec = ((v - (uint64_t)v) < FLT_MIN) ? 0 : 3;
d2391b54 1091 return g_strdup_printf("%.*f us", prec, v);
6984cfb2
SA
1092 } else if (freq > 1) {
1093 v = (double)v_p / v_q * 1000.0;
1094 prec = ((v - (uint64_t)v) < FLT_MIN) ? 0 : 3;
d2391b54 1095 return g_strdup_printf("%.*f ms", prec, v);
6984cfb2
SA
1096 } else {
1097 v = (double)v_p / v_q;
1098 prec = ((v - (uint64_t)v) < FLT_MIN) ? 0 : 3;
d2391b54 1099 return g_strdup_printf("%.*f s", prec, v);
2a3f9541 1100 }
2a3f9541 1101}
40f5ddac 1102
79afc8ca 1103/**
e0e15067
BV
1104 * Convert a numeric voltage value to the "natural" string representation
1105 * of its voltage value. The voltage is specified as a rational number's
1106 * numerator and denominator.
79afc8ca
BV
1107 *
1108 * E.g. a value of 300000 would be converted to "300mV", 2 to "2V".
1109 *
e0e15067
BV
1110 * @param v_p The voltage numerator.
1111 * @param v_q The voltage denominator.
79afc8ca 1112 *
91219afc 1113 * @return A newly allocated string representation of the voltage value,
79afc8ca
BV
1114 * or NULL upon errors. The caller is responsible to g_free() the
1115 * memory.
47117241
UH
1116 *
1117 * @since 0.2.0
79afc8ca 1118 */
e0e15067 1119SR_API char *sr_voltage_string(uint64_t v_p, uint64_t v_q)
79afc8ca 1120{
e0e15067 1121 if (v_q == 1000)
b5df922e 1122 return g_strdup_printf("%" PRIu64 " mV", v_p);
e0e15067 1123 else if (v_q == 1)
b5df922e 1124 return g_strdup_printf("%" PRIu64 " V", v_p);
79afc8ca 1125 else
b5df922e 1126 return g_strdup_printf("%g V", (float)v_p / (float)v_q);
79afc8ca
BV
1127}
1128
dfcc0bf9
UH
1129/**
1130 * Convert a "natural" string representation of a size value to uint64_t.
1131 *
1132 * E.g. a value of "3k" or "3 K" would be converted to 3000, a value
1133 * of "15M" would be converted to 15000000.
1134 *
1135 * Value representations other than decimal (such as hex or octal) are not
1136 * supported. Only 'k' (kilo), 'm' (mega), 'g' (giga) suffixes are supported.
1137 * Spaces (but not other whitespace) between value and suffix are allowed.
1138 *
1139 * @param sizestring A string containing a (decimal) size value.
f64c1414 1140 * @param size Pointer to uint64_t which will contain the string's size value.
dfcc0bf9 1141 *
44dae539 1142 * @return SR_OK upon success, SR_ERR upon errors.
47117241
UH
1143 *
1144 * @since 0.1.0
dfcc0bf9 1145 */
1a081ca6 1146SR_API int sr_parse_sizestring(const char *sizestring, uint64_t *size)
40f5ddac 1147{
751ba4c8
GS
1148 uint64_t multiplier;
1149 int done;
580f3099 1150 double frac_part;
40f5ddac
BV
1151 char *s;
1152
f64c1414 1153 *size = strtoull(sizestring, &s, 10);
40f5ddac 1154 multiplier = 0;
580f3099 1155 frac_part = 0;
f64c1414
BV
1156 done = FALSE;
1157 while (s && *s && multiplier == 0 && !done) {
40f5ddac
BV
1158 switch (*s) {
1159 case ' ':
1160 break;
580f3099
DJ
1161 case '.':
1162 frac_part = g_ascii_strtod(s, &s);
1163 break;
40f5ddac
BV
1164 case 'k':
1165 case 'K':
59df0c77 1166 multiplier = SR_KHZ(1);
40f5ddac
BV
1167 break;
1168 case 'm':
1169 case 'M':
59df0c77 1170 multiplier = SR_MHZ(1);
40f5ddac
BV
1171 break;
1172 case 'g':
1173 case 'G':
59df0c77 1174 multiplier = SR_GHZ(1);
40f5ddac 1175 break;
751ba4c8
GS
1176 case 't':
1177 case 'T':
1178 multiplier = SR_GHZ(1000);
1179 break;
1180 case 'p':
1181 case 'P':
1182 multiplier = SR_GHZ(1000 * 1000);
1183 break;
1184 case 'e':
1185 case 'E':
1186 multiplier = SR_GHZ(1000 * 1000 * 1000);
1187 break;
40f5ddac 1188 default:
f64c1414
BV
1189 done = TRUE;
1190 s--;
40f5ddac
BV
1191 }
1192 s++;
1193 }
580f3099 1194 if (multiplier > 0) {
f64c1414 1195 *size *= multiplier;
580f3099 1196 *size += frac_part * multiplier;
751ba4c8 1197 } else {
580f3099 1198 *size += frac_part;
751ba4c8 1199 }
40f5ddac 1200
34577da6 1201 if (s && *s && g_ascii_strcasecmp(s, "Hz"))
f64c1414
BV
1202 return SR_ERR;
1203
1204 return SR_OK;
40f5ddac
BV
1205}
1206
dfcc0bf9
UH
1207/**
1208 * Convert a "natural" string representation of a time value to an
1209 * uint64_t value in milliseconds.
1210 *
1211 * E.g. a value of "3s" or "3 s" would be converted to 3000, a value
1212 * of "15ms" would be converted to 15.
1213 *
1214 * Value representations other than decimal (such as hex or octal) are not
1215 * supported. Only lower-case "s" and "ms" time suffixes are supported.
1216 * Spaces (but not other whitespace) between value and suffix are allowed.
1217 *
1218 * @param timestring A string containing a (decimal) time value.
1219 * @return The string's time value as uint64_t, in milliseconds.
1220 *
6b2d8d3e
UH
1221 * @todo Add support for "m" (minutes) and others.
1222 * @todo Add support for picoseconds?
1223 * @todo Allow both lower-case and upper-case? If no, document it.
47117241
UH
1224 *
1225 * @since 0.1.0
dfcc0bf9 1226 */
1a081ca6 1227SR_API uint64_t sr_parse_timestring(const char *timestring)
40f5ddac
BV
1228{
1229 uint64_t time_msec;
1230 char *s;
1231
6b2d8d3e
UH
1232 /* TODO: Error handling, logging. */
1233
40f5ddac
BV
1234 time_msec = strtoull(timestring, &s, 10);
1235 if (time_msec == 0 && s == timestring)
1236 return 0;
1237
1238 if (s && *s) {
1239 while (*s == ' ')
1240 s++;
1241 if (!strcmp(s, "s"))
1242 time_msec *= 1000;
1243 else if (!strcmp(s, "ms"))
1244 ; /* redundant */
1245 else
1246 return 0;
1247 }
1248
1249 return time_msec;
1250}
4d436e71 1251
47117241 1252/** @since 0.1.0 */
1a081ca6 1253SR_API gboolean sr_parse_boolstring(const char *boolstr)
4d436e71 1254{
ad466f86
GS
1255 /*
1256 * Complete absence of an input spec is assumed to mean TRUE,
1257 * as in command line option strings like this:
1258 * ...:samplerate=100k:header:numchannels=4:...
1259 */
1260 if (!boolstr || !*boolstr)
1261 return TRUE;
4d436e71 1262
993526f8
BV
1263 if (!g_ascii_strncasecmp(boolstr, "true", 4) ||
1264 !g_ascii_strncasecmp(boolstr, "yes", 3) ||
1265 !g_ascii_strncasecmp(boolstr, "on", 2) ||
1266 !g_ascii_strncasecmp(boolstr, "1", 1))
4d436e71
GM
1267 return TRUE;
1268
1269 return FALSE;
1270}
76f4c610 1271
47117241 1272/** @since 0.2.0 */
76e107d6 1273SR_API int sr_parse_period(const char *periodstr, uint64_t *p, uint64_t *q)
76f4c610
BV
1274{
1275 char *s;
1276
76e107d6
BV
1277 *p = strtoull(periodstr, &s, 10);
1278 if (*p == 0 && s == periodstr)
76f4c610
BV
1279 /* No digits found. */
1280 return SR_ERR_ARG;
1281
1282 if (s && *s) {
1283 while (*s == ' ')
1284 s++;
8c012adb 1285 if (!strcmp(s, "fs"))
d9b716fc 1286 *q = UINT64_C(1000000000000000);
8c012adb 1287 else if (!strcmp(s, "ps"))
d9b716fc 1288 *q = UINT64_C(1000000000000);
8c012adb 1289 else if (!strcmp(s, "ns"))
d9b716fc 1290 *q = UINT64_C(1000000000);
76f4c610 1291 else if (!strcmp(s, "us"))
76e107d6 1292 *q = 1000000;
76f4c610 1293 else if (!strcmp(s, "ms"))
76e107d6 1294 *q = 1000;
76f4c610 1295 else if (!strcmp(s, "s"))
76e107d6 1296 *q = 1;
76f4c610
BV
1297 else
1298 /* Must have a time suffix. */
1299 return SR_ERR_ARG;
1300 }
1301
1302 return SR_OK;
1303}
1304
47117241 1305/** @since 0.2.0 */
76e107d6 1306SR_API int sr_parse_voltage(const char *voltstr, uint64_t *p, uint64_t *q)
79afc8ca
BV
1307{
1308 char *s;
1309
76e107d6
BV
1310 *p = strtoull(voltstr, &s, 10);
1311 if (*p == 0 && s == voltstr)
79afc8ca
BV
1312 /* No digits found. */
1313 return SR_ERR_ARG;
1314
1315 if (s && *s) {
1316 while (*s == ' ')
1317 s++;
34577da6 1318 if (!g_ascii_strcasecmp(s, "mv"))
76e107d6 1319 *q = 1000L;
34577da6 1320 else if (!g_ascii_strcasecmp(s, "v"))
76e107d6 1321 *q = 1;
79afc8ca
BV
1322 else
1323 /* Must have a base suffix. */
1324 return SR_ERR_ARG;
1325 }
1326
1327 return SR_OK;
1328}
1329
ba42283a
GS
1330/**
1331 * Append another text item to a NULL terminated string vector.
1332 *
1333 * @param[in] table The previous string vector.
1334 * @param[in,out] sz The previous and the resulting vector size
1335 * (item count).
1336 * @param[in] text The text string to append to the vector.
1337 * Can be #NULL.
1338 *
1339 * @returns The new vector, its location can differ from 'table'.
1340 * Or #NULL in case of failure.
1341 *
1342 * This implementation happens to work for the first invocation when
1343 * 'table' is #NULL and 'sz' is 0, as well as subsequent append calls.
1344 * The 'text' can be #NULL or can be a non-empty string. When 'sz' is
1345 * not provided, then the 'table' must be a NULL terminated vector,
1346 * so that the routine can auto-determine the vector's current length.
1347 *
1348 * This routine re-allocates the vector as needed. Callers must not
1349 * rely on the memory address to remain the same across calls.
1350 */
1351static char **append_probe_name(char **table, size_t *sz, const char *text)
1352{
1353 size_t curr_size, alloc_size;
1354 char **new_table;
1355
1356 /* Get the table's previous size (item count). */
1357 if (sz)
1358 curr_size = *sz;
1359 else if (table)
1360 curr_size = g_strv_length(table);
1361 else
1362 curr_size = 0;
1363
1364 /* Extend storage to hold one more item, and the termination. */
1365 alloc_size = curr_size + (text ? 1 : 0) + 1;
1366 alloc_size *= sizeof(table[0]);
1367 new_table = g_realloc(table, alloc_size);
1368 if (!new_table) {
1369 g_strfreev(table);
1370 if (sz)
1371 *sz = 0;
1372 return NULL;
1373 }
1374
1375 /* Append the item, NULL terminate. */
1376 if (text) {
1377 new_table[curr_size] = g_strdup(text);
1378 if (!new_table[curr_size]) {
1379 g_strfreev(new_table);
1380 if (sz)
1381 *sz = 0;
1382 return NULL;
1383 }
1384 curr_size++;
1385 }
1386 if (sz)
1387 *sz = curr_size;
1388 new_table[curr_size] = NULL;
1389
1390 return new_table;
1391}
1392
1393static char **append_probe_names(char **table, size_t *sz,
1394 const char **names)
1395{
1396 if (!names)
1397 return table;
1398
1399 while (names[0]) {
1400 table = append_probe_name(table, sz, names[0]);
1401 names++;
1402 }
1403 return table;
1404}
1405
1406static const struct {
1407 const char *name;
1408 const char **expands;
1409} probe_name_aliases[] = {
1410 {
1411 "ac97", (const char *[]){
1412 "sync", "clk",
1413 "out", "in", "rst",
1414 NULL,
1415 },
1416 },
1417 {
1418 "i2c", (const char *[]){
1419 "scl", "sda", NULL,
1420 },
1421 },
1422 {
1423 "jtag", (const char *[]){
1424 "tdi", "tdo", "tck", "tms", NULL,
1425 },
1426 },
1427 {
1428 "jtag-opt", (const char *[]){
1429 "tdi", "tdo", "tck", "tms",
1430 "trst", "srst", "rtck", NULL,
1431 },
1432 },
1433 {
1434 "ieee488", (const char *[]){
1435 "dio1", "dio2", "dio3", "dio4",
1436 "dio5", "dio6", "dio7", "dio8",
1437 "eoi", "dav", "nrfd", "ndac",
1438 "ifc", "srq", "atn", "ren", NULL,
1439 },
1440 },
1441 {
1442 "lpc", (const char *[]){
1443 "lframe", "lclk",
1444 "lad0", "lad1", "lad2", "lad3",
1445 NULL,
1446 },
1447 },
1448 {
1449 "lpc-opt", (const char *[]){
1450 "lframe", "lclk",
1451 "lad0", "lad1", "lad2", "lad3",
1452 "lreset", "ldrq", "serirq", "clkrun",
1453 "lpme", "lpcpd", "lsmi",
1454 NULL,
1455 },
1456 },
1457 {
1458 "mcs48", (const char *[]){
1459 "ale", "psen",
1460 "d0", "d1", "d2", "d3",
1461 "d4", "d5", "d6", "d7",
1462 "a8", "a9", "a10", "a11",
1463 "a12", "a13",
1464 NULL,
1465 },
1466 },
1467 {
1468 "microwire", (const char *[]){
1469 "cs", "sk", "si", "so", NULL,
1470 },
1471 },
1472 {
1473 "sdcard_sd", (const char *[]){
1474 "cmd", "clk",
1475 "dat0", "dat1", "dat2", "dat3",
1476 NULL,
1477 },
1478 },
1479 {
1480 "seven_segment", (const char *[]){
1481 "a", "b", "c", "d", "e", "f", "g",
1482 "dp", NULL,
1483 },
1484 },
1485 {
1486 "spi", (const char *[]){
1487 "clk", "miso", "mosi", "cs", NULL,
1488 },
1489 },
1490 {
1491 "swd", (const char *[]){
1492 "swclk", "swdio", NULL,
1493 },
1494 },
1495 {
1496 "uart", (const char *[]){
1497 "rx", "tx", NULL,
1498 },
1499 },
1500 {
1501 "usb", (const char *[]){
1502 "dp", "dm", NULL,
1503 },
1504 },
1505 {
1506 "z80", (const char *[]){
1507 "d0", "d1", "d2", "d3",
1508 "d4", "d5", "d6", "d7",
1509 "m1", "rd", "wr",
1510 "mreq", "iorq",
1511 "a0", "a1", "a2", "a3",
1512 "a4", "a5", "a6", "a7",
1513 "a8", "a9", "a10", "a11",
1514 "a12", "a13", "a14", "a15",
1515 NULL,
1516 },
1517 },
1518};
1519
1520/* Case insensitive lookup of an alias name. */
1521static const char **lookup_probe_alias(const char *name)
1522{
1523 size_t idx;
1524
1525 for (idx = 0; idx < ARRAY_SIZE(probe_name_aliases); idx++) {
1526 if (g_ascii_strcasecmp(probe_name_aliases[idx].name, name) != 0)
1527 continue;
1528 return probe_name_aliases[idx].expands;
1529 }
1530 return NULL;
1531}
1532
1533/**
1534 * Parse a probe names specification, allocate a string vector.
1535 *
1536 * @param[in] spec The input spec, list of probes or aliases.
1537 * @param[in] dflt_names The default probe names, a string array.
1538 * @param[in] dflt_count The default probe names count. Either must
1539 * match the unterminated array size, or can be 0 when the
1540 * default names are NULL terminated.
1541 * @param[in] max_count Optional resulting vector size limit.
1542 * @param[out] ret_count Optional result vector size (return value).
1543 *
1544 * @returns A string vector with resulting probe names. Or #NULL
1545 * in case of failure.
1546 *
1547 * The input spec is a comma separated list of probe names. Items can
1548 * be aliases which expand to a corresponding set of signal names.
1549 * The resulting names list optionally gets padded from the caller's
1550 * builtin probe names, an empty input spec yields the original names
1551 * as provided by the caller. Padding is omitted when the spec starts
1552 * with '-', which may result in a device with fewer channels being
1553 * created, enough to cover the user's spec, but none extra to maybe
1554 * enable and use later on. An optional maximum length spec will trim
1555 * the result set to that size. The resulting vector length optionally
1556 * is returned to the caller, so that it need not re-get the length.
1557 *
1558 * Calling applications must release the allocated vector by means
1559 * of @ref sr_free_probe_names().
1560 *
1561 * @since 0.6.0
1562 */
1563SR_API char **sr_parse_probe_names(const char *spec,
1564 const char **dflt_names, size_t dflt_count,
1565 size_t max_count, size_t *ret_count)
1566{
1567 char **result_names;
1568 size_t result_count;
1569 gboolean pad_from_dflt;
1570 char **spec_names, *spec_name;
1571 size_t spec_idx;
1572 const char **alias_names;
1573
1574 if (!spec || !*spec)
1575 spec = NULL;
1576
1577 /*
1578 * Accept zero length spec for default input names. Determine
1579 * the name table's length here. Cannot re-use g_strv_length()
1580 * because of the 'const' decoration in application code.
1581 */
1582 if (!dflt_count) {
1583 while (dflt_names && dflt_names[dflt_count])
1584 dflt_count++;
1585 }
1586 if (!dflt_count)
1587 return NULL;
1588
1589 /*
1590 * Start with an empty resulting names table. Will grow
1591 * dynamically as more names get appended.
1592 */
1593 result_names = NULL;
1594 result_count = 0;
1595 pad_from_dflt = TRUE;
1596
1597 /*
1598 * When an input spec exists, use its content. Lookup alias
1599 * names, and append their corresponding signals. Or append
1600 * the verbatim input name if it is not an alias. Recursion
1601 * is not supported in this implementation.
1602 *
1603 * A leading '-' before the signal names list suppresses the
1604 * padding of the resulting list from the device's default
1605 * probe names.
1606 */
1607 spec_names = NULL;
1608 if (spec && *spec == '-') {
1609 spec++;
1610 pad_from_dflt = FALSE;
1611 }
1612 if (spec && *spec)
1613 spec_names = g_strsplit(spec, ",", 0);
1614 for (spec_idx = 0; spec_names && spec_names[spec_idx]; spec_idx++) {
1615 spec_name = spec_names[spec_idx];
1616 if (!*spec_name)
1617 continue;
1618 alias_names = lookup_probe_alias(spec_name);
1619 if (alias_names) {
1620 result_names = append_probe_names(result_names,
1621 &result_count, alias_names);
1622 } else {
1623 result_names = append_probe_name(result_names,
1624 &result_count, spec_name);
1625 }
1626 }
1627 g_strfreev(spec_names);
1628
1629 /*
1630 * By default pad the resulting names from the caller's
1631 * probe names. Don't pad if the input spec started with
1632 * '-', when the spec's exact length was requested.
1633 */
1634 if (pad_from_dflt) do {
1635 if (max_count && result_count >= max_count)
1636 break;
1637 if (result_count >= dflt_count)
1638 break;
1639 result_names = append_probe_name(result_names, &result_count,
1640 dflt_names[result_count]);
1641 } while (1);
1642
1643 /* Optionally trim the result to the caller's length limit. */
1644 if (max_count) {
1645 while (result_count > max_count) {
1646 --result_count;
1647 g_free(result_names[result_count]);
1648 result_names[result_count] = NULL;
1649 }
1650 }
1651
1652 if (ret_count)
1653 *ret_count = result_count;
1654
1655 return result_names;
1656}
1657
1658/**
1659 * Release previously allocated probe names (string vector).
1660 *
1661 * @param[in] names The previously allocated string vector.
1662 *
1663 * @since 0.6.0
1664 */
1665SR_API void sr_free_probe_names(char **names)
1666{
1667 g_strfreev(names);
1668}
1669
227913f2
GS
1670/**
1671 * Trim leading and trailing whitespace off text.
1672 *
1673 * @param[in] s The input text.
1674 *
1675 * @return Start of trimmed input text.
1676 *
1677 * Manipulates the caller's input text in place.
1678 *
1679 * @since 0.6.0
1680 */
1681SR_API char *sr_text_trim_spaces(char *s)
1682{
1683 char *p;
1684
1685 if (!s || !*s)
1686 return s;
1687
1688 p = s + strlen(s);
1689 while (p > s && isspace((int)p[-1]))
1690 *(--p) = '\0';
1691 while (isspace((int)*s))
1692 s++;
1693
1694 return s;
1695}
1696
1697/**
1698 * Check for another complete text line, trim, return consumed char count.
1699 *
1700 * @param[in] s The input text, current read position.
1701 * @param[in] l The input text, remaining available characters.
1702 * @param[out] next Position after the current text line.
1703 * @param[out] taken Count of consumed chars in current text line.
1704 *
1705 * @return Start of trimmed and NUL terminated text line.
1706 * Or #NULL when no text line was found.
1707 *
1708 * Checks for the availability of another text line of input data.
1709 * Manipulates the caller's input text in place.
1710 *
1711 * The end-of-line condition is the LF character ('\n'). Which covers
1712 * LF-only as well as CR/LF input data. CR-only and LF/CR are considered
1713 * unpopular and are not supported. LF/CR may appear to work at the
1714 * caller's when leading whitespace gets trimmed (line boundaries will
1715 * be incorrect, but content may get processed as expected). Support for
1716 * all of the above combinations breaks the detection of empty lines (or
1717 * becomes unmaintainably complex).
1718 *
1719 * The input buffer must be end-of-line terminated, lack of EOL results
1720 * in failure to detect the text line. This is motivated by accumulating
1721 * input in chunks, and the desire to not process incomplete lines before
1722 * their reception has completed. Callers should enforce EOL if their
1723 * source of input provides an EOF condition and is unreliable in terms
1724 * of text line termination.
1725 *
1726 * When another text line is available, it gets NUL terminated and
1727 * space gets trimmed of both ends. The start position of the trimmed
1728 * text line is returned. Optionally the number of consumed characters
1729 * is returned to the caller. Optionally 'next' points to after the
1730 * returned text line, or #NULL when no other text is available in the
1731 * input buffer.
1732 *
1733 * The 'taken' value is not preset by this routine, only gets updated.
1734 * This is convenient for callers which expect to find multiple text
1735 * lines in a received chunk, before finally discarding processed data
1736 * from the input buffer (which can involve expensive memory move
1737 * operations, and may be desirable to defer as much as possible).
1738 *
1739 * @since 0.6.0
1740 */
1741SR_API char *sr_text_next_line(char *s, size_t l, char **next, size_t *taken)
1742{
1743 char *p;
1744
1745 if (next)
1746 *next = NULL;
1747 if (!l)
1748 l = strlen(s);
1749
1750 /* Immediate reject incomplete input data. */
1751 if (!s || !*s || !l)
1752 return NULL;
1753
1754 /* Search for the next line termination. NUL terminate. */
1755 p = g_strstr_len(s, l, "\n");
1756 if (!p)
1757 return NULL;
1758 *p++ = '\0';
1759 if (taken)
1760 *taken += p - s;
1761 l -= p - s;
1762 if (next)
1763 *next = l ? p : NULL;
1764
1765 /* Trim NUL terminated text line at both ends. */
1766 s = sr_text_trim_spaces(s);
1767 return s;
1768}
1769
1770/**
1771 * Isolates another space separated word in a text line.
1772 *
1773 * @param[in] s The input text, current read position.
1774 * @param[out] next The position after the current word.
1775 *
1776 * @return The start of the current word. Or #NULL if there is none.
1777 *
1778 * Advances over leading whitespace. Isolates (NUL terminates) the next
1779 * whitespace separated word. Optionally returns the position after the
1780 * current word. Manipulates the caller's input text in place.
1781 *
1782 * @since 0.6.0
1783 */
1784SR_API char *sr_text_next_word(char *s, char **next)
1785{
1786 char *word, *p;
1787
1788 word = s;
1789 if (next)
1790 *next = NULL;
1791
1792 /* Immediately reject incomplete input data. */
1793 if (!word || !*word)
1794 return NULL;
1795
1796 /* Advance over optional leading whitespace. */
1797 while (isspace((int)*word))
1798 word++;
1799 if (!*word)
1800 return NULL;
1801
1802 /*
1803 * Advance until whitespace or end of text. Quick return when
1804 * end of input is seen. Otherwise advance over whitespace and
1805 * return the position of trailing text.
1806 */
1807 p = word;
1808 while (*p && !isspace((int)*p))
1809 p++;
1810 if (!*p)
1811 return word;
1812 *p++ = '\0';
1813 while (isspace((int)*p))
1814 p++;
1815 if (!*p)
1816 return word;
1817 if (next)
1818 *next = p;
1819 return word;
1820}
1821
a2f3645b
GS
1822/**
1823 * Get the number of necessary bits to hold a given value. Also gets
1824 * the next power-of-two value at or above the caller provided value.
1825 *
1826 * @param[in] value The value that must get stored.
1827 * @param[out] bits The required number of bits.
1828 * @param[out] power The corresponding power-of-two.
1829 *
1830 * @return SR_OK upon success, SR_ERR* otherwise.
1831 *
1832 * TODO Move this routine to a more appropriate location, it is not
1833 * strictly string related.
1834 *
1835 * @since 0.6.0
1836 */
1837SR_API int sr_next_power_of_two(size_t value, size_t *bits, size_t *power)
1838{
1839 size_t need_bits;
1840 size_t check_mask;
1841
1842 if (bits)
1843 *bits = 0;
1844 if (power)
1845 *power = 0;
1846
c3ada48a
GS
1847 /*
1848 * Handle the special case of input value 0 (needs 1 bit
1849 * and results in "power of two" value 1) here. It is not
1850 * covered by the generic logic below.
1851 */
1852 if (!value) {
1853 if (bits)
1854 *bits = 1;
1855 if (power)
1856 *power = 1;
1857 return SR_OK;
1858 }
a2f3645b
GS
1859
1860 need_bits = 0;
1861 check_mask = 0;
1862 do {
1863 need_bits++;
1864 check_mask <<= 1;
1865 check_mask |= 1UL << 0;
1866 } while (value & ~check_mask);
1867
1868 if (bits)
1869 *bits = need_bits;
1870 if (power)
1871 *power = ++check_mask;
1872 return SR_OK;
1873}
1874
7b870c38 1875/** @} */