stdio: simplify output size management in scanf

This commit is contained in:
Lephenixnoir 2024-01-14 20:18:24 +01:00
parent 69eadb67d2
commit 55ae7df318
No known key found for this signature in database
GPG key ID: 1BBA026E13FC0495
2 changed files with 65 additions and 122 deletions

View file

@ -37,21 +37,6 @@ void __scanf_end(struct __scanf_input *in)
in->str--; in->str--;
} }
enum
{
MODSKIP,
MODCHAR,
MODSHORT,
MODNORMAL,
MODLONG,
MODLONGLONG,
MODLONGDOUBLE,
MODINTMAXT,
MODSIZET,
MODPTRDIFFT,
};
void __purge_space( struct __scanf_input * __restrict__ in ) void __purge_space( struct __scanf_input * __restrict__ in )
{ {
while (isspace(__scanf_peek(in))) __scanf_in(in); while (isspace(__scanf_peek(in))) __scanf_in(in);
@ -59,34 +44,24 @@ void __purge_space( struct __scanf_input * __restrict__ in )
void __scanf_store_i(int64_t value, int size, va_list *args) void __scanf_store_i(int64_t value, int size, va_list *args)
{ {
if(size == MODSKIP) return; if(size == 1)
if(size == MODCHAR)
*va_arg(*args, int8_t *) = value; *va_arg(*args, int8_t *) = value;
else if(size == MODSHORT) else if(size == 2)
*va_arg(*args, int16_t *) = value; *va_arg(*args, int16_t *) = value;
else if(size == MODLONGLONG) else if(size == 4)
*va_arg(*args, int32_t *) = value;
else if(size == 8)
*va_arg(*args, int64_t *) = value; *va_arg(*args, int64_t *) = value;
else if(size == MODINTMAXT)
*va_arg(*args, intmax_t *) = value;
else if(size == MODSIZET)
*va_arg(*args, size_t *) = value;
else if(size == MODPTRDIFFT)
*va_arg(*args, ptrdiff_t *) = value;
else
*va_arg(*args, int *) = value;
} }
void __scanf_store_d(long double value, int size, va_list *args) void __scanf_store_d(long double value, int size, va_list *args)
{ {
if (size==MODSKIP) return; if(size == sizeof(float))
if(size == MODLONG)
*va_arg(*args, double *) = value;
else if(size == MODLONGDOUBLE)
*va_arg(*args, long double *) = value;
else
*va_arg(*args, float *) = value; *va_arg(*args, float *) = value;
else if(size == sizeof(double))
*va_arg(*args, double *) = value;
else if(size == sizeof(long double))
*va_arg(*args, long double *) = value;
} }
/* STATUS OF __scanf DEVELOPMENT */ /* STATUS OF __scanf DEVELOPMENT */
@ -239,11 +214,9 @@ int __scanf(
{ {
bool skip = false; bool skip = false;
int MOD = sizeof(int);
int MOD = MODNORMAL;
in->readsofar = 0; // we haven't started to read char from the input stream in->bytes_read = 0; // we haven't started to read char from the input stream
in->readmaxlength = -1; // no specific maximum length to read is defined yet
int validrets = 0; // to be incremented each time we successfully read and store an input as per the format int validrets = 0; // to be incremented each time we successfully read and store an input as per the format
int err = 0; // err control on __strto_xx( ) functions int err = 0; // err control on __strto_xx( ) functions
@ -255,9 +228,8 @@ int __scanf(
// TODO: No __scanf_end() in any of the "return validrets"!! // TODO: No __scanf_end() in any of the "return validrets"!!
while( format[pos] != 0 ) { while( format[pos] != 0 ) {
in->readmaxlength = -1;
user_length = 0; user_length = 0;
MOD = MODNORMAL; MOD = sizeof(int);
skip = false; skip = false;
__allow_all_set(); __allow_all_set();
@ -268,7 +240,9 @@ int __scanf(
// we will have to manage a given format // we will have to manage a given format
else if( format[pos] == '%' ) { else if( format[pos] == '%' ) {
in->readmaxlength = INT_MAX; int readmaxlength = INT_MAX;
char size_letter = 0;
// main loop // main loop
loopagain: loopagain:
@ -282,7 +256,7 @@ int __scanf(
int currentlength = 0; int currentlength = 0;
// we need to assign the read char to the corresponding pointer // we need to assign the read char to the corresponding pointer
char *c = skip ? NULL : va_arg(*args, char *); char *c = skip ? NULL : va_arg(*args, char *);
for(unsigned int u=0; u<in->readmaxlength; u++) { for(int u=0; u<readmaxlength; u++) {
int temp = __scanf_peek(in); int temp = __scanf_peek(in);
if(__is_allowed(temp)) { if(__is_allowed(temp)) {
__scanf_in(in); __scanf_in(in);
@ -301,10 +275,9 @@ int __scanf(
} }
// return the number of char read so far (cannot be skipped %*n is not valid) // return the number of char read so far (cannot be skipped %*n is not valid)
case 'n': { case 'n':
*(int*) va_arg( *args, int* ) = in->readsofar; *va_arg(*args, int *) = in->bytes_read;
break; break;
}
// we are expecting the char '%' to be in the input stream, if not err and return // we are expecting the char '%' to be in the input stream, if not err and return
case '%': { case '%': {
@ -314,69 +287,36 @@ int __scanf(
} }
// the next read, even if valid, will not be stored // the next read, even if valid, will not be stored
case '*': { case '*':
skip = true; skip = true;
goto loopagain; goto loopagain;
break;
}
case 'h': { case 'h':
if (MOD==MODNORMAL || MOD==MODSHORT) { MOD = (size_letter == 'h') ? sizeof(char) : sizeof(short);
MOD--; size_letter = 'h';
goto loopagain; goto loopagain;
} case 'l':
else return validrets; // we cannot have %hhh format modifier --> err MOD = (size_letter == 'l') ? sizeof(long long) : sizeof(long);
break; /* FP conversions will adjust to sizeof(double) later */
} size_letter = 'l';
goto loopagain;
case 'l': { case 'L':
if (MOD==MODNORMAL || MOD==MODLONG) { MOD = sizeof(long double);
MOD++; size_letter = 'L';
goto loopagain; goto loopagain;
} case 'j':
else return validrets; // we cannot have %ll format modifier --> err MOD = sizeof(intmax_t);
break; goto loopagain;
} case 'z':
MOD = sizeof(size_t);
case 'L': { goto loopagain;
if (MOD==MODNORMAL) { case 't':
MOD=MODLONGDOUBLE; MOD = sizeof(ptrdiff_t);
goto loopagain; goto loopagain;
}
else return validrets; // we cannot have %LL format modifier --> err
break;
}
case 'j': {
if (MOD==MODNORMAL) {
MOD=MODINTMAXT;
goto loopagain;
}
else return validrets; // we cannot have %LL format modifier --> err
break;
}
case 'z': {
if (MOD==MODNORMAL) {
MOD=MODSIZET;
goto loopagain;
}
else return validrets; // we cannot have %LL format modifier --> err
break;
}
case 't': {
if (MOD==MODNORMAL) {
MOD=MODPTRDIFFT;
goto loopagain;
}
else return validrets; // we cannot have %LL format modifier --> err
break;
}
case '0' ... '9': { case '0' ... '9': {
user_length = user_length * 10 + (int) ( format[pos] - '0' ); user_length = user_length * 10 + (int) ( format[pos] - '0' );
in->readmaxlength = user_length; readmaxlength = user_length;
goto loopagain; goto loopagain;
break; break;
} }
@ -395,10 +335,10 @@ int __scanf(
long long int temp; long long int temp;
err = __strto_int(in, base, NULL, &temp, use_unsigned, err = __strto_int(in, base, NULL, &temp, use_unsigned,
in->readmaxlength); readmaxlength);
if (err == EOF && validrets == 0) return EOF; if (err == EOF && validrets == 0) return EOF;
if (err != 0) return validrets; if (err != 0) return validrets;
if (skip) __scanf_store_i( temp, MODSKIP, args ); if (skip) __scanf_store_i( temp, 0, args );
else __scanf_store_i( temp, MOD, args ); else __scanf_store_i( temp, MOD, args );
validrets++; validrets++;
break; break;
@ -411,15 +351,21 @@ int __scanf(
case 'f': case 'f':
case 'F': case 'F':
case 'g': case 'g':
case 'G': { case 'G': {
/* Adjust interpretation of no size / 'l' size */
if(size_letter == 0)
MOD = sizeof(float);
if(size_letter == 'l')
MOD = sizeof(double);
// read a double from the current input stream // read a double from the current input stream
// and store in the corresponding arg as a char by reference // and store in the corresponding arg as a char by reference
long double temp; long double temp;
err = __strto_fp( in, NULL, NULL, &temp, err = __strto_fp( in, NULL, NULL, &temp,
in->readmaxlength); readmaxlength);
if (err == EOF && validrets == 0) return EOF; if (err == EOF && validrets == 0) return EOF;
if (err != 0) return validrets; if (err != 0) return validrets;
if (skip) __scanf_store_d( temp, MODSKIP, args ); if (skip) __scanf_store_d( temp, 0, args );
else __scanf_store_d( temp, MOD, args ); else __scanf_store_d( temp, MOD, args );
validrets++; validrets++;
break; break;
@ -430,10 +376,10 @@ int __scanf(
if (!skip) { if (!skip) {
void *p = (void *) va_arg( *args, void** ); // get the adress of the target pointer (void**) void *p = (void *) va_arg( *args, void** ); // get the adress of the target pointer (void**)
err = __strto_int( in, 0, p, NULL, true, err = __strto_int( in, 0, p, NULL, true,
in->readmaxlength); readmaxlength);
} }
else err = __strto_int( in, 0, &temp, NULL, true, else err = __strto_int( in, 0, &temp, NULL, true,
in->readmaxlength); readmaxlength);
if (err == 0) validrets++; if (err == 0) validrets++;
else return validrets; else return validrets;
skip = false; skip = false;
@ -441,11 +387,11 @@ int __scanf(
} }
case 'c': { case 'c': {
if(in->readmaxlength == INT_MAX) if(readmaxlength == INT_MAX)
in->readmaxlength = 1; readmaxlength = 1;
char *c = skip ? NULL : va_arg(*args, char *); char *c = skip ? NULL : va_arg(*args, char *);
for(unsigned int u = 0; u < in->readmaxlength; u++) { for(int u = 0; u < readmaxlength; u++) {
int temp = __scanf_in(in); int temp = __scanf_in(in);
if(temp==EOF) return EOF; if(temp==EOF) return EOF;
else if(c) *c++ = temp; else if(c) *c++ = temp;
@ -460,7 +406,7 @@ int __scanf(
__purge_space(in); __purge_space(in);
char *c = skip ? NULL : va_arg(*args, char *); char *c = skip ? NULL : va_arg(*args, char *);
for(unsigned int u = 0; u < in->readmaxlength; u++) { for(int u = 0; u < readmaxlength; u++) {
temp = __scanf_peek(in); temp = __scanf_peek(in);
if(temp==EOF && curstrlength==0) return validrets; if(temp==EOF && curstrlength==0) return validrets;
if(isspace(temp) || ((temp==EOF && curstrlength!=0))) { if(isspace(temp) || ((temp==EOF && curstrlength!=0))) {

View file

@ -18,15 +18,12 @@ struct __scanf_input {
char const * __restrict__ str; char const * __restrict__ str;
FILE *fp; FILE *fp;
// max char to read from the input stream as per user length modifier /* Single-character lookahead buffer */
unsigned int readmaxlength;
// total number of char read so far in the current call of a XYscanf() function (to return a %n when required)
int readsofar;
int buffer; int buffer;
};
/* Total numbers of bytes read in a scall to *scanf() */
int bytes_read;
};
/* Generic formatted scaning. */ /* Generic formatted scaning. */
extern int __scanf( extern int __scanf(
@ -46,7 +43,7 @@ static inline int __scanf_in(struct __scanf_input *__in)
{ {
int c = __in->buffer; int c = __in->buffer;
__in->buffer = __scanf_fetch(__in); __in->buffer = __scanf_fetch(__in);
__in->readsofar++; __in->bytes_read++;
return c; return c;
} }