aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeels Hofmeyr <neels@hofmeyr.de>2020-09-30 21:47:47 +0000
committerNeels Hofmeyr <neels@hofmeyr.de>2020-10-07 11:39:46 +0000
commit87c3afb5a969838446433c6d0d0ece8e9821e2c0 (patch)
tree935fd5ebc1bc30636dd4733a50d6cba499ad6c8a
parentd745a0e7f3814ae47515c474386ca5358c57b252 (diff)
add osmo_float_str_to_int() and osmo_int_to_float_str_*()
This will be useful to handle latitude and longitude numbers for GAD, which is the location estimate representation used for LCS (Location Services). The OsmoSMLC VTY user interface will provide floating-point strings like "23.456" while GAD stores them as micro-degress 23456000. The osmo_gad_to_str* will also convert latitude and longitude to floating-point string. There was code review concerns against adding this API, upon which I tried to use floating point string formats. But I encountered various problems with accuracy and trailing zeros. For global positioning data (latitude and longitude), even inaccuracy on the sixth significant decimal digit causes noticeable positional shift. To achieve sufficient accuracy on the least significant end, I need to use double instead of float. To remove trailing zeros, the idea was to use '%.6g' format, but that can cause rounding. '%.6f' on a double looks ok, but always includes trailing zeros. A test program shows: %.6g of ((double)(int32_t)23230100)/1e6 = "23.2301" <-- good %.6g of ((double)(int32_t)42419993)/1e6 = "42.42" <-- bad rounding %.6g of ((double)(int32_t)23230199)/1e6 = "23.2302" <-- bad rounding %.6f of ((double)(int32_t)23230100)/1e6 = "23.230100" <-- trailing zeros %.6f of ((double)(int32_t)42419993)/1e6 = "42.419993" <-- good %.6f of ((double)(int32_t)23230199)/1e6 = "23.230199" <-- good It looks like when accepting that there will be trailing zeros, using double with '%.6f' would work out, but in the end I am not certain enough that there aren't more hidden rounding / precision glitches. Hence I decided to reinforce the need to add this API: it is glitch free in sufficient precision for latitude and longitude data, because it is based on integer arithmetic. The need for this precision is particular to the (new) OsmoSMLC vty configuration, where reading and writing back user config must not modify the values the user entered. Considering to add these functions to osmo-smlc.git, we might as well add them here to libosmocore utils, and also use them in osmo_gad_to_str_*() functions. Change-Id: Ib9aee749cd331712a4dcdadfb6a2dfa4c26da957
-rw-r--r--include/osmocom/core/utils.h4
-rw-r--r--src/utils.c189
-rw-r--r--tests/utils/utils_test.c443
-rw-r--r--tests/utils/utils_test.ok364
4 files changed, 1000 insertions, 0 deletions
diff --git a/include/osmocom/core/utils.h b/include/osmocom/core/utils.h
index 86191209..c9d5560d 100644
--- a/include/osmocom/core/utils.h
+++ b/include/osmocom/core/utils.h
@@ -279,6 +279,10 @@ struct osmo_strbuf {
bool osmo_str_startswith(const char *str, const char *startswith_str);
+int osmo_float_str_to_int(int64_t *val, const char *str, unsigned int precision);
+int osmo_int_to_float_str_buf(char *buf, size_t buflen, int64_t val, unsigned int precision);
+char *osmo_int_to_float_str_c(void *ctx, int64_t val, unsigned int precision);
+
/*! Translate a buffer function to a talloc context function.
* This is the full function body of a char *foo_name_c(void *ctx, val...) function, implemented by an
* int foo_name_buf(buf, buflen, val...) function:
diff --git a/src/utils.c b/src/utils.c
index 772b6714..c0ab1667 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -30,6 +30,7 @@
#include <errno.h>
#include <stdio.h>
#include <inttypes.h>
+#include <limits.h>
#include <osmocom/core/utils.h>
#include <osmocom/core/bit64gen.h>
@@ -1208,4 +1209,192 @@ bool osmo_str_startswith(const char *str, const char *startswith_str)
return strncmp(str, startswith_str, strlen(startswith_str)) == 0;
}
+/*! Convert a string of a floating point number to a signed int, with a decimal factor (fixed-point precision).
+ * For example, with precision=3, convert "-1.23" to -1230. In other words, the float value is multiplied by
+ * 10 to-the-power-of precision to obtain the returned integer.
+ * The usable range of digits is -INT64_MAX .. INT64_MAX -- note, not INT64_MIN! The value of INT64_MIN is excluded to
+ * reduce implementation complexity. See also utils_test.c.
+ * \param[out] val Returned integer value.
+ * \param[in] str String of a float, like '-12.345'.
+ * \param[in] in_len Length of string to parse, or -1 to use strlen(str).
+ * \param[in] precision Fixed-point precision, or * \returns 0 on success, negative on error.
+ */
+int osmo_float_str_to_int(int64_t *val, const char *str, unsigned int precision)
+{
+ const char *point;
+ char *endptr;
+ const char *p;
+ int64_t sign = 1;
+ int64_t integer = 0;
+ int64_t decimal = 0;
+ int64_t precision_factor;
+ int64_t integer_max;
+ int64_t decimal_max;
+ int i;
+
+ OSMO_ASSERT(val);
+ *val = 0;
+
+ if (!str)
+ return -EINVAL;
+ if (str[0] == '-') {
+ str = str + 1;
+ sign = -1;
+ } else if (str[0] == '+') {
+ str = str + 1;
+ }
+ if (!str[0])
+ return -EINVAL;
+
+ /* Validate entire string as purely digits and at most one decimal dot. If not doing this here in advance,
+ * parsing digits might stop early because of precision cut-off and miss validation of input data. */
+ point = NULL;
+ for (p = str; *p; p++) {
+ if (*p == '.') {
+ if (point)
+ return -EINVAL;
+ point = p;
+ } else if (!isdigit(*p))
+ return -EINVAL;
+ }
+
+ /* Parse integer part if there is one. If the string starts with a point, there's nothing to parse for the
+ * integer part. */
+ if (!point || point > str) {
+ errno = 0;
+ integer = strtoll(str, &endptr, 10);
+ if ((errno == ERANGE && (integer == LONG_MAX || integer == LONG_MIN))
+ || (errno != 0 && integer == 0))
+ return -ERANGE;
+
+ if ((point && endptr != point)
+ || (!point && *endptr))
+ return -EINVAL;
+ }
+
+ /* Parse the fractional part if there is any, and if the precision is nonzero (if we even care about fractional
+ * digits) */
+ if (precision && point && point[1] != '\0') {
+ /* limit the number of digits parsed to 'precision'.
+ * If 'precision' is larger than the 19 digits representable in int64_t, skip some, to pick up lower
+ * magnitude digits. */
+ unsigned int skip_digits = (precision < 20) ? 0 : precision - 20;
+ char decimal_str[precision + 1];
+ osmo_strlcpy(decimal_str, point+1, precision+1);
+
+ /* fill with zeros to make exactly 'precision' digits */
+ for (i = strlen(decimal_str); i < precision; i++)
+ decimal_str[i] = '0';
+ decimal_str[precision] = '\0';
+
+ for (i = 0; i < skip_digits; i++) {
+ /* When skipping digits because precision > nr-of-digits-in-int64_t, they must be zero;
+ * if there is a nonzero digit above the precision, it's -ERANGE. */
+ if (decimal_str[i] != '0')
+ return -ERANGE;
+ }
+ errno = 0;
+ decimal = strtoll(decimal_str + skip_digits, &endptr, 10);
+ if ((errno == ERANGE && (decimal == LONG_MAX || decimal == LONG_MIN))
+ || (errno != 0 && decimal == 0))
+ return -ERANGE;
+
+ if (*endptr)
+ return -EINVAL;
+ }
+
+ if (precision > 18) {
+ /* Special case of returning more digits than fit in int64_t range, e.g.
+ * osmo_float_str_to_int("0.0000000012345678901234567", precision=25) -> 12345678901234567. */
+ precision_factor = 0;
+ integer_max = 0;
+ decimal_max = INT64_MAX;
+ } else {
+ /* Do not surpass the resulting int64_t range. Depending on the amount of precision, the integer part
+ * and decimal part have specific ranges they must comply to. */
+ precision_factor = 1;
+ for (i = 0; i < precision; i++)
+ precision_factor *= 10;
+ integer_max = INT64_MAX / precision_factor;
+ if (integer == integer_max)
+ decimal_max = INT64_MAX % precision_factor;
+ else
+ decimal_max = INT64_MAX;
+ }
+
+ if (integer > integer_max)
+ return -ERANGE;
+ if (decimal > decimal_max)
+ return -ERANGE;
+
+ *val = sign * (integer * precision_factor + decimal);
+ return 0;
+}
+
+/*! Convert an integer with a factor of a million to a floating point string.
+ * For example, with precision = 3, convert -1230 to "-1.23".
+ * \param[out] buf Buffer to write string to.
+ * \param[in] buflen sizeof(buf).
+ * \param[in] val Value to convert to float.
+ * \returns number of chars that would be written, like snprintf().
+ */
+int osmo_int_to_float_str_buf(char *buf, size_t buflen, int64_t val, unsigned int precision)
+{
+ struct osmo_strbuf sb = { .buf = buf, .len = buflen };
+ unsigned int i;
+ unsigned int w;
+ int64_t precision_factor;
+ if (val < 0) {
+ OSMO_STRBUF_PRINTF(sb, "-");
+ if (val == INT64_MIN) {
+ OSMO_STRBUF_PRINTF(sb, "ERR");
+ return sb.chars_needed;
+ }
+ val = -val;
+ }
+
+ if (precision > 18) {
+ /* Special case of returning more digits than fit in int64_t range, e.g.
+ * osmo_int_to_float_str(12345678901234567, precision=25) -> "0.0000000012345678901234567". */
+ if (!val) {
+ OSMO_STRBUF_PRINTF(sb, "0");
+ return sb.chars_needed;
+ }
+ OSMO_STRBUF_PRINTF(sb, "0.");
+ for (i = 19; i < precision; i++)
+ OSMO_STRBUF_PRINTF(sb, "0");
+ precision = 19;
+ } else {
+ precision_factor = 1;
+ for (i = 0; i < precision; i++)
+ precision_factor *= 10;
+
+ OSMO_STRBUF_PRINTF(sb, "%" PRId64, val / precision_factor);
+ val %= precision_factor;
+ if (!val)
+ return sb.chars_needed;
+ OSMO_STRBUF_PRINTF(sb, ".");
+ }
+
+ /* print fractional part, skip trailing zeros */
+ w = precision;
+ while (!(val % 10)) {
+ val /= 10;
+ w--;
+ }
+ OSMO_STRBUF_PRINTF(sb, "%0*" PRId64, w, val);
+ return sb.chars_needed;
+}
+
+/*! Convert an integer with a factor of a million to a floating point string.
+ * For example, convert -1230000 to "-1.23".
+ * \param[in] ctx Talloc ctx to allocate string buffer from.
+ * \param[in] val Value to convert to float.
+ * \returns resulting string, dynamically allocated.
+ */
+char *osmo_int_to_float_str_c(void *ctx, int64_t val, unsigned int precision)
+{
+ OSMO_NAME_C_IMPL(ctx, 16, "ERROR", osmo_int_to_float_str_buf, val, precision)
+}
+
/*! @} */
diff --git a/tests/utils/utils_test.c b/tests/utils/utils_test.c
index 9ff023bf..108bf5a2 100644
--- a/tests/utils/utils_test.c
+++ b/tests/utils/utils_test.c
@@ -34,6 +34,7 @@
#include <arpa/inet.h>
#include <errno.h>
#include <limits.h>
+#include <inttypes.h>
static void hexdump_test(void)
{
@@ -1443,6 +1444,446 @@ static void osmo_strnchr_test(void)
}
}
+struct float_str_to_int_test {
+ unsigned int precision;
+ const char *str;
+ int64_t expect_val;
+ int expect_err;
+};
+struct float_str_to_int_test float_str_to_int_tests[] = {
+ { 0, "0", 0 },
+ { 0, "1", 1 },
+ { 0, "12.345", 12 },
+ { 0, "+12.345", 12 },
+ { 0, "-12.345", -12 },
+ { 0, "0.345", 0 },
+ { 0, ".345", 0 },
+ { 0, "-0.345", 0 },
+ { 0, "-.345", 0 },
+ { 0, "12.", 12 },
+ { 0, "-180", -180 },
+ { 0, "180", 180 },
+ { 0, "360", 360 },
+ { 0, "123.4567890123", 123 },
+ { 0, "123.4567890123456789012345", 123 },
+ { 0, "9223372036854775807", 9223372036854775807LL },
+ { 0, "-9223372036854775807", -9223372036854775807LL },
+ { 0, "-9223372036854775808", .expect_err = -ERANGE },
+ { 0, "9223372036854775808", .expect_err = -ERANGE },
+ { 0, "-9223372036854775809", .expect_err = -ERANGE },
+ { 0, "100000000000000000000", .expect_err = -ERANGE },
+ { 0, "-100000000000000000000", .expect_err = -ERANGE },
+ { 0, "999999999999999999999999999.99", .expect_err = -ERANGE },
+ { 0, "-999999999999999999999999999.99", .expect_err = -ERANGE },
+ { 0, "1.2.3", .expect_err = -EINVAL },
+ { 0, "foo", .expect_err = -EINVAL },
+ { 0, "1.foo", .expect_err = -EINVAL },
+ { 0, "1.foo", .expect_err = -EINVAL },
+ { 0, "12.-345", .expect_err = -EINVAL },
+ { 0, "-12.-345", .expect_err = -EINVAL },
+ { 0, "12.+345", .expect_err = -EINVAL },
+ { 0, "+12.+345", .expect_err = -EINVAL },
+ { 0, "", .expect_err = -EINVAL },
+ { 0, NULL, .expect_err = -EINVAL },
+
+ { 1, "0", 0 },
+ { 1, "1", 10 },
+ { 1, "12.345", 123 },
+ { 1, "+12.345", 123 },
+ { 1, "-12.345", -123 },
+ { 1, "0.345", 3 },
+ { 1, ".345", 3 },
+ { 1, "-0.345", -3 },
+ { 1, "-.345", -3 },
+ { 1, "12.", 120 },
+ { 1, "-180", -1800 },
+ { 1, "180", 1800 },
+ { 1, "360", 3600 },
+ { 1, "123.4567890123", 1234 },
+ { 1, "123.4567890123456789012345", 1234 },
+ { 1, "922337203685477580.7", 9223372036854775807LL },
+ { 1, "-922337203685477580.7", -9223372036854775807LL },
+ { 1, "-922337203685477580.8", .expect_err = -ERANGE },
+ { 1, "922337203685477580.8", .expect_err = -ERANGE },
+ { 1, "-922337203685477580.9", .expect_err = -ERANGE },
+ { 1, "100000000000000000000", .expect_err = -ERANGE },
+ { 1, "-100000000000000000000", .expect_err = -ERANGE },
+ { 1, "999999999999999999999999999.99", .expect_err = -ERANGE },
+ { 1, "-999999999999999999999999999.99", .expect_err = -ERANGE },
+ { 1, "1.2.3", .expect_err = -EINVAL },
+ { 1, "foo", .expect_err = -EINVAL },
+ { 1, "1.foo", .expect_err = -EINVAL },
+ { 1, "1.foo", .expect_err = -EINVAL },
+ { 1, "12.-345", .expect_err = -EINVAL },
+ { 1, "-12.-345", .expect_err = -EINVAL },
+ { 1, "12.+345", .expect_err = -EINVAL },
+ { 1, "+12.+345", .expect_err = -EINVAL },
+ { 1, "", .expect_err = -EINVAL },
+ { 1, NULL, .expect_err = -EINVAL },
+
+ { 6, "0", 0 },
+ { 6, "1", 1000000 },
+ { 6, "12.345", 12345000 },
+ { 6, "+12.345", 12345000 },
+ { 6, "-12.345", -12345000 },
+ { 6, "0.345", 345000 },
+ { 6, ".345", 345000 },
+ { 6, "-0.345", -345000 },
+ { 6, "-.345", -345000 },
+ { 6, "12.", 12000000 },
+ { 6, "-180", -180000000 },
+ { 6, "180", 180000000 },
+ { 6, "360", 360000000 },
+ { 6, "123.4567890123", 123456789 },
+ { 6, "123.4567890123456789012345", 123456789 },
+ { 6, "9223372036854.775807", 9223372036854775807LL },
+ { 6, "-9223372036854.775807", -9223372036854775807LL },
+ { 6, "-9223372036854.775808", .expect_err = -ERANGE },
+ { 6, "9223372036854.775808", .expect_err = -ERANGE },
+ { 6, "-9223372036854.775809", .expect_err = -ERANGE },
+ { 6, "100000000000000000000", .expect_err = -ERANGE },
+ { 6, "-100000000000000000000", .expect_err = -ERANGE },
+ { 6, "999999999999999999999999999.99", .expect_err = -ERANGE },
+ { 6, "-999999999999999999999999999.99", .expect_err = -ERANGE },
+ { 6, "1.2.3", .expect_err = -EINVAL },
+ { 6, "foo", .expect_err = -EINVAL },
+ { 6, "1.foo", .expect_err = -EINVAL },
+ { 6, "1.foo", .expect_err = -EINVAL },
+ { 6, "12.-345", .expect_err = -EINVAL },
+ { 6, "-12.-345", .expect_err = -EINVAL },
+ { 6, "12.+345", .expect_err = -EINVAL },
+ { 6, "+12.+345", .expect_err = -EINVAL },
+ { 6, "", .expect_err = -EINVAL },
+ { 6, NULL, .expect_err = -EINVAL },
+
+ { 18, "0", 0 },
+ { 18, "1", 1000000000000000000LL },
+ { 18, "1.2345", 1234500000000000000LL },
+ { 18, "+1.2345", 1234500000000000000LL },
+ { 18, "-1.2345", -1234500000000000000LL },
+ { 18, "0.345", 345000000000000000LL },
+ { 18, ".345", 345000000000000000LL },
+ { 18, "-0.345", -345000000000000000LL },
+ { 18, "-.345", -345000000000000000LL },
+ { 18, "2.", 2000000000000000000LL },
+ { 18, "-8", -8000000000000000000LL },
+ { 18, "1.234567890123", 1234567890123000000LL },
+ { 18, "1.234567890123456789012345", 1234567890123456789LL },
+ { 18, "123.4567890123", .expect_err = -ERANGE },
+ { 18, "9.223372036854775807", 9223372036854775807LL },
+ { 18, "-9.223372036854775807", -9223372036854775807LL },
+ { 18, "-9.223372036854775808", .expect_err = -ERANGE },
+ { 18, "9.223372036854775808", .expect_err = -ERANGE },
+ { 18, "-9.223372036854775809", .expect_err = -ERANGE },
+ { 18, "100000000000000000000", .expect_err = -ERANGE },
+ { 18, "-100000000000000000000", .expect_err = -ERANGE },
+ { 18, "999999999999999999999999999.99", .expect_err = -ERANGE },
+ { 18, "-999999999999999999999999999.99", .expect_err = -ERANGE },
+ { 18, "1.2.3", .expect_err = -EINVAL },
+ { 18, "foo", .expect_err = -EINVAL },
+ { 18, "1.foo", .expect_err = -EINVAL },
+ { 18, "1.foo", .expect_err = -EINVAL },
+ { 18, "12.-345", .expect_err = -EINVAL },
+ { 18, "-12.-345", .expect_err = -EINVAL },
+ { 18, "12.+345", .expect_err = -EINVAL },
+ { 18, "+12.+345", .expect_err = -EINVAL },
+ { 18, "", .expect_err = -EINVAL },
+ { 18, NULL, .expect_err = -EINVAL },
+
+ { 19, "0", 0 },
+ { 19, ".1", 1000000000000000000LL },
+ { 19, ".12345", 1234500000000000000LL },
+ { 19, "+.12345", 1234500000000000000LL },
+ { 19, "-.12345", -1234500000000000000LL },
+ { 19, "0.0345", 345000000000000000LL },
+ { 19, ".0345", 345000000000000000LL },
+ { 19, "-0.0345", -345000000000000000LL },
+ { 19, "-.0345", -345000000000000000LL },
+ { 19, ".2", 2000000000000000000LL },
+ { 19, "-.8", -8000000000000000000LL },
+ { 19, ".1234567890123", 1234567890123000000LL },
+ { 19, ".1234567890123456789012345", 1234567890123456789LL },
+ { 19, "123.4567890123", .expect_err = -ERANGE },
+ { 19, ".9223372036854775807", 9223372036854775807LL },
+ { 19, "-.9223372036854775807", -9223372036854775807LL },
+ { 19, "-.9223372036854775808", .expect_err = -ERANGE },
+ { 19, ".9223372036854775808", .expect_err = -ERANGE },
+ { 19, "-.9223372036854775809", .expect_err = -ERANGE },
+ { 19, "100000000000000000000", .expect_err = -ERANGE },
+ { 19, "-100000000000000000000", .expect_err = -ERANGE },
+ { 19, "999999999999999999999999999.99", .expect_err = -ERANGE },
+ { 19, "-999999999999999999999999999.99", .expect_err = -ERANGE },
+ { 19, "1.2.3", .expect_err = -EINVAL },
+ { 19, "foo", .expect_err = -EINVAL },
+ { 19, "1.foo", .expect_err = -EINVAL },
+ { 19, "1.foo", .expect_err = -EINVAL },
+ { 19, "12.-345", .expect_err = -EINVAL },
+ { 19, "-12.-345", .expect_err = -EINVAL },
+ { 19, "12.+345", .expect_err = -EINVAL },
+ { 19, "+12.+345", .expect_err = -EINVAL },
+ { 19, "", .expect_err = -EINVAL },
+ { 19, NULL, .expect_err = -EINVAL },
+
+ { 20, "0", 0 },
+ { 20, ".01", 1000000000000000000LL },
+ { 20, ".012345", 1234500000000000000LL },
+ { 20, "+.012345", 1234500000000000000LL },
+ { 20, "-.012345", -1234500000000000000LL },
+ { 20, "0.00345", 345000000000000000LL },
+ { 20, ".00345", 345000000000000000LL },
+ { 20, "-0.00345", -345000000000000000LL },
+ { 20, "-.00345", -345000000000000000LL },
+ { 20, ".02", 2000000000000000000LL },
+ { 20, "-.08", -8000000000000000000LL },
+ { 20, ".01234567890123", 1234567890123000000LL },
+ { 20, ".01234567890123456789012345", 1234567890123456789LL },
+ { 20, "12.34567890123", .expect_err = -ERANGE },
+ { 20, ".09223372036854775807", 9223372036854775807LL },
+ { 20, "-.09223372036854775807", -9223372036854775807LL },
+ { 20, "-.09223372036854775808", .expect_err = -ERANGE },
+ { 20, ".09223372036854775808", .expect_err = -ERANGE },
+ { 20, "-.09223372036854775809", .expect_err = -ERANGE },
+ { 20, ".1", .expect_err = -ERANGE },
+ { 20, "-.1", .expect_err = -ERANGE },
+ { 20, "999999999999999999999999999.99", .expect_err = -ERANGE },
+ { 20, "-999999999999999999999999999.99", .expect_err = -ERANGE },
+ { 20, "1.2.3", .expect_err = -EINVAL },
+ { 20, "foo", .expect_err = -EINVAL },
+ { 20, "1.foo", .expect_err = -EINVAL },
+ { 20, "1.foo", .expect_err = -EINVAL },
+ { 20, "12.-345", .expect_err = -EINVAL },
+ { 20, "-12.-345", .expect_err = -EINVAL },
+ { 20, "12.+345", .expect_err = -EINVAL },
+ { 20, "+12.+345", .expect_err = -EINVAL },
+ { 20, "", .expect_err = -EINVAL },
+ { 20, NULL, .expect_err = -EINVAL },
+
+ { 25, "0", 0 },
+ { 25, ".0000001", 1000000000000000000LL },
+ { 25, ".00000012345", 1234500000000000000LL },
+ { 25, "+.00000012345", 1234500000000000000LL },
+ { 25, "-.00000012345", -1234500000000000000LL },
+ { 25, "0.0000000345", 345000000000000000LL },
+ { 25, ".0000000345", 345000000000000000LL },
+ { 25, "-0.0000000345", -345000000000000000LL },
+ { 25, "-.0000000345", -345000000000000000LL },
+ { 25, ".0000002", 2000000000000000000LL },
+ { 25, "-.0000008", -8000000000000000000LL },
+ { 25, ".0000001234567890123", 1234567890123000000LL },
+ { 25, ".0000001234567890123456789012345", 1234567890123456789LL },
+ { 25, ".0001234567890123", .expect_err = -ERANGE },
+ { 25, ".0000009223372036854775807", 9223372036854775807LL },
+ { 25, "-.0000009223372036854775807", -9223372036854775807LL },
+ { 25, "-.0000009223372036854775808", .expect_err = -ERANGE },
+ { 25, ".0000009223372036854775808", .expect_err = -ERANGE },
+ { 25, "-.0000009223372036854775809", .expect_err = -ERANGE },
+ { 25, ".000001", .expect_err = -ERANGE },
+ { 25, "-.000001", .expect_err = -ERANGE },
+ { 25, "999999999999999999999999999.99", .expect_err = -ERANGE },
+ { 25, "-999999999999999999999999999.99", .expect_err = -ERANGE },
+ { 25, "1.2.3", .expect_err = -EINVAL },
+ { 25, "foo", .expect_err = -EINVAL },
+ { 25, "1.foo", .expect_err = -EINVAL },
+ { 25, "1.foo", .expect_err = -EINVAL },
+ { 25, "12.-345", .expect_err = -EINVAL },
+ { 25, "-12.-345", .expect_err = -EINVAL },
+ { 25, "12.+345", .expect_err = -EINVAL },
+ { 25, "+12.+345", .expect_err = -EINVAL },
+ { 25, "", .expect_err = -EINVAL },
+ { 25, NULL, .expect_err = -EINVAL },
+};
+const char *errno_str(int rc)
+{
+ if (rc == -EINVAL)
+ return "=-EINVAL";
+ if (rc == -ERANGE)
+ return "=-ERANGE";
+ return "";
+}
+void test_float_str_to_int()
+{
+ const struct float_str_to_int_test *t;
+ printf("--- %s\n", __func__);
+ for (t = float_str_to_int_tests; (t - float_str_to_int_tests) < ARRAY_SIZE(float_str_to_int_tests); t++) {
+ int rc;
+ int64_t val;
+ rc = osmo_float_str_to_int(&val, t->str, t->precision);
+ printf("osmo_float_str_to_int(%s, %u) -> rc=%d%s val=%" PRId64 "\n",
+ osmo_quote_str(t->str, -1), t->precision, rc, errno_str(rc), val);
+
+ if (rc != t->expect_err)
+ printf(" ERROR: expected rc=%d%s\n", t->expect_err, errno_str(t->expect_err));
+ if (val != t->expect_val)
+ printf(" ERROR: expected val=%" PRId64 "\n", t->expect_val);
+ if (rc != t->expect_err||val != t->expect_val)
+ exit(0);
+ }
+}
+
+struct int_to_float_str_test {
+ unsigned int precision;
+ int64_t val;
+ const char *expect_str;
+};
+struct int_to_float_str_test int_to_float_str_tests[] = {
+ { 0, 0, "0" },
+ { 0, 1, "1" },
+ { 0, 1000000, "1000000" },
+ { 0, -1000000, "-1000000" },
+ { 0, 1000001, "1000001" },
+ { 0, -1000001, "-1000001" },
+ { 0, 1000100, "1000100" },
+ { 0, -1010000, "-1010000" },
+ { 0, 1100000, "1100000" },
+ { 0, 10000000, "10000000" },
+ { 0, -10000000, "-10000000" },
+ { 0, 100000000, "100000000" },
+ { 0, -100000000, "-100000000" },
+ { 0, 9223372036854775807, "9223372036854775807" },
+ { 0, -9223372036854775807, "-9223372036854775807" },
+ { 0, INT64_MIN, "-ERR" },
+
+ { 1, 0, "0" },
+ { 1, 1, "0.1" },
+ { 1, 1000000, "100000" },
+ { 1, -1000000, "-100000" },
+ { 1, 1000001, "100000.1" },
+ { 1, -1000001, "-100000.1" },
+ { 1, 1000100, "100010" },
+ { 1, -1010000, "-101000" },
+ { 1, 1100000, "110000" },
+ { 1, 10000000, "1000000" },
+ { 1, -10000000, "-1000000" },
+ { 1, 100000000, "10000000" },
+ { 1, -100000000, "-10000000" },
+ { 1, 9223372036854775807, "922337203685477580.7" },
+ { 1, -9223372036854775807, "-922337203685477580.7" },
+ { 1, INT64_MIN, "-ERR" },
+
+ { 3, 0, "0" },
+ { 3, 1, "0.001" },
+ { 3, 1000000, "1000" },
+ { 3, -1000000, "-1000" },
+ { 3, 1000001, "1000.001" },
+ { 3, -1000001, "-1000.001" },
+ { 3, 1000100, "1000.1" },
+ { 3, -1010000, "-1010" },
+ { 3, 1100000, "1100" },
+ { 3, 10000000, "10000" },
+ { 3, -10000000, "-10000" },
+ { 3, 100000000, "100000" },
+ { 3, -100000000, "-100000" },
+ { 3, 9223372036854775807, "9223372036854775.807" },
+ { 3, -9223372036854775807, "-9223372036854775.807" },
+ { 3, INT64_MIN, "-ERR" },
+
+ { 6, 0, "0" },
+ { 6, 1, "0.000001" },
+ { 6, 1000000, "1" },
+ { 6, -1000000, "-1" },
+ { 6, 1000001, "1.000001" },
+ { 6, -1000001, "-1.000001" },
+ { 6, 1000100, "1.0001" },
+ { 6, -1010000, "-1.01" },
+ { 6, 1100000, "1.1" },
+ { 6, 10000000, "10" },
+ { 6, -10000000, "-10" },
+ { 6, 100000000, "100" },
+ { 6, -100000000, "-100" },
+ { 6, 9223372036854775807, "9223372036854.775807" },
+ { 6, -9223372036854775807, "-9223372036854.775807" },
+ { 6, INT64_MIN, "-ERR" },
+
+ { 17, 0, "0" },
+ { 17, 1, "0.00000000000000001" },
+ { 17, 1000000, "0.00000000001" },
+ { 17, -1000000, "-0.00000000001" },
+ { 17, 1000001, "0.00000000001000001" },
+ { 17, -1000001, "-0.00000000001000001" },
+ { 17, 1000100, "0.000000000010001" },
+ { 17, -1010000, "-0.0000000000101" },
+ { 17, 1100000, "0.000000000011" },
+ { 17, 10000000, "0.0000000001" },
+ { 17, -10000000, "-0.0000000001" },
+ { 17, 100000000, "0.000000001" },
+ { 17, -100000000, "-0.000000001" },
+ { 17, 9223372036854775807, "92.23372036854775807" },
+ { 17, -9223372036854775807, "-92.23372036854775807" },
+ { 17, INT64_MIN, "-ERR" },
+
+ { 18, 0, "0" },
+ { 18, 1, "0.000000000000000001" },
+ { 18, 1000000, "0.000000000001" },
+ { 18, -1000000, "-0.000000000001" },
+ { 18, 1000001, "0.000000000001000001" },
+ { 18, -1000001, "-0.000000000001000001" },
+ { 18, 1000100, "0.0000000000010001" },
+ { 18, -1010000, "-0.00000000000101" },
+ { 18, 1100000, "0.0000000000011" },
+ { 18, 10000000, "0.00000000001" },
+ { 18, -10000000, "-0.00000000001" },
+ { 18, 100000000, "0.0000000001" },
+ { 18, -100000000, "-0.0000000001" },
+ { 18, 9223372036854775807, "9.223372036854775807" },
+ { 18, -9223372036854775807, "-9.223372036854775807" },
+ { 18, INT64_MIN, "-ERR" },
+
+ { 19, 0, "0" },
+ { 19, 1, "0.0000000000000000001" },
+ { 19, 1000000, "0.0000000000001" },
+ { 19, -1000000, "-0.0000000000001" },
+ { 19, 1000001, "0.0000000000001000001" },
+ { 19, -1000001, "-0.0000000000001000001" },
+ { 19, 1000100, "0.00000000000010001" },
+ { 19, -1010000, "-0.000000000000101" },
+ { 19, 1100000, "0.00000000000011" },
+ { 19, 10000000, "0.000000000001" },
+ { 19, -10000000, "-0.000000000001" },
+ { 19, 100000000, "0.00000000001" },
+ { 19, -100000000, "-0.00000000001" },
+ { 19, 9223372036854775807, "0.9223372036854775807" },
+ { 19, -9223372036854775807, "-0.9223372036854775807" },
+ { 19, INT64_MIN, "-ERR" },
+
+ { 23, 0, "0" },
+ { 23, 1, "0.00000000000000000000001" },
+ { 23, 1000000, "0.00000000000000001" },
+ { 23, -1000000, "-0.00000000000000001" },
+ { 23, 1000001, "0.00000000000000001000001" },
+ { 23, -1000001, "-0.00000000000000001000001" },
+ { 23, 1000100, "0.000000000000000010001" },
+ { 23, -1010000, "-0.0000000000000000101" },
+ { 23, 1100000, "0.000000000000000011" },
+ { 23, 10000000, "0.0000000000000001" },
+ { 23, -10000000, "-0.0000000000000001" },
+ { 23, 100000000, "0.000000000000001" },
+ { 23, -100000000, "-0.000000000000001" },
+ { 23, 9223372036854775807, "0.00009223372036854775807" },
+ { 23, -9223372036854775807, "-0.00009223372036854775807" },
+ { 23, INT64_MIN, "-ERR" },
+};
+void test_int_to_float_str()
+{
+ const struct int_to_float_str_test *t;
+ printf("--- %s\n", __func__);
+ for (t = int_to_float_str_tests;
+ (t - int_to_float_str_tests) < ARRAY_SIZE(int_to_float_str_tests);
+ t++) {
+ char buf[128];
+ int rc;
+ rc = osmo_int_to_float_str_buf(buf, sizeof(buf), t->val, t->precision);
+ printf("osmo_int_to_float_str_buf(%" PRId64 ", %u) -> rc=%d str=%s\n", t->val, t->precision, rc,
+ osmo_quote_str(buf, -1));
+
+ if (rc != strlen(buf))
+ printf(" ERROR: expected rc=%zu\n", strlen(buf));
+ if (strcmp(buf, t->expect_str))
+ printf(" ERROR: expected str=%s\n", osmo_quote_str(t->expect_str, -1));
+ if (rc != strlen(buf) || strcmp(buf, t->expect_str))
+ exit(0);
+ }
+}
+
int main(int argc, char **argv)
{
static const struct log_info log_info = {};
@@ -1468,5 +1909,7 @@ int main(int argc, char **argv)
name_c_impl_test();
osmo_print_n_test();
osmo_strnchr_test();
+ test_float_str_to_int();
+ test_int_to_float_str();
return 0;
}
diff --git a/tests/utils/utils_test.ok b/tests/utils/utils_test.ok
index f1b07fa8..0c71b8fa 100644
--- a/tests/utils/utils_test.ok
+++ b/tests/utils/utils_test.ok
@@ -505,3 +505,367 @@ osmo_strnchr("foo=bar", 3, '=') -> -1
osmo_strnchr("foo=bar", 0, '=') -> -1
osmo_strnchr("foo", 9, '=') -> -1
osmo_strnchr("foo", 9, '\0') -> 3
+--- test_float_str_to_int
+osmo_float_str_to_int("0", 0) -> rc=0 val=0
+osmo_float_str_to_int("1", 0) -> rc=0 val=1
+osmo_float_str_to_int("12.345", 0) -> rc=0 val=12
+osmo_float_str_to_int("+12.345", 0) -> rc=0 val=12
+osmo_float_str_to_int("-12.345", 0) -> rc=0 val=-12
+osmo_float_str_to_int("0.345", 0) -> rc=0 val=0
+osmo_float_str_to_int(".345", 0) -> rc=0 val=0
+osmo_float_str_to_int("-0.345", 0) -> rc=0 val=0
+osmo_float_str_to_int("-.345", 0) -> rc=0 val=0
+osmo_float_str_to_int("12.", 0) -> rc=0 val=12
+osmo_float_str_to_int("-180", 0) -> rc=0 val=-180
+osmo_float_str_to_int("180", 0) -> rc=0 val=180
+osmo_float_str_to_int("360", 0) -> rc=0 val=360
+osmo_float_str_to_int("123.4567890123", 0) -> rc=0 val=123
+osmo_float_str_to_int("123.4567890123456789012345", 0) -> rc=0 val=123
+osmo_float_str_to_int("9223372036854775807", 0) -> rc=0 val=9223372036854775807
+osmo_float_str_to_int("-9223372036854775807", 0) -> rc=0 val=-9223372036854775807
+osmo_float_str_to_int("-9223372036854775808", 0) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("9223372036854775808", 0) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("-9223372036854775809", 0) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("100000000000000000000", 0) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("-100000000000000000000", 0) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("999999999999999999999999999.99", 0) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("-999999999999999999999999999.99", 0) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("1.2.3", 0) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("foo", 0) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("1.foo", 0) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("1.foo", 0) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("12.-345", 0) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("-12.-345", 0) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("12.+345", 0) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("+12.+345", 0) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("", 0) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int(NULL, 0) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("0", 1) -> rc=0 val=0
+osmo_float_str_to_int("1", 1) -> rc=0 val=10
+osmo_float_str_to_int("12.345", 1) -> rc=0 val=123
+osmo_float_str_to_int("+12.345", 1) -> rc=0 val=123
+osmo_float_str_to_int("-12.345", 1) -> rc=0 val=-123
+osmo_float_str_to_int("0.345", 1) -> rc=0 val=3
+osmo_float_str_to_int(".345", 1) -> rc=0 val=3
+osmo_float_str_to_int("-0.345", 1) -> rc=0 val=-3
+osmo_float_str_to_int("-.345", 1) -> rc=0 val=-3
+osmo_float_str_to_int("12.", 1) -> rc=0 val=120
+osmo_float_str_to_int("-180", 1) -> rc=0 val=-1800
+osmo_float_str_to_int("180", 1) -> rc=0 val=1800
+osmo_float_str_to_int("360", 1) -> rc=0 val=3600
+osmo_float_str_to_int("123.4567890123", 1) -> rc=0 val=1234
+osmo_float_str_to_int("123.4567890123456789012345", 1) -> rc=0 val=1234
+osmo_float_str_to_int("922337203685477580.7", 1) -> rc=0 val=9223372036854775807
+osmo_float_str_to_int("-922337203685477580.7", 1) -> rc=0 val=-9223372036854775807
+osmo_float_str_to_int("-922337203685477580.8", 1) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("922337203685477580.8", 1) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("-922337203685477580.9", 1) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("100000000000000000000", 1) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("-100000000000000000000", 1) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("999999999999999999999999999.99", 1) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("-999999999999999999999999999.99", 1) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("1.2.3", 1) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("foo", 1) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("1.foo", 1) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("1.foo", 1) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("12.-345", 1) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("-12.-345", 1) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("12.+345", 1) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("+12.+345", 1) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("", 1) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int(NULL, 1) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("0", 6) -> rc=0 val=0
+osmo_float_str_to_int("1", 6) -> rc=0 val=1000000
+osmo_float_str_to_int("12.345", 6) -> rc=0 val=12345000
+osmo_float_str_to_int("+12.345", 6) -> rc=0 val=12345000
+osmo_float_str_to_int("-12.345", 6) -> rc=0 val=-12345000
+osmo_float_str_to_int("0.345", 6) -> rc=0 val=345000
+osmo_float_str_to_int(".345", 6) -> rc=0 val=345000
+osmo_float_str_to_int("-0.345", 6) -> rc=0 val=-345000
+osmo_float_str_to_int("-.345", 6) -> rc=0 val=-345000
+osmo_float_str_to_int("12.", 6) -> rc=0 val=12000000
+osmo_float_str_to_int("-180", 6) -> rc=0 val=-180000000
+osmo_float_str_to_int("180", 6) -> rc=0 val=180000000
+osmo_float_str_to_int("360", 6) -> rc=0 val=360000000
+osmo_float_str_to_int("123.4567890123", 6) -> rc=0 val=123456789
+osmo_float_str_to_int("123.4567890123456789012345", 6) -> rc=0 val=123456789
+osmo_float_str_to_int("9223372036854.775807", 6) -> rc=0 val=9223372036854775807
+osmo_float_str_to_int("-9223372036854.775807", 6) -> rc=0 val=-9223372036854775807
+osmo_float_str_to_int("-9223372036854.775808", 6) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("9223372036854.775808", 6) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("-9223372036854.775809", 6) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("100000000000000000000", 6) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("-100000000000000000000", 6) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("999999999999999999999999999.99", 6) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("-999999999999999999999999999.99", 6) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("1.2.3", 6) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("foo", 6) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("1.foo", 6) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("1.foo", 6) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("12.-345", 6) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("-12.-345", 6) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("12.+345", 6) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("+12.+345", 6) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("", 6) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int(NULL, 6) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("0", 18) -> rc=0 val=0
+osmo_float_str_to_int("1", 18) -> rc=0 val=1000000000000000000
+osmo_float_str_to_int("1.2345", 18) -> rc=0 val=1234500000000000000
+osmo_float_str_to_int("+1.2345", 18) -> rc=0 val=1234500000000000000
+osmo_float_str_to_int("-1.2345", 18) -> rc=0 val=-1234500000000000000
+osmo_float_str_to_int("0.345", 18) -> rc=0 val=345000000000000000
+osmo_float_str_to_int(".345", 18) -> rc=0 val=345000000000000000
+osmo_float_str_to_int("-0.345", 18) -> rc=0 val=-345000000000000000
+osmo_float_str_to_int("-.345", 18) -> rc=0 val=-345000000000000000
+osmo_float_str_to_int("2.", 18) -> rc=0 val=2000000000000000000
+osmo_float_str_to_int("-8", 18) -> rc=0 val=-8000000000000000000
+osmo_float_str_to_int("1.234567890123", 18) -> rc=0 val=1234567890123000000
+osmo_float_str_to_int("1.234567890123456789012345", 18) -> rc=0 val=1234567890123456789
+osmo_float_str_to_int("123.4567890123", 18) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("9.223372036854775807", 18) -> rc=0 val=9223372036854775807
+osmo_float_str_to_int("-9.223372036854775807", 18) -> rc=0 val=-9223372036854775807
+osmo_float_str_to_int("-9.223372036854775808", 18) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("9.223372036854775808", 18) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("-9.223372036854775809", 18) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("100000000000000000000", 18) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("-100000000000000000000", 18) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("999999999999999999999999999.99", 18) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("-999999999999999999999999999.99", 18) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("1.2.3", 18) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("foo", 18) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("1.foo", 18) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("1.foo", 18) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("12.-345", 18) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("-12.-345", 18) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("12.+345", 18) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("+12.+345", 18) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("", 18) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int(NULL, 18) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("0", 19) -> rc=0 val=0
+osmo_float_str_to_int(".1", 19) -> rc=0 val=1000000000000000000
+osmo_float_str_to_int(".12345", 19) -> rc=0 val=1234500000000000000
+osmo_float_str_to_int("+.12345", 19) -> rc=0 val=1234500000000000000
+osmo_float_str_to_int("-.12345", 19) -> rc=0 val=-1234500000000000000
+osmo_float_str_to_int("0.0345", 19) -> rc=0 val=345000000000000000
+osmo_float_str_to_int(".0345", 19) -> rc=0 val=345000000000000000
+osmo_float_str_to_int("-0.0345", 19) -> rc=0 val=-345000000000000000
+osmo_float_str_to_int("-.0345", 19) -> rc=0 val=-345000000000000000
+osmo_float_str_to_int(".2", 19) -> rc=0 val=2000000000000000000
+osmo_float_str_to_int("-.8", 19) -> rc=0 val=-8000000000000000000
+osmo_float_str_to_int(".1234567890123", 19) -> rc=0 val=1234567890123000000
+osmo_float_str_to_int(".1234567890123456789012345", 19) -> rc=0 val=1234567890123456789
+osmo_float_str_to_int("123.4567890123", 19) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int(".9223372036854775807", 19) -> rc=0 val=9223372036854775807
+osmo_float_str_to_int("-.9223372036854775807", 19) -> rc=0 val=-9223372036854775807
+osmo_float_str_to_int("-.9223372036854775808", 19) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int(".9223372036854775808", 19) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("-.9223372036854775809", 19) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("100000000000000000000", 19) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("-100000000000000000000", 19) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("999999999999999999999999999.99", 19) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("-999999999999999999999999999.99", 19) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("1.2.3", 19) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("foo", 19) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("1.foo", 19) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("1.foo", 19) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("12.-345", 19) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("-12.-345", 19) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("12.+345", 19) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("+12.+345", 19) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("", 19) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int(NULL, 19) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("0", 20) -> rc=0 val=0
+osmo_float_str_to_int(".01", 20) -> rc=0 val=1000000000000000000
+osmo_float_str_to_int(".012345", 20) -> rc=0 val=1234500000000000000
+osmo_float_str_to_int("+.012345", 20) -> rc=0 val=1234500000000000000
+osmo_float_str_to_int("-.012345", 20) -> rc=0 val=-1234500000000000000
+osmo_float_str_to_int("0.00345", 20) -> rc=0 val=345000000000000000
+osmo_float_str_to_int(".00345", 20) -> rc=0 val=345000000000000000
+osmo_float_str_to_int("-0.00345", 20) -> rc=0 val=-345000000000000000
+osmo_float_str_to_int("-.00345", 20) -> rc=0 val=-345000000000000000
+osmo_float_str_to_int(".02", 20) -> rc=0 val=2000000000000000000
+osmo_float_str_to_int("-.08", 20) -> rc=0 val=-8000000000000000000
+osmo_float_str_to_int(".01234567890123", 20) -> rc=0 val=1234567890123000000
+osmo_float_str_to_int(".01234567890123456789012345", 20) -> rc=0 val=1234567890123456789
+osmo_float_str_to_int("12.34567890123", 20) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int(".09223372036854775807", 20) -> rc=0 val=9223372036854775807
+osmo_float_str_to_int("-.09223372036854775807", 20) -> rc=0 val=-9223372036854775807
+osmo_float_str_to_int("-.09223372036854775808", 20) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int(".09223372036854775808", 20) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("-.09223372036854775809", 20) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int(".1", 20) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("-.1", 20) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("999999999999999999999999999.99", 20) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("-999999999999999999999999999.99", 20) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("1.2.3", 20) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("foo", 20) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("1.foo", 20) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("1.foo", 20) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("12.-345", 20) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("-12.-345", 20) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("12.+345", 20) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("+12.+345", 20) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("", 20) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int(NULL, 20) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("0", 25) -> rc=0 val=0
+osmo_float_str_to_int(".0000001", 25) -> rc=0 val=1000000000000000000
+osmo_float_str_to_int(".00000012345", 25) -> rc=0 val=1234500000000000000
+osmo_float_str_to_int("+.00000012345", 25) -> rc=0 val=1234500000000000000
+osmo_float_str_to_int("-.00000012345", 25) -> rc=0 val=-1234500000000000000
+osmo_float_str_to_int("0.0000000345", 25) -> rc=0 val=345000000000000000
+osmo_float_str_to_int(".0000000345", 25) -> rc=0 val=345000000000000000
+osmo_float_str_to_int("-0.0000000345", 25) -> rc=0 val=-345000000000000000
+osmo_float_str_to_int("-.0000000345", 25) -> rc=0 val=-345000000000000000
+osmo_float_str_to_int(".0000002", 25) -> rc=0 val=2000000000000000000
+osmo_float_str_to_int("-.0000008", 25) -> rc=0 val=-8000000000000000000
+osmo_float_str_to_int(".0000001234567890123", 25) -> rc=0 val=1234567890123000000
+osmo_float_str_to_int(".0000001234567890123456789012345", 25) -> rc=0 val=1234567890123456789
+osmo_float_str_to_int(".0001234567890123", 25) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int(".0000009223372036854775807", 25) -> rc=0 val=9223372036854775807
+osmo_float_str_to_int("-.0000009223372036854775807", 25) -> rc=0 val=-9223372036854775807
+osmo_float_str_to_int("-.0000009223372036854775808", 25) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int(".0000009223372036854775808", 25) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("-.0000009223372036854775809", 25) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int(".000001", 25) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("-.000001", 25) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("999999999999999999999999999.99", 25) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("-999999999999999999999999999.99", 25) -> rc=-34=-ERANGE val=0
+osmo_float_str_to_int("1.2.3", 25) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("foo", 25) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("1.foo", 25) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("1.foo", 25) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("12.-345", 25) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("-12.-345", 25) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("12.+345", 25) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("+12.+345", 25) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int("", 25) -> rc=-22=-EINVAL val=0
+osmo_float_str_to_int(NULL, 25) -> rc=-22=-EINVAL val=0
+--- test_int_to_float_str
+osmo_int_to_float_str_buf(0, 0) -> rc=1 str="0"
+osmo_int_to_float_str_buf(1, 0) -> rc=1 str="1"
+osmo_int_to_float_str_buf(1000000, 0) -> rc=7 str="1000000"
+osmo_int_to_float_str_buf(-1000000, 0) -> rc=8 str="-1000000"
+osmo_int_to_float_str_buf(1000001, 0) -> rc=7 str="1000001"
+osmo_int_to_float_str_buf(-1000001, 0) -> rc=8 str="-1000001"
+osmo_int_to_float_str_buf(1000100, 0) -> rc=7 str="1000100"
+osmo_int_to_float_str_buf(-1010000, 0) -> rc=8 str="-1010000"
+osmo_int_to_float_str_buf(1100000, 0) -> rc=7 str="1100000"
+osmo_int_to_float_str_buf(10000000, 0) -> rc=8 str="10000000"
+osmo_int_to_float_str_buf(-10000000, 0) -> rc=9 str="-10000000"
+osmo_int_to_float_str_buf(100000000, 0) -> rc=9 str="100000000"
+osmo_int_to_float_str_buf(-100000000, 0) -> rc=10 str="-100000000"
+osmo_int_to_float_str_buf(9223372036854775807, 0) -> rc=19 str="9223372036854775807"
+osmo_int_to_float_str_buf(-9223372036854775807, 0) -> rc=20 str="-9223372036854775807"
+osmo_int_to_float_str_buf(-9223372036854775808, 0) -> rc=4 str="-ERR"
+osmo_int_to_float_str_buf(0, 1) -> rc=1 str="0"
+osmo_int_to_float_str_buf(1, 1) -> rc=3 str="0.1"
+osmo_int_to_float_str_buf(1000000, 1) -> rc=6 str="100000"
+osmo_int_to_float_str_buf(-1000000, 1) -> rc=7 str="-100000"
+osmo_int_to_float_str_buf(1000001, 1) -> rc=8 str="100000.1"
+osmo_int_to_float_str_buf(-1000001, 1) -> rc=9 str="-100000.1"
+osmo_int_to_float_str_buf(1000100, 1) -> rc=6 str="100010"
+osmo_int_to_float_str_buf(-1010000, 1) -> rc=7 str="-101000"
+osmo_int_to_float_str_buf(1100000, 1) -> rc=6 str="110000"
+osmo_int_to_float_str_buf(10000000, 1) -> rc=7 str="1000000"
+osmo_int_to_float_str_buf(-10000000, 1) -> rc=8 str="-1000000"
+osmo_int_to_float_str_buf(100000000, 1) -> rc=8 str="10000000"
+osmo_int_to_float_str_buf(-100000000, 1) -> rc=9 str="-10000000"
+osmo_int_to_float_str_buf(9223372036854775807, 1) -> rc=20 str="922337203685477580.7"
+osmo_int_to_float_str_buf(-9223372036854775807, 1) -> rc=21 str="-922337203685477580.7"
+osmo_int_to_float_str_buf(-9223372036854775808, 1) -> rc=4 str="-ERR"
+osmo_int_to_float_str_buf(0, 3) -> rc=1 str="0"
+osmo_int_to_float_str_buf(1, 3) -> rc=5 str="0.001"
+osmo_int_to_float_str_buf(1000000, 3) -> rc=4 str="1000"
+osmo_int_to_float_str_buf(-1000000, 3) -> rc=5 str="-1000"
+osmo_int_to_float_str_buf(1000001, 3) -> rc=8 str="1000.001"
+osmo_int_to_float_str_buf(-1000001, 3) -> rc=9 str="-1000.001"
+osmo_int_to_float_str_buf(1000100, 3) -> rc=6 str="1000.1"
+osmo_int_to_float_str_buf(-1010000, 3) -> rc=5 str="-1010"
+osmo_int_to_float_str_buf(1100000, 3) -> rc=4 str="1100"
+osmo_int_to_float_str_buf(10000000, 3) -> rc=5 str="10000"
+osmo_int_to_float_str_buf(-10000000, 3) -> rc=6 str="-10000"
+osmo_int_to_float_str_buf(100000000, 3) -> rc=6 str="100000"
+osmo_int_to_float_str_buf(-100000000, 3) -> rc=7 str="-100000"
+osmo_int_to_float_str_buf(9223372036854775807, 3) -> rc=20 str="9223372036854775.807"
+osmo_int_to_float_str_buf(-9223372036854775807, 3) -> rc=21 str="-9223372036854775.807"
+osmo_int_to_float_str_buf(-9223372036854775808, 3) -> rc=4 str="-ERR"
+osmo_int_to_float_str_buf(0, 6) -> rc=1 str="0"
+osmo_int_to_float_str_buf(1, 6) -> rc=8 str="0.000001"
+osmo_int_to_float_str_buf(1000000, 6) -> rc=1 str="1"
+osmo_int_to_float_str_buf(-1000000, 6) -> rc=2 str="-1"
+osmo_int_to_float_str_buf(1000001, 6) -> rc=8 str="1.000001"
+osmo_int_to_float_str_buf(-1000001, 6) -> rc=9 str="-1.000001"
+osmo_int_to_float_str_buf(1000100, 6) -> rc=6 str="1.0001"
+osmo_int_to_float_str_buf(-1010000, 6) -> rc=5 str="-1.01"
+osmo_int_to_float_str_buf(1100000, 6) -> rc=3 str="1.1"
+osmo_int_to_float_str_buf(10000000, 6) -> rc=2 str="10"
+osmo_int_to_float_str_buf(-10000000, 6) -> rc=3 str="-10"
+osmo_int_to_float_str_buf(100000000, 6) -> rc=3 str="100"
+osmo_int_to_float_str_buf(-100000000, 6) -> rc=4 str="-100"
+osmo_int_to_float_str_buf(9223372036854775807, 6) -> rc=20 str="9223372036854.775807"
+osmo_int_to_float_str_buf(-9223372036854775807, 6) -> rc=21 str="-9223372036854.775807"
+osmo_int_to_float_str_buf(-9223372036854775808, 6) -> rc=4 str="-ERR"
+osmo_int_to_float_str_buf(0, 17) -> rc=1 str="0"
+osmo_int_to_float_str_buf(1, 17) -> rc=19 str="0.00000000000000001"
+osmo_int_to_float_str_buf(1000000, 17) -> rc=13 str="0.00000000001"
+osmo_int_to_float_str_buf(-1000000, 17) -> rc=14 str="-0.00000000001"
+osmo_int_to_float_str_buf(1000001, 17) -> rc=19 str="0.00000000001000001"
+osmo_int_to_float_str_buf(-1000001, 17) -> rc=20 str="-0.00000000001000001"
+osmo_int_to_float_str_buf(1000100, 17) -> rc=17 str="0.000000000010001"
+osmo_int_to_float_str_buf(-1010000, 17) -> rc=16 str="-0.0000000000101"
+osmo_int_to_float_str_buf(1100000, 17) -> rc=14 str="0.000000000011"
+osmo_int_to_float_str_buf(10000000, 17) -> rc=12 str="0.0000000001"
+osmo_int_to_float_str_buf(-10000000, 17) -> rc=13 str="-0.0000000001"
+osmo_int_to_float_str_buf(100000000, 17) -> rc=11 str="0.000000001"
+osmo_int_to_float_str_buf(-100000000, 17) -> rc=12 str="-0.000000001"
+osmo_int_to_float_str_buf(9223372036854775807, 17) -> rc=20 str="92.23372036854775807"
+osmo_int_to_float_str_buf(-9223372036854775807, 17) -> rc=21 str="-92.23372036854775807"
+osmo_int_to_float_str_buf(-9223372036854775808, 17) -> rc=4 str="-ERR"
+osmo_int_to_float_str_buf(0, 18) -> rc=1 str="0"
+osmo_int_to_float_str_buf(1, 18) -> rc=20 str="0.000000000000000001"
+osmo_int_to_float_str_buf(1000000, 18) -> rc=14 str="0.000000000001"
+osmo_int_to_float_str_buf(-1000000, 18) -> rc=15 str="-0.000000000001"
+osmo_int_to_float_str_buf(1000001, 18) -> rc=20 str="0.000000000001000001"
+osmo_int_to_float_str_buf(-1000001, 18) -> rc=21 str="-0.000000000001000001"
+osmo_int_to_float_str_buf(1000100, 18) -> rc=18 str="0.0000000000010001"
+osmo_int_to_float_str_buf(-1010000, 18) -> rc=17 str="-0.00000000000101"
+osmo_int_to_float_str_buf(1100000, 18) -> rc=15 str="0.0000000000011"
+osmo_int_to_float_str_buf(10000000, 18) -> rc=13 str="0.00000000001"
+osmo_int_to_float_str_buf(-10000000, 18) -> rc=14 str="-0.00000000001"
+osmo_int_to_float_str_buf(100000000, 18) -> rc=12 str="0.0000000001"
+osmo_int_to_float_str_buf(-100000000, 18) -> rc=13 str="-0.0000000001"
+osmo_int_to_float_str_buf(9223372036854775807, 18) -> rc=20 str="9.223372036854775807"
+osmo_int_to_float_str_buf(-9223372036854775807, 18) -> rc=21 str="-9.223372036854775807"
+osmo_int_to_float_str_buf(-9223372036854775808, 18) -> rc=4 str="-ERR"
+osmo_int_to_float_str_buf(0, 19) -> rc=1 str="0"
+osmo_int_to_float_str_buf(1, 19) -> rc=21 str="0.0000000000000000001"
+osmo_int_to_float_str_buf(1000000, 19) -> rc=15 str="0.0000000000001"
+osmo_int_to_float_str_buf(-1000000, 19) -> rc=16 str="-0.0000000000001"
+osmo_int_to_float_str_buf(1000001, 19) -> rc=21 str="0.0000000000001000001"
+osmo_int_to_float_str_buf(-1000001, 19) -> rc=22 str="-0.0000000000001000001"
+osmo_int_to_float_str_buf(1000100, 19) -> rc=19 str="0.00000000000010001"
+osmo_int_to_float_str_buf(-1010000, 19) -> rc=18 str="-0.000000000000101"
+osmo_int_to_float_str_buf(1100000, 19) -> rc=16 str="0.00000000000011"
+osmo_int_to_float_str_buf(10000000, 19) -> rc=14 str="0.000000000001"
+osmo_int_to_float_str_buf(-10000000, 19) -> rc=15 str="-0.000000000001"
+osmo_int_to_float_str_buf(100000000, 19) -> rc=13 str="0.00000000001"
+osmo_int_to_float_str_buf(-100000000, 19) -> rc=14 str="-0.00000000001"
+osmo_int_to_float_str_buf(9223372036854775807, 19) -> rc=21 str="0.9223372036854775807"
+osmo_int_to_float_str_buf(-9223372036854775807, 19) -> rc=22 str="-0.9223372036854775807"
+osmo_int_to_float_str_buf(-9223372036854775808, 19) -> rc=4 str="-ERR"
+osmo_int_to_float_str_buf(0, 23) -> rc=1 str="0"
+osmo_int_to_float_str_buf(1, 23) -> rc=25 str="0.00000000000000000000001"
+osmo_int_to_float_str_buf(1000000, 23) -> rc=19 str="0.00000000000000001"
+osmo_int_to_float_str_buf(-1000000, 23) -> rc=20 str="-0.00000000000000001"
+osmo_int_to_float_str_buf(1000001, 23) -> rc=25 str="0.00000000000000001000001"
+osmo_int_to_float_str_buf(-1000001, 23) -> rc=26 str="-0.00000000000000001000001"
+osmo_int_to_float_str_buf(1000100, 23) -> rc=23 str="0.000000000000000010001"
+osmo_int_to_float_str_buf(-1010000, 23) -> rc=22 str="-0.0000000000000000101"
+osmo_int_to_float_str_buf(1100000, 23) -> rc=20 str="0.000000000000000011"
+osmo_int_to_float_str_buf(10000000, 23) -> rc=18 str="0.0000000000000001"
+osmo_int_to_float_str_buf(-10000000, 23) -> rc=19 str="-0.0000000000000001"
+osmo_int_to_float_str_buf(100000000, 23) -> rc=17 str="0.000000000000001"
+osmo_int_to_float_str_buf(-100000000, 23) -> rc=18 str="-0.000000000000001"
+osmo_int_to_float_str_buf(9223372036854775807, 23) -> rc=25 str="0.00009223372036854775807"
+osmo_int_to_float_str_buf(-9223372036854775807, 23) -> rc=26 str="-0.00009223372036854775807"
+osmo_int_to_float_str_buf(-9223372036854775808, 23) -> rc=4 str="-ERR"