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
This commit is contained in:
Neels Hofmeyr 2020-09-30 21:47:47 +00:00
parent d745a0e7f3
commit 87c3afb5a9
4 changed files with 1000 additions and 0 deletions

View File

@ -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:

View File

@ -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)
}
/*! @} */

View File

@ -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;
}

View File

@ -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"