libsigrok  0.5.2
sigrok hardware access and backend library
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
strutil.c
Go to the documentation of this file.
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 #define _XOPEN_SOURCE 700
22 #include <config.h>
23 #include <ctype.h>
24 #include <locale.h>
25 #if defined(__FreeBSD__) || defined(__APPLE__)
26 #include <xlocale.h>
27 #endif
28 #if defined(__FreeBSD__)
29 #include <sys/param.h>
30 #endif
31 #include <stdint.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <strings.h>
35 #include <errno.h>
36 #include <libsigrok/libsigrok.h>
37 #include "libsigrok-internal.h"
38 
39 /** @cond PRIVATE */
40 #define LOG_PREFIX "strutil"
41 /** @endcond */
42 
43 /**
44  * @file
45  *
46  * Helper functions for handling or converting libsigrok-related strings.
47  */
48 
49 /**
50  * @defgroup grp_strutil String utilities
51  *
52  * Helper functions for handling or converting libsigrok-related strings.
53  *
54  * @{
55  */
56 
57 /**
58  * @private
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 SR_PRIV int sr_atol(const char *str, long *ret)
72 {
73  long tmp;
74  char *endptr = NULL;
75 
76  errno = 0;
77  tmp = strtol(str, &endptr, 10);
78 
79  while (endptr && isspace(*endptr))
80  endptr++;
81 
82  if (!endptr || *endptr || errno) {
83  if (!errno)
84  errno = EINVAL;
85  return SR_ERR;
86  }
87 
88  *ret = tmp;
89  return SR_OK;
90 }
91 
92 /**
93  * @private
94  *
95  * Convert a string representation of a numeric value (base 10) to an integer. The
96  * conversion is strict and will fail if the complete string does not represent
97  * a valid integer. The function sets errno according to the details of the
98  * failure.
99  *
100  * @param str The string representation to convert.
101  * @param ret Pointer to int where the result of the conversion will be stored.
102  *
103  * @retval SR_OK Conversion successful.
104  * @retval SR_ERR Failure.
105  */
106 SR_PRIV int sr_atoi(const char *str, int *ret)
107 {
108  long tmp;
109 
110  if (sr_atol(str, &tmp) != SR_OK)
111  return SR_ERR;
112 
113  if ((int) tmp != tmp) {
114  errno = ERANGE;
115  return SR_ERR;
116  }
117 
118  *ret = (int) tmp;
119  return SR_OK;
120 }
121 
122 /**
123  * @private
124  *
125  * Convert a string representation of a numeric value to a double. The
126  * conversion is strict and will fail if the complete string does not represent
127  * a valid double. The function sets errno according to the details of the
128  * failure.
129  *
130  * @param str The string representation to convert.
131  * @param ret Pointer to double where the result of the conversion will be stored.
132  *
133  * @retval SR_OK Conversion successful.
134  * @retval SR_ERR Failure.
135  */
136 SR_PRIV int sr_atod(const char *str, double *ret)
137 {
138  double tmp;
139  char *endptr = NULL;
140 
141  errno = 0;
142  tmp = strtof(str, &endptr);
143 
144  while (endptr && isspace(*endptr))
145  endptr++;
146 
147  if (!endptr || *endptr || errno) {
148  if (!errno)
149  errno = EINVAL;
150  return SR_ERR;
151  }
152 
153  *ret = tmp;
154  return SR_OK;
155 }
156 
157 /**
158  * @private
159  *
160  * Convert a string representation of a numeric value to a float. The
161  * conversion is strict and will fail if the complete string does not represent
162  * a valid float. The function sets errno according to the details of the
163  * failure.
164  *
165  * @param str The string representation to convert.
166  * @param ret Pointer to float where the result of the conversion will be stored.
167  *
168  * @retval SR_OK Conversion successful.
169  * @retval SR_ERR Failure.
170  */
171 SR_PRIV int sr_atof(const char *str, float *ret)
172 {
173  double tmp;
174 
175  if (sr_atod(str, &tmp) != SR_OK)
176  return SR_ERR;
177 
178  if ((float) tmp != tmp) {
179  errno = ERANGE;
180  return SR_ERR;
181  }
182 
183  *ret = (float) tmp;
184  return SR_OK;
185 }
186 
187 /**
188  * @private
189  *
190  * Convert a string representation of a numeric value to a double. The
191  * conversion is strict and will fail if the complete string does not represent
192  * a valid double. The function sets errno according to the details of the
193  * failure. This version ignores the locale.
194  *
195  * @param str The string representation to convert.
196  * @param ret Pointer to double where the result of the conversion will be stored.
197  *
198  * @retval SR_OK Conversion successful.
199  * @retval SR_ERR Failure.
200  */
201 SR_PRIV int sr_atod_ascii(const char *str, double *ret)
202 {
203  double tmp;
204  char *endptr = NULL;
205 
206  errno = 0;
207  tmp = g_ascii_strtod(str, &endptr);
208 
209  if (!endptr || *endptr || errno) {
210  if (!errno)
211  errno = EINVAL;
212  return SR_ERR;
213  }
214 
215  *ret = tmp;
216  return SR_OK;
217 }
218 
219 /**
220  * @private
221  *
222  * Convert a string representation of a numeric value to a float. The
223  * conversion is strict and will fail if the complete string does not represent
224  * a valid float. The function sets errno according to the details of the
225  * failure. This version ignores the locale.
226  *
227  * @param str The string representation to convert.
228  * @param ret Pointer to float where the result of the conversion will be stored.
229  *
230  * @retval SR_OK Conversion successful.
231  * @retval SR_ERR Failure.
232  */
233 SR_PRIV int sr_atof_ascii(const char *str, float *ret)
234 {
235  double tmp;
236  char *endptr = NULL;
237 
238  errno = 0;
239  tmp = g_ascii_strtod(str, &endptr);
240 
241  if (!endptr || *endptr || errno) {
242  if (!errno)
243  errno = EINVAL;
244  return SR_ERR;
245  }
246 
247  /* FIXME This fails unexpectedly. Some other method to safel downcast
248  * needs to be found. Checking against FLT_MAX doesn't work as well. */
249  /*
250  if ((float) tmp != tmp) {
251  errno = ERANGE;
252  sr_dbg("ERANGEEEE %e != %e", (float) tmp, tmp);
253  return SR_ERR;
254  }
255  */
256 
257  *ret = (float) tmp;
258  return SR_OK;
259 }
260 
261 /**
262  * Compose a string with a format string in the buffer pointed to by buf.
263  *
264  * It is up to the caller to ensure that the allocated buffer is large enough
265  * to hold the formatted result.
266  *
267  * A terminating NUL character is automatically appended after the content
268  * written.
269  *
270  * After the format parameter, the function expects at least as many additional
271  * arguments as needed for format.
272  *
273  * This version ignores the current locale and uses the locale "C" for Linux,
274  * FreeBSD, OSX and Android.
275  *
276  * @param buf Pointer to a buffer where the resulting C string is stored.
277  * @param format C string that contains a format string (see printf).
278  * @param ... A sequence of additional arguments, each containing a value to be
279  * used to replace a format specifier in the format string.
280  *
281  * @return On success, the number of characters that would have been written,
282  * not counting the terminating NUL character.
283  *
284  * @since 0.5.1
285  */
286 SR_API int sr_sprintf_ascii(char *buf, const char *format, ...)
287 {
288  int ret;
289  va_list args;
290 
291  va_start(args, format);
292  ret = sr_vsprintf_ascii(buf, format, args);
293  va_end(args);
294 
295  return ret;
296 }
297 
298 /**
299  * Compose a string with a format string in the buffer pointed to by buf.
300  *
301  * It is up to the caller to ensure that the allocated buffer is large enough
302  * to hold the formatted result.
303  *
304  * Internally, the function retrieves arguments from the list identified by
305  * args as if va_arg was used on it, and thus the state of args is likely to
306  * be altered by the call.
307  *
308  * In any case, args should have been initialized by va_start at some point
309  * before the call, and it is expected to be released by va_end at some point
310  * after the call.
311  *
312  * This version ignores the current locale and uses the locale "C" for Linux,
313  * FreeBSD, OSX and Android.
314  *
315  * @param buf Pointer to a buffer where the resulting C string is stored.
316  * @param format C string that contains a format string (see printf).
317  * @param args A value identifying a variable arguments list initialized with
318  * va_start.
319  *
320  * @return On success, the number of characters that would have been written,
321  * not counting the terminating NUL character.
322  *
323  * @since 0.5.1
324  */
325 SR_API int sr_vsprintf_ascii(char *buf, const char *format, va_list args)
326 {
327 #if defined(_WIN32)
328  int ret;
329 
330 #if 0
331  /*
332  * TODO: This part compiles with mingw-w64 but doesn't run with Win7.
333  * Doesn't start because of "Procedure entry point _create_locale
334  * not found in msvcrt.dll".
335  * mingw-w64 should link to msvcr100.dll not msvcrt.dll!
336  * See: https://msdn.microsoft.com/en-us/en-en/library/1kt27hek.aspx
337  */
338  _locale_t locale;
339 
340  locale = _create_locale(LC_NUMERIC, "C");
341  ret = _vsprintf_l(buf, format, locale, args);
342  _free_locale(locale);
343 #endif
344 
345  /* vsprintf() uses the current locale, may not work correctly for floats. */
346  ret = vsprintf(buf, format, args);
347 
348  return ret;
349 #elif defined(__APPLE__)
350  /*
351  * See:
352  * https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man3/printf_l.3.html
353  * https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man3/xlocale.3.html
354  */
355  int ret;
356  locale_t locale;
357 
358  locale = newlocale(LC_NUMERIC_MASK, "C", NULL);
359  ret = vsprintf_l(buf, locale, format, args);
360  freelocale(locale);
361 
362  return ret;
363 #elif defined(__FreeBSD__) && __FreeBSD_version >= 901000
364  /*
365  * See:
366  * https://www.freebsd.org/cgi/man.cgi?query=printf_l&apropos=0&sektion=3&manpath=FreeBSD+9.1-RELEASE
367  * https://www.freebsd.org/cgi/man.cgi?query=xlocale&apropos=0&sektion=3&manpath=FreeBSD+9.1-RELEASE
368  */
369  int ret;
370  locale_t locale;
371 
372  locale = newlocale(LC_NUMERIC_MASK, "C", NULL);
373  ret = vsprintf_l(buf, locale, format, args);
374  freelocale(locale);
375 
376  return ret;
377 #elif defined(__ANDROID__)
378  /*
379  * The Bionic libc only has two locales ("C" aka "POSIX" and "C.UTF-8"
380  * aka "en_US.UTF-8"). The decimal point is hard coded as "."
381  * See: https://android.googlesource.com/platform/bionic/+/master/libc/bionic/locale.cpp
382  */
383  int ret;
384 
385  ret = vsprintf(buf, format, args);
386 
387  return ret;
388 #elif defined(__linux__)
389  int ret;
390  locale_t old_locale, temp_locale;
391 
392  /* Switch to C locale for proper float/double conversion. */
393  temp_locale = newlocale(LC_NUMERIC, "C", NULL);
394  old_locale = uselocale(temp_locale);
395 
396  ret = vsprintf(buf, format, args);
397 
398  /* Switch back to original locale. */
399  uselocale(old_locale);
400  freelocale(temp_locale);
401 
402  return ret;
403 #elif defined(__unix__) || defined(__unix)
404  /*
405  * This is a fallback for all other BSDs, *nix and FreeBSD <= 9.0, by
406  * using the current locale for snprintf(). This may not work correctly
407  * for floats!
408  */
409  int ret;
410 
411  ret = vsprintf(buf, format, args);
412 
413  return ret;
414 #else
415  /* No implementation for unknown systems! */
416  return -1;
417 #endif
418 }
419 
420 /**
421  * Composes a string with a format string (like printf) in the buffer pointed
422  * by buf (taking buf_size as the maximum buffer capacity to fill).
423  * If the resulting string would be longer than n - 1 characters, the remaining
424  * characters are discarded and not stored, but counted for the value returned
425  * by the function.
426  * A terminating NUL character is automatically appended after the content
427  * written.
428  * After the format parameter, the function expects at least as many additional
429  * arguments as needed for format.
430  *
431  * This version ignores the current locale and uses the locale "C" for Linux,
432  * FreeBSD, OSX and Android.
433  *
434  * @param buf Pointer to a buffer where the resulting C string is stored.
435  * @param buf_size Maximum number of bytes to be used in the buffer. The
436  * generated string has a length of at most buf_size - 1, leaving space
437  * for the additional terminating NUL character.
438  * @param format C string that contains a format string (see printf).
439  * @param ... A sequence of additional arguments, each containing a value to be
440  * used to replace a format specifier in the format string.
441  *
442  * @return On success, the number of characters that would have been written if
443  * buf_size had been sufficiently large, not counting the terminating
444  * NUL character. On failure, a negative number is returned.
445  * Notice that only when this returned value is non-negative and less
446  * than buf_size, the string has been completely written.
447  *
448  * @since 0.5.1
449  */
450 SR_API int sr_snprintf_ascii(char *buf, size_t buf_size,
451  const char *format, ...)
452 {
453  int ret;
454  va_list args;
455 
456  va_start(args, format);
457  ret = sr_vsnprintf_ascii(buf, buf_size, format, args);
458  va_end(args);
459 
460  return ret;
461 }
462 
463 /**
464  * Composes a string with a format string (like printf) in the buffer pointed
465  * by buf (taking buf_size as the maximum buffer capacity to fill).
466  * If the resulting string would be longer than n - 1 characters, the remaining
467  * characters are discarded and not stored, but counted for the value returned
468  * by the function.
469  * A terminating NUL character is automatically appended after the content
470  * written.
471  * Internally, the function retrieves arguments from the list identified by
472  * args as if va_arg was used on it, and thus the state of args is likely to
473  * be altered by the call.
474  * In any case, arg should have been initialized by va_start at some point
475  * before the call, and it is expected to be released by va_end at some point
476  * after the call.
477  *
478  * This version ignores the current locale and uses the locale "C" for Linux,
479  * FreeBSD, OSX and Android.
480  *
481  * @param buf Pointer to a buffer where the resulting C string is stored.
482  * @param buf_size Maximum number of bytes to be used in the buffer. The
483  * generated string has a length of at most buf_size - 1, leaving space
484  * for the additional terminating NUL character.
485  * @param format C string that contains a format string (see printf).
486  * @param args A value identifying a variable arguments list initialized with
487  * va_start.
488  *
489  * @return On success, the number of characters that would have been written if
490  * buf_size had been sufficiently large, not counting the terminating
491  * NUL character. On failure, a negative number is returned.
492  * Notice that only when this returned value is non-negative and less
493  * than buf_size, the string has been completely written.
494  *
495  * @since 0.5.1
496  */
497 SR_API int sr_vsnprintf_ascii(char *buf, size_t buf_size,
498  const char *format, va_list args)
499 {
500 #if defined(_WIN32)
501  int ret;
502 
503 #if 0
504  /*
505  * TODO: This part compiles with mingw-w64 but doesn't run with Win7.
506  * Doesn't start because of "Procedure entry point _create_locale
507  * not found in msvcrt.dll".
508  * mingw-w64 should link to msvcr100.dll not msvcrt.dll!.
509  * See: https://msdn.microsoft.com/en-us/en-en/library/1kt27hek.aspx
510  */
511  _locale_t locale;
512 
513  locale = _create_locale(LC_NUMERIC, "C");
514  ret = _vsnprintf_l(buf, buf_size, format, locale, args);
515  _free_locale(locale);
516 #endif
517 
518  /* vsprintf uses the current locale, may cause issues for floats. */
519  ret = vsnprintf(buf, buf_size, format, args);
520 
521  return ret;
522 #elif defined(__APPLE__)
523  /*
524  * See:
525  * https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man3/printf_l.3.html
526  * https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man3/xlocale.3.html
527  */
528  int ret;
529  locale_t locale;
530 
531  locale = newlocale(LC_NUMERIC_MASK, "C", NULL);
532  ret = vsnprintf_l(buf, buf_size, locale, format, args);
533  freelocale(locale);
534 
535  return ret;
536 #elif defined(__FreeBSD__) && __FreeBSD_version >= 901000
537  /*
538  * See:
539  * https://www.freebsd.org/cgi/man.cgi?query=printf_l&apropos=0&sektion=3&manpath=FreeBSD+9.1-RELEASE
540  * https://www.freebsd.org/cgi/man.cgi?query=xlocale&apropos=0&sektion=3&manpath=FreeBSD+9.1-RELEASE
541  */
542  int ret;
543  locale_t locale;
544 
545  locale = newlocale(LC_NUMERIC_MASK, "C", NULL);
546  ret = vsnprintf_l(buf, buf_size, locale, format, args);
547  freelocale(locale);
548 
549  return ret;
550 #elif defined(__ANDROID__)
551  /*
552  * The Bionic libc only has two locales ("C" aka "POSIX" and "C.UTF-8"
553  * aka "en_US.UTF-8"). The decimal point is hard coded as ".".
554  * See: https://android.googlesource.com/platform/bionic/+/master/libc/bionic/locale.cpp
555  */
556  int ret;
557 
558  ret = vsnprintf(buf, buf_size, format, args);
559 
560  return ret;
561 #elif defined(__linux__)
562  int ret;
563  locale_t old_locale, temp_locale;
564 
565  /* Switch to C locale for proper float/double conversion. */
566  temp_locale = newlocale(LC_NUMERIC, "C", NULL);
567  old_locale = uselocale(temp_locale);
568 
569  ret = vsnprintf(buf, buf_size, format, args);
570 
571  /* Switch back to original locale. */
572  uselocale(old_locale);
573  freelocale(temp_locale);
574 
575  return ret;
576 #elif defined(__unix__) || defined(__unix)
577  /*
578  * This is a fallback for all other BSDs, *nix and FreeBSD <= 9.0, by
579  * using the current locale for snprintf(). This may not work correctly
580  * for floats!
581  */
582  int ret;
583 
584  ret = vsnprintf(buf, buf_size, format, args);
585 
586  return ret;
587 #else
588  /* No implementation for unknown systems! */
589  return -1;
590 #endif
591 }
592 
593 /**
594  * Convert a sequence of bytes to its textual representation ("hex dump").
595  *
596  * Callers should free the allocated GString. See @ref sr_hexdump_free().
597  *
598  * @param[in] data Pointer to the byte sequence to print.
599  * @param[in] len Number of bytes to print.
600  *
601  * @return #NULL upon error, newly allocated GString pointer otherwise.
602  */
603 SR_PRIV GString *sr_hexdump_new(const uint8_t *data, const size_t len)
604 {
605  GString *s;
606  size_t i;
607 
608  s = g_string_sized_new(3 * len);
609  for (i = 0; i < len; i++) {
610  if (i)
611  g_string_append_c(s, ' ');
612  g_string_append_printf(s, "%02x", data[i]);
613  }
614 
615  return s;
616 }
617 
618 /**
619  * Free a hex dump text that was created by @ref sr_hexdump_new().
620  *
621  * @param[in] s Pointer to the GString to release.
622  */
623 SR_PRIV void sr_hexdump_free(GString *s)
624 {
625  if (s)
626  g_string_free(s, TRUE);
627 }
628 
629 /**
630  * Convert a string representation of a numeric value to a sr_rational.
631  *
632  * The conversion is strict and will fail if the complete string does not
633  * represent a valid number. The function sets errno according to the details
634  * of the failure. This version ignores the locale.
635  *
636  * @param str The string representation to convert.
637  * @param ret Pointer to sr_rational where the result of the conversion will be stored.
638  *
639  * @retval SR_OK Conversion successful.
640  * @retval SR_ERR Failure.
641  *
642  * @since 0.5.0
643  */
644 SR_API int sr_parse_rational(const char *str, struct sr_rational *ret)
645 {
646  char *endptr = NULL;
647  int64_t integral;
648  int64_t fractional = 0;
649  int64_t denominator = 1;
650  int32_t fractional_len = 0;
651  int32_t exponent = 0;
652  gboolean is_negative = FALSE;
653  gboolean no_integer, no_fractional;
654 
655  while (isspace(*str))
656  str++;
657 
658  errno = 0;
659  integral = g_ascii_strtoll(str, &endptr, 10);
660 
661  if (str == endptr && (str[0] == '-' || str[0] == '+') && str[1] == '.') {
662  endptr += 1;
663  no_integer = TRUE;
664  } else if (str == endptr && str[0] == '.') {
665  no_integer = TRUE;
666  } else if (errno) {
667  return SR_ERR;
668  } else {
669  no_integer = FALSE;
670  }
671 
672  if (integral < 0 || str[0] == '-')
673  is_negative = TRUE;
674 
675  errno = 0;
676  if (*endptr == '.') {
677  gboolean is_exp, is_eos;
678  const char *start = endptr + 1;
679  fractional = g_ascii_strtoll(start, &endptr, 10);
680  is_exp = *endptr == 'E' || *endptr == 'e';
681  is_eos = *endptr == '\0';
682  if (endptr == start && (is_exp || is_eos)) {
683  fractional = 0;
684  errno = 0;
685  }
686  if (errno)
687  return SR_ERR;
688  no_fractional = endptr == start;
689  if (no_integer && no_fractional)
690  return SR_ERR;
691  fractional_len = endptr - start;
692  }
693 
694  errno = 0;
695  if ((*endptr == 'E') || (*endptr == 'e')) {
696  exponent = g_ascii_strtoll(endptr + 1, &endptr, 10);
697  if (errno)
698  return SR_ERR;
699  }
700 
701  if (*endptr != '\0')
702  return SR_ERR;
703 
704  for (int i = 0; i < fractional_len; i++)
705  integral *= 10;
706  exponent -= fractional_len;
707 
708  if (!is_negative)
709  integral += fractional;
710  else
711  integral -= fractional;
712 
713  while (exponent > 0) {
714  integral *= 10;
715  exponent--;
716  }
717 
718  while (exponent < 0) {
719  denominator *= 10;
720  exponent++;
721  }
722 
723  ret->p = integral;
724  ret->q = denominator;
725 
726  return SR_OK;
727 }
728 
729 /**
730  * Convert a numeric value value to its "natural" string representation
731  * in SI units.
732  *
733  * E.g. a value of 3000000, with units set to "W", would be converted
734  * to "3 MW", 20000 to "20 kW", 31500 would become "31.5 kW".
735  *
736  * @param x The value to convert.
737  * @param unit The unit to append to the string, or NULL if the string
738  * has no units.
739  *
740  * @return A newly allocated string representation of the samplerate value,
741  * or NULL upon errors. The caller is responsible to g_free() the
742  * memory.
743  *
744  * @since 0.2.0
745  */
746 SR_API char *sr_si_string_u64(uint64_t x, const char *unit)
747 {
748  uint8_t i;
749  uint64_t quot, divisor[] = {
750  SR_HZ(1), SR_KHZ(1), SR_MHZ(1), SR_GHZ(1),
751  SR_GHZ(1000), SR_GHZ(1000 * 1000), SR_GHZ(1000 * 1000 * 1000),
752  };
753  const char *p, prefix[] = "\0kMGTPE";
754  char fmt[16], fract[20] = "", *f;
755 
756  if (!unit)
757  unit = "";
758 
759  for (i = 0; (quot = x / divisor[i]) >= 1000; i++);
760 
761  if (i) {
762  sprintf(fmt, ".%%0%d"PRIu64, i * 3);
763  f = fract + sprintf(fract, fmt, x % divisor[i]) - 1;
764 
765  while (f >= fract && strchr("0.", *f))
766  *f-- = 0;
767  }
768 
769  p = prefix + i;
770 
771  return g_strdup_printf("%" PRIu64 "%s %.1s%s", quot, fract, p, unit);
772 }
773 
774 /**
775  * Convert a numeric samplerate value to its "natural" string representation.
776  *
777  * E.g. a value of 3000000 would be converted to "3 MHz", 20000 to "20 kHz",
778  * 31500 would become "31.5 kHz".
779  *
780  * @param samplerate The samplerate in Hz.
781  *
782  * @return A newly allocated string representation of the samplerate value,
783  * or NULL upon errors. The caller is responsible to g_free() the
784  * memory.
785  *
786  * @since 0.1.0
787  */
788 SR_API char *sr_samplerate_string(uint64_t samplerate)
789 {
790  return sr_si_string_u64(samplerate, "Hz");
791 }
792 
793 /**
794  * Convert a numeric period value to the "natural" string representation
795  * of its period value.
796  *
797  * The period is specified as a rational number's numerator and denominator.
798  *
799  * E.g. a pair of (1, 5) would be converted to "200 ms", (10, 100) to "100 ms".
800  *
801  * @param v_p The period numerator.
802  * @param v_q The period denominator.
803  *
804  * @return A newly allocated string representation of the period value,
805  * or NULL upon errors. The caller is responsible to g_free() the
806  * memory.
807  *
808  * @since 0.5.0
809  */
810 SR_API char *sr_period_string(uint64_t v_p, uint64_t v_q)
811 {
812  double freq, v;
813  int prec;
814 
815  freq = 1 / ((double)v_p / v_q);
816 
817  if (freq > SR_GHZ(1)) {
818  v = (double)v_p / v_q * 1000000000000.0;
819  prec = ((v - (uint64_t)v) < FLT_MIN) ? 0 : 3;
820  return g_strdup_printf("%.*f ps", prec, v);
821  } else if (freq > SR_MHZ(1)) {
822  v = (double)v_p / v_q * 1000000000.0;
823  prec = ((v - (uint64_t)v) < FLT_MIN) ? 0 : 3;
824  return g_strdup_printf("%.*f ns", prec, v);
825  } else if (freq > SR_KHZ(1)) {
826  v = (double)v_p / v_q * 1000000.0;
827  prec = ((v - (uint64_t)v) < FLT_MIN) ? 0 : 3;
828  return g_strdup_printf("%.*f us", prec, v);
829  } else if (freq > 1) {
830  v = (double)v_p / v_q * 1000.0;
831  prec = ((v - (uint64_t)v) < FLT_MIN) ? 0 : 3;
832  return g_strdup_printf("%.*f ms", prec, v);
833  } else {
834  v = (double)v_p / v_q;
835  prec = ((v - (uint64_t)v) < FLT_MIN) ? 0 : 3;
836  return g_strdup_printf("%.*f s", prec, v);
837  }
838 }
839 
840 /**
841  * Convert a numeric voltage value to the "natural" string representation
842  * of its voltage value. The voltage is specified as a rational number's
843  * numerator and denominator.
844  *
845  * E.g. a value of 300000 would be converted to "300mV", 2 to "2V".
846  *
847  * @param v_p The voltage numerator.
848  * @param v_q The voltage denominator.
849  *
850  * @return A newly allocated string representation of the voltage value,
851  * or NULL upon errors. The caller is responsible to g_free() the
852  * memory.
853  *
854  * @since 0.2.0
855  */
856 SR_API char *sr_voltage_string(uint64_t v_p, uint64_t v_q)
857 {
858  if (v_q == 1000)
859  return g_strdup_printf("%" PRIu64 " mV", v_p);
860  else if (v_q == 1)
861  return g_strdup_printf("%" PRIu64 " V", v_p);
862  else
863  return g_strdup_printf("%g V", (float)v_p / (float)v_q);
864 }
865 
866 /**
867  * Convert a "natural" string representation of a size value to uint64_t.
868  *
869  * E.g. a value of "3k" or "3 K" would be converted to 3000, a value
870  * of "15M" would be converted to 15000000.
871  *
872  * Value representations other than decimal (such as hex or octal) are not
873  * supported. Only 'k' (kilo), 'm' (mega), 'g' (giga) suffixes are supported.
874  * Spaces (but not other whitespace) between value and suffix are allowed.
875  *
876  * @param sizestring A string containing a (decimal) size value.
877  * @param size Pointer to uint64_t which will contain the string's size value.
878  *
879  * @return SR_OK upon success, SR_ERR upon errors.
880  *
881  * @since 0.1.0
882  */
883 SR_API int sr_parse_sizestring(const char *sizestring, uint64_t *size)
884 {
885  uint64_t multiplier;
886  int done;
887  double frac_part;
888  char *s;
889 
890  *size = strtoull(sizestring, &s, 10);
891  multiplier = 0;
892  frac_part = 0;
893  done = FALSE;
894  while (s && *s && multiplier == 0 && !done) {
895  switch (*s) {
896  case ' ':
897  break;
898  case '.':
899  frac_part = g_ascii_strtod(s, &s);
900  break;
901  case 'k':
902  case 'K':
903  multiplier = SR_KHZ(1);
904  break;
905  case 'm':
906  case 'M':
907  multiplier = SR_MHZ(1);
908  break;
909  case 'g':
910  case 'G':
911  multiplier = SR_GHZ(1);
912  break;
913  case 't':
914  case 'T':
915  multiplier = SR_GHZ(1000);
916  break;
917  case 'p':
918  case 'P':
919  multiplier = SR_GHZ(1000 * 1000);
920  break;
921  case 'e':
922  case 'E':
923  multiplier = SR_GHZ(1000 * 1000 * 1000);
924  break;
925  default:
926  done = TRUE;
927  s--;
928  }
929  s++;
930  }
931  if (multiplier > 0) {
932  *size *= multiplier;
933  *size += frac_part * multiplier;
934  } else {
935  *size += frac_part;
936  }
937 
938  if (s && *s && g_ascii_strcasecmp(s, "Hz"))
939  return SR_ERR;
940 
941  return SR_OK;
942 }
943 
944 /**
945  * Convert a "natural" string representation of a time value to an
946  * uint64_t value in milliseconds.
947  *
948  * E.g. a value of "3s" or "3 s" would be converted to 3000, a value
949  * of "15ms" would be converted to 15.
950  *
951  * Value representations other than decimal (such as hex or octal) are not
952  * supported. Only lower-case "s" and "ms" time suffixes are supported.
953  * Spaces (but not other whitespace) between value and suffix are allowed.
954  *
955  * @param timestring A string containing a (decimal) time value.
956  * @return The string's time value as uint64_t, in milliseconds.
957  *
958  * @todo Add support for "m" (minutes) and others.
959  * @todo Add support for picoseconds?
960  * @todo Allow both lower-case and upper-case? If no, document it.
961  *
962  * @since 0.1.0
963  */
964 SR_API uint64_t sr_parse_timestring(const char *timestring)
965 {
966  uint64_t time_msec;
967  char *s;
968 
969  /* TODO: Error handling, logging. */
970 
971  time_msec = strtoull(timestring, &s, 10);
972  if (time_msec == 0 && s == timestring)
973  return 0;
974 
975  if (s && *s) {
976  while (*s == ' ')
977  s++;
978  if (!strcmp(s, "s"))
979  time_msec *= 1000;
980  else if (!strcmp(s, "ms"))
981  ; /* redundant */
982  else
983  return 0;
984  }
985 
986  return time_msec;
987 }
988 
989 /** @since 0.1.0 */
990 SR_API gboolean sr_parse_boolstring(const char *boolstr)
991 {
992  /*
993  * Complete absence of an input spec is assumed to mean TRUE,
994  * as in command line option strings like this:
995  * ...:samplerate=100k:header:numchannels=4:...
996  */
997  if (!boolstr || !*boolstr)
998  return TRUE;
999 
1000  if (!g_ascii_strncasecmp(boolstr, "true", 4) ||
1001  !g_ascii_strncasecmp(boolstr, "yes", 3) ||
1002  !g_ascii_strncasecmp(boolstr, "on", 2) ||
1003  !g_ascii_strncasecmp(boolstr, "1", 1))
1004  return TRUE;
1005 
1006  return FALSE;
1007 }
1008 
1009 /** @since 0.2.0 */
1010 SR_API int sr_parse_period(const char *periodstr, uint64_t *p, uint64_t *q)
1011 {
1012  char *s;
1013 
1014  *p = strtoull(periodstr, &s, 10);
1015  if (*p == 0 && s == periodstr)
1016  /* No digits found. */
1017  return SR_ERR_ARG;
1018 
1019  if (s && *s) {
1020  while (*s == ' ')
1021  s++;
1022  if (!strcmp(s, "fs"))
1023  *q = UINT64_C(1000000000000000);
1024  else if (!strcmp(s, "ps"))
1025  *q = UINT64_C(1000000000000);
1026  else if (!strcmp(s, "ns"))
1027  *q = UINT64_C(1000000000);
1028  else if (!strcmp(s, "us"))
1029  *q = 1000000;
1030  else if (!strcmp(s, "ms"))
1031  *q = 1000;
1032  else if (!strcmp(s, "s"))
1033  *q = 1;
1034  else
1035  /* Must have a time suffix. */
1036  return SR_ERR_ARG;
1037  }
1038 
1039  return SR_OK;
1040 }
1041 
1042 /** @since 0.2.0 */
1043 SR_API int sr_parse_voltage(const char *voltstr, uint64_t *p, uint64_t *q)
1044 {
1045  char *s;
1046 
1047  *p = strtoull(voltstr, &s, 10);
1048  if (*p == 0 && s == voltstr)
1049  /* No digits found. */
1050  return SR_ERR_ARG;
1051 
1052  if (s && *s) {
1053  while (*s == ' ')
1054  s++;
1055  if (!g_ascii_strcasecmp(s, "mv"))
1056  *q = 1000L;
1057  else if (!g_ascii_strcasecmp(s, "v"))
1058  *q = 1;
1059  else
1060  /* Must have a base suffix. */
1061  return SR_ERR_ARG;
1062  }
1063 
1064  return SR_OK;
1065 }
1066 
1067 /** @} */
Generic/unspecified error.
Definition: libsigrok.h:68
int sr_snprintf_ascii(char *buf, size_t buf_size, const char *format,...)
Composes a string with a format string (like printf) in the buffer pointed by buf (taking buf_size as...
Definition: strutil.c:450
int sr_parse_period(const char *periodstr, uint64_t *p, uint64_t *q)
Definition: strutil.c:1010
char * sr_voltage_string(uint64_t v_p, uint64_t v_q)
Convert a numeric voltage value to the "natural" string representation of its voltage value...
Definition: strutil.c:856
No error.
Definition: libsigrok.h:67
The public libsigrok header file to be used by frontends.
#define SR_GHZ(n)
Definition: libsigrok.h:89
SR_PRIV GString * sr_hexdump_new(const uint8_t *data, const size_t len)
Convert a sequence of bytes to its textual representation ("hex dump").
Definition: strutil.c:603
int sr_vsprintf_ascii(char *buf, const char *format, va_list args)
Compose a string with a format string in the buffer pointed to by buf.
Definition: strutil.c:325
SR_PRIV void sr_hexdump_free(GString *s)
Free a hex dump text that was created by sr_hexdump_new().
Definition: strutil.c:623
int sr_vsnprintf_ascii(char *buf, size_t buf_size, const char *format, va_list args)
Composes a string with a format string (like printf) in the buffer pointed by buf (taking buf_size as...
Definition: strutil.c:497
int sr_parse_sizestring(const char *sizestring, uint64_t *size)
Convert a "natural" string representation of a size value to uint64_t.
Definition: strutil.c:883
#define SR_PRIV
Definition: libsigrok.h:128
int sr_parse_voltage(const char *voltstr, uint64_t *p, uint64_t *q)
Definition: strutil.c:1043
int sr_sprintf_ascii(char *buf, const char *format,...)
Compose a string with a format string in the buffer pointed to by buf.
Definition: strutil.c:286
char * sr_period_string(uint64_t v_p, uint64_t v_q)
Convert a numeric period value to the "natural" string representation of its period value...
Definition: strutil.c:810
#define SR_HZ(n)
Definition: libsigrok.h:86
uint64_t q
Denominator of the rational number.
Definition: libsigrok.h:472
gboolean sr_parse_boolstring(const char *boolstr)
Definition: strutil.c:990
int64_t p
Numerator of the rational number.
Definition: libsigrok.h:470
char * sr_samplerate_string(uint64_t samplerate)
Convert a numeric samplerate value to its "natural" string representation.
Definition: strutil.c:788
Function argument error.
Definition: libsigrok.h:70
char * sr_si_string_u64(uint64_t x, const char *unit)
Convert a numeric value value to its "natural" string representation in SI units. ...
Definition: strutil.c:746
#define SR_KHZ(n)
Definition: libsigrok.h:87
#define SR_MHZ(n)
Definition: libsigrok.h:88
int sr_parse_rational(const char *str, struct sr_rational *ret)
Convert a string representation of a numeric value to a sr_rational.
Definition: strutil.c:644
uint64_t sr_parse_timestring(const char *timestring)
Convert a "natural" string representation of a time value to an uint64_t value in milliseconds...
Definition: strutil.c:964
#define SR_API
Definition: libsigrok.h:121