From 0cef8ca89125a405a9e6876aabd59ed800c8b9bf Mon Sep 17 00:00:00 2001 From: Lephenixnoir Date: Sun, 14 Jan 2024 21:58:03 +0100 Subject: [PATCH] stdio: slight cleanup and documentation --- src/stdio/scanf/scan.c | 120 ++++++++++++++++------------------------- 1 file changed, 45 insertions(+), 75 deletions(-) diff --git a/src/stdio/scanf/scan.c b/src/stdio/scanf/scan.c index 0d13551..bdaa4ed 100644 --- a/src/stdio/scanf/scan.c +++ b/src/stdio/scanf/scan.c @@ -5,6 +5,28 @@ #include #include +/* Features of this implementation: + - Specifiers: + * Integers (%i, %d, %o, %u, %x, %X) + * Floating-point numbers (%e, %f, %F, %g, %a) + * Strings (%c, %s, %[]) + * Pointers (%p) + * Total number of bytes read so far (%n) + - Integer size modifiers: hh, h, l, ll, L, j, z, t. Supported for all + integer conversions, i.e. %i, %d, %u, %o, %x, %X and %n. + - Floating-point size modifiers: l, L for %a, %e, %f, %g. + - Assignment suppression character '*'. + - Maximum field width (but buggy for floating-point, see below). + + NOT SUPPORTED: + - Wide characters: %lc, %ls. + - q size modifier. + - "'" (quote) specifier for locale-specific thousand separators. + - String allocation: %mc, %ms. + - Out-of-order assignments "%n$". + - TODO: Maximum field width for floating-point is mostly untested and likely + has bugs when the field ends in the middle of the number. */ + void __scanf_start(struct __scanf_input *in) { if(in->fp) @@ -38,12 +60,13 @@ void __scanf_end(struct __scanf_input *in) in->str--; } -void __purge_space( struct __scanf_input * __restrict__ in ) +static void __skip_spaces(struct __scanf_input *in) { - while (isspace(__scanf_peek(in))) __scanf_in(in); + while(isspace(__scanf_peek(in))) + __scanf_in(in); } -void __scanf_store_i(int64_t value, int size, va_list *args) +static void __scanf_store_i(int64_t value, int size, va_list *args) { if(size == 1) *va_arg(*args, int8_t *) = value; @@ -55,7 +78,7 @@ void __scanf_store_i(int64_t value, int size, va_list *args) *va_arg(*args, int64_t *) = value; } -void __scanf_store_d(long double value, int size, va_list *args) +static void __scanf_store_d(long double value, int size, va_list *args) { if(size == sizeof(float)) *va_arg(*args, float *) = value; @@ -65,47 +88,6 @@ void __scanf_store_d(long double value, int size, va_list *args) *va_arg(*args, long double *) = value; } -/* STATUS OF __scanf DEVELOPMENT */ - -// XX = not done yet (but will be done) -// OK = OK, done and tested -// -- = not applicable -// NO = not supported (and will not be done) only for %lc as long char are not supported by gint - - -/*************************************************************************************************************/ -/* Specifier * Explanation * num * hh * h *none* l * ll * j * z * t * L */ -/*************************************************************************************************************/ -/* % * Parse literal '%' * -- * -- * -- * OK * -- * -- * -- * -- * -- * -- */ -/*************************************************************************************************************/ -/* c * match a char or several char * OK * -- * -- * OK * NO * -- * -- * -- * -- * -- */ -/*************************************************************************************************************/ -/* s * match a string * OK * -- * -- * OK * NO * -- * -- * -- * -- * -- */ -/*************************************************************************************************************/ -/* [set] * match a set of char * OK * -- * -- * OK * -- * -- * -- * -- * -- * -- */ -/*************************************************************************************************************/ -/* d * match a decimal integer * OK * OK * OK * OK * OK * OK * OK * OK * OK * -- */ -/*************************************************************************************************************/ -/* i * match an integer * OK * OK * OK * OK * OK * OK * OK * OK * OK * -- */ -/*************************************************************************************************************/ -/* d * match an unsigned decimal integer * OK * OK * OK * OK * OK * OK * OK * OK * OK * -- */ -/*************************************************************************************************************/ -/* o * match a unsigned octal integer * OK * OK * OK * OK * OK * OK * OK * OK * OK * -- */ -/*************************************************************************************************************/ -/* x,X * match a unsigned hexadecimal integer * OK * OK * OK * OK * OK * OK * OK * OK * OK * -- */ -/*************************************************************************************************************/ -/* n * return the nb of chars read so far * -- * -- * -- * OK * -- * -- * -- * -- * -- * -- */ -/*************************************************************************************************************/ -/* a,A * match a floating point number * OK * -- * -- * OK * OK * -- * -- * -- * -- * OK */ -/* e,E * match a floating point number * OK * -- * -- * OK * OK * -- * -- * -- * -- * OK */ -/* f,F * match a floating point number * OK * -- * -- * OK * OK * -- * -- * -- * -- * OK */ -/* g,G * match a floating point number * OK * -- * -- * OK * OK * -- * -- * -- * -- * OK */ -/*************************************************************************************************************/ -/* p * match a pointer * -- * -- * -- * OK * -- * -- * -- * -- * -- * -- */ -/*************************************************************************************************************/ - -// %ms and %m[set] are not implemented (with memory allocation while parsing a chain or a set of characters) - struct scanf_format { /* Maximum field width */ int field_width; @@ -113,7 +95,6 @@ struct scanf_format { uint8_t size; /* Whether to skip assignment */ bool skip; - /* Set of bytes allowed for bracket sets in %[] */ uint8_t bracket_set[32]; }; @@ -182,6 +163,7 @@ static bool bracket_set_parse(uint8_t *set, char const *format, int *pos) return (format[*pos] == ']'); } +/* Parse a format in the format string. Returns specifier, 0 on error. */ static int parse_fmt(char const *fmt, int *pos, struct scanf_format *opt) { opt->field_width = INT_MAX; @@ -255,7 +237,7 @@ int __scanf( for(int pos = 0; format[pos]; pos++) { if(format[pos] == ' ') { - __purge_space(in); + __skip_spaces(in); continue; } else if(format[pos] != '%' || format[pos + 1] == '%') { @@ -275,21 +257,19 @@ int __scanf( switch(spec) { case '[': { - int currentlength = 0; - // we need to assign the read char to the corresponding pointer char *c = opt.skip ? NULL : va_arg(*args, char *); - for(int u=0; ubytes_read; + __scanf_store_i(in->bytes_read, opt.size, args); break; case 'd': @@ -331,8 +311,6 @@ int __scanf( case 'F': case 'g': case 'G': { - // read a double from the current input stream - // and store in the corresponding arg as a char by reference long double temp; int err = __strto_fp(in, NULL, NULL, &temp, opt.field_width); if(err == EOF && validrets == 0) return EOF; @@ -344,15 +322,11 @@ int __scanf( } case 'p': { - long int temp; - int err = 0; - if(!opt.skip) { - void *p = va_arg(*args, void *); - err = __strto_int(in, 0, p, NULL, true, opt.field_width); - validrets += (err == 0); - } - else err = __strto_int(in, 0, &temp, NULL, true, opt.field_width); + void *p = opt.skip ? NULL : va_arg(*args, void *); + _Static_assert(sizeof(p) == sizeof(long)); + int err = __strto_int(in, 0, p, NULL, true, opt.field_width); if(err) return validrets; + validrets += !opt.skip; break; } @@ -369,15 +343,13 @@ int __scanf( } case 's': { - char temp; - int curstrlength = 0; - __purge_space(in); - char *c = opt.skip ? NULL : va_arg(*args, char *); - for(int u = 0; u < opt.field_width; u++) { - temp = __scanf_peek(in); - if(temp==EOF && curstrlength==0) return validrets; - if(isspace(temp) || ((temp==EOF && curstrlength!=0))) { + __skip_spaces(in); + + for(int i = 0; i < opt.field_width; i++) { + int temp = __scanf_peek(in); + if(temp==EOF && !i) return validrets; + if(isspace(temp) || temp==EOF) { if(c) { *c = 0; validrets++; @@ -386,9 +358,7 @@ int __scanf( } else { int temp = __scanf_in(in); - if(c) - *c++ = temp; - curstrlength++; + if(c) *c++ = temp; } } break;