git.cappig.dev / apheleiaOS.git master

1
#include <ctype.h>
2
#include <errno.h>
3
#include <float.h>
4
#include <stdbool.h>
5
#include <stdlib.h>
6
7
static long double _ld_abs(long double value) {
8
    return value < 0.0L ? -value : value;
9
}
10
11
long double strtold(char const *restrict str, char **restrict endptr) {
12
    if (!str) {
13
        errno = EINVAL;
14
        if (endptr) {
15
            *endptr = NULL;
16
        }
17
        return 0.0L;
18
    }
19
20
    const char *cursor = str;
21
    while (isspace((unsigned char)*cursor)) {
22
        cursor++;
23
    }
24
25
    int sign = 1;
26
    if (*cursor == '+' || *cursor == '-') {
27
        if (*cursor == '-') {
28
            sign = -1;
29
        }
30
        cursor++;
31
    }
32
33
    long double value = 0.0L;
34
    bool has_digits = false;
35
36
    while (isdigit((unsigned char)*cursor)) {
37
        has_digits = true;
38
        value = value * 10.0L + (long double)(*cursor - '0');
39
        cursor++;
40
    }
41
42
    if (*cursor == '.') {
43
        long double scale = 0.1L;
44
        cursor++;
45
46
        while (isdigit((unsigned char)*cursor)) {
47
            has_digits = true;
48
            value += (long double)(*cursor - '0') * scale;
49
            scale *= 0.1L;
50
            cursor++;
51
        }
52
    }
53
54
    if (!has_digits) {
55
        if (endptr) {
56
            *endptr = (char *)str;
57
        }
58
        return 0.0L;
59
    }
60
61
    int exp_sign = 1;
62
    int exp_value = 0;
63
64
    const char *exp_mark = cursor;
65
    if (*cursor == 'e' || *cursor == 'E') {
66
        cursor++;
67
68
        if (*cursor == '+' || *cursor == '-') {
69
            if (*cursor == '-') {
70
                exp_sign = -1;
71
            }
72
            cursor++;
73
        }
74
75
        const char *exp_start = cursor;
76
        while (isdigit((unsigned char)*cursor)) {
77
            if (exp_value < 1000000) {
78
                exp_value = exp_value * 10 + (*cursor - '0');
79
            }
80
            cursor++;
81
        }
82
83
        if (cursor == exp_start) {
84
            cursor = exp_mark;
85
            exp_value = 0;
86
            exp_sign = 1;
87
        }
88
    }
89
90
    int exponent = exp_sign * exp_value;
91
    bool overflow = false;
92
    bool underflow = false;
93
94
    if (exponent > 0) {
95
        for (int i = 0; i < exponent; i++) {
96
            if (value > LDBL_MAX / 10.0L) {
97
                value = LDBL_MAX;
98
                overflow = true;
99
                break;
100
            }
101
102
            value *= 10.0L;
103
        }
104
    } else if (exponent < 0) {
105
        for (int i = exponent; i < 0; i++) {
106
            value /= 10.0L;
107
            if (value != 0.0L && _ld_abs(value) < LDBL_MIN) {
108
                underflow = true;
109
            }
110
        }
111
    }
112
113
    if (overflow || underflow) {
114
        errno = ERANGE;
115
    }
116
117
    if (endptr) {
118
        *endptr = (char *)cursor;
119
    }
120
121
    return sign < 0 ? -value : value;
122
}
123
124
double strtod(char const *restrict str, char **restrict endptr) {
125
    long double value = strtold(str, endptr);
126
    long double abs_value = _ld_abs(value);
127
128
    if (abs_value > (long double)DBL_MAX) {
129
        errno = ERANGE;
130
        return value < 0 ? -DBL_MAX : DBL_MAX;
131
    }
132
133
    if (abs_value != 0.0L && abs_value < (long double)DBL_MIN) {
134
        errno = ERANGE;
135
    }
136
137
    return (double)value;
138
}
139
140
float strtof(char const *restrict str, char **restrict endptr) {
141
    long double value = strtold(str, endptr);
142
    long double abs_value = _ld_abs(value);
143
144
    if (abs_value > (long double)FLT_MAX) {
145
        errno = ERANGE;
146
        return value < 0 ? -FLT_MAX : FLT_MAX;
147
    }
148
149
    if (abs_value != 0.0L && abs_value < (long double)FLT_MIN) {
150
        errno = ERANGE;
151
    }
152
153
    return (float)value;
154
}
155
156
double atof(char const *str) {
157
    return strtod(str, NULL);
158
}