stdlib: add and test strtoull (DONE)

This commit is contained in:
Lephenixnoir 2021-05-19 21:39:33 +02:00
parent 41ab197ba2
commit b1dc3e77de
No known key found for this signature in database
GPG key ID: 1BBA026E13FC0495
4 changed files with 111 additions and 1 deletions

View file

@ -106,6 +106,7 @@ set(SOURCES
src/libc/stdlib/llabs.c
src/libc/stdlib/lldiv.c
src/libc/stdlib/reallocarray.c
src/libc/stdlib/strtoull.c
# string
src/libc/string/strchr.c
src/libc/string/strcpy.c

8
STATUS
View file

@ -67,6 +67,8 @@ DONE: Function/symbol/macro is defined, builds, links, and is tested
files in /usr/share/i18n/locales
-> Implement setlocale() and localeconv() properly (not hard)
-> Probably support nl_langinfo(), which is much better than localeconv()
-> Fix the "TODO: locale: ..." messages wherever assumptions on the locale
are made in the code
7.12 <math.h>
Provided by Lephenixnoir's port of OpenLibm.
@ -95,7 +97,11 @@ DONE: Function/symbol/macro is defined, builds, links, and is tested
TODO (will give the full list later on)
7.20 <stdlib.h>
7.20.1 Numeric conversion functions: TODO
7.20.1.1 atof: TODO
7.20.1.2 atoi, atol, atoll: TODO
7.20.1.3 strtod, strtof, strtold: TODO
7.20.1.4 strtol, strtoul, strtoll: TODO
strtoull: DONE
7.20.2 Pseudo-random sequence generation functions: TODO
7.20.3 Memory management functions: TODO (check existing code first)
7.20.4 Communication with the environment: TODO

View file

@ -63,4 +63,45 @@ div_t div(int __num, int __denom);
ldiv_t ldiv(long int __num, long int __denom);
lldiv_t lldiv(long long int __num, long long int __denom);
/* Numeric conversion functions. */
/* Parse a long int from a string. */
extern long int strtol(
char const * restrict __ptr,
char ** restrict __endptr,
int __base);
/* Parse a long unsigned int from a string. */
extern unsigned long int strtoul(
char const * restrict __ptr,
char ** restrict __endptr,
int __base);
/* Parse a long long int from a string. */
extern long long int strtoll(
char const * restrict __ptr,
char ** restrict __endptr,
int __base);
/* Parse a long long unsigned int from a string. */
extern unsigned long long int strtoull(
char const * restrict __ptr,
char ** restrict __endptr,
int __base);
/* Parse a double from a string. */
extern double strtod(
char const * restrict __ptr,
char ** restrict __endptr);
/* Parse a float from a string. */
extern float strtof(
char const * restrict __ptr,
char ** restrict __endptr);
/* Parse a long double from a string. */
extern long double strtold(
char const * restrict __ptr,
char ** restrict __endptr);
#endif /*__STDLIB_H__*/

View file

@ -0,0 +1,62 @@
#include <stdlib.h>
#include <stdbool.h>
#include <ctype.h>
#include <errno.h>
unsigned long long int strtoull(char const * restrict ptr,
char ** restrict endptr, int base)
{
/* Save the value of ptr in endptr now in case the format is invalid */
if(endptr) *endptr = (char *)ptr;
/* Skip initial whitespace */
while(isspace(*ptr)) ptr++;
/* Accept a sign character */
bool negative = false;
if(*ptr == '-') negative = true;
if(*ptr == '-' || *ptr == '+') ptr++;
unsigned long long x = 0;
bool valid = false;
/* Read prefixes and determine base */
if((base == 0 || base == 16) && ptr[0]=='0' && tolower(ptr[1])=='x') {
ptr += 2;
base = 16;
}
else if(base == 0 && ptr[0] == '0') {
ptr++;
base = 8;
}
else if(base == 0) {
base = 10;
}
/* Read digits */
while(1) {
int v = -1;
if(isdigit(*ptr)) v = *ptr - '0';
if(islower(*ptr)) v = *ptr - 'a' + 10;
if(v == -1 || v >= base) break;
/* The value is valid as long as there is at least one digit */
valid = true;
/* (x = base*x + v) but with overflow checks */
if(__builtin_umulll_overflow(x, base, &x))
errno = ERANGE;
if(__builtin_uaddll_overflow(x, v, &x))
errno = ERANGE;
ptr++;
}
if(negative) {
if(x != 0) errno = ERANGE;
x = -x;
}
if(endptr && valid) *endptr = (char *)ptr;
return x;
}