A locale-independent strtod
There is a need in some utilities to have a way of accepting both types of decimal points "." and ",". The only way seems to be to rebuild strtod(). This new function will accept "123.456" and "123,456" as 123.456 and considers them the same number. It means we lose thousands separator, but this is rarely used. test scripts are added to check the function returns the proper values. There was simpler predecessor that got stuck on negative 0 or -0.123 which these tests flushed out. References:
This commit is contained in:
@ -21,6 +21,7 @@
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "c.h"
|
||||
#include "strutils.h"
|
||||
@ -60,3 +61,63 @@ double strtod_or_err(const char *str, const char *errmesg)
|
||||
error(EXIT_FAILURE, errno, "%s: '%s'", errmesg, str);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Covert a string into a double in a non-locale aware way.
|
||||
* This means the decimal point can be either . or ,
|
||||
* Also means you cannot use the other for thousands separator
|
||||
*
|
||||
* Exits on failure like its other _or_err cousins
|
||||
*/
|
||||
double strtod_nol_or_err(char *str, const char *errmesg)
|
||||
{
|
||||
double num;
|
||||
const char *cp, *radix;
|
||||
double mult;
|
||||
int negative = 0;
|
||||
|
||||
if (str != NULL && *str != '\0') {
|
||||
num = 0.0;
|
||||
cp = str;
|
||||
/* strip leading spaces */
|
||||
while (isspace(*cp))
|
||||
cp++;
|
||||
|
||||
/* get sign */
|
||||
if (*cp == '-') {
|
||||
negative = 1;
|
||||
cp++;
|
||||
} else if (*cp == '+')
|
||||
cp++;
|
||||
|
||||
/* find radix */
|
||||
radix = cp;
|
||||
mult=0.1;
|
||||
while(isdigit(*radix)) {
|
||||
radix++;
|
||||
mult *= 10;
|
||||
}
|
||||
while(isdigit(*cp)) {
|
||||
num += (*cp - '0') * mult;
|
||||
mult /= 10;
|
||||
cp++;
|
||||
}
|
||||
/* got the integers */
|
||||
if (*cp == '\0')
|
||||
return (negative?-num:num);
|
||||
if (*cp != '.' && *cp != ',')
|
||||
error(EXIT_FAILURE, EINVAL, "%s: '%s'", errmesg, str);
|
||||
|
||||
cp++;
|
||||
mult = 0.1;
|
||||
while(isdigit(*cp)) {
|
||||
num += (*cp - '0') * mult;
|
||||
mult /= 10;
|
||||
cp++;
|
||||
}
|
||||
if (*cp == '\0')
|
||||
return (negative?-num:num);
|
||||
}
|
||||
error(EXIT_FAILURE, errno, "%s: '%s'", errmesg, str);
|
||||
return 0;
|
||||
}
|
||||
|
Reference in New Issue
Block a user