#include #include #include #include void __scanf_start(struct __scanf_input *in) { if(in->fp) in->buffer = fgetc(in->fp); else { in->buffer = *in->str; in->str += (in->buffer != 0); } } int __scanf_fetch(struct __scanf_input *in) { if(in->fp) return fgetc(in->fp); int c = *in->str; if(c == 0) return EOF; in->str++; return c; } void __scanf_end(struct __scanf_input *in) { if(in->buffer == EOF) return; if(in->fp) ungetc(in->buffer, in->fp); else in->str--; } enum { MODSHORTSHORT, MODSHORT, MODNORMAL, MODLONG, MODLONGLONG, MODLONGDOUBLE, }; void __scanf_store_i(int64_t value, int size, va_list *args) { if(size == MODSHORTSHORT) *va_arg(*args, int8_t *) = value; else if(size == MODSHORT) *va_arg(*args, int16_t *) = value; else if(size == MODLONGLONG) *va_arg(*args, int64_t *) = value; else *va_arg(*args, int *) = value; } void __scanf_store_d(long double value, int size, va_list *args) { if(size == MODLONG) *va_arg(*args, double *) = value; else if(size == MODLONGDOUBLE) *va_arg(*args, long double *) = value; else *va_arg(*args, float *) = value; } /* STATUS OF __scanf DEVELOPMENT */ // XX = not done yet (but will be done) // OK = OK, done and tested // -- = not applicable // NO = not supported (and will not be done) /*************************************************************************************************************/ /* Specifier * Explanation * num * hh * h *none* l * ll * j * z * t * L */ /*************************************************************************************************************/ /* % * Parse literal '%' * -- * -- * -- * OK * -- * -- * -- * -- * -- * -- */ /*************************************************************************************************************/ /* c * match a char or several char * OK * -- * -- * OK * NO * -- * -- * -- * -- * -- */ /*************************************************************************************************************/ /* s * match a string * OK * -- * -- * OK * NO * -- * -- * -- * -- * -- */ /*************************************************************************************************************/ /* [set] * match a set of char * XX * -- * -- * XX * NO * -- * -- * -- * -- * -- */ /*************************************************************************************************************/ /* d * match a decimal integer * OK * OK * OK * OK * OK * OK * XX * XX * XX * -- */ /*************************************************************************************************************/ /* i * match an integer * OK * OK * OK * OK * OK * OK * XX * XX * XX * -- */ /*************************************************************************************************************/ /* d * match an unsigned decimal integer * OK * OK * OK * OK * OK * OK * XX * XX * XX * -- */ /*************************************************************************************************************/ /* o * match a unsigned octal integer * OK * OK * OK * OK * OK * OK * XX * XX * XX * -- */ /*************************************************************************************************************/ /* x,X * match a unsigned hexadecimal integer * OK * OK * OK * OK * OK * OK * XX * XX * XX * -- */ /*************************************************************************************************************/ /* d * match a decimal integer * OK * OK * OK * OK * OK * OK * XX * XX * XX * -- */ /*************************************************************************************************************/ /* n * return the nb of chars read so far * -- * -- * -- * OK * -- * -- * -- * -- * -- * -- */ /*************************************************************************************************************/ /* a,A * match a floating point number * OK * -- * -- * OK * OK * -- * -- * -- * -- * OK */ /* e,E * match a floating point number * OK * -- * -- * OK * OK * -- * -- * -- * -- * OK */ /* f,F * match a floating point number * OK * -- * -- * OK * OK * -- * -- * -- * -- * OK */ /* g,G * match a floating point number * OK * -- * -- * OK * OK * -- * -- * -- * -- * OK */ /*************************************************************************************************************/ /* p * mathc a pointer * -- * -- * -- * OK * -- * -- * -- * -- * -- * -- */ /*************************************************************************************************************/ // TODO : add the support of in->readsofar into strto_fp(...) and str_to_int(...) // to be able to get correct '%n' returned value 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; in->readsofar = 0; in->readmaxlength = -1; __scanf_start( in ); while( format[i]!=0 ) { in->readmaxlength = -1; 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] ) { case 'h': // we start with MODNORMAL and decrease the length first to MODSHORT and after to MODSHORTSHORT { if(mod==MODNORMAL) { mod=MODSHORT; goto loopagain; } else if(mod==MODSHORT) { mod=MODSHORTSHORT; goto loopagain; } else { mod=MODNORMAL; break; // 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; goto loopagain; } else if(mod==MODLONG) { mod=MODLONGLONG; goto loopagain; } else { mod=MODNORMAL; break; // we cannot have %lll } } case 'L': // idem, but only for Double and limiter only to MODLONG (no long long double available) { mod=MODLONGDOUBLE; goto loopagain; } 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 '%': { // 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; } 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 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; } 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 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; } 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 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; } 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 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; } case 'a': case 'A': case 'e': case 'E': case 'f': case 'F': case 'g': case 'G': { long double temp; err = __strto_fp( in, NULL, NULL, &temp ); if (err == 0) { __scanf_store_d( temp, mod, args ); mod = MODNORMAL; ret++; } break; } case 's': { // 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(;;) { temp = __scanf_peek( in ); if (!isspace(temp) && temp != EOF) { *c = __scanf_in( in ); c++; } else break; } *c = '\0'; // add the mandatory terminal '\0' } else { for(int u = 0; u < in->readmaxlength; u++ ) { temp = __scanf_peek( in ); if (!isspace(temp) && temp != EOF) { *c = __scanf_in( in ); c++; } else break; } *c = '\0'; } in->readmaxlength=-1; ret++; break; } case 'n': { // rreturn 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 ); if (err == 0) ret++; break; } } } else i++; if (err!=0) break; // an error occured somewhere whiloe parsing the values } __scanf_end( in ); return ret; }