libc: Add borrowed strtod implementation

This commit is contained in:
apio 2023-08-08 15:17:25 +02:00
parent bfb76b5625
commit d96ff92461
Signed by: apio
GPG Key ID: B8A7D06E42258954
4 changed files with 151 additions and 2 deletions

View File

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

View File

@ -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. */

View File

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