libutil

C Utility Library
git clone http://git.omkov.net/libutil
Log | Tree | Refs | README | LICENCE | Download

libutil/src/strtos.c (138 lines, 3.9 KiB) -rw-r--r-- blame download

0123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
// util/strtos.c
// String conversion source file from libutil
// Copyright (C) 2021, Jakob Wakeling
// MIT Licence

#include "util.h"

#include <ctype.h>
#include <errno.h>

/* Convert a string to a signed 8-bit integer */
s8 strtos8(const char *nptr, char **endptr, register int base) {
	register const char *s = nptr; register u8 i = 0, c; bool neg = false;
	
	for (; isspace(*s); ++s);
	
	if (*s == '+') { ++s; } else if (*s == '-') { ++s; neg = true; }
	
	if ((!base || base == 16) && s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) {
		s += 2; base = 16;
	}
	else if (base == 0) { base = s[0] == '0' ? 8 : 10; }
	else if (base < 2 || base > 36) { errno = EINVAL; goto end; }
	
	for (;; ++s) {
		if (*s >= '0' && *s <= '9') { c = *s - '0'; }
		else if (*s >= 'A' && *s <= 'Z') { c = *s - ('A' - 10); }
		else if (*s >= 'a' && *s <= 'z') { c = *s - ('a' - 10); }
		else { break; }
		
		if (c >= base) { break; }
		if (i > (neg ? -(S8_MIN + 1) : S8_MAX - c) / base) {
			errno = ERANGE; i = neg ? S8_MIN : S8_MAX; goto end;
		}
		
		i = i * base + c;
	}
	
end:;
	if (endptr) { *endptr = (char *)s; } return neg ? -i : i;
}

/* Convert a string to a signed 16-bit integer */
s16 strtos16(const char *nptr, char **endptr, register int base) {
	register const char *s = nptr; register u16 i = 0, c; bool neg = false;
	
	for (; isspace(*s); ++s);
	
	if (*s == '+') { ++s; } else if (*s == '-') { ++s; neg = true; }
	
	if ((!base || base == 16) && s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) {
		s += 2; base = 16;
	}
	else if (base == 0) { base = s[0] == '0' ? 8 : 10; }
	else if (base < 2 || base > 36) { errno = EINVAL; goto end; }
	
	for (;; ++s) {
		if (*s >= '0' && *s <= '9') { c = *s - '0'; }
		else if (*s >= 'A' && *s <= 'Z') { c = *s - ('A' - 10); }
		else if (*s >= 'a' && *s <= 'z') { c = *s - ('a' - 10); }
		else { break; }
		
		if (c >= base) { break; }
		if (i > (neg ? -(S16_MIN + 1) : S16_MAX - c) / base) {
			errno = ERANGE; i = neg ? S16_MIN : S16_MAX; goto end;
		}
		
		i = i * base + c;
	}
	
end:;
	if (endptr) { *endptr = (char *)s; } return neg ? -i : i;
}

/* Convert a string to a signed 32-bit integer */
s32 strtos32(const char *nptr, char **endptr, register int base) {
	register const char *s = nptr; register u32 i = 0, c; bool neg = false;
	
	for (; isspace(*s); ++s);
	
	if (*s == '+') { ++s; } else if (*s == '-') { ++s; neg = true; }
	
	if ((!base || base == 16) && s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) {
		s += 2; base = 16;
	}
	else if (base == 0) { base = s[0] == '0' ? 8 : 10; }
	else if (base < 2 || base > 36) { errno = EINVAL; goto end; }
	
	for (;; ++s) {
		if (*s >= '0' && *s <= '9') { c = *s - '0'; }
		else if (*s >= 'A' && *s <= 'Z') { c = *s - ('A' - 10); }
		else if (*s >= 'a' && *s <= 'z') { c = *s - ('a' - 10); }
		else { break; }
		
		if (c >= base) { break; }
		if (i > (neg ? -(S32_MIN + 1) : S32_MAX - c) / base) {
			errno = ERANGE; i = neg ? S32_MIN : S32_MAX; goto end;
		}
		
		i = i * base + c;
	}
	
end:;
	if (endptr) { *endptr = (char *)s; } return neg ? -i : i;
}

/* Convert a string to a signed 64-bit integer */
s64 strtos64(const char *nptr, char **endptr, register int base) {
	register const char *s = nptr; register u64 i = 0, c; bool neg = false;
	
	for (; isspace(*s); ++s);
	
	if (*s == '+') { ++s; } else if (*s == '-') { ++s; neg = true; }
	
	if ((!base || base == 16) && s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) {
		s += 2; base = 16;
	}
	else if (base == 0) { base = s[0] == '0' ? 8 : 10; }
	else if (base < 2 || base > 36) { errno = EINVAL; goto end; }
	
	for (;; ++s) {
		if (*s >= '0' && *s <= '9') { c = *s - '0'; }
		else if (*s >= 'A' && *s <= 'Z') { c = *s - ('A' - 10); }
		else if (*s >= 'a' && *s <= 'z') { c = *s - ('a' - 10); }
		else { break; }
		
		if (c >= base) { break; }
		if (i > (neg ? -(S64_MIN + 1) : S64_MAX - c) / base) {
			errno = ERANGE; i = neg ? S64_MIN : S64_MAX; goto end;
		}
		
		i = i * base + c;
	}
	
end:;
	if (endptr) { *endptr = (char *)s; } return neg ? -i : i;
}