libc: Add borrowed strtod implementation
This commit is contained in:
parent
bfb76b5625
commit
d96ff92461
@ -24,6 +24,7 @@ set(SOURCES
|
||||
src/signal.cpp
|
||||
src/termios.cpp
|
||||
src/utime.cpp
|
||||
src/strtod.cpp
|
||||
src/sys/stat.cpp
|
||||
src/sys/mman.cpp
|
||||
src/sys/wait.cpp
|
||||
|
@ -84,9 +84,11 @@ extern "C"
|
||||
/* Parse a decimal integer from a string. */
|
||||
long long atoll(const char* s);
|
||||
|
||||
double atof(const char*);
|
||||
/* Parse a floating-point number from a string. */
|
||||
double atof(const char* str);
|
||||
|
||||
double strtod(const char*, char**);
|
||||
/* Parse a floating-point number from a string. */
|
||||
double strtod(const char* str, char** endptr);
|
||||
|
||||
/* Parse an integer of the specified base from a string, storing the first non-number character in endptr if
|
||||
* nonnull. */
|
||||
|
@ -297,4 +297,9 @@ extern "C"
|
||||
if (errno != EEXIST) return -1;
|
||||
}
|
||||
}
|
||||
|
||||
double atof(const char* str)
|
||||
{
|
||||
return strtod(str, nullptr);
|
||||
}
|
||||
}
|
||||
|
141
libc/src/strtod.cpp
Normal file
141
libc/src/strtod.cpp
Normal file
@ -0,0 +1,141 @@
|
||||
/* vi:set ts=8 sts=4 sw=4: */
|
||||
/*
|
||||
* strtod implementation.
|
||||
* author: Yasuhiro Matsumoto
|
||||
* license: public domain
|
||||
*
|
||||
* source from https://gist.github.com/mattn/1890186
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static const char* skipwhite(const char* q)
|
||||
{
|
||||
const char* p = q;
|
||||
while (isspace(*p)) ++p;
|
||||
return p;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
{
|
||||
double strtod(const char* str, char** end)
|
||||
{
|
||||
double d = 0.0;
|
||||
int sign;
|
||||
int n = 0;
|
||||
const char *p, *a;
|
||||
|
||||
a = p = str;
|
||||
p = skipwhite(p);
|
||||
|
||||
/* decimal part */
|
||||
sign = 1;
|
||||
if (*p == '-')
|
||||
{
|
||||
sign = -1;
|
||||
++p;
|
||||
}
|
||||
else if (*p == '+')
|
||||
++p;
|
||||
if (isdigit(*p))
|
||||
{
|
||||
d = (double)(*p++ - '0');
|
||||
while (*p && isdigit(*p))
|
||||
{
|
||||
d = d * 10.0 + (double)(*p - '0');
|
||||
++p;
|
||||
++n;
|
||||
}
|
||||
a = p;
|
||||
}
|
||||
else if (*p != '.')
|
||||
goto done;
|
||||
d *= sign;
|
||||
|
||||
/* fraction part */
|
||||
if (*p == '.')
|
||||
{
|
||||
double f = 0.0;
|
||||
double base = 0.1;
|
||||
++p;
|
||||
|
||||
if (isdigit(*p))
|
||||
{
|
||||
while (*p && isdigit(*p))
|
||||
{
|
||||
f += base * (*p - '0');
|
||||
base /= 10.0;
|
||||
++p;
|
||||
++n;
|
||||
}
|
||||
}
|
||||
d += f * sign;
|
||||
a = p;
|
||||
}
|
||||
|
||||
/* exponential part */
|
||||
if ((*p == 'E') || (*p == 'e'))
|
||||
{
|
||||
int e = 0;
|
||||
++p;
|
||||
|
||||
sign = 1;
|
||||
if (*p == '-')
|
||||
{
|
||||
sign = -1;
|
||||
++p;
|
||||
}
|
||||
else if (*p == '+')
|
||||
++p;
|
||||
|
||||
if (isdigit(*p))
|
||||
{
|
||||
while (*p == '0') ++p;
|
||||
if (*p == '\0') --p;
|
||||
e = (int)(*p++ - '0');
|
||||
while (*p && isdigit(*p))
|
||||
{
|
||||
e = e * 10 + (int)(*p - '0');
|
||||
++p;
|
||||
}
|
||||
e *= sign;
|
||||
}
|
||||
else if (!isdigit(*(a - 1)))
|
||||
{
|
||||
a = str;
|
||||
goto done;
|
||||
}
|
||||
else if (*p == 0)
|
||||
goto done;
|
||||
|
||||
if (d == 2.2250738585072011 && e == -308)
|
||||
{
|
||||
d = 0.0;
|
||||
a = p;
|
||||
errno = ERANGE;
|
||||
goto done;
|
||||
}
|
||||
if (d == 2.2250738585072012 && e <= -308)
|
||||
{
|
||||
d *= 1.0e-308;
|
||||
a = p;
|
||||
goto done;
|
||||
}
|
||||
d *= __builtin_powi(10.0, e);
|
||||
a = p;
|
||||
}
|
||||
else if (p > str && !isdigit(*(p - 1)))
|
||||
{
|
||||
a = str;
|
||||
goto done;
|
||||
}
|
||||
|
||||
done:
|
||||
if (end) *end = const_cast<char*>(a);
|
||||
return d;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user