diff options
author | Anton Kling <anton@kling.gg> | 2024-04-17 16:55:16 +0200 |
---|---|---|
committer | Anton Kling <anton@kling.gg> | 2024-04-17 16:55:16 +0200 |
commit | d0cca44913356f8ce15e15216b0e26c2e74b4d06 (patch) | |
tree | f85f5360e528da9914cd4c45f4719d454711f012 /userland | |
parent | d3f8196eb2cd57fec5f6e2691fdbc802c4d92fc8 (diff) |
LibC: Add more functions that support "long long" integers
Diffstat (limited to 'userland')
-rw-r--r-- | userland/libc/Makefile | 2 | ||||
-rw-r--r-- | userland/libc/include/limits.h | 1 | ||||
-rw-r--r-- | userland/libc/include/stdlib.h | 3 | ||||
-rw-r--r-- | userland/libc/stdio/vfprintf.c | 26 | ||||
-rw-r--r-- | userland/libc/stdlib/atol.c | 5 | ||||
-rw-r--r-- | userland/libc/stdlib/atoll.c | 5 | ||||
-rw-r--r-- | userland/libc/stdlib/strtol.c | 11 | ||||
-rw-r--r-- | userland/libc/stdlib/strtoll.c | 56 | ||||
-rw-r--r-- | userland/test/test.c | 18 |
9 files changed, 117 insertions, 10 deletions
diff --git a/userland/libc/Makefile b/userland/libc/Makefile index e7b9f23..af5fa59 100644 --- a/userland/libc/Makefile +++ b/userland/libc/Makefile @@ -3,7 +3,7 @@ AR="i686-sb-ar" AS="i686-sb-as" #CFLAGS = -ggdb -ffreestanding -O2 -Wall -Wextra -pedantic -Wimplicit-fallthrough -I./include/ -static -I../../include/ -Wno-int-conversion -Wno-unused-parameter -Wno-return-type CFLAGS = -ggdb -ffreestanding -Wall -Wextra -pedantic -Wimplicit-fallthrough -I./include/ -static -I../../include/ -Wno-int-conversion -Wno-unused-parameter -Wno-return-type -OBJ=crt0.o libc.o malloc/malloc.o pty.o sys/mman/mmap.o sys/mman/munmap.o memset.o assert.o stdio/snprintf.o stdio/vfprintf.o string/memcpy.o string/memcmp.o string/strcmp.o ubsan.o string/strcpy.o isspace.o stdio/puts.o stdio/putchar.o dirent/opendir.o dirent/readdir.o dirent/closedir.o unistd/getopt.o dirent/scandir.o dirent/alphasort.o stdio/printf.o stdio/vdprintf.o stdio/vprintf.o stdio/dprintf.o stdio/vprintf.o string/strlen.o string/strnlen.o stdio/stdin.o stdio/getchar.o stdio/fgetc.o arpa/inet/htons.o arpa/inet/htonl.o stdio/fread.o stdio/fwrite.o stdio/fopen.o stdio/fclose.o stdio/fseek.o ctype/isascii.o stdio/fprintf.o stdlib/atoi.o stdlib/strtol.o ctype/toupper.o ctype/tolower.o string/strcat.o string/strchr.o string/sscanf.o sys/stat/stat.o stdlib/getenv.o string/strrchr.o stdio/ftell.o stdio/tmpfile.o stdio/fgets.o stdio/feof.o stdio/fscanf.o stdio/ungetc.o string/strncmp.o stdio/fputc.o string/strncpy.o stdio/remove.o stdio/ferror.o stdio/fputs.o stdlib/rand.o stdlib/srand.o unistd/getpid.o stdlib/strtoul.o stdio/fflush.o stdlib/abort.o string/strcspn.o time/localtime.o time/time.o time/clock_gettime.o time/gmtime.o time/strftime.o string/strpbrk.o ctype/isdigit.o ctype/isalpha.o ctype/isxdigit.o ctype/ispunct.o stdio/setvbuf.o stdio/fileno.o stdio/putc.o stdio/sprintf.o stdlib/abs.o string/strspn.o stdlib/qsort.o string/memmove.o setjmp/longjmp.o setjmp/setjmp.o libgen/basename.o string/strdup.o string/strndup.o string/strlcpy.o stdlib/atexit.o stdio/open_memstream.o libgen/dirname.o unistd/unlink.o string/strstr.o string/strcasecmp.o string/strncasecmp.o stdlib/mkstemp.o string/strtok.o unistd/execvp.o unistd/_exit.o ctype/isalnum.o time/ctime_r.o stdlib/strtold.o sys/time/gettimeofday.o stdio/fgetpos.o stdio/fsetpos.o ctype/isprint.o stdlib/system.o stdio/tmpnam.o unistd/msleep.o stdlib/atof.o stdlib/strtod.o stdio/rename.o sys/stat/mkdir.o unistd/uptime.o unistd/ftruncate.o sys/socket/recvfrom.o sys/socket/sendto.o signal/kill.o signal/sigaction.o unistd/chdir.o unistd/getcwd.o stdio/getdelim.o stdio/getline.o unistd/isatty.o sys/socket/listen.o stdlib/realpath.o systemcall.o sys/random/randomfill.o fcntl/open.o unistd/write.o unistd/pwrite.o fcntl/open_process.o tb/sb.o tb/sv.o string/memchr.o +OBJ=crt0.o libc.o malloc/malloc.o pty.o sys/mman/mmap.o sys/mman/munmap.o memset.o assert.o stdio/snprintf.o stdio/vfprintf.o string/memcpy.o string/memcmp.o string/strcmp.o ubsan.o string/strcpy.o isspace.o stdio/puts.o stdio/putchar.o dirent/opendir.o dirent/readdir.o dirent/closedir.o unistd/getopt.o dirent/scandir.o dirent/alphasort.o stdio/printf.o stdio/vdprintf.o stdio/vprintf.o stdio/dprintf.o stdio/vprintf.o string/strlen.o string/strnlen.o stdio/stdin.o stdio/getchar.o stdio/fgetc.o arpa/inet/htons.o arpa/inet/htonl.o stdio/fread.o stdio/fwrite.o stdio/fopen.o stdio/fclose.o stdio/fseek.o ctype/isascii.o stdio/fprintf.o stdlib/atoi.o stdlib/strtol.o ctype/toupper.o ctype/tolower.o string/strcat.o string/strchr.o string/sscanf.o sys/stat/stat.o stdlib/getenv.o string/strrchr.o stdio/ftell.o stdio/tmpfile.o stdio/fgets.o stdio/feof.o stdio/fscanf.o stdio/ungetc.o string/strncmp.o stdio/fputc.o string/strncpy.o stdio/remove.o stdio/ferror.o stdio/fputs.o stdlib/rand.o stdlib/srand.o unistd/getpid.o stdlib/strtoul.o stdio/fflush.o stdlib/abort.o string/strcspn.o time/localtime.o time/time.o time/clock_gettime.o time/gmtime.o time/strftime.o string/strpbrk.o ctype/isdigit.o ctype/isalpha.o ctype/isxdigit.o ctype/ispunct.o stdio/setvbuf.o stdio/fileno.o stdio/putc.o stdio/sprintf.o stdlib/abs.o string/strspn.o stdlib/qsort.o string/memmove.o setjmp/longjmp.o setjmp/setjmp.o libgen/basename.o string/strdup.o string/strndup.o string/strlcpy.o stdlib/atexit.o stdio/open_memstream.o libgen/dirname.o unistd/unlink.o string/strstr.o string/strcasecmp.o string/strncasecmp.o stdlib/mkstemp.o string/strtok.o unistd/execvp.o unistd/_exit.o ctype/isalnum.o time/ctime_r.o stdlib/strtold.o sys/time/gettimeofday.o stdio/fgetpos.o stdio/fsetpos.o ctype/isprint.o stdlib/system.o stdio/tmpnam.o unistd/msleep.o stdlib/atof.o stdlib/strtod.o stdio/rename.o sys/stat/mkdir.o unistd/uptime.o unistd/ftruncate.o sys/socket/recvfrom.o sys/socket/sendto.o signal/kill.o signal/sigaction.o unistd/chdir.o unistd/getcwd.o stdio/getdelim.o stdio/getline.o unistd/isatty.o sys/socket/listen.o stdlib/realpath.o systemcall.o sys/random/randomfill.o fcntl/open.o unistd/write.o unistd/pwrite.o fcntl/open_process.o tb/sb.o tb/sv.o string/memchr.o stdlib/atol.o stdlib/atoll.o stdlib/strtoll.o all: libc.a %.o: %.c diff --git a/userland/libc/include/limits.h b/userland/libc/include/limits.h index 6d0abe0..ad9e40c 100644 --- a/userland/libc/include/limits.h +++ b/userland/libc/include/limits.h @@ -2,3 +2,4 @@ #define FILENAME_MAX PATH_MAX #define ULONG_MAX 0xFFFFFFFFUL #define LONG_MAX 2147483647 +#define LLONG_MAX 9223372036854775807 diff --git a/userland/libc/include/stdlib.h b/userland/libc/include/stdlib.h index 0c3d0f4..7e23035 100644 --- a/userland/libc/include/stdlib.h +++ b/userland/libc/include/stdlib.h @@ -18,6 +18,7 @@ void srand(unsigned int seed); unsigned long strtoul(const char *restrict str, char **restrict endptr, int base); long strtol(const char *str, char **restrict endptr, int base); +long long strtoll(const char *str, char **restrict endptr, int base); void abort(void); int abs(int i); void qsort(void *base, size_t nel, size_t width, @@ -30,4 +31,6 @@ double atof(const char *str); double strtod(const char *restrict nptr, char **restrict endptr); int atoi(const char *str); char *realpath(const char *filename, char *resolvedname); +long atol(const char *nptr); +long long atoll(const char *nptr); #endif diff --git a/userland/libc/stdio/vfprintf.c b/userland/libc/stdio/vfprintf.c index 65a2c27..7006578 100644 --- a/userland/libc/stdio/vfprintf.c +++ b/userland/libc/stdio/vfprintf.c @@ -15,7 +15,7 @@ const char HEX_SET[0x10] = {'0', '1', '2', '3', '4', '5', '6', '7', *(int *)(_r) += _rc; \ } -int fprint_num(FILE *f, int n, int base, char *char_set, int prefix, +int fprint_num(FILE *f, long long n, int base, char *char_set, int prefix, int zero_padding, int right_padding) { int c = 0; if (0 == n) { @@ -58,19 +58,19 @@ int fprint_num(FILE *f, int n, int base, char *char_set, int prefix, return c; } -int fprint_int(FILE *f, int n, int prefix, int zero_padding, +int fprint_int(FILE *f, long long n, int prefix, int zero_padding, int right_padding) { return fprint_num(f, n, 10, "0123456789", prefix, zero_padding, right_padding); } -int fprint_hex(FILE *f, int n, int prefix, int zero_padding, +int fprint_hex(FILE *f, long long n, int prefix, int zero_padding, int right_padding) { return fprint_num(f, n, 16, "0123456789abcdef", prefix, zero_padding, right_padding); } -int fprint_octal(FILE *f, int n, int prefix, int zero_padding, +int fprint_octal(FILE *f, long long n, int prefix, int zero_padding, int right_padding) { return fprint_num(f, n, 8, "012345678", prefix, zero_padding, right_padding); } @@ -131,6 +131,8 @@ int vfprintf(FILE *f, const char *fmt, va_list ap) { const char *s = fmt; int prefix = 0; + int long_level = 0; + int zero_padding = 0; int right_padding = 0; @@ -183,6 +185,10 @@ int vfprintf(FILE *f, const char *fmt, va_list ap) { prefix += (*s) - '0'; cont = 1; break; + case 'l': + long_level++; + assert(long_level <= 2); + break; case 'i': case 'd': if (-1 != precision) { @@ -190,7 +196,17 @@ int vfprintf(FILE *f, const char *fmt, va_list ap) { prefix = precision; right_padding = 0; } - rc += fprint_int(f, va_arg(ap, int), prefix, zero_padding, right_padding); + if (2 == long_level) { + rc += fprint_int(f, va_arg(ap, long long), prefix, zero_padding, + right_padding); + } else if (1 == long_level) { + rc += fprint_int(f, va_arg(ap, long long), prefix, zero_padding, + right_padding); + } else { + rc += + fprint_int(f, va_arg(ap, int), prefix, zero_padding, right_padding); + } + long_level = 0; cont = 0; break; case 'u': diff --git a/userland/libc/stdlib/atol.c b/userland/libc/stdlib/atol.c new file mode 100644 index 0000000..7669457 --- /dev/null +++ b/userland/libc/stdlib/atol.c @@ -0,0 +1,5 @@ +#include <stdlib.h> + +long atol(const char *nptr) { + return strtol(nptr, (char **)NULL, 10); +} diff --git a/userland/libc/stdlib/atoll.c b/userland/libc/stdlib/atoll.c new file mode 100644 index 0000000..a7fc26a --- /dev/null +++ b/userland/libc/stdlib/atoll.c @@ -0,0 +1,5 @@ +#include <stdlib.h> + +long long atoll(const char *nptr) { + return strtoll(nptr, (char **)NULL, 10); +} diff --git a/userland/libc/stdlib/strtol.c b/userland/libc/stdlib/strtol.c index 09a5ad7..30d04ec 100644 --- a/userland/libc/stdlib/strtol.c +++ b/userland/libc/stdlib/strtol.c @@ -4,8 +4,7 @@ #include <limits.h> #include <stdlib.h> -extern int errno; -extern int get_value(char c, long base); +int get_value(char c, long base); // https://pubs.opengroup.org/onlinepubs/9699919799/functions/strtol.html long strtol(const char *str, char **restrict endptr, int base) { @@ -35,11 +34,15 @@ long strtol(const char *str, char **restrict endptr, int base) { if (2 <= base && 36 >= base) { for (; *str; str++) { + if (ret_value > LONG_MAX / base) { + errno = ERANGE; + return LONG_MAX; + } ret_value *= base; int val = get_value(*str, base); if (ret_value > LONG_MAX - val) { errno = ERANGE; - return 0; + return LONG_MAX; } ret_value += val; } @@ -48,6 +51,6 @@ long strtol(const char *str, char **restrict endptr, int base) { return 0; } if (endptr) - *endptr = (char*)str; + *endptr = (char *)str; return ret_value; } diff --git a/userland/libc/stdlib/strtoll.c b/userland/libc/stdlib/strtoll.c new file mode 100644 index 0000000..486f91d --- /dev/null +++ b/userland/libc/stdlib/strtoll.c @@ -0,0 +1,56 @@ +#include <assert.h> +#include <ctype.h> +#include <errno.h> +#include <limits.h> +#include <stdlib.h> + +int get_value(char c, long base); + +// https://pubs.opengroup.org/onlinepubs/9699919799/functions/strtoll.html +long long strtoll(const char *str, char **restrict endptr, int base) { + long long ret_value = 0; + if (endptr) + *endptr = (char *)str; + // Ignore inital white-space sequence + for (; *str && isspace(*str); str++) + ; + if (!*str) + return ret_value; + + // int sign = 0; + if ('-' == *str) { + // FIXME + // sign = 1; + str++; + assert(0); + } else if ('+' == *str) { + str++; + } + + if (0 == base) { + // FIXME + assert(0); + } + + if (2 <= base && 36 >= base) { + for (; *str; str++) { + if (ret_value > LLONG_MAX / base) { + errno = ERANGE; + return LLONG_MAX; + } + ret_value *= base; + int val = get_value(*str, base); + if (ret_value > LLONG_MAX - val) { + errno = ERANGE; + return LLONG_MAX; + } + ret_value += val; + } + } else { + errno = EINVAL; + return 0; + } + if (endptr) + *endptr = (char *)str; + return ret_value; +} diff --git a/userland/test/test.c b/userland/test/test.c index 53fbf55..28e84d9 100644 --- a/userland/test/test.c +++ b/userland/test/test.c @@ -2,6 +2,7 @@ #include <fcntl.h> //#include <json.h> #include <ctype.h> +#include <errno.h> #include <stddef.h> #include <stdint.h> #include <stdio.h> @@ -385,6 +386,22 @@ void strtol_test(void) { dbgln("strtol TEST PASSED"); } +void strtoll_test(void) { + dbgln("strtoll TEST"); + { + char *s = "9223372036854775807"; + char *e; + long r; + assert(9223372036854775807 == strtoll(s, &e, 10)); + assert(ERANGE != errno); + assert(e == (s + strlen(s))); + char *super_long = "92233720368547758070"; + assert(LLONG_MAX == strtoll(super_long, &e, 10)); + assert(ERANGE == errno); + } + dbgln("strtoll TEST PASSED"); +} + void strcmp_test(void) { #define EQ(_s1) \ { assert(0 == strcmp(_s1, _s1)); } @@ -796,6 +813,7 @@ int main(void) { strndup_test(); strspn_test(); strtol_test(); + strtoll_test(); strcmp_test(); strncmp_test(); strcasecmp_test(); |