]> sigrok.org Git - libsigrok.git/blob - src/strutil.c
korad-kaxxxxp: use ID text prefix with optional version for RND models
[libsigrok.git] / src / strutil.c
1 /*
2  * This file is part of the libsigrok project.
3  *
4  * Copyright (C) 2010 Uwe Hermann <uwe@hermann-uwe.de>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 /* 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  */
73 SR_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  */
115 SR_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  */
169 SR_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 && 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  */
216 SR_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  */
246 SR_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  */
281 SR_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  */
311 SR_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  */
341 SR_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  */
414 SR_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  */
467 SR_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  */
506 SR_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  */
631 SR_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  */
678 SR_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  */
786 SR_PRIV GString *sr_hexdump_new(const uint8_t *data, const size_t len)
787 {
788         GString *s;
789         size_t i;
790
791         s = g_string_sized_new(3 * len);
792         for (i = 0; i < len; i++) {
793                 if (i)
794                         g_string_append_c(s, ' ');
795                 g_string_append_printf(s, "%02x", data[i]);
796         }
797
798         return s;
799 }
800
801 /**
802  * Free a hex dump text that was created by sr_hexdump_new().
803  *
804  * @param[in] s Pointer to the GString to release.
805  *
806  * @private
807  */
808 SR_PRIV void sr_hexdump_free(GString *s)
809 {
810         if (s)
811                 g_string_free(s, TRUE);
812 }
813
814 /**
815  * Convert a string representation of a numeric value to a sr_rational.
816  *
817  * The conversion is strict and will fail if the complete string does not
818  * represent a valid number. The function sets errno according to the details
819  * of the failure. This version ignores the locale.
820  *
821  * @param str The string representation to convert.
822  * @param ret Pointer to sr_rational where the result of the conversion will be stored.
823  *
824  * @retval SR_OK Conversion successful.
825  * @retval SR_ERR Failure.
826  *
827  * @since 0.5.0
828  */
829 SR_API int sr_parse_rational(const char *str, struct sr_rational *ret)
830 {
831         const char *readptr;
832         char *endptr;
833         gboolean is_negative, empty_integral, empty_fractional, exp_negative;
834         int64_t integral;
835         int64_t fractional;
836         int64_t denominator;
837         uint32_t fractional_len;
838         int32_t exponent;
839
840         /*
841          * Implementor's note: This routine tries hard to avoid calling
842          * glib's or the platform's conversion routines with input that
843          * cannot get converted *at all* (see bug #1093). It also takes
844          * care to return with non-zero errno values for any failed
845          * conversion attempt. It's assumed that correctness and robustness
846          * are more important than performance, which is why code paths
847          * are not optimized at all. Maintainability took priority.
848          */
849
850         readptr = str;
851
852         /* Skip leading whitespace. */
853         while (isspace(*readptr))
854                 readptr++;
855
856         /* Determine the sign, default to non-negative. */
857         is_negative = FALSE;
858         if (*readptr == '-') {
859                 is_negative = TRUE;
860                 readptr++;
861         } else if (*readptr == '+') {
862                 is_negative = FALSE;
863                 readptr++;
864         }
865
866         /* Get the (optional) integral part. */
867         empty_integral = TRUE;
868         integral = 0;
869         endptr = (char *)readptr;
870         errno = 0;
871         if (isdigit(*readptr)) {
872                 empty_integral = FALSE;
873                 integral = g_ascii_strtoll(readptr, &endptr, 10);
874                 if (errno)
875                         return SR_ERR;
876                 if (endptr == str) {
877                         errno = -EINVAL;
878                         return SR_ERR;
879                 }
880                 readptr = endptr;
881         }
882
883         /* Get the optional fractional part. */
884         empty_fractional = TRUE;
885         fractional = 0;
886         fractional_len = 0;
887         if (*readptr == '.') {
888                 readptr++;
889                 endptr++;
890                 errno = 0;
891                 if (isdigit(*readptr)) {
892                         empty_fractional = FALSE;
893                         fractional = g_ascii_strtoll(readptr, &endptr, 10);
894                         if (errno)
895                                 return SR_ERR;
896                         if (endptr == readptr) {
897                                 errno = -EINVAL;
898                                 return SR_ERR;
899                         }
900                         fractional_len = endptr - readptr;
901                         readptr = endptr;
902                 }
903         }
904
905         /* At least one of integral or fractional is required. */
906         if (empty_integral && empty_fractional) {
907                 errno = -EINVAL;
908                 return SR_ERR;
909         }
910
911         /* Get the (optional) exponent. */
912         exponent = 0;
913         if ((*readptr == 'E') || (*readptr == 'e')) {
914                 readptr++;
915                 endptr++;
916                 exp_negative = FALSE;
917                 if (*readptr == '+') {
918                         exp_negative = FALSE;
919                         readptr++;
920                         endptr++;
921                 } else if (*readptr == '-') {
922                         exp_negative = TRUE;
923                         readptr++;
924                         endptr++;
925                 }
926                 if (!isdigit(*readptr)) {
927                         errno = -EINVAL;
928                         return SR_ERR;
929                 }
930                 errno = 0;
931                 exponent = g_ascii_strtoll(readptr, &endptr, 10);
932                 if (errno)
933                         return SR_ERR;
934                 if (endptr == readptr) {
935                         errno = -EINVAL;
936                         return SR_ERR;
937                 }
938                 readptr = endptr;
939                 if (exp_negative)
940                         exponent = -exponent;
941         }
942
943         /* Input must be exhausted. Unconverted remaining input is fatal. */
944         if (*endptr != '\0') {
945                 errno = -EINVAL;
946                 return SR_ERR;
947         }
948
949         /*
950          * Apply the sign to the integral (and fractional) part(s).
951          * Adjust exponent (decimal position) such that the above integral
952          * and fractional parts both fit into the (new) integral part.
953          */
954         if (is_negative)
955                 integral = -integral;
956         while (fractional_len-- > 0) {
957                 integral *= 10;
958                 exponent--;
959         }
960         if (!is_negative)
961                 integral += fractional;
962         else
963                 integral -= fractional;
964         while (exponent > 0) {
965                 integral *= 10;
966                 exponent--;
967         }
968
969         /*
970          * When significant digits remain after the decimal, scale up the
971          * denominator such that we end up with two integer p/q numbers.
972          */
973         denominator = 1;
974         while (exponent < 0) {
975                 denominator *= 10;
976                 exponent++;
977         }
978
979         ret->p = integral;
980         ret->q = denominator;
981
982         return SR_OK;
983 }
984
985 /**
986  * Convert a numeric value value to its "natural" string representation
987  * in SI units.
988  *
989  * E.g. a value of 3000000, with units set to "W", would be converted
990  * to "3 MW", 20000 to "20 kW", 31500 would become "31.5 kW".
991  *
992  * @param x The value to convert.
993  * @param unit The unit to append to the string, or NULL if the string
994  *             has no units.
995  *
996  * @return A newly allocated string representation of the samplerate value,
997  *         or NULL upon errors. The caller is responsible to g_free() the
998  *         memory.
999  *
1000  * @since 0.2.0
1001  */
1002 SR_API char *sr_si_string_u64(uint64_t x, const char *unit)
1003 {
1004         uint8_t i;
1005         uint64_t quot, divisor[] = {
1006                 SR_HZ(1), SR_KHZ(1), SR_MHZ(1), SR_GHZ(1),
1007                 SR_GHZ(1000), SR_GHZ(1000 * 1000), SR_GHZ(1000 * 1000 * 1000),
1008         };
1009         const char *p, prefix[] = "\0kMGTPE";
1010         char fmt[16], fract[20] = "", *f;
1011
1012         if (!unit)
1013                 unit = "";
1014
1015         for (i = 0; (quot = x / divisor[i]) >= 1000; i++);
1016
1017         if (i) {
1018                 sprintf(fmt, ".%%0%d"PRIu64, i * 3);
1019                 f = fract + sprintf(fract, fmt, x % divisor[i]) - 1;
1020
1021                 while (f >= fract && strchr("0.", *f))
1022                         *f-- = 0;
1023         }
1024
1025         p = prefix + i;
1026
1027         return g_strdup_printf("%" PRIu64 "%s %.1s%s", quot, fract, p, unit);
1028 }
1029
1030 /**
1031  * Convert a numeric samplerate value to its "natural" string representation.
1032  *
1033  * E.g. a value of 3000000 would be converted to "3 MHz", 20000 to "20 kHz",
1034  * 31500 would become "31.5 kHz".
1035  *
1036  * @param samplerate The samplerate in Hz.
1037  *
1038  * @return A newly allocated string representation of the samplerate value,
1039  *         or NULL upon errors. The caller is responsible to g_free() the
1040  *         memory.
1041  *
1042  * @since 0.1.0
1043  */
1044 SR_API char *sr_samplerate_string(uint64_t samplerate)
1045 {
1046         return sr_si_string_u64(samplerate, "Hz");
1047 }
1048
1049 /**
1050  * Convert a numeric period value to the "natural" string representation
1051  * of its period value.
1052  *
1053  * The period is specified as a rational number's numerator and denominator.
1054  *
1055  * E.g. a pair of (1, 5) would be converted to "200 ms", (10, 100) to "100 ms".
1056  *
1057  * @param v_p The period numerator.
1058  * @param v_q The period denominator.
1059  *
1060  * @return A newly allocated string representation of the period value,
1061  *         or NULL upon errors. The caller is responsible to g_free() the
1062  *         memory.
1063  *
1064  * @since 0.5.0
1065  */
1066 SR_API char *sr_period_string(uint64_t v_p, uint64_t v_q)
1067 {
1068         double freq, v;
1069         int prec;
1070
1071         freq = 1 / ((double)v_p / v_q);
1072
1073         if (freq > SR_GHZ(1)) {
1074                 v = (double)v_p / v_q * 1000000000000.0;
1075                 prec = ((v - (uint64_t)v) < FLT_MIN) ? 0 : 3;
1076                 return g_strdup_printf("%.*f ps", prec, v);
1077         } else if (freq > SR_MHZ(1)) {
1078                 v = (double)v_p / v_q * 1000000000.0;
1079                 prec = ((v - (uint64_t)v) < FLT_MIN) ? 0 : 3;
1080                 return g_strdup_printf("%.*f ns", prec, v);
1081         } else if (freq > SR_KHZ(1)) {
1082                 v = (double)v_p / v_q * 1000000.0;
1083                 prec = ((v - (uint64_t)v) < FLT_MIN) ? 0 : 3;
1084                 return g_strdup_printf("%.*f us", prec, v);
1085         } else if (freq > 1) {
1086                 v = (double)v_p / v_q * 1000.0;
1087                 prec = ((v - (uint64_t)v) < FLT_MIN) ? 0 : 3;
1088                 return g_strdup_printf("%.*f ms", prec, v);
1089         } else {
1090                 v = (double)v_p / v_q;
1091                 prec = ((v - (uint64_t)v) < FLT_MIN) ? 0 : 3;
1092                 return g_strdup_printf("%.*f s", prec, v);
1093         }
1094 }
1095
1096 /**
1097  * Convert a numeric voltage value to the "natural" string representation
1098  * of its voltage value. The voltage is specified as a rational number's
1099  * numerator and denominator.
1100  *
1101  * E.g. a value of 300000 would be converted to "300mV", 2 to "2V".
1102  *
1103  * @param v_p The voltage numerator.
1104  * @param v_q The voltage denominator.
1105  *
1106  * @return A newly allocated string representation of the voltage value,
1107  *         or NULL upon errors. The caller is responsible to g_free() the
1108  *         memory.
1109  *
1110  * @since 0.2.0
1111  */
1112 SR_API char *sr_voltage_string(uint64_t v_p, uint64_t v_q)
1113 {
1114         if (v_q == 1000)
1115                 return g_strdup_printf("%" PRIu64 " mV", v_p);
1116         else if (v_q == 1)
1117                 return g_strdup_printf("%" PRIu64 " V", v_p);
1118         else
1119                 return g_strdup_printf("%g V", (float)v_p / (float)v_q);
1120 }
1121
1122 /**
1123  * Convert a "natural" string representation of a size value to uint64_t.
1124  *
1125  * E.g. a value of "3k" or "3 K" would be converted to 3000, a value
1126  * of "15M" would be converted to 15000000.
1127  *
1128  * Value representations other than decimal (such as hex or octal) are not
1129  * supported. Only 'k' (kilo), 'm' (mega), 'g' (giga) suffixes are supported.
1130  * Spaces (but not other whitespace) between value and suffix are allowed.
1131  *
1132  * @param sizestring A string containing a (decimal) size value.
1133  * @param size Pointer to uint64_t which will contain the string's size value.
1134  *
1135  * @return SR_OK upon success, SR_ERR upon errors.
1136  *
1137  * @since 0.1.0
1138  */
1139 SR_API int sr_parse_sizestring(const char *sizestring, uint64_t *size)
1140 {
1141         uint64_t multiplier;
1142         int done;
1143         double frac_part;
1144         char *s;
1145
1146         *size = strtoull(sizestring, &s, 10);
1147         multiplier = 0;
1148         frac_part = 0;
1149         done = FALSE;
1150         while (s && *s && multiplier == 0 && !done) {
1151                 switch (*s) {
1152                 case ' ':
1153                         break;
1154                 case '.':
1155                         frac_part = g_ascii_strtod(s, &s);
1156                         break;
1157                 case 'k':
1158                 case 'K':
1159                         multiplier = SR_KHZ(1);
1160                         break;
1161                 case 'm':
1162                 case 'M':
1163                         multiplier = SR_MHZ(1);
1164                         break;
1165                 case 'g':
1166                 case 'G':
1167                         multiplier = SR_GHZ(1);
1168                         break;
1169                 case 't':
1170                 case 'T':
1171                         multiplier = SR_GHZ(1000);
1172                         break;
1173                 case 'p':
1174                 case 'P':
1175                         multiplier = SR_GHZ(1000 * 1000);
1176                         break;
1177                 case 'e':
1178                 case 'E':
1179                         multiplier = SR_GHZ(1000 * 1000 * 1000);
1180                         break;
1181                 default:
1182                         done = TRUE;
1183                         s--;
1184                 }
1185                 s++;
1186         }
1187         if (multiplier > 0) {
1188                 *size *= multiplier;
1189                 *size += frac_part * multiplier;
1190         } else {
1191                 *size += frac_part;
1192         }
1193
1194         if (s && *s && g_ascii_strcasecmp(s, "Hz"))
1195                 return SR_ERR;
1196
1197         return SR_OK;
1198 }
1199
1200 /**
1201  * Convert a "natural" string representation of a time value to an
1202  * uint64_t value in milliseconds.
1203  *
1204  * E.g. a value of "3s" or "3 s" would be converted to 3000, a value
1205  * of "15ms" would be converted to 15.
1206  *
1207  * Value representations other than decimal (such as hex or octal) are not
1208  * supported. Only lower-case "s" and "ms" time suffixes are supported.
1209  * Spaces (but not other whitespace) between value and suffix are allowed.
1210  *
1211  * @param timestring A string containing a (decimal) time value.
1212  * @return The string's time value as uint64_t, in milliseconds.
1213  *
1214  * @todo Add support for "m" (minutes) and others.
1215  * @todo Add support for picoseconds?
1216  * @todo Allow both lower-case and upper-case? If no, document it.
1217  *
1218  * @since 0.1.0
1219  */
1220 SR_API uint64_t sr_parse_timestring(const char *timestring)
1221 {
1222         uint64_t time_msec;
1223         char *s;
1224
1225         /* TODO: Error handling, logging. */
1226
1227         time_msec = strtoull(timestring, &s, 10);
1228         if (time_msec == 0 && s == timestring)
1229                 return 0;
1230
1231         if (s && *s) {
1232                 while (*s == ' ')
1233                         s++;
1234                 if (!strcmp(s, "s"))
1235                         time_msec *= 1000;
1236                 else if (!strcmp(s, "ms"))
1237                         ; /* redundant */
1238                 else
1239                         return 0;
1240         }
1241
1242         return time_msec;
1243 }
1244
1245 /** @since 0.1.0 */
1246 SR_API gboolean sr_parse_boolstring(const char *boolstr)
1247 {
1248         /*
1249          * Complete absence of an input spec is assumed to mean TRUE,
1250          * as in command line option strings like this:
1251          *   ...:samplerate=100k:header:numchannels=4:...
1252          */
1253         if (!boolstr || !*boolstr)
1254                 return TRUE;
1255
1256         if (!g_ascii_strncasecmp(boolstr, "true", 4) ||
1257             !g_ascii_strncasecmp(boolstr, "yes", 3) ||
1258             !g_ascii_strncasecmp(boolstr, "on", 2) ||
1259             !g_ascii_strncasecmp(boolstr, "1", 1))
1260                 return TRUE;
1261
1262         return FALSE;
1263 }
1264
1265 /** @since 0.2.0 */
1266 SR_API int sr_parse_period(const char *periodstr, uint64_t *p, uint64_t *q)
1267 {
1268         char *s;
1269
1270         *p = strtoull(periodstr, &s, 10);
1271         if (*p == 0 && s == periodstr)
1272                 /* No digits found. */
1273                 return SR_ERR_ARG;
1274
1275         if (s && *s) {
1276                 while (*s == ' ')
1277                         s++;
1278                 if (!strcmp(s, "fs"))
1279                         *q = UINT64_C(1000000000000000);
1280                 else if (!strcmp(s, "ps"))
1281                         *q = UINT64_C(1000000000000);
1282                 else if (!strcmp(s, "ns"))
1283                         *q = UINT64_C(1000000000);
1284                 else if (!strcmp(s, "us"))
1285                         *q = 1000000;
1286                 else if (!strcmp(s, "ms"))
1287                         *q = 1000;
1288                 else if (!strcmp(s, "s"))
1289                         *q = 1;
1290                 else
1291                         /* Must have a time suffix. */
1292                         return SR_ERR_ARG;
1293         }
1294
1295         return SR_OK;
1296 }
1297
1298 /** @since 0.2.0 */
1299 SR_API int sr_parse_voltage(const char *voltstr, uint64_t *p, uint64_t *q)
1300 {
1301         char *s;
1302
1303         *p = strtoull(voltstr, &s, 10);
1304         if (*p == 0 && s == voltstr)
1305                 /* No digits found. */
1306                 return SR_ERR_ARG;
1307
1308         if (s && *s) {
1309                 while (*s == ' ')
1310                         s++;
1311                 if (!g_ascii_strcasecmp(s, "mv"))
1312                         *q = 1000L;
1313                 else if (!g_ascii_strcasecmp(s, "v"))
1314                         *q = 1;
1315                 else
1316                         /* Must have a base suffix. */
1317                         return SR_ERR_ARG;
1318         }
1319
1320         return SR_OK;
1321 }
1322
1323 /**
1324  * Append another text item to a NULL terminated string vector.
1325  *
1326  * @param[in] table The previous string vector.
1327  * @param[in,out] sz The previous and the resulting vector size
1328  *       (item count).
1329  * @param[in] text The text string to append to the vector.
1330  *       Can be #NULL.
1331  *
1332  * @returns The new vector, its location can differ from 'table'.
1333  *       Or #NULL in case of failure.
1334  *
1335  * This implementation happens to work for the first invocation when
1336  * 'table' is #NULL and 'sz' is 0, as well as subsequent append calls.
1337  * The 'text' can be #NULL or can be a non-empty string. When 'sz' is
1338  * not provided, then the 'table' must be a NULL terminated vector,
1339  * so that the routine can auto-determine the vector's current length.
1340  *
1341  * This routine re-allocates the vector as needed. Callers must not
1342  * rely on the memory address to remain the same across calls.
1343  */
1344 static char **append_probe_name(char **table, size_t *sz, const char *text)
1345 {
1346         size_t curr_size, alloc_size;
1347         char **new_table;
1348
1349         /* Get the table's previous size (item count). */
1350         if (sz)
1351                 curr_size = *sz;
1352         else if (table)
1353                 curr_size = g_strv_length(table);
1354         else
1355                 curr_size = 0;
1356
1357         /* Extend storage to hold one more item, and the termination. */
1358         alloc_size = curr_size + (text ? 1 : 0) + 1;
1359         alloc_size *= sizeof(table[0]);
1360         new_table = g_realloc(table, alloc_size);
1361         if (!new_table) {
1362                 g_strfreev(table);
1363                 if (sz)
1364                         *sz = 0;
1365                 return NULL;
1366         }
1367
1368         /* Append the item, NULL terminate. */
1369         if (text) {
1370                 new_table[curr_size] = g_strdup(text);
1371                 if (!new_table[curr_size]) {
1372                         g_strfreev(new_table);
1373                         if (sz)
1374                                 *sz = 0;
1375                         return NULL;
1376                 }
1377                 curr_size++;
1378         }
1379         if (sz)
1380                 *sz = curr_size;
1381         new_table[curr_size] = NULL;
1382
1383         return new_table;
1384 }
1385
1386 static char **append_probe_names(char **table, size_t *sz,
1387         const char **names)
1388 {
1389         if (!names)
1390                 return table;
1391
1392         while (names[0]) {
1393                 table = append_probe_name(table, sz, names[0]);
1394                 names++;
1395         }
1396         return table;
1397 }
1398
1399 static const struct {
1400         const char *name;
1401         const char **expands;
1402 } probe_name_aliases[] = {
1403         {
1404                 "ac97", (const char *[]){
1405                         "sync", "clk",
1406                         "out", "in", "rst",
1407                         NULL,
1408                 },
1409         },
1410         {
1411                 "i2c", (const char *[]){
1412                         "scl", "sda", NULL,
1413                 },
1414         },
1415         {
1416                 "jtag", (const char *[]){
1417                         "tdi", "tdo", "tck", "tms", NULL,
1418                 },
1419         },
1420         {
1421                 "jtag-opt", (const char *[]){
1422                         "tdi", "tdo", "tck", "tms",
1423                         "trst", "srst", "rtck", NULL,
1424                 },
1425         },
1426         {
1427                 "ieee488", (const char *[]){
1428                         "dio1", "dio2", "dio3", "dio4",
1429                         "dio5", "dio6", "dio7", "dio8",
1430                         "eoi", "dav", "nrfd", "ndac",
1431                         "ifc", "srq", "atn", "ren", NULL,
1432                 },
1433         },
1434         {
1435                 "lpc", (const char *[]){
1436                         "lframe", "lclk",
1437                         "lad0", "lad1", "lad2", "lad3",
1438                         NULL,
1439                 },
1440         },
1441         {
1442                 "lpc-opt", (const char *[]){
1443                         "lframe", "lclk",
1444                         "lad0", "lad1", "lad2", "lad3",
1445                         "lreset", "ldrq", "serirq", "clkrun",
1446                         "lpme", "lpcpd", "lsmi",
1447                         NULL,
1448                 },
1449         },
1450         {
1451                 "mcs48", (const char *[]){
1452                         "ale", "psen",
1453                         "d0", "d1", "d2", "d3",
1454                         "d4", "d5", "d6", "d7",
1455                         "a8", "a9", "a10", "a11",
1456                         "a12", "a13",
1457                         NULL,
1458                 },
1459         },
1460         {
1461                 "microwire", (const char *[]){
1462                         "cs", "sk", "si", "so", NULL,
1463                 },
1464         },
1465         {
1466                 "sdcard_sd", (const char *[]){
1467                         "cmd", "clk",
1468                         "dat0", "dat1", "dat2", "dat3",
1469                         NULL,
1470                 },
1471         },
1472         {
1473                 "seven_segment", (const char *[]){
1474                         "a", "b", "c", "d", "e", "f", "g",
1475                         "dp", NULL,
1476                 },
1477         },
1478         {
1479                 "spi", (const char *[]){
1480                         "clk", "miso", "mosi", "cs", NULL,
1481                 },
1482         },
1483         {
1484                 "swd", (const char *[]){
1485                         "swclk", "swdio", NULL,
1486                 },
1487         },
1488         {
1489                 "uart", (const char *[]){
1490                         "rx", "tx", NULL,
1491                 },
1492         },
1493         {
1494                 "usb", (const char *[]){
1495                         "dp", "dm", NULL,
1496                 },
1497         },
1498         {
1499                 "z80", (const char *[]){
1500                         "d0", "d1", "d2", "d3",
1501                         "d4", "d5", "d6", "d7",
1502                         "m1", "rd", "wr",
1503                         "mreq", "iorq",
1504                         "a0", "a1", "a2", "a3",
1505                         "a4", "a5", "a6", "a7",
1506                         "a8", "a9", "a10", "a11",
1507                         "a12", "a13", "a14", "a15",
1508                         NULL,
1509                 },
1510         },
1511 };
1512
1513 /* Case insensitive lookup of an alias name. */
1514 static const char **lookup_probe_alias(const char *name)
1515 {
1516         size_t idx;
1517
1518         for (idx = 0; idx < ARRAY_SIZE(probe_name_aliases); idx++) {
1519                 if (g_ascii_strcasecmp(probe_name_aliases[idx].name, name) != 0)
1520                         continue;
1521                 return probe_name_aliases[idx].expands;
1522         }
1523         return NULL;
1524 }
1525
1526 /**
1527  * Parse a probe names specification, allocate a string vector.
1528  *
1529  * @param[in] spec The input spec, list of probes or aliases.
1530  * @param[in] dflt_names The default probe names, a string array.
1531  * @param[in] dflt_count The default probe names count. Either must
1532  *        match the unterminated array size, or can be 0 when the
1533  *        default names are NULL terminated.
1534  * @param[in] max_count Optional resulting vector size limit.
1535  * @param[out] ret_count Optional result vector size (return value).
1536  *
1537  * @returns A string vector with resulting probe names. Or #NULL
1538  *        in case of failure.
1539  *
1540  * The input spec is a comma separated list of probe names. Items can
1541  * be aliases which expand to a corresponding set of signal names.
1542  * The resulting names list optionally gets padded from the caller's
1543  * builtin probe names, an empty input spec yields the original names
1544  * as provided by the caller. Padding is omitted when the spec starts
1545  * with '-', which may result in a device with fewer channels being
1546  * created, enough to cover the user's spec, but none extra to maybe
1547  * enable and use later on. An optional maximum length spec will trim
1548  * the result set to that size. The resulting vector length optionally
1549  * is returned to the caller, so that it need not re-get the length.
1550  *
1551  * Calling applications must release the allocated vector by means
1552  * of @ref sr_free_probe_names().
1553  *
1554  * @since 0.6.0
1555  */
1556 SR_API char **sr_parse_probe_names(const char *spec,
1557         const char **dflt_names, size_t dflt_count,
1558         size_t max_count, size_t *ret_count)
1559 {
1560         char **result_names;
1561         size_t result_count;
1562         gboolean pad_from_dflt;
1563         char **spec_names, *spec_name;
1564         size_t spec_idx;
1565         const char **alias_names;
1566
1567         if (!spec || !*spec)
1568                 spec = NULL;
1569
1570         /*
1571          * Accept zero length spec for default input names. Determine
1572          * the name table's length here. Cannot re-use g_strv_length()
1573          * because of the 'const' decoration in application code.
1574          */
1575         if (!dflt_count) {
1576                 while (dflt_names && dflt_names[dflt_count])
1577                         dflt_count++;
1578         }
1579         if (!dflt_count)
1580                 return NULL;
1581
1582         /*
1583          * Start with an empty resulting names table. Will grow
1584          * dynamically as more names get appended.
1585          */
1586         result_names = NULL;
1587         result_count = 0;
1588         pad_from_dflt = TRUE;
1589
1590         /*
1591          * When an input spec exists, use its content. Lookup alias
1592          * names, and append their corresponding signals. Or append
1593          * the verbatim input name if it is not an alias. Recursion
1594          * is not supported in this implementation.
1595          *
1596          * A leading '-' before the signal names list suppresses the
1597          * padding of the resulting list from the device's default
1598          * probe names.
1599          */
1600         spec_names = NULL;
1601         if (spec && *spec == '-') {
1602                 spec++;
1603                 pad_from_dflt = FALSE;
1604         }
1605         if (spec && *spec)
1606                 spec_names = g_strsplit(spec, ",", 0);
1607         for (spec_idx = 0; spec_names && spec_names[spec_idx]; spec_idx++) {
1608                 spec_name = spec_names[spec_idx];
1609                 if (!*spec_name)
1610                         continue;
1611                 alias_names = lookup_probe_alias(spec_name);
1612                 if (alias_names) {
1613                         result_names = append_probe_names(result_names,
1614                                 &result_count, alias_names);
1615                 } else {
1616                         result_names = append_probe_name(result_names,
1617                                 &result_count, spec_name);
1618                 }
1619         }
1620         g_strfreev(spec_names);
1621
1622         /*
1623          * By default pad the resulting names from the caller's
1624          * probe names. Don't pad if the input spec started with
1625          * '-', when the spec's exact length was requested.
1626          */
1627         if (pad_from_dflt) do {
1628                 if (max_count && result_count >= max_count)
1629                         break;
1630                 if (result_count >= dflt_count)
1631                         break;
1632                 result_names = append_probe_name(result_names, &result_count,
1633                         dflt_names[result_count]);
1634         } while (1);
1635
1636         /* Optionally trim the result to the caller's length limit. */
1637         if (max_count) {
1638                 while (result_count > max_count) {
1639                         --result_count;
1640                         g_free(result_names[result_count]);
1641                         result_names[result_count] = NULL;
1642                 }
1643         }
1644
1645         if (ret_count)
1646                 *ret_count = result_count;
1647
1648         return result_names;
1649 }
1650
1651 /**
1652  * Release previously allocated probe names (string vector).
1653  *
1654  * @param[in] names The previously allocated string vector.
1655  *
1656  * @since 0.6.0
1657  */
1658 SR_API void sr_free_probe_names(char **names)
1659 {
1660         g_strfreev(names);
1661 }
1662
1663 /** @} */