Skip to content

Commit

Permalink
iio: fix string to value parsing in iio_parse_value.
Browse files Browse the repository at this point in the history
Fix wrong parsing for cases when fractional part has leading zeros,
when fractional part exceeds subunit limit, and when values to parse
are between 0 and -1.

Signed-off-by: Cedric Encarnacion <[email protected]>
  • Loading branch information
cencarna authored and buha committed Oct 15, 2024
1 parent 841e8da commit 70d148c
Showing 1 changed file with 40 additions and 13 deletions.
53 changes: 40 additions & 13 deletions iio/iio.c
Original file line number Diff line number Diff line change
Expand Up @@ -566,7 +566,7 @@ static int32_t debug_reg_write(struct iio_dev_priv *dev, const char *buf,
}

static int32_t __iio_str_parse(char *buf, int32_t *integer, int32_t *_fract,
bool scale_db)
int32_t *_fract_scale, bool scale_db)
{
char *p;

Expand All @@ -588,12 +588,32 @@ static int32_t __iio_str_parse(char *buf, int32_t *integer, int32_t *_fract,

*_fract = strtol(p, NULL, 10);

/* Handle leading zeroes */
while (*p++ == '0' && *_fract > 0)
*_fract_scale *= 10;

/* Handle values between -1 and 0 */
if (*integer == 0 && buf[0] == '-')
*_fract *= -1;

return 0;
}

static int32_t _iio_fract_interpret(int32_t fract, int32_t subunits)
{
int32_t temp = fract;
int32_t temp;
int32_t mult = 1;

if (fract < 0) {
mult = -1;
fract = -fract;
}

/* Divide to nearest subunit-scale if fract part is more than subunit */
while (fract >= subunits)
fract = NO_OS_DIV_ROUND_CLOSEST(fract, 10);

temp = fract;

while ((subunits != 0) || (temp != 0)) {
temp /= 10;
Expand All @@ -604,40 +624,45 @@ static int32_t _iio_fract_interpret(int32_t fract, int32_t subunits)
fract /= 10;
}

return fract * subunits;
return fract * subunits * mult;
}

int32_t iio_parse_value(char *buf, enum iio_val fmt, int32_t *val,
int32_t *val2)
{
int32_t ret = 0;
int32_t integer, _fract = 0;
int32_t integer, _fract = 0, _fract_scale = 1;
char ch;

switch (fmt) {
case IIO_VAL_INT:
integer = strtol(buf, NULL, 0);
break;
case IIO_VAL_INT_PLUS_MICRO_DB:
ret = __iio_str_parse(buf, &integer, &_fract, true);
ret = __iio_str_parse(buf, &integer, &_fract,
&_fract_scale, true);
if (ret < 0)
return ret;
_fract = _iio_fract_interpret(_fract, 1000000);
_fract = _iio_fract_interpret(_fract, 1000000 / _fract_scale);
break;
case IIO_VAL_INT_PLUS_MICRO:
ret = __iio_str_parse(buf, &integer, &_fract, false);
ret = __iio_str_parse(buf, &integer, &_fract,
&_fract_scale, false);
if (ret < 0)
return ret;
_fract = _iio_fract_interpret(_fract, 1000000);
_fract = _iio_fract_interpret(_fract, 1000000 / _fract_scale);
break;
case IIO_VAL_INT_PLUS_NANO:
ret = __iio_str_parse(buf, &integer, &_fract, false);
ret = __iio_str_parse(buf, &integer, &_fract,
&_fract_scale, false);
if (ret < 0)
return ret;
_fract = _iio_fract_interpret(_fract, 1000000000);
_fract = _iio_fract_interpret(_fract,
1000000000 / _fract_scale);
break;
case IIO_VAL_FRACTIONAL:
ret = __iio_str_parse(buf, &integer, &_fract, false);
ret = __iio_str_parse(buf, &integer, &_fract,
&_fract_scale, false);
if (ret < 0)
return ret;
break;
Expand Down Expand Up @@ -674,10 +699,12 @@ int iio_format_value(char *buf, uint32_t len, enum iio_val fmt,
dB = true;
/* intentional fall through */
case IIO_VAL_INT_PLUS_MICRO:
return snprintf(buf, len, "%"PRIi32".%06"PRIu32"%s", vals[0],
return snprintf(buf, len, "%s%"PRIi32".%06"PRIu32"%s",
vals[1] < 0 ? "-" : "", vals[0],
(uint32_t)vals[1], dB ? " dB" : "");
case IIO_VAL_INT_PLUS_NANO:
return snprintf(buf, len, "%"PRIi32".%09"PRIu32"", vals[0],
return snprintf(buf, len, "%s%"PRIi32".%09"PRIu32"",
vals[1] < 0 ? "-" : "", vals[0],
(uint32_t)vals[1]);
case IIO_VAL_FRACTIONAL:
tmp = no_os_div_s64((int64_t)vals[0] * 1000000000LL, vals[1]);
Expand Down

0 comments on commit 70d148c

Please sign in to comment.