diff options
author | dzwdz | 2023-08-25 14:06:00 +0200 |
---|---|---|
committer | dzwdz | 2023-08-25 14:06:00 +0200 |
commit | a767724386c9fe175c2fe4311511c0a402339c37 (patch) | |
tree | 7667b5b9a0cd40da58a778c83666467e0a40b9ce /src/libc | |
parent | 3e09037780ca95633749be3acd52e817eed7f98c (diff) |
libc: get as+ld to work
Diffstat (limited to 'src/libc')
-rw-r--r-- | src/libc/include/stdio.h | 2 | ||||
-rw-r--r-- | src/libc/stdio/file.c | 4 | ||||
-rw-r--r-- | src/libc/stdio/misc.c | 6 | ||||
-rw-r--r-- | src/libc/vendor/sortix/sscanf.c | 31 | ||||
-rw-r--r-- | src/libc/vendor/sortix/vcbscanf.c | 475 | ||||
-rw-r--r-- | src/libc/vendor/sortix/vsscanf.c | 59 |
6 files changed, 567 insertions, 10 deletions
diff --git a/src/libc/include/stdio.h b/src/libc/include/stdio.h index 169646f..c579df5 100644 --- a/src/libc/include/stdio.h +++ b/src/libc/include/stdio.h @@ -85,3 +85,5 @@ int rename(const char *old, const char *new); char *tmpnam(char *s); int sscanf(const char *restrict s, const char *restrict format, ...); +int vsscanf(const char* str, const char* format, va_list ap); +int vcbscanf(void* fp, int (*fgetc)(void*), int (*ungetc)(int, void*), const char* restrict format, va_list ap); diff --git a/src/libc/stdio/file.c b/src/libc/stdio/file.c index 984c419..de88a9f 100644 --- a/src/libc/stdio/file.c +++ b/src/libc/stdio/file.c @@ -305,10 +305,6 @@ int fseeko(FILE *f, off_t offset, int whence) { break; case SEEK_CUR: base = f->pos; - // TODO untested - if (f->readbuf) { - base -= f->rblen; - } break; case SEEK_END: base = _sys_getsize(f->fd); diff --git a/src/libc/stdio/misc.c b/src/libc/stdio/misc.c index 45144f3..7e8e746 100644 --- a/src/libc/stdio/misc.c +++ b/src/libc/stdio/misc.c @@ -44,9 +44,3 @@ char *tmpnam(char *s) { strcpy(s, "/tmp/tmpnam"); return s; } - -// TODO sscanf -int sscanf(const char *restrict s, const char *restrict format, ...) { - (void)s; (void)format; - return 0; -} diff --git a/src/libc/vendor/sortix/sscanf.c b/src/libc/vendor/sortix/sscanf.c new file mode 100644 index 0000000..dd7aca4 --- /dev/null +++ b/src/libc/vendor/sortix/sscanf.c @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2012 Jonas 'Sortie' Termansen. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * stdio/sscanf.c + * Input format conversion. + */ + +#include <stdarg.h> +#include <stdio.h> + +int sscanf(const char* str, const char* format, ...) +{ + va_list ap; + va_start(ap, format); + int ret = vsscanf(str, format, ap); + va_end(ap); + return ret; +} + diff --git a/src/libc/vendor/sortix/vcbscanf.c b/src/libc/vendor/sortix/vcbscanf.c new file mode 100644 index 0000000..3aef233 --- /dev/null +++ b/src/libc/vendor/sortix/vcbscanf.c @@ -0,0 +1,475 @@ +/* + * Copyright (c) 2012, 2014, 2016, 2020 Jonas 'Sortie' Termansen. + * Modified by dzwdz. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * stdio/vcbscanf.c + * Input format conversion. + */ + +#include <ctype.h> +#include <errno.h> +#include <limits.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> + +enum scan_type +{ + TYPE_SHORT, + TYPE_SHORTSHORT, + TYPE_INT, + TYPE_LONG, + TYPE_LONGLONG, + TYPE_SIZE, + TYPE_PTRDIFF, + TYPE_MAX, + TYPE_PTR, +}; + +typedef int64_t ssize_t; + +static int debase(unsigned char c, int base) +{ + if ( c == '0' ) + return 0; + int ret = -1; + if ( '0' <= c && c <= '9' ) { ret = c - '0' + 0; } + if ( 'a' <= c && c <= 'f' ) { ret = c - 'a' + 10; } + if ( 'A' <= c && c <= 'F' ) { ret = c - 'A' + 10; } + if ( base <= ret ) + return -1; + return ret; +} + +static size_t parse_scanset(bool scanset[256], const char* spec) +{ + bool negate = spec[0] == '^'; + size_t offset = negate ? 1 : 0; + for ( size_t i = 0; i < 256; i++ ) + scanset[i] = negate; + if ( spec[offset] == ']' ) + { + offset++; + scanset[(unsigned char) ']'] = !negate; + } + for ( ; spec[offset] && spec[offset] != ']'; offset++ ) + { + unsigned char c = (unsigned char) spec[offset]; + // Only allow ASCII in the scanset besides negation. + if ( 128 < c ) + return offset; + if ( spec[offset + 1] == '-' && + spec[offset + 2] && + spec[offset + 2] != ']' ) + { + unsigned char to = (unsigned char) spec[offset + 2]; + for ( int i = c; i <= to; i++ ) + scanset[i] = !negate; + offset += 2; + } + else + scanset[(unsigned char) spec[offset]] = !negate; + } + return offset; +} + +int vcbscanf(void* fp, + int (*fgetc)(void*), + int (*ungetc)(int, void*), + const char* restrict format, + va_list ap) +{ + int matched_items = 0; + uintmax_t bytes_parsed = 0; + int ic = 0; + while ( *format ) + { + if ( isspace((unsigned char) *format) ) + { + do format++; + while ( isspace((unsigned char) *format) ); + while ( true ) + { + ic = fgetc(fp); + if ( ic == EOF ) + break; + bytes_parsed++; + if ( !isspace(ic) ) + { + ungetc(ic, fp); + bytes_parsed--; + break; + } + } + continue; + } + else if ( format[0] != '%' || format[1] == '%' ) + { + if ( *format == '%' ) + format++; + unsigned char c = *format++; + ic = fgetc(fp); + if ( ic == EOF ) + return matched_items ? matched_items : EOF; + bytes_parsed++; + if ( ic != c ) + { + ungetc(ic, fp); + bytes_parsed--; + break; + } + continue; + } + format++; + bool discard = format[0] == '*'; + if ( discard ) + format++; + size_t field_width = 0; + while ( '0'<= *format && *format <= '9' ) + field_width = field_width * 10 + *format++ - '0'; + bool allocate = false; + if ( *format == 'm' ) + { + allocate = true; + format++; + } + enum scan_type scan_type = TYPE_INT; + switch ( *format++ ) + { + case 'h': + scan_type = *format == 'h' ? + (format++, TYPE_SHORTSHORT) : + TYPE_SHORT; + break; + case 'j': scan_type = TYPE_MAX; break; + case 'l': + scan_type = *format == 'l' ? + (format++, TYPE_LONGLONG) : + TYPE_LONG; + break; + case 'L': scan_type = TYPE_LONGLONG; break; + case 't': scan_type = TYPE_PTRDIFF; break; + case 'z': scan_type = TYPE_SIZE; break; + default: format--; + } + if ( *format == 'd' || *format == 'i' || *format == 'o' || + *format == 'u' || *format == 'x' || *format == 'X' || + *format == 'p' ) + { + int base; + bool is_unsigned; + switch ( *format++ ) + { + case 'd': base = 10; is_unsigned = false; break; + case 'i': base = 0; is_unsigned = false; break; + case 'o': base = 8; is_unsigned = true; break; + case 'u': base = 10; is_unsigned = true; break; + case 'p': + if ( scan_type != TYPE_INT ) + return errno = EINVAL, matched_items ? matched_items : EOF; + scan_type = TYPE_PTR; + /* fallthrough */ + case 'X': + case 'x': base = 16; is_unsigned = true; break; + default: __builtin_unreachable(); + } + if ( allocate ) + return errno = EINVAL, matched_items ? matched_items : EOF; + bool parsed_int = false; + uintmax_t int_value = 0; + bool negative = false; + bool has_prefix = false; + bool maybe_base16 = false; + if ( !field_width ) + field_width = SIZE_MAX; + size_t i = 0; + for ( ; i < field_width; i++ ) + { + ic = fgetc(fp); + if ( ic == EOF ) + break; + bytes_parsed++; + if ( i == 0 && isspace(ic) ) + { + i--; + continue; + } + if ( ic == '-' && i == 0 && !has_prefix ) + { + negative = true; + has_prefix = true; + } + else if ( ic == '+' && i == 0 && !has_prefix ) + { + negative = false; + has_prefix = true; + } + else if ( (ic == 'x' || ic == 'X') && + (base == 0 || base == 16) && + (has_prefix ? i == 2 : i == 1) && + int_value == 0 ) + { + maybe_base16 = true; + parsed_int = false; + } + else if ( ic == '0' && (has_prefix ? i == 1 : i == 0) ) + { + int_value = 0; + parsed_int = true; + } + else + { + if ( base == 0 ) + { + if ( maybe_base16 ) + { + if ( debase(ic, 16) < 0 ) + { + ungetc(ic, fp); + bytes_parsed--; + break; + } + base = 16; + } + else if ( parsed_int ) + base = 8; + else + base = 10; + } + int cval = debase(ic, base); + if ( cval < 0 ) + { + ungetc(ic, fp); + bytes_parsed--; + break; + } + if ( __builtin_mul_overflow(int_value, base, &int_value) ) + int_value = UINTMAX_MAX; + if ( __builtin_add_overflow(int_value, cval, &int_value) ) + int_value = UINTMAX_MAX; + parsed_int = true; + } + } + if ( !parsed_int ) + return matched_items || i || ic != EOF ? matched_items : EOF; + if ( discard ) + continue; + uintmax_t uintmaxval = int_value; + if ( negative ) + uintmaxval = -uintmaxval; + intmax_t intmaxval = uintmaxval; + bool un = is_unsigned; + switch ( scan_type ) + { + case TYPE_SHORTSHORT: + if ( un ) *va_arg(ap, unsigned char*) = uintmaxval; + else *va_arg(ap, signed char*) = intmaxval; + break; + case TYPE_SHORT: + if ( un ) *va_arg(ap, unsigned short*) = uintmaxval; + else *va_arg(ap, signed short*) = intmaxval; + break; + case TYPE_INT: + if ( un ) *va_arg(ap, unsigned int*) = uintmaxval; + else *va_arg(ap, signed int*) = intmaxval; + break; + case TYPE_LONG: + if ( un ) *va_arg(ap, unsigned long*) = uintmaxval; + else *va_arg(ap, signed long*) = intmaxval; + break; + case TYPE_LONGLONG: + if ( un ) *va_arg(ap, unsigned long long*) = uintmaxval; + else *va_arg(ap, signed long long*) = intmaxval; + break; + case TYPE_PTRDIFF: + *va_arg(ap, ptrdiff_t*) = intmaxval; + break; + case TYPE_SIZE: + if ( un ) *va_arg(ap, size_t*) = uintmaxval; + else *va_arg(ap, ssize_t*) = intmaxval; + break; + case TYPE_MAX: + if ( un ) *va_arg(ap, uintmax_t*) = uintmaxval; + else *va_arg(ap, intmax_t*) = intmaxval; + break; + case TYPE_PTR: + *va_arg(ap, void**) = (void*) (uintptr_t) uintmaxval; + break; + } + matched_items++; + } + else if ( *format == 's' || *format == '[' || *format == 'c' || + *format == 'C' || *format == 'S' ) + { + bool scanset[256]; + bool string; + bool use_scanset; + switch ( *format++ ) + { + case 'S': + if ( scan_type != TYPE_INT ) + return errno = EINVAL, matched_items ? matched_items : EOF; + scan_type = TYPE_LONG; + /* fallthrough */ + case 's': string = true; use_scanset = false; break; + case '[': string = true; use_scanset = true; break; + case 'C': + if ( scan_type != TYPE_INT ) + return errno = EINVAL, matched_items ? matched_items : EOF; + scan_type = TYPE_LONG; + /* fallthrough */ + case 'c': string = false; use_scanset = false; break; + default: __builtin_unreachable(); + } + if ( use_scanset ) + { + size_t offset = parse_scanset(scanset, format); + if ( format[offset] != ']' ) + return errno = EINVAL, matched_items ? matched_items : EOF; + format += offset + 1; + } + if ( scan_type != TYPE_INT ) + { +#ifndef __is_sortix_libk + fprintf(stderr, + "%s:%u: error: scanf does not support wide strings\n", + __FILE__, __LINE__); +#endif + return errno = EINVAL, matched_items ? matched_items : EOF; + } + if ( !field_width ) + field_width = string ? SIZE_MAX : 1; + char** strptr = NULL; + char* str = NULL; + size_t strsize = 0; + if ( !discard ) + { + if ( allocate ) + { + strptr = va_arg(ap, char**); + strsize = 16; + str = (char*) malloc(strsize); + if ( !str ) + return matched_items ? matched_items : EOF; + } + else + str = va_arg(ap, char*); + } + size_t i = 0; + while ( i < field_width ) + { + ic = fgetc(fp); + if ( ic == EOF ) + break; + bytes_parsed++; + if ( string && (use_scanset ? !scanset[ic] : isspace(ic)) ) + { + if ( !use_scanset && !i ) + continue; + ungetc(ic, fp); + bytes_parsed--; + break; + } + if ( !discard ) + { + if ( allocate && i + string == strsize ) + { + char* newstr = (char*) realloc(str, strsize * 2); + if ( !newstr ) + { + free(str); + return matched_items ? matched_items : EOF; + } + str = newstr; + strsize *= 2; + } + str[i++] = (char) ic; + } + else + i++; + } + if ( string ? !i : i < field_width ) + { + if ( !discard && allocate ) + free(str); + return matched_items || i || ic != EOF ? matched_items : EOF; + } + if ( !discard ) + { + if ( string ) + str[i] = '\0'; + if ( allocate ) + { + char* newstr = realloc(str, i + string); + str = newstr ? newstr : str; + *strptr = str; + } + if ( string || i == field_width ) + matched_items++; + } + } + else if ( *format == 'n' ) + { + format++; + if ( allocate ) + return errno = EINVAL, matched_items ? matched_items : EOF; + switch ( scan_type ) + { + case TYPE_SHORTSHORT: + *va_arg(ap, signed char*) = bytes_parsed; + break; + case TYPE_SHORT: + *va_arg(ap, signed short*) = bytes_parsed; + break; + case TYPE_INT: + *va_arg(ap, signed int*) = bytes_parsed; + break; + case TYPE_LONG: + *va_arg(ap, signed long*) = bytes_parsed; + break; + case TYPE_LONGLONG: + *va_arg(ap, signed long long*) = bytes_parsed; + break; + case TYPE_PTRDIFF: + *va_arg(ap, ptrdiff_t*) = bytes_parsed; + break; + case TYPE_SIZE: + *va_arg(ap, ssize_t*) = bytes_parsed; + break; + case TYPE_MAX: + *va_arg(ap, intmax_t*) = bytes_parsed; + break; + case TYPE_PTR: __builtin_unreachable(); + } + } + else if ( *format == 'a' || *format == 'A' || + *format == 'e' || *format == 'E' || + *format == 'f' || *format == 'F' || + *format == 'g' || *format == 'G' ) + { +#ifndef __is_sortix_libk + fprintf(stderr, "%s:%u: error: scanf does not support \"%%%c\")\n", + __FILE__, __LINE__, *format); +#endif + return errno = EINVAL, matched_items ? matched_items : EOF; + } + else + return errno = EINVAL, matched_items ? matched_items : EOF; + } + return matched_items; +} diff --git a/src/libc/vendor/sortix/vsscanf.c b/src/libc/vendor/sortix/vsscanf.c new file mode 100644 index 0000000..d2388be --- /dev/null +++ b/src/libc/vendor/sortix/vsscanf.c @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2012, 2014 Jonas 'Sortie' Termansen. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * stdio/vsscanf.c + * Input format conversion. + */ + +#include <assert.h> +#include <stdio.h> + +struct vsscanf_input +{ + union + { + const char* str; + const unsigned char* ustr; + }; + size_t offset; +}; + +static int vsscanf_fgetc(void* fp) +{ + struct vsscanf_input* input = (struct vsscanf_input*) fp; + if ( !input->ustr[input->offset] ) + return EOF; + return (int) input->ustr[input->offset++]; +} + +static int vsscanf_ungetc(int c, void* fp) +{ + struct vsscanf_input* input = (struct vsscanf_input*) fp; + if ( c == EOF && !input->ustr[input->offset] ) + return c; + assert(input->offset); + input->offset--; + assert(input->ustr[input->offset] == (unsigned char) c); + return c; +} + +int vsscanf(const char* str, const char* format, va_list ap) +{ + struct vsscanf_input input; + input.str = str; + input.offset = 0; + return vcbscanf(&input, vsscanf_fgetc, vsscanf_ungetc, format, ap); +} + |