Compare commits

...

4 Commits

2 changed files with 650 additions and 180 deletions

View File

@ -8,6 +8,7 @@ extern "C" {
#include <stdio.h>
#include <stdbool.h>
/*
** General utilities for scanf(); we expose them here as we use subfunctions of
@ -26,9 +27,12 @@ struct __scanf_input {
int readmaxlength;
int currentlength;
int skip;
// total number of char read so far in the current call of a XYscanf() function (to return a %n when required)
int readsofar;
bool purgewhitespace;
int buffer;
};

View File

@ -2,6 +2,7 @@
#include <ctype.h>
#include <fxlibc/scanf.h>
#include <fxlibc/stdlib_p.h>
#include <stdbool.h>
void __scanf_start(struct __scanf_input *in)
{
@ -9,7 +10,7 @@ void __scanf_start(struct __scanf_input *in)
if(in->fp)
in->buffer = fgetc(in->fp);
else {
in->buffer = *in->str;
in->buffer = (*in->str ? *in->str : EOF);
in->str += (in->buffer != 0);
}
}
@ -40,6 +41,7 @@ void __scanf_end(struct __scanf_input *in)
enum
{
MODSKIP,
MODSHORTSHORT,
MODSHORT,
MODNORMAL,
@ -48,9 +50,15 @@ enum
MODLONGDOUBLE,
};
void __purge_space( struct __scanf_input * __restrict__ in )
{
while (isspace(__scanf_peek(in))) __scanf_in(in);
}
void __scanf_store_i(int64_t value, int size, va_list *args)
{
if (size==MODSKIP) return;
if(size == MODSHORTSHORT)
*va_arg(*args, int8_t *) = value;
else if(size == MODSHORT)
@ -63,6 +71,8 @@ void __scanf_store_i(int64_t value, int size, va_list *args)
void __scanf_store_d(long double value, int size, va_list *args)
{
if (size==MODSKIP) return;
if(size == MODLONG)
*va_arg(*args, double *) = value;
else if(size == MODLONGDOUBLE)
@ -111,102 +121,135 @@ void __scanf_store_d(long double value, int size, va_list *args)
/* p * mathc a pointer * -- * -- * -- * OK * -- * -- * -- * -- * -- * -- */
/*************************************************************************************************************/
#define DEBUG 0
#if DEBUG
#include <gint/gint.h>
void DBGPrint( char * const str)
{
FILE* f= fopen( "BDG_Out.txt", "a" );
fprintf( f, "%s\n", str );
fclose( f );
}
void DBG( char * const str )
{
gint_world_switch( GINT_CALL( DBGPrint, str ) );
}
#else
void DBG( char * const str )
{
}
#endif
int __scanf(
struct __scanf_input * __restrict__ in,
char const * __restrict__ format,
va_list *args)
{
int i=0;
int ret = 0;
int err = 0;
int mod = MODNORMAL;
int length = 0;
bool SKIP = false;
int MOD = MODNORMAL;
in->readsofar = 0; // we haven't started to read char from the input stream
in->readmaxlength = -1; // no specific maximum length to read is defined yet
in->readsofar = 0;
in->readmaxlength = -1;
int VALIDRETS = 0; // to be incremented each time we successfully read and store an input as per the format
int ERROR = 0; // ERROR control on __strto_xx( ) functions
int user_length = 0;
int pos = 0;
__scanf_start( in );
DBG( "---------\n" );
DBG( "In Scanf " );
while( format[i]!=0 )
while( format[pos] != 0 )
{
DBG( "Parsing ..." );
in->readmaxlength = -1;
user_length = 0;
MOD = MODNORMAL;
SKIP = false;
if( format[pos] == '%' ) // we will have to manage a given format
{
DBG( "'%' read");
if ( format[i] == ' ' ) // a space in the format string mean that all white-space after the last read and before the next one are to be removed
{
char flush;
for(;;)
{
flush = __scanf_peek( in ); // check if the next character is a whitespace
if (isspace(flush))
{
flush = __scanf_in( in ); // if so, we remove it from the pile and advance
}
else break; // if not, we can move to the following
}
in->readmaxlength = -1;
i++;
}
else if ( format[i] == '%' ) // read conversion
{
mod = MODNORMAL;
length = 0;
in->readmaxlength=-1;
loopagain:
i++;
switch( format[i] )
DBG( "Looping ..." );
pos++;
switch( format[pos] )
{
case 'h': // we start with MODNORMAL and decrease the length first to MODSHORT and after to MODSHORTSHORT
case 'n': // return the number of char read so far (cannot be skipped %*n is not valid)
{
if(mod==MODNORMAL)
{
mod=MODSHORT;
goto loopagain;
}
else if(mod==MODSHORT)
{
mod=MODSHORTSHORT;
goto loopagain;
}
else
{
mod=MODNORMAL;
break; // we cannot have %hhh
}
DBG( "'n' read");
*(int*) va_arg( *args, int* ) = in->readsofar;
break;
}
case 'l': // we start with MODNORMAL and decrease the length first to MODLONG and after to MODLONGLONG
case '%': // we are expecting the char '%' to be in the input stream, if not ERROR and return
{
if(mod==MODNORMAL)
{
mod=MODLONG;
goto loopagain;
}
else if(mod==MODLONG)
{
mod=MODLONGLONG;
goto loopagain;
}
else
{
mod=MODNORMAL;
break; // we cannot have %lll
}
DBG( "'%' read");
if (__scanf_peek(in) != '%' ) return VALIDRETS;
break;
}
case 'L': // idem, but only for Double and limiter only to MODLONG (no long long double available)
case '*': // the next read, even if valid, will not be stored
{
mod=MODLONGDOUBLE;
DBG( "'*' read");
SKIP = true;
goto loopagain;
}
case 'h':
{
if (MOD==MODNORMAL || MOD==MODSHORT)
{
MOD--;
goto loopagain;
}
else return VALIDRETS; // we cannot have %hhh format modifier --> ERROR
}
case 'l':
{
if (MOD==MODNORMAL || MOD==MODLONG)
{
MOD++;
goto loopagain;
}
else return VALIDRETS; // we cannot have %ll format modifier --> ERROR
}
case 'L':
{
if (MOD==MODNORMAL)
{
MOD=MODLONGDOUBLE;
goto loopagain;
}
else return VALIDRETS; // we cannot have %LL format modifier --> ERROR
}
case '0':
case '1':
case '2':
@ -218,119 +261,91 @@ int __scanf(
case '8':
case '9':
{
length = length * 10 + (int) ( format[i] - '0');
in->readmaxlength = length;
user_length = user_length * 10 + (int) ( format[pos] - '0' );
in->readmaxlength = user_length;
goto loopagain;
}
case '%':
{
// NOthing to do this is just the character '%'
in->readmaxlength = -1;
break;
}
case 'c':
{
// read a char from the current input stream
// and store in the corresponding arg as a char by reference
char *c = (char *) va_arg( *args, char* );
if (in->readmaxlength==-1)
{
*c = __scanf_in( in );
}
else
{
for(int u = 0; u < in->readmaxlength; u++ )
{
*c = __scanf_in( in );
c++;
}
}
in->readmaxlength=-1;
ret++;
break;
}
case 'd':
{
// read a long int (in base 10 - decimal) from the current input stream
// and store in the corresponding arg as a char by reference
long long int temp;
err = __strto_int( in, 10, NULL, &temp, false ); // base is 10 as for strtol
if (err == 0)
{
__scanf_store_i( temp, mod, args );
mod = MODNORMAL;
ret++;
}
break;
ERROR = __strto_int( in, 10, NULL, &temp, false ); // base is 10 as for strtol
if (ERROR != 0) return VALIDRETS;
if (SKIP) __scanf_store_i( temp, MODSKIP, args );
else __scanf_store_i( temp, MOD, args );
VALIDRETS++;
break;
}
case 'i':
{
// read a long int (in base determined by the first character) from the current input stream
// read a signed int (base to be defined at read) from the current input stream
// and store in the corresponding arg as a char by reference
long long int temp;
err = __strto_int( in, 0, NULL, &temp, false ); // base is 0 as for strtol
if (err == 0)
{
__scanf_store_i( temp, mod, args );
mod = MODNORMAL;
ret++;
}
break;
ERROR = __strto_int( in, 0, NULL, &temp, false ); // base is 0 as for strtol
if (ERROR != 0) return VALIDRETS;
if (SKIP) __scanf_store_i( temp, MODSKIP, args );
else __scanf_store_i( temp, MOD, args );
VALIDRETS++;
break;
}
case 'u':
{
// read a unsigned long int (in base 10 - decimal) from the current input stream
// read a unsigned int (in base 10 - decimal) from the current input stream
// and store in the corresponding arg as a char by reference
long long int temp;
err = __strto_int( in, 10, NULL, &temp, true ); // base is 10 as for strtol
if (err == 0)
{
__scanf_store_i( temp, mod, args );
mod = MODNORMAL;
ret++;
}
break;
ERROR = __strto_int( in, 10, NULL, &temp, false ); // base is 10 as for strtol - use_unsigned must be false (validated with glibc6.2 behaviour)
if (ERROR != 0) return VALIDRETS;
if (SKIP) __scanf_store_i( temp, MODSKIP, args );
else __scanf_store_i( temp, MOD, args );
VALIDRETS++;
break;
}
case 'o':
{
// read a unsigned long int (in base 8 - octal) from the current input stream
// read a unsigned int (in base 8 - octal) from the current input stream
// and store in the corresponding arg as a char by reference
long long int temp;
err = __strto_int( in, 8, NULL, &temp, true ); // base is 8 as for strtol
if (err == 0)
{
__scanf_store_i( temp, mod, args );
mod = MODNORMAL;
ret++;
}
break;
ERROR = __strto_int( in, 8, NULL, &temp, true ); // base is 8 as for strtol
if (ERROR != 0) return VALIDRETS;
if (SKIP) __scanf_store_i( temp, MODSKIP, args );
else __scanf_store_i( temp, MOD, args );
VALIDRETS++;
break;
}
case 'x':
case 'X':
{
// read a unsigned long int (in base 16 - hexadecimal) from the current input stream
// read a unsigned int (in base 16 - hexadecimal) from the current input stream
// and store in the corresponding arg as a char by reference
long long int temp;
err = __strto_int( in, 16, NULL, &temp, true ); // base is 16 as for strtol
if (err == 0)
{
__scanf_store_i( temp, mod, args );
mod = MODNORMAL;
ret++;
}
break;
}
ERROR = __strto_int( in, 16, NULL, &temp, true ); // base is 16 as for strtol
if (ERROR != 0) return VALIDRETS;
if (SKIP) __scanf_store_i( temp, MODSKIP, args );
else __scanf_store_i( temp, MOD, args );
VALIDRETS++;
break;
}
case 'a':
case 'A':
@ -340,47 +355,485 @@ 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;
err = __strto_fp( in, NULL, NULL, &temp );
if (err == 0)
ERROR = __strto_fp( in, NULL, NULL, &temp );
if (ERROR != 0) return VALIDRETS;
if (SKIP) __scanf_store_d( temp, MODSKIP, args );
else __scanf_store_d( temp, MOD, args );
VALIDRETS++;
break;
}
case 'p':
{
long int dummy;
if (SKIP == false)
{
__scanf_store_d( temp, mod, args );
mod = MODNORMAL;
ret++;
void *p = (void *) va_arg( *args, void** ); // get the adress of the target pointer (void**)
ERROR = __strto_int( in, 0, p, NULL, true );
}
else ERROR = __strto_int( in, 0, &dummy, NULL, true );
if (ERROR == 0) VALIDRETS++;
else return VALIDRETS;
SKIP = false;
break;
}
}
case 'c':
{
DBG( "'c' read");
char dummy;
if (SKIP == false)
{
char *c = (char *) va_arg( *args, char* );
if (in->readmaxlength==-1)
{
dummy = __scanf_peek( in );
if (dummy==EOF) return EOF;
else
{
*c = __scanf_in( in );
}
}
else
{
for( int u = 0; u < in->readmaxlength; u++ )
{
dummy = __scanf_peek( in );
if (dummy==EOF) return EOF;
else
{
*c++ = __scanf_in( in );
}
}
}
}
else
{
if (in->readmaxlength==-1)
{
dummy = __scanf_peek( in );
if (dummy==EOF) return EOF;
else
{
__scanf_in( in );
goto endcharskip;
}
}
else
{
for( int u = 0; u < in->readmaxlength; u++ )
{
dummy = __scanf_peek( in );
if (dummy==EOF) return EOF;
else __scanf_in( in );
}
goto endcharskip;
}
}
VALIDRETS++;
endcharskip:
break;
}
case 's':
{
DBG( "'s' read");
__purge_space( in );
char dummy;
int curstrlength = 0;
if (SKIP == false)
{
char *c = (char *) va_arg( *args, char* );
if (in->readmaxlength==-1)
{
loopstring:
dummy = __scanf_peek( in );
if (dummy==EOF && curstrlength==0) return VALIDRETS;
if (isspace(dummy) || ( (dummy==EOF && curstrlength!=0) ))
{
*c = 0;
goto loopstringend;
}
else
{
*c++ = __scanf_in( in );
curstrlength++;
goto loopstring;
}
}
else
{
for( int u = 0; u < in->readmaxlength; u++ )
{
dummy = __scanf_peek( in );
if (dummy==EOF && curstrlength==0) return VALIDRETS;
if (isspace(dummy) || ( (dummy==EOF && curstrlength!=0) ))
{
*c = 0;
goto loopstringend;
}
else
{
*c++ = __scanf_in( in );
curstrlength++;
}
}
}
}
else
{
if (in->readmaxlength==-1)
{
loopstringskip:
dummy = __scanf_peek( in );
if (dummy==EOF && curstrlength==0) return VALIDRETS;
if (isspace(dummy) || ( (dummy==EOF && curstrlength!=0) ))
{
goto loopstringendskip;
}
else
{
__scanf_in( in );
curstrlength++;
goto loopstringskip;
}
}
else
{
for( int u = 0; u < in->readmaxlength; u++ )
{
dummy = __scanf_peek( in );
if (dummy==EOF && curstrlength==0) return VALIDRETS;
if (isspace(dummy) || ( (dummy==EOF && curstrlength!=0) ))
{
goto loopstringendskip;
}
else
{
__scanf_in( in );
curstrlength++;
}
}
}
}
loopstringend:
VALIDRETS++;
loopstringendskip:
break;
}
}
}
else // we are looking for a specific character in the input stream
{
if( format[pos] == __scanf_peek( in )) // if the next char of the stream is corresponding, we validate the read and go to the following char
{
__scanf_in( in );
pos++; // TODO : check if VALIDRETS needs to be incremented
}
return VALIDRETS; // else we return the number of valid read
}
pos++;
}
__scanf_end( in );
return VALIDRETS;
/*
int i=0;
int ret = 0;
int err = 0;
int mod = MODNORMAL;
int length = 0;
in->readsofar = 0;
in->readmaxlength = -1;
in->purgewhitespace = false;
in->skip = false;
__scanf_start( in );
while( format[i]!= '\0' )
{
in->readmaxlength = -1;
mod = MODNORMAL;
length = 0;
if ( format[i] == '%' ) {// read conversion
loopagain:
i++;
switch( format[i] ) {
case '*': {
in->skip = true;
goto loopagain;
}
case 'h': { // we start with MODNORMAL and decrease the length first to MODSHORT and after to MODSHORTSHORT
if(mod==MODNORMAL || mod==MODSHORT) {
mod--;
goto loopagain;
}
return ret; // we cannot have %hhh
}
case 'l': { // we start with MODNORMAL and decrease the length first to MODLONG and after to MODLONGLONG
if(mod==MODNORMAL || mod==MODLONG) {
mod++;
goto loopagain;
}
return ret; // we cannot have %lll
}
case 'L': // idem, but only for Double and limiter only to MODLONG (no long long double available)
{
if (mod==MODNORMAL) {
mod=MODLONGDOUBLE;
goto loopagain;
}
return ret; // we cannot have %LL
}
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9': {
length = length * 10 + (int) ( format[i] - '0' );
in->readmaxlength = length;
goto loopagain;
}
case '%': {
char c = __scanf_peek( in );
if (c=='%') __scanf_in( in );
else return ret;
// Nothing to do this is just the character '%'
in->readmaxlength = -1;
in->purgewhitespace = false;
in->skip = false;
break;
}
case 'c': {
// read a char from the current input stream
// and store in the corresponding arg as a char by reference
char *c = (char *) va_arg( *args, char* );
if (in->readmaxlength==-1) {
if (in->skip==false) *c = __scanf_in( in );
else __scanf_in( in );
}
else {
for(int u = 0; u < in->readmaxlength; u++ ) {
if (in->skip==false) {
*c = __scanf_in( in );
c++;
}
else __scanf_in( in );
}
}
in->readmaxlength=-1;
in->skip = false;
ret++;
break;
}
case 'd': {
// read a long int (in base 10 - decimal) from the current input stream
// and store in the corresponding arg as a char by reference
in->purgewhitespace = false;
long long int temp;
err = __strto_int( in, 10, NULL, &temp, false ); // base is 10 as for strtol
if (err == 0) {
if (in->skip==false) __scanf_store_i( temp, mod, args );
else __scanf_store_i( temp, MODSKIP, args );
in->skip = false;
mod = MODNORMAL;
ret++;
}
else return ret;
break;
}
case 'i': {
// read a long int (in base determined by the first character) from the current input stream
// and store in the corresponding arg as a char by reference
in->purgewhitespace = false;
long long int temp;
err = __strto_int( in, 0, NULL, &temp, false ); // base is 0 as for strtol
if (err == 0) {
if (in->skip==false) __scanf_store_i( temp, mod, args );
else __scanf_store_i( temp, MODSKIP, args );
in->skip = false;
mod = MODNORMAL;
ret++;
}
else return ret;
break;
}
case 'u': {
// read a unsigned long int (in base 10 - decimal) from the current input stream
// and store in the corresponding arg as a char by reference
in->purgewhitespace = false;
long long int temp;
err = __strto_int( in, 10, NULL, &temp, true ); // base is 10 as for strtol
if (err == 0) {
if (in->skip==false) __scanf_store_i( temp, mod, args );
else __scanf_store_i( temp, MODSKIP, args );
in->skip = false;
mod = MODNORMAL;
ret++;
}
else return ret;
break;
}
case 'o': {
// read a unsigned long int (in base 8 - octal) from the current input stream
// and store in the corresponding arg as a char by reference
in->purgewhitespace = false;
long long int temp;
err = __strto_int( in, 8, NULL, &temp, true ); // base is 8 as for strtol
if (err == 0) {
if (in->skip==false) __scanf_store_i( temp, mod, args );
else __scanf_store_i( temp, MODSKIP, args );
in->skip = false;
mod = MODNORMAL;
ret++;
}
else return ret;
break;
}
case 'x':
case 'X': {
// read a unsigned long int (in base 16 - hexadecimal) from the current input stream
// and store in the corresponding arg as a char by reference
in->purgewhitespace = false;
long long int temp;
err = __strto_int( in, 16, NULL, &temp, true ); // base is 16 as for strtol
if (err == 0) {
if (in->skip==false) __scanf_store_i( temp, mod, args );
else __scanf_store_i( temp, MODSKIP, args );
in->skip = false;
mod = MODNORMAL;
ret++;
}
else return ret;
break;
}
case 'a':
case 'A':
case 'e':
case 'E':
case 'f':
case 'F':
case 'g':
case 'G': {
in->purgewhitespace = false;
long double temp;
err = __strto_fp( in, NULL, NULL, &temp );
if (err == 0) {
if (in->skip==false) __scanf_store_d( temp, mod, args );
else __scanf_store_d( temp, MODSKIP, args );
in->skip = false;
mod = MODNORMAL;
ret++;
}
else return ret;
break;
}
case 's': {
__purge_space( in );
in->purgewhitespace=false;
// read a serie of non whitespace char from the current input stream
// and store in the corresponding arg as a char by reference
char *c = (char *) va_arg( *args, char* );
char temp;
if (in->readmaxlength==-1) // read the maximum number of non-whitespace characters
{
for(;;)
{
if (in->readmaxlength==-1) { // read the maximum number of non-whitespace characters
for(;;) {
temp = __scanf_peek( in );
if (!isspace(temp) && temp != EOF)
{
*c = __scanf_in( in );
c++;
if (!isspace(temp) && temp != EOF) {
if (in->skip == false ) {
*c = __scanf_in( in );
c++;
}
else __scanf_in( in );
}
else break;
}
*c = '\0'; // add the mandatory terminal '\0'
}
else
{
for(int u = 0; u < in->readmaxlength; u++ )
{
else {
for(int u = 0; u < in->readmaxlength; u++ ) {
temp = __scanf_peek( in );
if (!isspace(temp) && temp != EOF)
{
*c = __scanf_in( in );
c++;
if (!isspace(temp) && temp != EOF) {
if (in->skip == false ) {
*c = __scanf_in( in );
c++;
}
else __scanf_in( in );
}
else break;
}
@ -391,32 +844,45 @@ int __scanf(
break;
}
case 'n':
{
// rreturn the number of characters read so far
case 'n': {
in->purgewhitespace = false;
// return the number of characters read so far
int *n = (int *) va_arg( *args, int* );
*n = in->readsofar;
// TODO: need to chack if the '%n' with a valid results counts for the return of scanf()
ret++;
break;
}
case 'p':
{
void *p = (void *) va_arg( *args, void** ); // get the adress of the target pointer (void**)
err = __strto_int( in, 0, p, NULL, true );
case 'p': {
in->purgewhitespace = false;
long int dummy;
if (in->skip == false) {
void *p = (void *) va_arg( *args, void** ); // get the adress of the target pointer (void**)
err = __strto_int( in, 0, p, NULL, true );
}
else err = __strto_int( in, 0, &dummy, NULL, true );
if (err == 0) ret++;
else return ret;
in->skip = false;
break;
}
}
}
else i++;
else
{
if (format[i] == __scanf_in( in )) i++;
else err=1;
}
if (err!=0) break; // an error occured somewhere whiloe parsing the values
if (err!=0) break; // an ERROR occured somewhere whiloe parsing the values
}
__scanf_end( in );
return ret;
*/
}