summaryrefslogtreecommitdiff
path: root/Libraries/LibC/stdlib.cpp
diff options
context:
space:
mode:
authorJesse Buhagiar <jesse.buhagiar@student.rmit.edu.au>2019-11-04 01:56:41 +1100
committerAndreas Kling <awesomekling@gmail.com>2019-11-04 12:34:46 +0100
commit70fb92fa0e462feaac7e24e988f2ba367a883310 (patch)
tree485e0967537789b8a8d3715180d966290ecd341e /Libraries/LibC/stdlib.cpp
parentc538648465d1a35f1eb6d059245537e186a7e855 (diff)
downloadserenity-70fb92fa0e462feaac7e24e988f2ba367a883310.zip
LibC: Implemented atof()
`atof()` has now been implemented as part of the standard C library. It supports scientific notation such as `1.2e-3` etc, ala the version found as part of `glibc`. It's a bit chunky, so there's probably room for optimisations here and there, however, for now it works as intended (and allows Quake to run).
Diffstat (limited to 'Libraries/LibC/stdlib.cpp')
-rw-r--r--Libraries/LibC/stdlib.cpp78
1 files changed, 70 insertions, 8 deletions
diff --git a/Libraries/LibC/stdlib.cpp b/Libraries/LibC/stdlib.cpp
index 94c23b23a0..3e2a8e1204 100644
--- a/Libraries/LibC/stdlib.cpp
+++ b/Libraries/LibC/stdlib.cpp
@@ -1,7 +1,7 @@
-#include <AK/String.h>
#include <AK/Assertions.h>
#include <AK/HashMap.h>
#include <AK/StdLibExtras.h>
+#include <AK/String.h>
#include <AK/Types.h>
#include <Kernel/Syscall.h>
#include <alloca.h>
@@ -166,7 +166,6 @@ int putenv(char* new_var)
environ = new_environ;
return 0;
}
-
}
double strtod(const char* str, char** endptr)
@@ -185,7 +184,6 @@ long double strtold(const char* str, char** endptr)
ASSERT_NOT_REACHED();
}
-
float strtof(const char* str, char** endptr)
{
(void)str;
@@ -196,8 +194,72 @@ float strtof(const char* str, char** endptr)
double atof(const char* str)
{
- dbgprintf("LibC: atof: '%s'\n", str);
- ASSERT_NOT_REACHED();
+ size_t len = strlen(str);
+ size_t weight = 1;
+ int exp_val = 0;
+ double value = 0.0f;
+ double fraction = 0.0f;
+ bool has_sign = false;
+ bool is_negative = false;
+ bool is_fractional = false;
+ bool is_scientific = false;
+
+ if (str[0] == '-') {
+ is_negative = true;
+ has_sign = true;
+ }
+ if (str[0] == '+') {
+ has_sign = true;
+ }
+
+ for (size_t i = has_sign; i < len; i++) {
+
+ // Looks like we're about to start working on the fractional part
+ if (str[i] == '.') {
+ is_fractional = true;
+ continue;
+ }
+
+ if (str[i] == 'e' || str[i] == 'E') {
+ if (str[i + 1] == '-' || str[i + 1] == '+')
+ exp_val = atoi(str + i + 2);
+ else
+ exp_val = atoi(str + i + 1);
+
+ is_scientific = true;
+ continue;
+ }
+
+ if (str[i] < '0' || str[i] > '9' || exp_val != 0)
+ continue;
+
+ if (is_fractional) {
+ fraction *= 10;
+ fraction += str[i] - '0';
+ weight *= 10;
+ } else {
+ value = value * 10;
+ value += str[i] - '0';
+ }
+ }
+
+ fraction /= weight;
+ value += fraction;
+
+ if (is_scientific) {
+ bool divide = exp_val < 0;
+ if (divide)
+ exp_val *= -1;
+
+ for (int i = 0; i < exp_val; i++) {
+ if (divide)
+ value /= 10;
+ else
+ value *= 10;
+ }
+ }
+
+ return is_negative ? -value : value;
}
int atoi(const char* str)
@@ -338,10 +400,10 @@ char* mkdtemp(char* pattern)
struct stat st;
int rc = lstat(pattern, &st);
if (rc < 0 && errno == ENOENT) {
- if (mkdir(pattern, 0700) < 0)
+ if (mkdir(pattern, 0700) < 0)
return nullptr;
- return pattern;
- }
+ return pattern;
+ }
}
errno = EEXIST;