diff options
author | Jesse Buhagiar <jesse.buhagiar@student.rmit.edu.au> | 2019-11-04 01:56:41 +1100 |
---|---|---|
committer | Andreas Kling <awesomekling@gmail.com> | 2019-11-04 12:34:46 +0100 |
commit | 70fb92fa0e462feaac7e24e988f2ba367a883310 (patch) | |
tree | 485e0967537789b8a8d3715180d966290ecd341e /Libraries/LibC/stdlib.cpp | |
parent | c538648465d1a35f1eb6d059245537e186a7e855 (diff) | |
download | serenity-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.cpp | 78 |
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; |