diff options
Diffstat (limited to 'src/stdlib')
32 files changed, 688 insertions, 0 deletions
| diff --git a/src/stdlib/abs.c b/src/stdlib/abs.c new file mode 100644 index 00000000..4806d629 --- /dev/null +++ b/src/stdlib/abs.c @@ -0,0 +1,4 @@ +int abs(int a) +{ +	return a>0 ? a : -a; +} diff --git a/src/stdlib/atof.c b/src/stdlib/atof.c new file mode 100644 index 00000000..f7fcd826 --- /dev/null +++ b/src/stdlib/atof.c @@ -0,0 +1,6 @@ +#include <stdlib.h> + +double atof(const char *s) +{ +	return strtod(s, 0); +} diff --git a/src/stdlib/atoi.c b/src/stdlib/atoi.c new file mode 100644 index 00000000..648b154f --- /dev/null +++ b/src/stdlib/atoi.c @@ -0,0 +1,15 @@ +#include <stdlib.h> +#include <ctype.h> + +int atoi(const char *s) +{ +	int n=0, neg=0; +	while (isspace(*s)) s++; +	switch (*s) { +	case '-': neg=1; +	case '+': s++; +	} +	while (isdigit(*s)) +		n = 10*n + *s++ - '0'; +	return neg ? -n : n; +} diff --git a/src/stdlib/atol.c b/src/stdlib/atol.c new file mode 100644 index 00000000..9c91bba9 --- /dev/null +++ b/src/stdlib/atol.c @@ -0,0 +1,16 @@ +#include <stdlib.h> +#include <ctype.h> + +long atol(const char *s) +{ +	long n=0; +	int neg=0; +	while (isspace(*s)) s++; +	switch (*s) { +	case '-': neg=1; +	case '+': s++; +	} +	while (isdigit(*s)) +		n = 10*n + *s++ - '0'; +	return neg ? -n : n; +} diff --git a/src/stdlib/atoll.c b/src/stdlib/atoll.c new file mode 100644 index 00000000..0e03e0a1 --- /dev/null +++ b/src/stdlib/atoll.c @@ -0,0 +1,16 @@ +#include <stdlib.h> +#include <ctype.h> + +long long atoll(const char *s) +{ +	long long n=0; +	int neg=0; +	while (isspace(*s)) s++; +	switch (*s) { +	case '-': neg=1; +	case '+': s++; +	} +	while (isdigit(*s)) +		n = 10*n + *s++ - '0'; +	return neg ? -n : n; +} diff --git a/src/stdlib/bsearch.c b/src/stdlib/bsearch.c new file mode 100644 index 00000000..61d89367 --- /dev/null +++ b/src/stdlib/bsearch.c @@ -0,0 +1,20 @@ +#include <stdlib.h> + +void *bsearch(const void *key, const void *base, size_t nel, size_t width, int (*cmp)(const void *, const void *)) +{ +	void *try; +	int sign; +	while (nel > 0) { +		try = (char *)base + width*(nel/2); +		sign = cmp(key, try); +		if (!sign) return try; +		else if (nel == 1) break; +		else if (sign < 0) +			nel /= 2; +		else { +			base = try; +			nel -= nel/2; +		} +	} +	return NULL; +} diff --git a/src/stdlib/div.c b/src/stdlib/div.c new file mode 100644 index 00000000..e42c1f14 --- /dev/null +++ b/src/stdlib/div.c @@ -0,0 +1,6 @@ +#include <stdlib.h> + +div_t div(int num, int den) +{ +	return (div_t){ num/den, num%den }; +} diff --git a/src/stdlib/frexp.c b/src/stdlib/frexp.c new file mode 100644 index 00000000..ae82cb30 --- /dev/null +++ b/src/stdlib/frexp.c @@ -0,0 +1,23 @@ +#include <math.h> +#include <inttypes.h> + +double frexp(double x, int *e) +{ +	union { double d; uint64_t i; } y = { x }; +	int ee = y.i>>52 & 0x7ff; + +	if (!ee) { +		if (x) { +			x = frexp(x*0x1p64, e); +			*e -= 64; +		} else *e = 0; +		return x; +	} else if (ee == 0x7ff) { +		return x; +	} + +	*e = ee - 0x3fe; +	y.i &= 0x800fffffffffffffull; +	y.i |= 0x3fe0000000000000ull; +	return y.d; +} diff --git a/src/stdlib/frexpf.c b/src/stdlib/frexpf.c new file mode 100644 index 00000000..ee5e910a --- /dev/null +++ b/src/stdlib/frexpf.c @@ -0,0 +1,23 @@ +#include <math.h> +#include <inttypes.h> + +float frexpf(float x, int *e) +{ +	union { float f; uint32_t i; } y = { x }; +	int ee = y.i>>23 & 0xff; + +	if (!ee) { +		if (x) { +			x = frexpf(x*0x1p64, e); +			*e -= 64; +		} else *e = 0; +		return x; +	} else if (ee == 0xff) { +		return x; +	} + +	*e = ee - 0x7e; +	y.i &= 0x807ffffful; +	y.i |= 0x3f000000ul; +	return y.f; +} diff --git a/src/stdlib/frexpl.c b/src/stdlib/frexpl.c new file mode 100644 index 00000000..ecfff007 --- /dev/null +++ b/src/stdlib/frexpl.c @@ -0,0 +1,25 @@ +#include <math.h> +#include <inttypes.h> + +/* This version is for 80-bit little endian long double */ + +long double frexpl(long double x, int *e) +{ +	union { long double ld; uint16_t hw[5]; } y = { x }; +	int ee = y.hw[4]&0x7fff; + +	if (!ee) { +		if (x) { +			x = frexpl(x*0x1p64, e); +			*e -= 64; +		} else *e = 0; +		return x; +	} else if (ee == 0x7fff) { +		return x; +	} + +	*e = ee - 0x3ffe; +	y.hw[4] &= 0x8000; +	y.hw[4] |= 0x3ffe; +	return y.ld; +} diff --git a/src/stdlib/imaxabs.c b/src/stdlib/imaxabs.c new file mode 100644 index 00000000..81001819 --- /dev/null +++ b/src/stdlib/imaxabs.c @@ -0,0 +1,6 @@ +#include <inttypes.h> + +intmax_t imaxabs(intmax_t a) +{ +	return a>0 ? a : -a; +} diff --git a/src/stdlib/imaxdiv.c b/src/stdlib/imaxdiv.c new file mode 100644 index 00000000..b2ce821f --- /dev/null +++ b/src/stdlib/imaxdiv.c @@ -0,0 +1,6 @@ +#include <inttypes.h> + +imaxdiv_t imaxdiv(intmax_t num, intmax_t den) +{ +	return (imaxdiv_t){ num/den, num%den }; +} diff --git a/src/stdlib/labs.c b/src/stdlib/labs.c new file mode 100644 index 00000000..675b95b8 --- /dev/null +++ b/src/stdlib/labs.c @@ -0,0 +1,4 @@ +long labs(long a) +{ +	return a>0 ? a : -a; +} diff --git a/src/stdlib/ldiv.c b/src/stdlib/ldiv.c new file mode 100644 index 00000000..36eb960b --- /dev/null +++ b/src/stdlib/ldiv.c @@ -0,0 +1,6 @@ +#include <stdlib.h> + +ldiv_t ldiv(long num, long den) +{ +	return (ldiv_t){ num/den, num%den }; +} diff --git a/src/stdlib/llabs.c b/src/stdlib/llabs.c new file mode 100644 index 00000000..bec4a03d --- /dev/null +++ b/src/stdlib/llabs.c @@ -0,0 +1,4 @@ +long long llabs(long long a) +{ +	return a>0 ? a : -a; +} diff --git a/src/stdlib/lldiv.c b/src/stdlib/lldiv.c new file mode 100644 index 00000000..7aaf7a0e --- /dev/null +++ b/src/stdlib/lldiv.c @@ -0,0 +1,6 @@ +#include <stdlib.h> + +lldiv_t lldiv(long long num, long long den) +{ +	return (lldiv_t){ num/den, num%den }; +} diff --git a/src/stdlib/qsort.c b/src/stdlib/qsort.c new file mode 100644 index 00000000..f5bf3d02 --- /dev/null +++ b/src/stdlib/qsort.c @@ -0,0 +1,50 @@ +#include <stdlib.h> +#include <string.h> + +/* A simple heap sort implementation.. only in-place O(nlogn) sort I know. */ + +#define MIN(a, b) ((a)<(b) ? (a) : (b)) + +static void swap(char *a, char *b, size_t len) +{ +	char tmp[256]; +	size_t l; +	while (len) { +		l = MIN(sizeof tmp, len); +		memcpy(tmp, a, l); +		memcpy(a, b, l); +		memcpy(b, tmp, l); +		a += l; +		b += l; +		len -= l; +	} +} + +static void sift(char *base, size_t root, size_t nel, size_t width, int (*cmp)(const void *, const void *)) +{ +	size_t max; + +	while (2*root <= nel) { +		max = 2*root; +		if (max < nel && cmp(base+max*width, base+(max+1)*width) < 0) +			max++; +		if (cmp(base+root*width, base+max*width) < 0) { +			swap(base+root*width, base+max*width, width); +			root = max; +		} else break; +	} +} + +void qsort(void *_base, size_t nel, size_t width, int (*cmp)(const void *, const void *)) +{ +	char *base = _base; +	size_t i; + +	if (!nel) return; +	for (i=(nel+1)/2; i; i--) +		sift(base, i-1, nel-1, width, cmp); +	for (i=nel-1; i; i--) { +		swap(base, base+i*width, width); +		sift(base, 0, i-1, width, cmp); +	} +} diff --git a/src/stdlib/strtod.c b/src/stdlib/strtod.c new file mode 100644 index 00000000..388058fe --- /dev/null +++ b/src/stdlib/strtod.c @@ -0,0 +1,6 @@ +#include <stdlib.h> + +double strtod(const char *s, char **p) +{ +	return strtold(s, p); +} diff --git a/src/stdlib/strtof.c b/src/stdlib/strtof.c new file mode 100644 index 00000000..07b32df4 --- /dev/null +++ b/src/stdlib/strtof.c @@ -0,0 +1,6 @@ +#include <stdlib.h> + +float strtof(const char *s, char **p) +{ +	return strtold(s, p); +} diff --git a/src/stdlib/strtoimax.c b/src/stdlib/strtoimax.c new file mode 100644 index 00000000..19691091 --- /dev/null +++ b/src/stdlib/strtoimax.c @@ -0,0 +1,25 @@ +#include <inttypes.h> +#include <errno.h> +#include <ctype.h> + +intmax_t strtoimax(const char *s1, char **p, int base) +{ +	const unsigned char *s = s1; +	int sign = 0; +	uintmax_t x; + +	/* Initial whitespace */ +	for (; isspace(*s); s++); + +	/* Optional sign */ +	if (*s == '-') sign = *s++; +	else if (*s == '+') s++; + +	x = strtoumax(s, p, base); +	if (x > INTMAX_MAX) { +		if (!sign || -x != INTMAX_MIN) +			errno = ERANGE; +		return sign ? INTMAX_MIN : INTMAX_MAX; +	} +	return sign ? -x : x; +} diff --git a/src/stdlib/strtol.c b/src/stdlib/strtol.c new file mode 100644 index 00000000..ace820af --- /dev/null +++ b/src/stdlib/strtol.c @@ -0,0 +1,17 @@ +#include <stdlib.h> +#include <inttypes.h> +#include <errno.h> +#include <limits.h> + +long strtol(const char *s, char **p, int base) +{ +	intmax_t x = strtoimax(s, p, base); +	if (x > LONG_MAX) { +		errno = ERANGE; +		return LONG_MAX; +	} else if (x < LONG_MIN) { +		errno = ERANGE; +		return LONG_MIN; +	} +	return x; +} diff --git a/src/stdlib/strtold.c b/src/stdlib/strtold.c new file mode 100644 index 00000000..54f80469 --- /dev/null +++ b/src/stdlib/strtold.c @@ -0,0 +1,93 @@ +#include <stdlib.h> +#include <errno.h> +#include <ctype.h> + +long double strtold(const char *s1, char **p) +{ +	const unsigned char *s = s1; +	long double x = 0; +	long double frac; +	int sign = 0; +	int nonzero = 0; +	int radix = '.'; +	long e; + +	if (!p) p = (char **)&s1; + +	/* Initial whitespace */ +	for (; isspace(*s); s++); + +	/* Optional sign */ +	if (*s == '-') sign = *s++; +	else if (*s == '+') s++; + +	/* Handle infinities and NaNs. */ +	if ((s[0]|32)=='i' && (s[1]|32)=='n' && (s[2]|32)=='f') { +		*p = (char *)s + 3; +		return sign ? -1.0/0.0 : 1.0/0.0; +	} else if ((s[0]|32)=='n' && (s[1]|32)=='a' && (s[2]|32)=='n') { +		*p = (char *)s + 3; +		return 0.0/0.0; +	} + +	/* Possible hex float */ +	if (s[0]=='0' && (s[1]|32)=='x') { +		/* Mantissa must be non-degenerate */ +		if (!isxdigit(s[2]) && (s[2]!=radix || !isxdigit(s[3]))) { +			/* Decimal float 0, 'x' extraneous */ +			*p = (char *)++s; +			return 0; +		} +		/* We have a real hex float */ +		s += 2; +		for (; isxdigit(*s); s++) { +			x = 16*x + (isdigit(*s)?*s-'0':(*s|32)-'a'); +			if (*s!='0') nonzero=1; +		} +		if (*s == radix) { +			frac = 1.0/16.0; +			for (s++; isxdigit(*s); s++) { +				x += frac * (isdigit(*s)?*s-'0':(*s|32)-'a'); +				frac *= 1.0/16.0; +				if (*s!='0') nonzero=1; +			} +		} +		if ((*s|32) == 'p') { +			e = strtol(s+1, (void *)&s, 10); +			for (; e>0; e--) x *= 2.0; +			for (; e<0; e++) x *= 0.5; +		} +		if ((nonzero && !x) || !(1.0/x)) +			errno = ERANGE; +		*p = (char *)s; +		return sign ? -x : x; +	} + +	/* Mantissa must be non-degenerate */ +	if (!isdigit(s[0]) && (s[0]!=radix || !isdigit(s[1]))) { +		*p = (char *)s1; +		return 0; +	} + +	for (; isdigit(*s); s++) { +		x = 10*x + *s-'0'; +		if (*s!='0') nonzero=1; +	} +	if (*s == radix) { +		frac = 10.0; +		for (s++; isdigit(*s); s++) { +			x += (*s-'0') / frac; +			frac *= 10.0; +			if (*s!='0') nonzero=1; +		} +	} +	if ((*s|32)=='e') { +		e = strtol(++s, (void *)&s, 10); +		for (; e>0; e--) x *= 10.0; +		for (; e<0; e++) x /= 10.0; +	} +	if ((nonzero && !x) || !(1.0/x)) +		errno = ERANGE; +	*p = (char*)s; +	return sign ? -x : x; +} diff --git a/src/stdlib/strtoll.c b/src/stdlib/strtoll.c new file mode 100644 index 00000000..9ab66fd9 --- /dev/null +++ b/src/stdlib/strtoll.c @@ -0,0 +1,17 @@ +#include <stdlib.h> +#include <inttypes.h> +#include <errno.h> +#include <limits.h> + +long long strtoll(const char *s, char **p, int base) +{ +	intmax_t x = strtoimax(s, p, base); +	if (x > LLONG_MAX) { +		errno = ERANGE; +		return LLONG_MAX; +	} else if (x < LLONG_MIN) { +		errno = ERANGE; +		return LLONG_MIN; +	} +	return x; +} diff --git a/src/stdlib/strtoul.c b/src/stdlib/strtoul.c new file mode 100644 index 00000000..951d5e8c --- /dev/null +++ b/src/stdlib/strtoul.c @@ -0,0 +1,14 @@ +#include <stdlib.h> +#include <inttypes.h> +#include <errno.h> +#include <limits.h> + +unsigned long strtoul(const char *s, char **p, int base) +{ +	uintmax_t x = strtoumax(s, p, base); +	if (x > ULONG_MAX) { +		errno = ERANGE; +		return ULONG_MAX; +	} +	return x; +} diff --git a/src/stdlib/strtoull.c b/src/stdlib/strtoull.c new file mode 100644 index 00000000..20aa7bde --- /dev/null +++ b/src/stdlib/strtoull.c @@ -0,0 +1,14 @@ +#include <stdlib.h> +#include <inttypes.h> +#include <errno.h> +#include <limits.h> + +unsigned long long strtoull(const char *s, char **p, int base) +{ +	uintmax_t x = strtoumax(s, p, base); +	if (x > ULLONG_MAX) { +		errno = ERANGE; +		return ULLONG_MAX; +	} +	return x; +} diff --git a/src/stdlib/strtoumax.c b/src/stdlib/strtoumax.c new file mode 100644 index 00000000..a529f6e8 --- /dev/null +++ b/src/stdlib/strtoumax.c @@ -0,0 +1,123 @@ +#include <inttypes.h> +#include <stdlib.h> +#include <errno.h> +#include <ctype.h> +#include <stdio.h> + +/* Lookup table for digit values. -1==255>=36 -> invalid */ +static const unsigned char digits[] = { +-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, +-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, +-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1, +-1,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24, +25,26,27,28,29,30,31,32,33,34,35,-1,-1,-1,-1,-1, +-1,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24, +25,26,27,28,29,30,31,32,33,34,35,-1,-1,-1,-1,-1, +-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, +-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, +-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, +-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, +-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, +-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, +-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, +-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, +}; + +uintmax_t strtoumax(const char *s1, char **p, int base) +{ +	const unsigned char *s = s1; +	size_t x1, z1; +	uintmax_t x, z=0; +	int sign = 0; +	int shift; + +	if (!p) p = (char **)&s1; + +	/* Initial whitespace */ +	for (; isspace(*s); s++); + +	/* Optional sign */ +	if (*s == '-') sign = *s++; +	else if (*s == '+') s++; + +	/* Default base 8, 10, or 16 depending on prefix */ +	if (base == 0) { +		if (s[0] == '0') { +			if ((s[1]|32) == 'x') base = 16; +			else base = 8; +		} else { +			base = 10; +		} +	} + +	if ((unsigned)base-2 > 36-2 || digits[*s]>=base) { +		*p = (char *)s1; +		errno = EINVAL; +		return 0; +	} + +	/* Main loops. Only use big types if we have to. */ +	if (base == 10) { +		for (x1=0; isdigit(*s) && x1<=SIZE_MAX/10-10; s++) +			x1 = 10*x1 + *s-'0'; +		for (x=x1; isdigit(*s) && x<=UINTMAX_MAX/10-10; s++) +			x = 10*x + *s-'0'; +		if (isdigit(*s)) { +			if (isdigit(s[1]) || 10*x>UINTMAX_MAX-(*s-'0')) +				goto overflow; +			x = 10*x + *s-'0'; +		} +	} else if (!(base & base/2)) { +		if (base == 16) { +			if (s[0]=='0' && (s[1]|32)=='x' && digits[s[2]]<16) +				s+=2; +			shift=4; +			z1 = SIZE_MAX/16; +			z = UINTMAX_MAX/16; +		} else if (base == 8) { +			shift=3; +			z1 = SIZE_MAX/8; +			z = UINTMAX_MAX/8; +		} else if (base == 2) { +			shift=1; +			z1 = SIZE_MAX/2; +			z = UINTMAX_MAX/2; +		} else if (base == 4) { +			shift=2; +			z1 = SIZE_MAX/4; +			z = UINTMAX_MAX/4; +		} else /* if (base == 32) */ { +			shift=5; +			z1 = SIZE_MAX/32; +			z = UINTMAX_MAX/32; +		} +		for (x1=0; digits[*s]<base && x1<=z1; s++) +			x1 = (x1<<shift) + digits[*s]; +		for (x=x1; digits[*s]<base && x<=z; s++) +			x = (x<<shift) + digits[*s]; +		if (digits[*s] < base) goto overflow; +	} else { +		z1 = SIZE_MAX/base-base; +		for (x1=0; digits[*s]<base && x1<=z1; s++) +			x1 = x1*base + digits[*s]; +		if (digits[*s]<base) +			z = UINTMAX_MAX/base-base; +		for (x=x1; digits[*s]<base && x<=z; s++) +			x = x*base + digits[*s]; +		if (digits[*s] < base) { +			if (digits[s[1]]<base || x*base>UINTMAX_MAX-digits[*s]) +				goto overflow; +			x = x*base + digits[*s]; +		} +	} + +	*p = (char *)s; +	return sign ? -x : x; + +overflow: +	for (; digits[*s] < base; s++); +	*p = (char *)s; +	errno = ERANGE; +	return UINTMAX_MAX; +} diff --git a/src/stdlib/wcstoimax.c b/src/stdlib/wcstoimax.c new file mode 100644 index 00000000..861fcb54 --- /dev/null +++ b/src/stdlib/wcstoimax.c @@ -0,0 +1,24 @@ +#include <wchar.h> +#include <inttypes.h> +#include <errno.h> + +intmax_t wcstoimax(const wchar_t *s, wchar_t **p, int base) +{ +	int sign = 0; +	uintmax_t x; + +	/* Initial whitespace */ +	for (; iswspace(*s); s++); + +	/* Optional sign */ +	if (*s == '-') sign = *s++; +	else if (*s == '+') s++; + +	x = wcstoumax(s, p, base); +	if (x > INTMAX_MAX) { +		if (!sign || -x != INTMAX_MIN) +			errno = ERANGE; +		return sign ? INTMAX_MIN : INTMAX_MAX; +	} +	return sign ? -x : x; +} diff --git a/src/stdlib/wcstol.c b/src/stdlib/wcstol.c new file mode 100644 index 00000000..aad62e5b --- /dev/null +++ b/src/stdlib/wcstol.c @@ -0,0 +1,18 @@ +#include <wchar.h> +#include <stdlib.h> +#include <inttypes.h> +#include <errno.h> +#include <limits.h> + +long wcstol(const wchar_t *s, wchar_t **p, int base) +{ +	intmax_t x = wcstoimax(s, p, base); +	if (x > LONG_MAX) { +		errno = ERANGE; +		return LONG_MAX; +	} else if (x < LONG_MIN) { +		errno = ERANGE; +		return LONG_MIN; +	} +	return x; +} diff --git a/src/stdlib/wcstoll.c b/src/stdlib/wcstoll.c new file mode 100644 index 00000000..ddfea74b --- /dev/null +++ b/src/stdlib/wcstoll.c @@ -0,0 +1,18 @@ +#include <wchar.h> +#include <stdlib.h> +#include <inttypes.h> +#include <errno.h> +#include <limits.h> + +long long wcstoll(const wchar_t *s, wchar_t **p, int base) +{ +	intmax_t x = wcstoimax(s, p, base); +	if (x > LLONG_MAX) { +		errno = ERANGE; +		return LLONG_MAX; +	} else if (x < LLONG_MIN) { +		errno = ERANGE; +		return LLONG_MIN; +	} +	return x; +} diff --git a/src/stdlib/wcstoul.c b/src/stdlib/wcstoul.c new file mode 100644 index 00000000..e39faafe --- /dev/null +++ b/src/stdlib/wcstoul.c @@ -0,0 +1,15 @@ +#include <wchar.h> +#include <stdlib.h> +#include <inttypes.h> +#include <errno.h> +#include <limits.h> + +unsigned long wcstoul(const wchar_t *s, wchar_t **p, int base) +{ +	uintmax_t x = wcstoumax(s, p, base); +	if (x > ULONG_MAX) { +		errno = ERANGE; +		return ULONG_MAX; +	} +	return x; +} diff --git a/src/stdlib/wcstoull.c b/src/stdlib/wcstoull.c new file mode 100644 index 00000000..e324dfb2 --- /dev/null +++ b/src/stdlib/wcstoull.c @@ -0,0 +1,15 @@ +#include <wchar.h> +#include <stdlib.h> +#include <inttypes.h> +#include <errno.h> +#include <limits.h> + +unsigned long long wcstoull(const wchar_t *s, wchar_t **p, int base) +{ +	uintmax_t x = wcstoumax(s, p, base); +	if (x > ULLONG_MAX) { +		errno = ERANGE; +		return ULLONG_MAX; +	} +	return x; +} diff --git a/src/stdlib/wcstoumax.c b/src/stdlib/wcstoumax.c new file mode 100644 index 00000000..a8f4680f --- /dev/null +++ b/src/stdlib/wcstoumax.c @@ -0,0 +1,47 @@ +#include <wchar.h> +#include <stdlib.h> +#include <inttypes.h> +#include <errno.h> + +uintmax_t wcstoumax(const wchar_t *s, wchar_t **p, int base) +{ +	/* Large enough for largest value in binary */ +	char buf[sizeof(uintmax_t)*8+2]; +	int sign = 0, skipped=0; + +	if (!p) p = (wchar_t **)&s; + +	if (base && (unsigned)base-2 > 36-2) { +		*p = (wchar_t *)s; +		errno = EINVAL; +		return 0; +	} + +	/* Initial whitespace */ +	for (; iswspace(*s); s++); + +	/* Optional sign */ +	if (*s == '-') sign = *s++; +	else if (*s == '+') s++; + +	/* Skip leading zeros but don't allow leading zeros before "0x". */ +	for (; s[0]=='0' && s[1]=='0'; s++) skipped=1; +	if (skipped && (base==0 || base==16) && (s[1]|32)=='x') { +		*p = (wchar_t *)(s+1); +		return 0; +	} + +	/* Convert to normal char string so we can use strtoumax */ +	buf[0] = sign; +	if (wcstombs(buf+!!sign, s, sizeof buf-1) < 0) return 0; +	buf[sizeof buf-1]=0; + +	/* Compute final position */ +	if (p) { +		if ((base==0 || base==16) && s[0]=='0' && (s[1]|32)=='x' && iswxdigit(s[2])) s+=2; +		for(;*s&&((unsigned)*s-'0'<base||((unsigned)*s|32)-'a'<base-10);s++); +		*p = (wchar_t *)s; +	} + +	return strtoumax(buf, 0, base); +} | 
