]> sigrok.org Git - libsigrok.git/blame_incremental - src/strutil.c
output/csv: use intermediate time_t var, silence compiler warning
[libsigrok.git] / src / strutil.c
... / ...
CommitLineData
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/* Needed for POSIX.1-2008 locale functions */
21/** @cond PRIVATE */
22#define _XOPEN_SOURCE 700
23/** @endcond */
24#include <config.h>
25#include <ctype.h>
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
33#include <stdint.h>
34#include <stdlib.h>
35#include <string.h>
36#include <strings.h>
37#include <errno.h>
38#include <libsigrok/libsigrok.h>
39#include "libsigrok-internal.h"
40
41/** @cond PRIVATE */
42#define LOG_PREFIX "strutil"
43/** @endcond */
44
45/**
46 * @file
47 *
48 * Helper functions for handling or converting libsigrok-related strings.
49 */
50
51/**
52 * @defgroup grp_strutil String utilities
53 *
54 * Helper functions for handling or converting libsigrok-related strings.
55 *
56 * @{
57 */
58
59/**
60 * Convert a string representation of a numeric value (base 10) to a long integer. The
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 *
68 * @retval SR_OK Conversion successful.
69 * @retval SR_ERR Failure.
70 *
71 * @private
72 */
73SR_PRIV int sr_atol(const char *str, long *ret)
74{
75 long tmp;
76 char *endptr = NULL;
77
78 errno = 0;
79 tmp = strtol(str, &endptr, 10);
80
81 while (endptr && isspace(*endptr))
82 endptr++;
83
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
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
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++;
177 if ((!base || base == 2) && strncmp(str, "0b", strlen("0b")) == 0) {
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
202/**
203 * Convert a string representation of a numeric value (base 10) to an integer. The
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 *
211 * @retval SR_OK Conversion successful.
212 * @retval SR_ERR Failure.
213 *
214 * @private
215 */
216SR_PRIV int sr_atoi(const char *str, int *ret)
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 *
241 * @retval SR_OK Conversion successful.
242 * @retval SR_ERR Failure.
243 *
244 * @private
245 */
246SR_PRIV int sr_atod(const char *str, double *ret)
247{
248 double tmp;
249 char *endptr = NULL;
250
251 errno = 0;
252 tmp = strtof(str, &endptr);
253
254 while (endptr && isspace(*endptr))
255 endptr++;
256
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 *
276 * @retval SR_OK Conversion successful.
277 * @retval SR_ERR Failure.
278 *
279 * @private
280 */
281SR_PRIV int sr_atof(const char *str, float *ret)
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
297/**
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.
308 *
309 * @private
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
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
400/**
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 *
409 * @retval SR_OK Conversion successful.
410 * @retval SR_ERR Failure.
411 *
412 * @private
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
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
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 *
612 * This version ignores the current locale and uses the locale "C" for Linux,
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 *
659 * This version ignores the current locale and uses the locale "C" for Linux,
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!.
690 * See: https://msdn.microsoft.com/en-us/en-en/library/1kt27hek.aspx
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
774/**
775 * Convert a sequence of bytes to its textual representation ("hex dump").
776 *
777 * Callers should free the allocated GString. See sr_hexdump_free().
778 *
779 * @param[in] data Pointer to the byte sequence to print.
780 * @param[in] len Number of bytes to print.
781 *
782 * @return NULL upon error, newly allocated GString pointer otherwise.
783 *
784 * @private
785 */
786SR_PRIV GString *sr_hexdump_new(const uint8_t *data, const size_t len)
787{
788 GString *s;
789 size_t i;
790
791 i = 3 * len;
792 i += len / 8;
793 i += len / 16;
794 s = g_string_sized_new(i);
795 for (i = 0; i < len; i++) {
796 if (i)
797 g_string_append_c(s, ' ');
798 if (i && (i % 8) == 0)
799 g_string_append_c(s, ' ');
800 if (i && (i % 16) == 0)
801 g_string_append_c(s, ' ');
802 g_string_append_printf(s, "%02x", data[i]);
803 }
804
805 return s;
806}
807
808/**
809 * Free a hex dump text that was created by sr_hexdump_new().
810 *
811 * @param[in] s Pointer to the GString to release.
812 *
813 * @private
814 */
815SR_PRIV void sr_hexdump_free(GString *s)
816{
817 if (s)
818 g_string_free(s, TRUE);
819}
820
821/**
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.
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{
838 const char *readptr;
839 char *endptr;
840 gboolean is_negative, empty_integral, empty_fractional, exp_negative;
841 int64_t integral;
842 int64_t fractional;
843 int64_t denominator;
844 uint32_t fractional_len;
845 int32_t exponent;
846
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;
858
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 == '-') {
866 is_negative = TRUE;
867 readptr++;
868 } else if (*readptr == '+') {
869 is_negative = FALSE;
870 readptr++;
871 }
872
873 /* Get the (optional) integral part. */
874 empty_integral = TRUE;
875 integral = 0;
876 endptr = (char *)readptr;
877 errno = 0;
878 if (isdigit(*readptr)) {
879 empty_integral = FALSE;
880 integral = g_ascii_strtoll(readptr, &endptr, 10);
881 if (errno)
882 return SR_ERR;
883 if (endptr == str) {
884 errno = -EINVAL;
885 return SR_ERR;
886 }
887 readptr = endptr;
888 }
889
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);
939 if (errno)
940 return SR_ERR;
941 if (endptr == readptr) {
942 errno = -EINVAL;
943 return SR_ERR;
944 }
945 readptr = endptr;
946 if (exp_negative)
947 exponent = -exponent;
948 }
949
950 /* Input must be exhausted. Unconverted remaining input is fatal. */
951 if (*endptr != '\0') {
952 errno = -EINVAL;
953 return SR_ERR;
954 }
955
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) {
964 integral *= 10;
965 exponent--;
966 }
967 if (!is_negative)
968 integral += fractional;
969 else
970 integral -= fractional;
971 while (exponent > 0) {
972 integral *= 10;
973 exponent--;
974 }
975
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;
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
992/**
993 * Convert a numeric value value to its "natural" string representation
994 * in SI units.
995 *
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".
998 *
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.
1002 *
1003 * @return A newly allocated string representation of the samplerate value,
1004 * or NULL upon errors. The caller is responsible to g_free() the
1005 * memory.
1006 *
1007 * @since 0.2.0
1008 */
1009SR_API char *sr_si_string_u64(uint64_t x, const char *unit)
1010{
1011 uint8_t i;
1012 uint64_t quot, divisor[] = {
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),
1015 };
1016 const char *p, prefix[] = "\0kMGTPE";
1017 char fmt[16], fract[20] = "", *f;
1018
1019 if (!unit)
1020 unit = "";
1021
1022 for (i = 0; (quot = x / divisor[i]) >= 1000; i++);
1023
1024 if (i) {
1025 sprintf(fmt, ".%%0%d"PRIu64, i * 3);
1026 f = fract + sprintf(fract, fmt, x % divisor[i]) - 1;
1027
1028 while (f >= fract && strchr("0.", *f))
1029 *f-- = 0;
1030 }
1031
1032 p = prefix + i;
1033
1034 return g_strdup_printf("%" PRIu64 "%s %.1s%s", quot, fract, p, unit);
1035}
1036
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 *
1045 * @return A newly allocated string representation of the samplerate value,
1046 * or NULL upon errors. The caller is responsible to g_free() the
1047 * memory.
1048 *
1049 * @since 0.1.0
1050 */
1051SR_API char *sr_samplerate_string(uint64_t samplerate)
1052{
1053 return sr_si_string_u64(samplerate, "Hz");
1054}
1055
1056/**
1057 * Convert a numeric period value to the "natural" string representation
1058 * of its period value.
1059 *
1060 * The period is specified as a rational number's numerator and denominator.
1061 *
1062 * E.g. a pair of (1, 5) would be converted to "200 ms", (10, 100) to "100 ms".
1063 *
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,
1068 * or NULL upon errors. The caller is responsible to g_free() the
1069 * memory.
1070 *
1071 * @since 0.5.0
1072 */
1073SR_API char *sr_period_string(uint64_t v_p, uint64_t v_q)
1074{
1075 double freq, v;
1076 int prec;
1077
1078 freq = 1 / ((double)v_p / v_q);
1079
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;
1083 return g_strdup_printf("%.*f ps", prec, v);
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;
1087 return g_strdup_printf("%.*f ns", prec, v);
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;
1091 return g_strdup_printf("%.*f us", prec, v);
1092 } else if (freq > 1) {
1093 v = (double)v_p / v_q * 1000.0;
1094 prec = ((v - (uint64_t)v) < FLT_MIN) ? 0 : 3;
1095 return g_strdup_printf("%.*f ms", prec, v);
1096 } else {
1097 v = (double)v_p / v_q;
1098 prec = ((v - (uint64_t)v) < FLT_MIN) ? 0 : 3;
1099 return g_strdup_printf("%.*f s", prec, v);
1100 }
1101}
1102
1103/**
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.
1107 *
1108 * E.g. a value of 300000 would be converted to "300mV", 2 to "2V".
1109 *
1110 * @param v_p The voltage numerator.
1111 * @param v_q The voltage denominator.
1112 *
1113 * @return A newly allocated string representation of the voltage value,
1114 * or NULL upon errors. The caller is responsible to g_free() the
1115 * memory.
1116 *
1117 * @since 0.2.0
1118 */
1119SR_API char *sr_voltage_string(uint64_t v_p, uint64_t v_q)
1120{
1121 if (v_q == 1000)
1122 return g_strdup_printf("%" PRIu64 " mV", v_p);
1123 else if (v_q == 1)
1124 return g_strdup_printf("%" PRIu64 " V", v_p);
1125 else
1126 return g_strdup_printf("%g V", (float)v_p / (float)v_q);
1127}
1128
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.
1140 * @param size Pointer to uint64_t which will contain the string's size value.
1141 *
1142 * @return SR_OK upon success, SR_ERR upon errors.
1143 *
1144 * @since 0.1.0
1145 */
1146SR_API int sr_parse_sizestring(const char *sizestring, uint64_t *size)
1147{
1148 uint64_t multiplier;
1149 int done;
1150 double frac_part;
1151 char *s;
1152
1153 *size = strtoull(sizestring, &s, 10);
1154 multiplier = 0;
1155 frac_part = 0;
1156 done = FALSE;
1157 while (s && *s && multiplier == 0 && !done) {
1158 switch (*s) {
1159 case ' ':
1160 break;
1161 case '.':
1162 frac_part = g_ascii_strtod(s, &s);
1163 break;
1164 case 'k':
1165 case 'K':
1166 multiplier = SR_KHZ(1);
1167 break;
1168 case 'm':
1169 case 'M':
1170 multiplier = SR_MHZ(1);
1171 break;
1172 case 'g':
1173 case 'G':
1174 multiplier = SR_GHZ(1);
1175 break;
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;
1188 default:
1189 done = TRUE;
1190 s--;
1191 }
1192 s++;
1193 }
1194 if (multiplier > 0) {
1195 *size *= multiplier;
1196 *size += frac_part * multiplier;
1197 } else {
1198 *size += frac_part;
1199 }
1200
1201 if (s && *s && g_ascii_strcasecmp(s, "Hz"))
1202 return SR_ERR;
1203
1204 return SR_OK;
1205}
1206
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 *
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.
1224 *
1225 * @since 0.1.0
1226 */
1227SR_API uint64_t sr_parse_timestring(const char *timestring)
1228{
1229 uint64_t time_msec;
1230 char *s;
1231
1232 /* TODO: Error handling, logging. */
1233
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}
1251
1252/** @since 0.1.0 */
1253SR_API gboolean sr_parse_boolstring(const char *boolstr)
1254{
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;
1262
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))
1267 return TRUE;
1268
1269 return FALSE;
1270}
1271
1272/** @since 0.2.0 */
1273SR_API int sr_parse_period(const char *periodstr, uint64_t *p, uint64_t *q)
1274{
1275 char *s;
1276
1277 *p = strtoull(periodstr, &s, 10);
1278 if (*p == 0 && s == periodstr)
1279 /* No digits found. */
1280 return SR_ERR_ARG;
1281
1282 if (s && *s) {
1283 while (*s == ' ')
1284 s++;
1285 if (!strcmp(s, "fs"))
1286 *q = UINT64_C(1000000000000000);
1287 else if (!strcmp(s, "ps"))
1288 *q = UINT64_C(1000000000000);
1289 else if (!strcmp(s, "ns"))
1290 *q = UINT64_C(1000000000);
1291 else if (!strcmp(s, "us"))
1292 *q = 1000000;
1293 else if (!strcmp(s, "ms"))
1294 *q = 1000;
1295 else if (!strcmp(s, "s"))
1296 *q = 1;
1297 else
1298 /* Must have a time suffix. */
1299 return SR_ERR_ARG;
1300 }
1301
1302 return SR_OK;
1303}
1304
1305/** @since 0.2.0 */
1306SR_API int sr_parse_voltage(const char *voltstr, uint64_t *p, uint64_t *q)
1307{
1308 char *s;
1309
1310 *p = strtoull(voltstr, &s, 10);
1311 if (*p == 0 && s == voltstr)
1312 /* No digits found. */
1313 return SR_ERR_ARG;
1314
1315 if (s && *s) {
1316 while (*s == ' ')
1317 s++;
1318 if (!g_ascii_strcasecmp(s, "mv"))
1319 *q = 1000L;
1320 else if (!g_ascii_strcasecmp(s, "v"))
1321 *q = 1;
1322 else
1323 /* Must have a base suffix. */
1324 return SR_ERR_ARG;
1325 }
1326
1327 return SR_OK;
1328}
1329
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
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
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
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 }
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
1875/** @} */