diff --git a/src/stdio/scanf/scan.c b/src/stdio/scanf/scan.c index 15673a2..82192fc 100644 --- a/src/stdio/scanf/scan.c +++ b/src/stdio/scanf/scan.c @@ -2,6 +2,7 @@ #include "../../stdlib/stdlib_p.h" #include #include +#include #include void __scanf_start(struct __scanf_input *in) @@ -106,50 +107,44 @@ void __scanf_store_d(long double value, int size, va_list *args) // %ms and %m[set] are not implemented (with memory allocation while parsing a chain or a set of characters) -/* list of allowed char given by a set %[], this is updated at every set */ -bool __asciiallowed[256] = { true }; +/* Set of bytes allowed in a given set %[]. */ +static uint8_t bracket_set[32]; -/* unallow all the char for the current set */ -void __unallow_all_set( void ) +/* Allow/disallow the entire set */ +static void bracket_set_init(bool allow) { - for(int u =0; u<=255; u++) - __asciiallowed[u]=false; + memset(bracket_set, allow ? 0xff : 0x00, sizeof bracket_set); } -/* allow all the char for the current set */ -void __allow_all_set( void ) +/* Allow/disallow a range of characters. Both ends are included. */ +static void bracket_set_range(uint8_t start, uint8_t end, bool allow) { - for(int u =0; u<=255; u++) - __asciiallowed[u]=true; + for(int u = start; u <= end; u++) { + int byte = u >> 3; + int bit = 1 << (u & 7); + if(allow) + bracket_set[byte] |= bit; + else + bracket_set[byte] &= ~bit; + } } -/* allo a range of char for the current set */ -/* note1 : c1 and c2 do not to be sorted */ -/* note2 : not sur if C standard requires to be ordered or not */ -void __define_set_range( char c1, char c2, bool value ) +/* Check whether a byte is allowed by the bracket set. */ +static bool bracket_set_test(int c) { - char beg = (c1 < c2 ? c1 : c2 ); - char end = (c1 >= c2 ? c1 : c2 ); - - for (int u=beg; u<=end; u++) - __asciiallowed[u] = value; + int byte = (c >> 3); + int bit = 1 << (c & 7); + return (c != EOF) && (bracket_set[byte] & bit); } -/* return true if the char is in the allowed set or false otherwise */ -bool __is_allowed(int c) -{ - return (c != EOF) && __asciiallowed[c]; -} - - /* return 0 if Ok or -1 if syntax err in the set format */ -int __scanset(char const * __restrict__ format, int *pos ) +static int bracket_set_parse(char const * __restrict__ format, int *pos ) { int __sor = 0; int __eor = 0; bool __neg = false; - __unallow_all_set(); + bracket_set_init(false); (*pos)++; @@ -157,11 +152,11 @@ int __scanset(char const * __restrict__ format, int *pos ) if (format[*pos] == '^' ) { __neg = true; (*pos)++; - __allow_all_set(); + bracket_set_init(true); // the char ']' is part of the set if (format[*pos] == ']' ) { - __asciiallowed[ ']' ] = !__neg; + bracket_set_range(']', ']', !__neg); (*pos)++; } } @@ -170,7 +165,7 @@ int __scanset(char const * __restrict__ format, int *pos ) __neg = false; // the char ']' is part of the set if (format[*pos] == ']' ) { - __asciiallowed[ ']' ] = !__neg; + bracket_set_range(']', ']', !__neg); (*pos)++; } } @@ -180,7 +175,7 @@ int __scanset(char const * __restrict__ format, int *pos ) if (format[*pos]=='-') { // the char '-' is included in the allowed set if (format[*pos+1]==']') { - __asciiallowed[ '-' ] = !__neg; // if set in very final position before']', this is the char '-' only + bracket_set_range('-', '-', !__neg); (*pos)++; // we have now finished the reading of the set cause the following char is ']' return 0; @@ -189,7 +184,7 @@ int __scanset(char const * __restrict__ format, int *pos ) else { (*pos)++; __eor = format[*pos]; - __define_set_range( __sor, __eor, !__neg ); + bracket_set_range( __sor, __eor, !__neg ); } } // we find the char ']' so it means we reach the end of this set @@ -199,7 +194,7 @@ int __scanset(char const * __restrict__ format, int *pos ) // we are considering one particular char and prepare for a potential range if we find the char '-' later on else { __sor = format[*pos]; - __asciiallowed[ __sor ] = !__neg; + bracket_set_range(__sor, __sor, !__neg); (*pos)++; } } @@ -232,8 +227,6 @@ int __scanf( MOD = sizeof(int); skip = false; - __allow_all_set(); - if( format[pos] == ' ' ) { __purge_space(in); } @@ -251,14 +244,14 @@ int __scanf( switch(format[pos]) { // we need to decrypt the corresponding scanf set of character case '[': { - err = __scanset( format, &pos ); + err = bracket_set_parse( format, &pos ); if (err!=0) return validrets; int currentlength = 0; // we need to assign the read char to the corresponding pointer char *c = skip ? NULL : va_arg(*args, char *); for(int u=0; u