mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH RFC 0/3] Add E notation support to kstrtodec64() and IIO sysfs writes
@ 2026-10-01 15:34 Rodrigo Alencar via B4 Relay
  2026-10-01 15:34 ` [PATCH RFC 1/3] lib: kstrtox: support E notation in kstrtoudec64() and kstrtodec64() Rodrigo Alencar via B4 Relay
                   ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: Rodrigo Alencar via B4 Relay @ 2026-10-01 15:34 UTC (permalink / raw)
  To: linux-kernel, linux-iio
  Cc: Andrew Morton, Jonathan Cameron, David Lechner, Andy Shevchenko,
	Rodrigo Alencar

This series lets kstrtoudec64() and kstrtodec64() accept numbers in E
notation (scientific notation), such as "2.7e9", "1.5E-3" or "1e+16".
It then moves the IIO core fixed-point parser over to kstrtodec64(), so
every IIO channel attribute written through iio_write_channel_info()
accepts that format as well.

There are two main motivations:

1. Shell usage of sysfs attributes

   Some IIO devices take values that are long to type and easy to get
   wrong in plain decimal. A frequency synthesizer or DDS might be
   programmed in the GHz range, and a scale might be a tiny fraction.
   With this series one can write:

     echo 2.7e9 > out_altvoltage0_frequency
     echo 1.5e-6 > in_voltage0_scale

   instead of counting zeros in "2700000000" or "0.0000015". It also
   works with shell tools that print in E notation by default, such as
   printf's %g conversion ("printf '%g' 2700000000" prints "2.7e+09")
   and awk, whose default output format ("%.6g") prints
   non-integral values like 1234567.5 as "1.23457e+06".

2. Userspace software that formats numbers automatically

   Many languages and libraries switch to E notation when converting
   floating point numbers to strings, without the caller asking for it:

   - Python: str() and repr() of a float use E notation for exponents
     below -4 or from 16 up, e.g. str(0.00001) == '1e-05' and
     str(1e16) == '1e+16'. Writing such a value straight to an attribute
     with open(...).write(str(value)) currently fails with -EINVAL.
     The same applies to NumPy scalars and to f-strings with the 'g'
     format spec (f"{2.7e9:g}" == '2.7e+09').
   - JavaScript/Node.js: Number.prototype.toString() uses E notation
     for magnitudes from 1e21 up or below 1e-6, e.g. String(1e-7)
     gives '1e-7'.
   - C/C++ applications and bindings that use printf("%g") or
     std::to_chars() with general formatting, as well as MATLAB/Octave
     and other numeric environments that print in a "short" form.

   Today these values have to be reformatted by the application, or are
   rejected by the kernel without warning. Accepting E notation in the
   kernel makes the IIO sysfs ABI more robust to this common
   behaviour.

The exponent is folded into the requested decimal scale, so no floating
point arithmetic is involved. Digits beyond the resulting precision are
truncated, matching the existing kstrtodec64() behaviour. Overflow is
reported as -ERANGE and a malformed exponent ("1e", "1e+") as -EINVAL.

Signed-off-by: Rodrigo Alencar <rodrigo.alencar@analog.com>
---
Rodrigo Alencar (3):
      lib: kstrtox: support E notation in kstrtoudec64() and kstrtodec64()
      lib: test-kstrtox: add E notation tests for kstrto[u]dec64()
      iio: core: use kstrtodec64() to parse fixed-point values

 drivers/iio/industrialio-core.c | 155 ++++++++++++++++++++--------------------
 lib/kstrtox.c                   |  64 +++++++++++------
 lib/test-kstrtox.c              |  52 ++++++++++++++
 3 files changed, 170 insertions(+), 101 deletions(-)
---
base-commit: a3b3580713f3ac5a32dc2874ee546828977a1d68
change-id: 20261001-e-notation-0f07757910e5

Best regards,
--  
Rodrigo Alencar <rodrigo.alencar@analog.com>



^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH RFC 1/3] lib: kstrtox: support E notation in kstrtoudec64() and kstrtodec64()
  2026-10-01 15:34 [PATCH RFC 0/3] Add E notation support to kstrtodec64() and IIO sysfs writes Rodrigo Alencar via B4 Relay
@ 2026-10-01 15:34 ` Rodrigo Alencar via B4 Relay
  2026-10-01 15:34 ` [PATCH RFC 2/3] lib: test-kstrtox: add E notation tests for kstrto[u]dec64() Rodrigo Alencar via B4 Relay
  2026-10-01 15:34 ` [PATCH RFC 3/3] iio: core: use kstrtodec64() to parse fixed-point values Rodrigo Alencar via B4 Relay
  2 siblings, 0 replies; 6+ messages in thread
From: Rodrigo Alencar via B4 Relay @ 2026-10-01 15:34 UTC (permalink / raw)
  To: linux-kernel, linux-iio
  Cc: Andrew Morton, Jonathan Cameron, David Lechner, Andy Shevchenko,
	Rodrigo Alencar

From: Rodrigo Alencar <rodrigo.alencar@analog.com>

Allow decimal strings to carry an exponent suffix, such as "2.7e10" or
"271828e-5", in kstrtoudec64() and kstrtodec64(). The exponent is added
to the requested scale to work out how many integer and fractional digits
are consumed. A negative effective exponent drops integer digits. Digits
beyond the resulting precision are truncated, as before.

The digits are now scanned first and the string termination is checked
before any conversion. A missing or malformed exponent ("1e", "1e+")
returns -EINVAL. An exponent that overflows when added to the scale, or
that makes the result exceed 64 bits, returns -ERANGE.

Signed-off-by: Rodrigo Alencar <rodrigo.alencar@analog.com>
---
 lib/kstrtox.c | 64 +++++++++++++++++++++++++++++++++++++++--------------------
 1 file changed, 42 insertions(+), 22 deletions(-)

diff --git a/lib/kstrtox.c b/lib/kstrtox.c
index bac1c057e1b0..4755fc78a62c 100644
--- a/lib/kstrtox.c
+++ b/lib/kstrtox.c
@@ -397,39 +397,59 @@ EXPORT_SYMBOL(kstrtobool);
 
 static int _kstrtoudec64(const char *s, unsigned int scale, u64 *res)
 {
-	unsigned int rv_int, rv_frac;
+	const char *s_int, *s_frac;
+	int exp = 0, len_int = 0;
+	unsigned int rv;
 	u64 _res = 0;
+	int ret;
 
-	rv_int = _parse_integer(s, 10, &_res);
-	if (rv_int & KSTRTOX_OVERFLOW)
-		return -ERANGE;
-	s += rv_int;
+	s_int = s;
+	while (isdigit(*s)) {
+		s++;
+		len_int++;
+	}
 
 	if (*s == '.')
 		s++; /* skip decimal point */
 
-	rv_frac = _parse_integer(s, 10, &_res, scale, _res);
-	if (rv_frac & KSTRTOX_OVERFLOW)
+	s_frac = s;
+	while (isdigit(*s))
+		s++;
+
+	if (!len_int && s_frac == s)
+		return -EINVAL;
+
+	if (*s == 'e' || *s == 'E') { /* E Notation */
+		s++;
+		ret = kstrtoint(s, 10, &exp);
+		if (ret)
+			return ret;
+	} else { /* verify termination */
+		if (*s == '\n')
+			s++;
+		if (*s)
+			return -EINVAL;
+	}
+
+	if (check_add_overflow(exp, (int)scale, &exp))
 		return -ERANGE;
-	s += rv_frac;
 
-	/*
-	 * Check input beyond rv_int and rv_frac to cover cases like ".5" with
-	 * scale 0, which is considered a valid input, being parsed as 0.
-	 */
-	if (!rv_int && !rv_frac && !isdigit(*s))
-		return -EINVAL;
+	if (exp < 0) {
+		len_int = max(len_int + exp, 0);
+		exp = 0;
+	}
 
-	while (isdigit(*s)) /* truncate digits */
-		s++;
+	rv = _parse_integer(s_int, 10, &_res, len_int);
+	if (rv & KSTRTOX_OVERFLOW)
+		return -ERANGE;
 
-	if (*s == '\n')
-		s++;
-	if (*s)
-		return -EINVAL;
+	rv = _parse_integer(s_frac, 10, &_res, exp, _res);
+	if (rv & KSTRTOX_OVERFLOW)
+		return -ERANGE;
 
-	if (_res && ((scale - rv_frac) > 19 /* log10(2^64) = 19.26 */ ||
-		     check_mul_overflow(_res, int_pow(10, scale - rv_frac), &_res)))
+	exp -= rv;
+	if (_res && (exp > 19 /* log10(2^64) = 19.26 */ ||
+		     check_mul_overflow(_res, int_pow(10, exp), &_res)))
 		return -ERANGE;
 
 	*res = _res;

-- 
2.43.0



^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH RFC 2/3] lib: test-kstrtox: add E notation tests for kstrto[u]dec64()
  2026-10-01 15:34 [PATCH RFC 0/3] Add E notation support to kstrtodec64() and IIO sysfs writes Rodrigo Alencar via B4 Relay
  2026-10-01 15:34 ` [PATCH RFC 1/3] lib: kstrtox: support E notation in kstrtoudec64() and kstrtodec64() Rodrigo Alencar via B4 Relay
@ 2026-10-01 15:34 ` Rodrigo Alencar via B4 Relay
  2026-10-01 19:20   ` Andy Shevchenko
  2026-10-01 15:34 ` [PATCH RFC 3/3] iio: core: use kstrtodec64() to parse fixed-point values Rodrigo Alencar via B4 Relay
  2 siblings, 1 reply; 6+ messages in thread
From: Rodrigo Alencar via B4 Relay @ 2026-10-01 15:34 UTC (permalink / raw)
  To: linux-kernel, linux-iio
  Cc: Andrew Morton, Jonathan Cameron, David Lechner, Andy Shevchenko,
	Rodrigo Alencar

From: Rodrigo Alencar <rodrigo.alencar@analog.com>

Cover E notation parsing in kstrtoudec64() and kstrtodec64(): positive,
zero and negative exponents, upper case 'E', an explicit '+' sign,
truncation of integer digits by negative exponents, large values, and
failures for overflowing or incomplete exponents.

Signed-off-by: Rodrigo Alencar <rodrigo.alencar@analog.com>
---
 lib/test-kstrtox.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 52 insertions(+)

diff --git a/lib/test-kstrtox.c b/lib/test-kstrtox.c
index 9255234752db..bfdb109752e9 100644
--- a/lib/test-kstrtox.c
+++ b/lib/test-kstrtox.c
@@ -769,6 +769,28 @@ static void __init test_kstrtoudec64_ok(void)
 		/* truncation with many excess digits */
 		{"0.00000000000000000000000000000000423",	34,	42},
 		{"1.99999999999999999999999999999999999",	3,	1999},
+		/* E notation: positive exponent, no fraction */
+		{"1e3",			3,	1000000ULL},
+		{"42e2",		3,	4200000ULL},
+		/* E notation: positive exponent with fraction */
+		{"2.718e3",		3,	2718000ULL},
+		{"1.5e2",		1,	1500ULL},
+		/* E notation: uppercase E */
+		{"1E3",			3,	1000000ULL},
+		/* E notation: explicit positive exponent sign */
+		{"1e+3",		3,	1000000ULL},
+		/* E notation: zero exponent */
+		{"1.5e0",		1,	15ULL},
+		/* E notation: negative exponent shifts decimal left */
+		{"271828e-5",		3,	2718ULL},
+		{"2.71828e-1",		3,	271ULL},
+		{"270e-2",		3,	2700ULL},
+		/* E notation: negative exponent that truncates integer digits */
+		{"27e-4",		3,	2ULL},
+		/* E notation: negative exponent below 1 ULP truncates to 0 */
+		{"1e-5",		3,	0ULL},
+		/* E notation: large value (27 GHz in micro Hz) */
+		{"2.7e10",		6,	27000000000000000ULL},
 	};
 	TEST_OK(kstrtoudec64, u64, "%llu", test_udec64_ok);
 }
@@ -801,6 +823,14 @@ static void __init test_kstrtoudec64_fail(void)
 		{"0.2",				20},
 		{"0.18446744073709551616",	20},
 		{"1",				20},
+		/* E notation: exponent causes overflow */
+		{"1e21",			1},
+		{"2e20",			1},
+		/* E notation: no digits after exponent marker */
+		{"1e",			3},
+		/* E notation: sign only after exponent marker */
+		{"1e+",			3},
+		{"1e-",			3},
 	};
 	TEST_FAIL(kstrtoudec64, u64, "%llu", test_udec64_fail);
 }
@@ -853,6 +883,21 @@ static void __init test_kstrtodec64_ok(void)
 		{"-0.00000000000000000001",	20,	-1},
 		{"0.009223372036854775807",	21,	LLONG_MAX},
 		{"-0.009223372036854775808",	21,	LLONG_MIN},
+		/* E notation: positive number */
+		{"1e3",			3,	1000000LL},
+		{"2.7e3",		3,	2700000LL},
+		{"1.5e0",		1,	15LL},
+		/* E notation: negative number with positive exponent */
+		{"-1e3",		3,	-1000000LL},
+		{"-2.7e3",		3,	-2700000LL},
+		/* E notation: negative exponent */
+		{"27e-1",		3,	2700LL},
+		{"-27e-1",		3,	-2700LL},
+		{"2.7e-1",		3,	270LL},
+		{"-2.7e-1",		3,	-270LL},
+		/* E notation: negative exponent truncates to 0 */
+		{"1e-5",		3,	0LL},
+		{"-1e-5",		3,	0LL},
 	};
 	TEST_OK(kstrtodec64, s64, "%lld", test_dec64_ok);
 }
@@ -881,6 +926,13 @@ static void __init test_kstrtodec64_fail(void)
 		{"-0.1",			20},
 		{"0.09223372036854775808",	20},
 		{"-0.09223372036854775809",	20},
+		/* E notation: exponent causes overflow */
+		{"1e21",		1},
+		{"-1e21",		1},
+		/* E notation: no digits after exponent marker */
+		{"1e",			3},
+		{"1e+",			3},
+		{"1e-",			3},
 	};
 	TEST_FAIL(kstrtodec64, s64, "%lld", test_dec64_fail);
 }

-- 
2.43.0



^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH RFC 3/3] iio: core: use kstrtodec64() to parse fixed-point values
  2026-10-01 15:34 [PATCH RFC 0/3] Add E notation support to kstrtodec64() and IIO sysfs writes Rodrigo Alencar via B4 Relay
  2026-10-01 15:34 ` [PATCH RFC 1/3] lib: kstrtox: support E notation in kstrtoudec64() and kstrtodec64() Rodrigo Alencar via B4 Relay
  2026-10-01 15:34 ` [PATCH RFC 2/3] lib: test-kstrtox: add E notation tests for kstrto[u]dec64() Rodrigo Alencar via B4 Relay
@ 2026-10-01 15:34 ` Rodrigo Alencar via B4 Relay
  2026-10-01 19:29   ` Andy Shevchenko
  2 siblings, 1 reply; 6+ messages in thread
From: Rodrigo Alencar via B4 Relay @ 2026-10-01 15:34 UTC (permalink / raw)
  To: linux-kernel, linux-iio
  Cc: Andrew Morton, Jonathan Cameron, David Lechner, Andy Shevchenko,
	Rodrigo Alencar

From: Rodrigo Alencar <rodrigo.alencar@analog.com>

Replace the open-coded __iio_str_to_fixpoint() parser with
kstrtodec64(), so sysfs writes of fixed-point values also accept E
notation. The scale passed to kstrtodec64() comes from fract_mult, which
is a power of ten, 10^n, so ffs(10^n) = n + 1. The fractional part only
keeps the sign when the integer part is zero, as before.

The dB suffix for scale attributes is now handled by a separate
iio_str_to_fixpoint_units() helper. It strips an optional trailing
newline and the "dB" or " dB" suffix before parsing.

When there is no fractional part (fract_mult == 0, or dec_scale == 0 for
64-bit values), try base-autodetecting kstrtoll() first so hexadecimal
and octal input keeps its meaning ("010" is still 8). Fall back to
kstrtodec64() on -EINVAL to accept E notation.

As a side effect, inputs that used to be rejected for integer-only
attributes are now accepted. An invalid octal number such as "08" is
parsed as decimal 8, and a fractional value such as "1.5" is truncated
to 1, matching how kstrtodec64() drops digits beyond the requested
scale.

Signed-off-by: Rodrigo Alencar <rodrigo.alencar@analog.com>
---
 drivers/iio/industrialio-core.c | 155 ++++++++++++++++++++--------------------
 1 file changed, 76 insertions(+), 79 deletions(-)

diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
index d73f2541375f..b22d2f427bbd 100644
--- a/drivers/iio/industrialio-core.c
+++ b/drivers/iio/industrialio-core.c
@@ -994,77 +994,6 @@ static ssize_t iio_read_channel_info_avail(struct device *dev,
 	}
 }
 
-/**
- * __iio_str_to_fixpoint() - Parse a fixed-point number from a string
- * @str: The string to parse
- * @fract_mult: Multiplier for the first decimal place, should be a power of 10
- * @integer: The integer part of the number
- * @fract: The fractional part of the number
- * @scale_db: True if this should parse as dB
- *
- * Returns:
- * 0 on success, or a negative error code if the string could not be parsed.
- */
-static int __iio_str_to_fixpoint(const char *str, int fract_mult,
-				 int *integer, int *fract, bool scale_db)
-{
-	int i = 0, f = 0;
-	bool integer_part = true, negative = false;
-
-	if (fract_mult == 0) {
-		*fract = 0;
-
-		return kstrtoint(str, 0, integer);
-	}
-
-	if (str[0] == '-') {
-		negative = true;
-		str++;
-	} else if (str[0] == '+') {
-		str++;
-	}
-
-	while (*str) {
-		if ('0' <= *str && *str <= '9') {
-			if (integer_part) {
-				i = i * 10 + *str - '0';
-			} else {
-				f += fract_mult * (*str - '0');
-				fract_mult /= 10;
-			}
-		} else if (*str == '\n') {
-			if (*(str + 1) == '\0')
-				break;
-			return -EINVAL;
-		} else if (!strncmp(str, " dB", sizeof(" dB") - 1) && scale_db) {
-			/* Ignore the dB suffix */
-			str += sizeof(" dB") - 1;
-			continue;
-		} else if (!strncmp(str, "dB", sizeof("dB") - 1) && scale_db) {
-			/* Ignore the dB suffix */
-			str += sizeof("dB") - 1;
-			continue;
-		} else if (*str == '.' && integer_part) {
-			integer_part = false;
-		} else {
-			return -EINVAL;
-		}
-		str++;
-	}
-
-	if (negative) {
-		if (i)
-			i = -i;
-		else
-			f = -f;
-	}
-
-	*integer = i;
-	*fract = f;
-
-	return 0;
-}
-
 /**
  * iio_str_to_fixpoint() - Parse a fixed-point number from a string
  * @str: The string to parse
@@ -1075,13 +1004,76 @@ static int __iio_str_to_fixpoint(const char *str, int fract_mult,
  * Returns:
  * 0 on success, or a negative error code if the string could not be parsed.
  */
-int iio_str_to_fixpoint(const char *str, int fract_mult,
-			int *integer, int *fract)
+int iio_str_to_fixpoint(const char *str, int fract_mult, int *integer,
+			int *fract)
 {
-	return __iio_str_to_fixpoint(str, fract_mult, integer, fract, false);
+	/* fract_mult = 10^n, so ffs(10^n) = ffs(2^n * 5^n) = n + 1 */
+	unsigned int scale = ffs(fract_mult);
+	s64 dec64;
+	int ret;
+
+	ret = -EINVAL;
+	if (!fract_mult) /* keep hex/octal support for integers */
+		ret = kstrtoll(str, 0, &dec64);
+	if (ret == -EINVAL)
+		ret = kstrtodec64(str, scale, &dec64);
+	if (ret)
+		return ret;
+
+	if (fract_mult > 0)
+		dec64 = div_s64_rem(dec64, fract_mult * 10, fract);
+	else
+		*fract = 0;
+
+	if (dec64 > INT_MAX || dec64 < INT_MIN)
+		return -ERANGE;
+
+	*integer = (int)dec64;
+	/* only carry the sign in the fractional part if the integer is zero */
+	if (*integer)
+		*fract = abs(*fract);
+
+	return 0;
 }
 EXPORT_SYMBOL_GPL(iio_str_to_fixpoint);
 
+/**
+ * iio_str_to_fixpoint_units() - Parse a fixed-point number with units from a string
+ * @str: The string to parse
+ * @units: The units to expect at the end of the string
+ * @fract_mult: Multiplier for the first decimal place, should be a power of 10
+ * @integer: The integer part of the number
+ * @fract: The fractional part of the number
+ *
+ * Returns:
+ * 0 on success, or a negative error code if the string could not be parsed.
+ */
+static int iio_str_to_fixpoint_units(const char *str, const char *units,
+				     int fract_mult, int *integer, int *fract)
+{
+	size_t units_len = strlen(units);
+	size_t num_len = strlen(str);
+	const char *dec_str = str;
+	char buf[64];
+
+	if (num_len && str[num_len - 1] == '\n')
+		num_len--;
+
+	if (num_len > units_len &&
+	    !strncmp(str + num_len - units_len, units, units_len)) {
+		num_len -= units_len;
+		if (str[num_len - 1] == ' ')
+			num_len--;
+		if (num_len >= sizeof(buf))
+			return -EINVAL;
+		memcpy(buf, str, num_len);
+		buf[num_len] = '\0';
+		dec_str = buf;
+	}
+
+	return iio_str_to_fixpoint(dec_str, fract_mult, integer, fract);
+}
+
 static ssize_t iio_write_channel_info(struct device *dev,
 				      struct device_attribute *attr,
 				      const char *buf,
@@ -1143,17 +1135,22 @@ static ssize_t iio_write_channel_info(struct device *dev,
 			return -EINVAL;
 		integer = ch;
 	} else if (is_64bit) {
-		if (dec_scale)
-			ret = kstrtodec64(buf, dec_scale, &integer64);
-		else
+		ret = -EINVAL;
+		if (!dec_scale) /* keep hex/octal support for integers */
 			ret = kstrtoll(buf, 0, &integer64);
+		if (ret == -EINVAL)
+			ret = kstrtodec64(buf, dec_scale, &integer64);
 		if (ret)
 			return ret;
 
 		iio_val_s64_decompose(integer64, &integer, &fract);
 	} else {
-		ret = __iio_str_to_fixpoint(buf, fract_mult, &integer, &fract,
-					    scale_db);
+		if (scale_db)
+			ret = iio_str_to_fixpoint_units(buf, "dB", fract_mult,
+							&integer, &fract);
+		else
+			ret = iio_str_to_fixpoint(buf, fract_mult, &integer,
+						  &fract);
 		if (ret)
 			return ret;
 	}

-- 
2.43.0



^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH RFC 2/3] lib: test-kstrtox: add E notation tests for kstrto[u]dec64()
  2026-10-01 15:34 ` [PATCH RFC 2/3] lib: test-kstrtox: add E notation tests for kstrto[u]dec64() Rodrigo Alencar via B4 Relay
@ 2026-10-01 19:20   ` Andy Shevchenko
  0 siblings, 0 replies; 6+ messages in thread
From: Andy Shevchenko @ 2026-10-01 19:20 UTC (permalink / raw)
  To: rodrigo.alencar
  Cc: linux-kernel, linux-iio, Andrew Morton, Jonathan Cameron,
	David Lechner, Andy Shevchenko

On Thu, Oct 01, 2026 at 12:34:57PM -0300, Rodrigo Alencar via B4 Relay wrote:

> Cover E notation parsing in kstrtoudec64() and kstrtodec64(): positive,
> zero and negative exponents, upper case 'E', an explicit '+' sign,
> truncation of integer digits by negative exponents, large values, and
> failures for overflowing or incomplete exponents.

...

>  		{"0.2",				20},
>  		{"0.18446744073709551616",	20},
>  		{"1",				20},
> +		/* E notation: exponent causes overflow */
> +		{"1e21",			1},
> +		{"2e20",			1},
> +		/* E notation: no digits after exponent marker */
> +		{"1e",			3},
> +		/* E notation: sign only after exponent marker */
> +		{"1e+",			3},
> +		{"1e-",			3},

I would also consider something like

	1ee // double 'e'
	1e+0b // an attempt to have a hexadecimal exponent

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH RFC 3/3] iio: core: use kstrtodec64() to parse fixed-point values
  2026-10-01 15:34 ` [PATCH RFC 3/3] iio: core: use kstrtodec64() to parse fixed-point values Rodrigo Alencar via B4 Relay
@ 2026-10-01 19:29   ` Andy Shevchenko
  0 siblings, 0 replies; 6+ messages in thread
From: Andy Shevchenko @ 2026-10-01 19:29 UTC (permalink / raw)
  To: rodrigo.alencar
  Cc: linux-kernel, linux-iio, Andrew Morton, Jonathan Cameron,
	David Lechner, Andy Shevchenko

On Thu, Oct 01, 2026 at 12:34:58PM -0300, Rodrigo Alencar via B4 Relay wrote:

> Replace the open-coded __iio_str_to_fixpoint() parser with
> kstrtodec64(), so sysfs writes of fixed-point values also accept E
> notation. The scale passed to kstrtodec64() comes from fract_mult, which
> is a power of ten, 10^n, so ffs(10^n) = n + 1. The fractional part only
> keeps the sign when the integer part is zero, as before.
> 
> The dB suffix for scale attributes is now handled by a separate
> iio_str_to_fixpoint_units() helper. It strips an optional trailing
> newline and the "dB" or " dB" suffix before parsing.
> 
> When there is no fractional part (fract_mult == 0, or dec_scale == 0 for
> 64-bit values), try base-autodetecting kstrtoll() first so hexadecimal
> and octal input keeps its meaning ("010" is still 8). Fall back to
> kstrtodec64() on -EINVAL to accept E notation.
> 
> As a side effect, inputs that used to be rejected for integer-only
> attributes are now accepted. An invalid octal number such as "08" is
> parsed as decimal 8, and a fractional value such as "1.5" is truncated
> to 1, matching how kstrtodec64() drops digits beyond the requested
> scale.

...

> +	/* fract_mult = 10^n, so ffs(10^n) = ffs(2^n * 5^n) = n + 1 */
> +	unsigned int scale = ffs(fract_mult);
> +	s64 dec64;
> +	int ret;
> +
> +	ret = -EINVAL;
> +	if (!fract_mult) /* keep hex/octal support for integers */
> +		ret = kstrtoll(str, 0, &dec64);
> +	if (ret == -EINVAL)
> +		ret = kstrtodec64(str, scale, &dec64);
> +	if (ret)
> +		return ret;

Wouldn't be better to write as

	if (fract_mult) {
		ret = kstrtodec64(str, scale, &dec64);
	} else {
		/* keep hex/octal support for integers */
		ret = kstrtoll(str, 0, &dec64);
		if (ret == -EINVAL)
			ret = kstrtodec64(str, scale, &dec64);
	}
	if (ret)
		return ret;

> +	if (fract_mult > 0)
> +		dec64 = div_s64_rem(dec64, fract_mult * 10, fract);
> +	else
> +		*fract = 0;
> +
> +	if (dec64 > INT_MAX || dec64 < INT_MIN)
> +		return -ERANGE;
> +
> +	*integer = (int)dec64;
> +	/* only carry the sign in the fractional part if the integer is zero */
> +	if (*integer)
> +		*fract = abs(*fract);
> +

...

> +static int iio_str_to_fixpoint_units(const char *str, const char *units,
> +				     int fract_mult, int *integer, int *fract)
> +{
> +	size_t units_len = strlen(units);
> +	size_t num_len = strlen(str);
> +	const char *dec_str = str;
> +	char buf[64];
> +
> +	if (num_len && str[num_len - 1] == '\n')
> +		num_len--;
> +
> +	if (num_len > units_len &&
> +	    !strncmp(str + num_len - units_len, units, units_len)) {
> +		num_len -= units_len;
> +		if (str[num_len - 1] == ' ')
> +			num_len--;
> +		if (num_len >= sizeof(buf))
> +			return -EINVAL;
> +		memcpy(buf, str, num_len);
> +		buf[num_len] = '\0';
> +		dec_str = buf;
> +	}
> +
> +	return iio_str_to_fixpoint(dec_str, fract_mult, integer, fract);
> +}

This won't support cases when we have too many leading 0:s.
All these functions should also strip leading and unneeded 0:s.

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2026-10-01 19:29 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-01 15:34 [PATCH RFC 0/3] Add E notation support to kstrtodec64() and IIO sysfs writes Rodrigo Alencar via B4 Relay
2026-10-01 15:34 ` [PATCH RFC 1/3] lib: kstrtox: support E notation in kstrtoudec64() and kstrtodec64() Rodrigo Alencar via B4 Relay
2026-10-01 15:34 ` [PATCH RFC 2/3] lib: test-kstrtox: add E notation tests for kstrto[u]dec64() Rodrigo Alencar via B4 Relay
2026-10-01 19:20   ` Andy Shevchenko
2026-10-01 15:34 ` [PATCH RFC 3/3] iio: core: use kstrtodec64() to parse fixed-point values Rodrigo Alencar via B4 Relay
2026-10-01 19:29   ` Andy Shevchenko

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®