ciabatta/code/stdlib/conv.c

161 lines
3.3 KiB
C

#include <stdlib.h>
#include <ctype.h>
#include <stdbool.h>
#include <limits.h>
#include <errno.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:
#define inrange(start, c, end) ((start) <= (c) && (c) <= (end))
static bool isbase(int c, int base) {
int val;
if(isdigit(c)) {
val = c-'0';
}
else if(islower(c)) {
val = c-'a'+10;
}
else if(isupper(c)) {
val = c-'A'+10;
}
else {
return false;
}
return val < base;
}
// Called only when isbase(c, base) for some base in range
static long todigitl(int c) {
int val;
if(isdigit(c)) {
val = c-'0';
}
else if(islower(c)) {
val = c-'a'+10;
}
else if(isupper(c)) {
val = c-'A'+10;
}
return val;
}
long
strtol(const char *restrict nptr, char **restrict endptr, int inbase) {
if(!inrange(0, inbase, 36)) {
*endptr = NULL;
return 0;
}
// Skip space on the beginning
while(isspace(*nptr)) {
++nptr;
}
// Parse sign
long coef = 1;
if(*nptr == '-') {
coef = -1;
++nptr;
}
if(*nptr == '+') {
++nptr;
}
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;
if(base == 16 || base == 0) {
++nptr;
base = 16;
}
else {
value = 0;
goto end;
}
}
else if(*nptr == '0') {
++nptr;
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;
}
value = base*value + digit;
++nptr;
}
unsigned long max_modulo = (unsigned long)LONG_MAX+1;
if(value > max_modulo) {
errno = ERANGE;
value = 0;
goto end;
}
if(value == max_modulo) {
if(coef == 1) {
errno = ERANGE;
value = 0;
goto end;
}
else {
value = LONG_MIN;
coef = 1;
}
}
end:
if(endptr != NULL) {
*endptr = (char *)nptr;
}
return coef*(long)value;
}
long long
strtoll(const char *restrict nptr, char **restrict endptr, int base) {
return 0;
}
unsigned long
strtoul(const char *restrict nptr, char **restrict endptr, int base) {
return 0;
}
unsigned long long
strtoull(const char *restrict nptr, char **restrict endptr, int base) {
return 0;
}
double atof(const char *nptr) {
return strtod(nptr, (char **)NULL);
}
int atoi(const char *nptr) {
return (int)strtol(nptr, (char **)NULL, 10);
}
long int atol(const char *nptr) {
return strtol(nptr, (char **)NULL, 10);
}
long long int atoll(const char *nptr) {
return strtoll(nptr, (char **)NULL, 10);
}
double strtod(const char *restrict nptr, char **restrict endptr) {
return 0;
}
float strtof(const char *restrict nptr, char **restrict endptr) {
return 0;
}
long double strtold(const char *restrict nptr, char **restrict endptr) {
return 0;
}