stdio: more syntaxic refactoring of scanf

This commit is contained in:
Lephenixnoir 2024-01-14 21:27:48 +01:00
parent 9f6e0c8039
commit 527c2e48fc
Signed by: Lephenixnoir
GPG Key ID: 1BBA026E13FC0495
1 changed files with 130 additions and 144 deletions

View File

@ -273,169 +273,155 @@ int __scanf(
char const * __restrict__ format,
va_list *args)
{
in->bytes_read = 0; // we haven't started to read char from the input stream
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 pos = 0; // current pos in the format string
/* Number of successful assignments */
int validrets = 0;
__scanf_start( in );
// TODO: No __scanf_end() in any of the "return validrets"!!
for(; format[pos]; pos++) {
for(int pos = 0; format[pos]; pos++) {
if(format[pos] == ' ') {
__purge_space(in);
continue;
}
else if(format[pos] != '%') {
// if the next char of the stream is corresponding, we validate the read and go to the following char
if(format[pos] == __scanf_peek( in )) {
__scanf_in( in );
pos++;
continue;
}
else return validrets; // else we return the number of valid read
}
else if(format[pos + 1] == '%') {
if(__scanf_peek(in) != '%') return validrets;
else __scanf_in( in );
pos++;
else if(format[pos] != '%' || format[pos + 1] == '%') {
/* Expect this specific character */
if(__scanf_peek(in) != format[pos])
return validrets;
__scanf_in(in);
pos += (format[pos] == '%');
continue;
}
/* Perform a conversion */
else {
struct scanf_format opt;
int spec = parse_fmt(format, &pos, &opt);
if(spec == 0)
struct scanf_format opt;
int spec = parse_fmt(format, &pos, &opt);
if(spec == 0)
return validrets;
switch(spec) {
// we need to decrypt the corresponding scanf set of character
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; u<opt.field_width; u++) {
int temp = __scanf_peek(in);
if(bracket_set_test(opt.bracket_set, temp)) {
__scanf_in(in);
if(c) *c++ = temp;
currentlength++;
}
else if(temp==EOF && !currentlength && !validrets)
return EOF;
else break;
}
if(!currentlength)
return validrets;
*c = '\0';
validrets += !opt.skip;
break;
}
switch(spec) {
// we need to decrypt the corresponding scanf set of character
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; u<opt.field_width; u++) {
int temp = __scanf_peek(in);
if(bracket_set_test(opt.bracket_set, temp)) {
__scanf_in(in);
if(c) *c++ = temp;
currentlength++;
// return the number of char read so far (cannot be skipped %*n is not valid)
case 'n':
*va_arg(*args, int *) = in->bytes_read;
break;
case 'd':
case 'i':
case 'o':
case 'u':
case 'x':
case 'X': {
int f = format[pos];
int base = (f == 'd' || f == 'u') ? 10 :
(f == 'o') ? 8:
(f == 'x' || f == 'X') ? 16 : 0;
bool use_unsigned = (f == 'o' || f == 'x' || f == 'X');
long long int temp;
int err = __strto_int(in, base, NULL, &temp, use_unsigned,
opt.field_width);
if(err == EOF && validrets == 0) return EOF;
if(err) return validrets;
if(!opt.skip)
__scanf_store_i(temp, opt.size, args);
validrets++;
break;
}
case 'a':
case 'A':
case 'e':
case 'E':
case 'f':
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;
if(err) return validrets;
if(!opt.skip)
__scanf_store_d(temp, opt.size, args);
validrets++;
break;
}
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);
if(err) return validrets;
break;
}
case 'c': {
char *c = opt.skip ? NULL : va_arg(*args, char *);
for(int u = 0; u < opt.field_width; u++) {
int temp = __scanf_in(in);
if(temp==EOF) return EOF;
else if(c) *c++ = temp;
}
validrets += !opt.skip;
break;
}
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))) {
if(c) {
*c = 0;
validrets++;
}
else if(temp==EOF && !currentlength && !validrets)
return EOF;
else break;
break;
}
if(!currentlength)
return validrets;
*c = '\0';
validrets += !opt.skip;
break;
}
// return the number of char read so far (cannot be skipped %*n is not valid)
case 'n':
*va_arg(*args, int *) = in->bytes_read;
break;
case 'd':
case 'i':
case 'o':
case 'u':
case 'x':
case 'X': {
int f = format[pos];
int base = (f == 'd' || f == 'u') ? 10 :
(f == 'o') ? 8:
(f == 'x' || f == 'X') ? 16 : 0;
bool use_unsigned = (f == 'o' || f == 'x' || f == 'X');
long long int temp;
err = __strto_int(in, base, NULL, &temp, use_unsigned,
opt.field_width);
if (err == EOF && validrets == 0) return EOF;
if (err != 0) return validrets;
if(!opt.skip)
__scanf_store_i( temp, opt.size, args );
validrets++;
break;
}
case 'a':
case 'A':
case 'e':
case 'E':
case 'f':
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,
opt.field_width);
if (err == EOF && validrets == 0) return EOF;
if (err != 0) return validrets;
if(!opt.skip)
__scanf_store_d( temp, opt.size, args );
validrets++;
break;
}
case 'p': {
long int temp;
if (!opt.skip) {
void *p = (void *) va_arg( *args, void** ); // get the adress of the target pointer (void**)
err = __strto_int( in, 0, p, NULL, true,
opt.field_width);
}
else err = __strto_int( in, 0, &temp, NULL, true,
opt.field_width);
if (err == 0) validrets++;
else return validrets;
break;
}
case 'c': {
char *c = opt.skip ? NULL : va_arg(*args, char *);
for(int u = 0; u < opt.field_width; u++) {
else {
int temp = __scanf_in(in);
if(temp==EOF) return EOF;
else if(c) *c++ = temp;
if(c)
*c++ = temp;
curstrlength++;
}
validrets += !opt.skip;
break;
}
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))) {
if(c) {
*c = 0;
validrets++;
}
break;
}
else {
int temp = __scanf_in( in );
if(c)
*c++ = temp;
curstrlength++;
}
}
break;
}
}
break;
}
}
}