stdio: use compact storage for %[] set in scanf

256 bytes of globals is a *lot* on the G-III.
This commit is contained in:
Lephenixnoir 2024-01-14 20:35:45 +01:00
parent 5b85d53826
commit 1caaa8ff63
No known key found for this signature in database
GPG key ID: 1BBA026E13FC0495

View file

@ -2,6 +2,7 @@
#include "../../stdlib/stdlib_p.h"
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdbool.h>
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<readmaxlength; u++) {
int temp = __scanf_peek(in);
if(__is_allowed(temp)) {
if(bracket_set_test(temp)) {
__scanf_in(in);
if(c) *c++ = temp;
currentlength++;