From 97aa41e9b59c7a5f6f902939a769efa8aba33efc Mon Sep 17 00:00:00 2001 From: Gerhard Sittig Date: Sun, 3 May 2020 16:38:13 +0200 Subject: [PATCH] strutil: introduce sr_atol_base() conversion helper (non-decimal) Introduce a text to number conversion routine which is more general than sr_atol() is. It accepts non-decimal numbers, with optional caller given or automatic base, including 0b for binary. It is not as strict and can return the position after the number, so that callers can optionally support suffix notations (units, or scale factors, or multiple separated numbers in the same text string). --- src/libsigrok-internal.h | 1 + src/strutil.c | 54 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/src/libsigrok-internal.h b/src/libsigrok-internal.h index 8925cbff..5b20e54b 100644 --- a/src/libsigrok-internal.h +++ b/src/libsigrok-internal.h @@ -1501,6 +1501,7 @@ SR_PRIV void *sr_resource_load(struct sr_context *ctx, int type, /*--- strutil.c -------------------------------------------------------------*/ SR_PRIV int sr_atol(const char *str, long *ret); +SR_PRIV int sr_atol_base(const char *str, long *ret, char **end, int base); SR_PRIV int sr_atoi(const char *str, int *ret); SR_PRIV int sr_atod(const char *str, double *ret); SR_PRIV int sr_atof(const char *str, float *ret); diff --git a/src/strutil.c b/src/strutil.c index 5ee680e5..0dff3c4b 100644 --- a/src/strutil.c +++ b/src/strutil.c @@ -91,6 +91,60 @@ SR_PRIV int sr_atol(const char *str, long *ret) return SR_OK; } +/** + * Convert a text to a number including support for non-decimal bases. + * Also optionally returns the position after the number, where callers + * can either error out, or support application specific suffixes. + * + * @param[in] str The input text to convert. + * @param[out] ret The conversion result. + * @param[out] end The position after the number. + * @param[in] base The number format's base, can be 0. + * + * @retval SR_OK Conversion successful. + * @retval SR_ERR Conversion failed. + * + * @private + * + * This routine is more general than @ref sr_atol(), which strictly + * expects the input text to contain just a decimal number, and nothing + * else in addition. The @ref sr_atol_base() routine accepts trailing + * text after the number, and supports non-decimal numbers (bin, hex), + * including automatic detection from prefix text. + */ +SR_PRIV int sr_atol_base(const char *str, long *ret, char **end, int base) +{ + long num; + char *endptr; + + /* Add "0b" prefix support which strtol(3) may be missing. */ + while (str && isspace(*str)) + str++; + if (!base && strncmp(str, "0b", strlen("0b")) == 0) { + str += strlen("0b"); + base = 2; + } + + /* Run the number conversion. Quick bail out if that fails. */ + errno = 0; + endptr = NULL; + num = strtol(str, &endptr, base); + if (!endptr || errno) { + if (!errno) + errno = EINVAL; + return SR_ERR; + } + *ret = num; + + /* Advance to optional non-space trailing suffix. */ + while (endptr && isspace(*endptr)) + endptr++; + if (end) + *end = endptr; + + return SR_OK; +} + /** * Convert a string representation of a numeric value (base 10) to an integer. The * conversion is strict and will fail if the complete string does not represent