mirror of https://github.com/flysand7/ciabatta.git
fixed merge conflicts
This commit is contained in:
commit
67e15fbb4e
|
@ -0,0 +1,4 @@
|
|||
|
||||
#include <errno.h>
|
||||
|
||||
int errno;
|
|
@ -4,10 +4,18 @@
|
|||
#include <stdbool.h>
|
||||
#include <limits.h>
|
||||
#include <errno.h>
|
||||
#include <math.h>
|
||||
|
||||
// TODO: strto*: locale-based parsing for integers
|
||||
// TODO: i made a function that parses longs and i'm fucken
|
||||
// tired. someone make float parsing :kekw:
|
||||
// TODO: strto*: locale-based parsing
|
||||
// TODO: correctly rounded base 16 floats parsing
|
||||
|
||||
// Call me weak if you want but I'm actually too lazy to type
|
||||
// them out every time, also they take up a lot of horiz space.
|
||||
typedef long long intll;
|
||||
typedef long intl;
|
||||
typedef unsigned long long intull;
|
||||
typedef unsigned long intul;
|
||||
typedef unsigned intu;
|
||||
|
||||
#define inrange(start, c, end) ((start) <= (c) && (c) <= (end))
|
||||
|
||||
|
@ -28,8 +36,18 @@ static bool isbase(int c, int base) {
|
|||
return val < base;
|
||||
}
|
||||
|
||||
static bool strprefix_i(char const *restrict str, char const *restrict prefix) {
|
||||
while(*prefix != 0) {
|
||||
if(*str == 0) break;
|
||||
if(toupper(*str) != toupper(*prefix)) return false;
|
||||
++prefix;
|
||||
++str;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Called only when isbase(c, base) for some base in range
|
||||
static long todigitl(int c) {
|
||||
static long todigit(int c) {
|
||||
int val;
|
||||
if(isdigit(c)) {
|
||||
val = c-'0';
|
||||
|
@ -43,92 +61,255 @@ static long todigitl(int c) {
|
|||
return val;
|
||||
}
|
||||
|
||||
long
|
||||
strtol(const char *restrict nptr, char **restrict endptr, int inbase) {
|
||||
if(!inrange(0, inbase, 36)) {
|
||||
*endptr = NULL;
|
||||
return 0;
|
||||
static intull strtoi_generic(const char *restrict nptr,
|
||||
char **restrict endptr,
|
||||
int inbase,
|
||||
intl *coefptr,
|
||||
intull int_max) {
|
||||
const char *restrict str = nptr;
|
||||
intull value = 0;
|
||||
int digits_read = 0;
|
||||
bool is_signed = (coefptr != NULL);
|
||||
// Find max{abs(int)}. Signed integers have negative,
|
||||
// whose absolute value is 1 bigger than int_max.
|
||||
intull int_abs_max = int_max;
|
||||
if(is_signed) {
|
||||
++int_abs_max;
|
||||
}
|
||||
if(!inrange(0, inbase, 36)) {
|
||||
goto finish;
|
||||
}
|
||||
intull base = (intull)inbase;
|
||||
// Skip space on the beginning
|
||||
while(isspace(*nptr)) {
|
||||
++nptr;
|
||||
while(isspace(*str)) {
|
||||
++str;
|
||||
}
|
||||
// Parse sign
|
||||
long coef = 1;
|
||||
if(*nptr == '-') {
|
||||
coef = -1;
|
||||
++nptr;
|
||||
intl coef = 1;
|
||||
if(is_signed) {
|
||||
if(*str == '-') {
|
||||
coef = -1;
|
||||
++str;
|
||||
}
|
||||
}
|
||||
if(*nptr == '+') {
|
||||
++nptr;
|
||||
if(*str == '+') {
|
||||
++str;
|
||||
}
|
||||
unsigned long base = (unsigned long)inbase;
|
||||
unsigned long value = 0;
|
||||
// See if we need to parse base in C-like format
|
||||
if(*nptr == '0' && *(nptr+1) == 'x') {
|
||||
++nptr;
|
||||
// then set the base accordingly
|
||||
if(strprefix_i(str, "0X")) {
|
||||
++str;
|
||||
if(base == 16 || base == 0) {
|
||||
++nptr;
|
||||
++str;
|
||||
base = 16;
|
||||
}
|
||||
else {
|
||||
value = 0;
|
||||
goto end;
|
||||
goto finish;
|
||||
}
|
||||
}
|
||||
else if(*nptr == '0') {
|
||||
++nptr;
|
||||
else if(*str == '0') {
|
||||
++str;
|
||||
++digits_read;
|
||||
if(base == 8 || base == 0) {
|
||||
base = 8;
|
||||
}
|
||||
}
|
||||
while(isbase(*nptr, (int)base)) {
|
||||
unsigned long digit = (unsigned long)todigitl(*nptr);
|
||||
if(value > (ULONG_MAX - digit)/base) {
|
||||
errno = ERANGE;
|
||||
value = 0;
|
||||
goto end;
|
||||
// Parse the string of digits in the given base. If the value
|
||||
// exceeds abs(int_min) we exit with range error.
|
||||
while(isbase(*str, (int)base)) {
|
||||
intull digit = (intull)todigit(*str);
|
||||
if(value > (int_abs_max - digit)/base) {
|
||||
goto error_out_of_range;
|
||||
}
|
||||
value = base*value + digit;
|
||||
++nptr;
|
||||
++str;
|
||||
++digits_read;
|
||||
}
|
||||
unsigned long max_modulo = (unsigned long)LONG_MAX+1;
|
||||
if(value > max_modulo) {
|
||||
errno = ERANGE;
|
||||
// We only allow the modulo of value equal to abs(int_min) if it is
|
||||
// preceeded by the minus sign.
|
||||
if(is_signed) {
|
||||
if(value == int_abs_max && coef != -1) {
|
||||
goto error_out_of_range;
|
||||
}
|
||||
}
|
||||
goto finish;
|
||||
error_out_of_range:
|
||||
// Skip the remainder of the subject string
|
||||
while(isbase(*str, (int)base)) {
|
||||
++str;
|
||||
}
|
||||
errno = ERANGE;
|
||||
value = int_max;
|
||||
goto finish;
|
||||
finish:
|
||||
// If no conversion is performed we return the value of 0 and *endptr
|
||||
// is set to the nptr.
|
||||
bool conv_performed = (digits_read > 0);
|
||||
if(!conv_performed) {
|
||||
value = 0;
|
||||
goto end;
|
||||
}
|
||||
if(value == max_modulo) {
|
||||
if(coef == 1) {
|
||||
errno = ERANGE;
|
||||
value = 0;
|
||||
goto end;
|
||||
if(endptr != NULL) {
|
||||
if(!conv_performed) {
|
||||
*endptr = (char *)nptr;
|
||||
}
|
||||
else {
|
||||
value = LONG_MIN;
|
||||
coef = 1;
|
||||
*endptr = (char *)str;
|
||||
}
|
||||
}
|
||||
end:
|
||||
if(endptr != NULL) {
|
||||
*endptr = (char *)nptr;
|
||||
*coefptr = coef;
|
||||
return value;
|
||||
}
|
||||
|
||||
static double strtod_generic(const char *restrict nptr, char **restrict endptr) {
|
||||
const char *restrict str = nptr;
|
||||
bool conv_performed = false;
|
||||
double value = 0.0;
|
||||
double coef = 1.0;
|
||||
// Skip space on the beginning
|
||||
while(isspace(*str)) {
|
||||
++str;
|
||||
}
|
||||
return coef*(long)value;
|
||||
// Check for inf and nan
|
||||
if(strprefix_i(str, "INF")) {
|
||||
str += sizeof "INF"-1;
|
||||
value = HUGE_VAL;
|
||||
conv_performed = true;
|
||||
goto finish;
|
||||
}
|
||||
if(strprefix_i(str, "INFINITY")) {
|
||||
str += sizeof "INFINITY"-1;
|
||||
value = HUGE_VAL;
|
||||
conv_performed = true;
|
||||
goto finish;
|
||||
}
|
||||
if(strprefix_i(str, "NAN")) {
|
||||
str += sizeof "NAN"-1;
|
||||
value = NAN;
|
||||
conv_performed = true;
|
||||
if(*str == '(') {
|
||||
while(*str != ')') {
|
||||
++str;
|
||||
}
|
||||
++str;
|
||||
}
|
||||
goto finish;
|
||||
}
|
||||
// Parse C float
|
||||
if(*str == '+') {
|
||||
++str;
|
||||
}
|
||||
else if(*str == '-') {
|
||||
coef = -1.;
|
||||
++str;
|
||||
}
|
||||
int base = 10;
|
||||
if(strprefix_i(str, "0X")) {
|
||||
str += sizeof "0X"-1;
|
||||
base = 16;
|
||||
}
|
||||
// Parse the whole part
|
||||
while(isbase(*str, base)) {
|
||||
long digit = todigit(*str);
|
||||
value = 10.0*value + (double)digit;
|
||||
++str;
|
||||
}
|
||||
if(*str != '.') {
|
||||
value = 0.0;
|
||||
goto finish;
|
||||
}
|
||||
++str;
|
||||
// Parse the fractional part
|
||||
long exp = 1;
|
||||
while(isbase(*str, base)) {
|
||||
long digit = todigit(*str);
|
||||
double fract = (double)digit;
|
||||
long cexp = exp;
|
||||
while(cexp-- != 0) {
|
||||
fract /= (double)base;
|
||||
}
|
||||
value += fract;
|
||||
++exp;
|
||||
++str;
|
||||
}
|
||||
// Parse the exponent
|
||||
if((base == 10 && strprefix_i(str, "E"))
|
||||
|| (base == 16 && strprefix_i(str, "P")))
|
||||
{
|
||||
++str;
|
||||
long exp = 0;
|
||||
long exp_coef = 1;
|
||||
if(*str == '+') {
|
||||
++str;
|
||||
}
|
||||
else if(*str == '-') {
|
||||
exp_coef = -1;
|
||||
++str;
|
||||
}
|
||||
while(isdigit(*str)) {
|
||||
exp = 10*exp + (long)(*str-'0');
|
||||
++str;
|
||||
}
|
||||
if(exp_coef == 1) {
|
||||
while(exp--!=0) value = value * base;
|
||||
}
|
||||
else if(exp_coef == -1) {
|
||||
while(exp--!=0) value = value / base;
|
||||
}
|
||||
}
|
||||
if(!isfinite(value)) {
|
||||
errno = ERANGE;
|
||||
value = coef*HUGE_VAL;
|
||||
}
|
||||
conv_performed = true;
|
||||
finish:
|
||||
if(endptr != NULL) {
|
||||
if(conv_performed) {
|
||||
*endptr = (char *)str;
|
||||
}
|
||||
else {
|
||||
*endptr = (char *)nptr;
|
||||
}
|
||||
}
|
||||
return coef*value;
|
||||
}
|
||||
|
||||
long long
|
||||
strtoll(const char *restrict nptr, char **restrict endptr, int base) {
|
||||
return 0;
|
||||
intl strtol(const char *restrict nptr, char **restrict endptr, int base) {
|
||||
intull int_max = (intull)LONG_MAX;
|
||||
intl coef;
|
||||
intull modulo = strtoi_generic(nptr, endptr, base, &coef, int_max);
|
||||
intl value;
|
||||
if(modulo == int_max) {
|
||||
value = LONG_MIN;
|
||||
}
|
||||
else {
|
||||
value = coef * (intl)modulo;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
unsigned long
|
||||
strtoul(const char *restrict nptr, char **restrict endptr, int base) {
|
||||
return 0;
|
||||
intll strtoll(const char *restrict nptr, char **restrict endptr, int base) {
|
||||
intull int_max = (intull)LLONG_MAX;
|
||||
intl coef;
|
||||
intull modulo = strtoi_generic(nptr, endptr, base, &coef, int_max);
|
||||
intll value;
|
||||
if(modulo == int_max) {
|
||||
value = LLONG_MIN;
|
||||
}
|
||||
else {
|
||||
value = (intll)coef * (intll)modulo;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
unsigned long long
|
||||
strtoull(const char *restrict nptr, char **restrict endptr, int base) {
|
||||
return 0;
|
||||
intul strtoul(const char *restrict nptr, char **restrict endptr, int base) {
|
||||
intull int_max = (intull)ULONG_MAX;
|
||||
intull value = strtoi_generic(nptr, endptr, base, NULL, int_max);
|
||||
return (intul)value;
|
||||
}
|
||||
|
||||
intull strtoull(const char *restrict nptr, char **restrict endptr, int base) {
|
||||
intull int_max = (intull)ULLONG_MAX;
|
||||
return strtoi_generic(nptr, endptr, base, NULL, int_max);
|
||||
}
|
||||
|
||||
double atof(const char *nptr) {
|
||||
|
@ -148,13 +329,13 @@ long long int atoll(const char *nptr) {
|
|||
}
|
||||
|
||||
double strtod(const char *restrict nptr, char **restrict endptr) {
|
||||
return 0;
|
||||
return strtod_generic(nptr, endptr);
|
||||
}
|
||||
|
||||
float strtof(const char *restrict nptr, char **restrict endptr) {
|
||||
return 0;
|
||||
return (float)strtod_generic(nptr, endptr);
|
||||
}
|
||||
|
||||
long double strtold(const char *restrict nptr, char **restrict endptr) {
|
||||
return 0;
|
||||
return (long double)strtod_generic(nptr, endptr);
|
||||
}
|
||||
|
|
|
@ -5,4 +5,4 @@
|
|||
#define ERANGE 3
|
||||
|
||||
// TODO: make it thread-local
|
||||
int errno;
|
||||
extern int errno;
|
||||
|
|
17
inc/math.h
17
inc/math.h
|
@ -21,11 +21,11 @@ typedef double double_t;
|
|||
#define FP_INFINITE 1
|
||||
#define FP_NAN 2
|
||||
|
||||
FP_INFINITE
|
||||
FP_NAN
|
||||
FP_NORMAL
|
||||
FP_SUBNORMAL
|
||||
FP_ZERO
|
||||
//FP_INFINITE
|
||||
//FP_NAN
|
||||
//FP_NORMAL
|
||||
//FP_SUBNORMAL
|
||||
//FP_ZERO
|
||||
#define FP_FAST_FMA 1
|
||||
#define FP_FAST_FMAF 1
|
||||
#define FP_FAST_FMAL 1
|
||||
|
@ -39,8 +39,11 @@ FP_ZERO
|
|||
|
||||
// TODO: implement this
|
||||
#define fpclassify(x) 0
|
||||
#define isfinite(x) 0
|
||||
#define isinf(x) 0
|
||||
|
||||
// HACK: If its fine just remove the comment
|
||||
#define isfinite(x) ((double)(x) != HUGE_VAL && (double)(x) != -HUGE_VAL)
|
||||
#define isinf(x) (!(isinf(x)))
|
||||
|
||||
#define isnan(x) 0
|
||||
#define isnormal(x) 0
|
||||
#define signbit(x) 0
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#if !defined(NULL)
|
||||
|
|
23
test/test.c
23
test/test.c
|
@ -1,6 +1,8 @@
|
|||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
for (int i = 0; i < argc; i++) {
|
||||
|
@ -13,5 +15,24 @@ int main(int argc, char** argv) {
|
|||
for (char c = 'a'; c != 'z'; ++c) {
|
||||
assert(isupper(toupper(c)));
|
||||
}
|
||||
return 0;
|
||||
|
||||
double v0 = strtod("0X1.BC70A3D70A3D7P+6", NULL);
|
||||
|
||||
// parsing with error handling
|
||||
const char *p = "111.11 -2.22 Nan nan(2) inF 0X1.BC70A3D70A3D7P+6 1.18973e+4932zzz";
|
||||
|
||||
char *end;
|
||||
for (double f = strtod(p, &end); p != end; f = strtod(p, &end)) {
|
||||
printf("'%.*s' -> ", (int)(end - p), p);
|
||||
p = end;
|
||||
if (errno == ERANGE){
|
||||
printf("range error, got ");
|
||||
}
|
||||
|
||||
printf("%f\n", f);
|
||||
}
|
||||
|
||||
// parsing without error handling
|
||||
double v1 = strtod(" -0.0000000123junk", NULL);
|
||||
double v2 = strtod("junk", NULL);
|
||||
}
|
Loading…
Reference in New Issue