Add scanf(3) %n support.

This commit is contained in:
Jonas 'Sortie' Termansen 2016-09-23 14:21:22 +02:00
parent 0e78aec1c3
commit 0756a7ee96
1 changed files with 37 additions and 1 deletions

View File

@ -19,6 +19,7 @@
#include <ctype.h> #include <ctype.h>
#include <errno.h> #include <errno.h>
#include <limits.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h> #include <stddef.h>
@ -33,6 +34,7 @@ enum scanmode
MODE_SCANINT_REAL, MODE_SCANINT_REAL,
MODE_SCANSTRING, MODE_SCANSTRING,
MODE_SCANSTRING_REAL, MODE_SCANSTRING_REAL,
MODE_SCANREPORT,
}; };
enum scantype enum scantype
@ -91,11 +93,14 @@ int vscanf_callback(void* fp,
size_t strwritten = 0; size_t strwritten = 0;
char* strdest = NULL; char* strdest = NULL;
char convc; char convc;
int bytesparsed = 0;
enum scantype scantype = TYPE_INT; enum scantype scantype = TYPE_INT;
enum scanmode scanmode = MODE_INIT; enum scanmode scanmode = MODE_INIT;
while ( true ) while ( true )
{ {
ic = fgetc(fp); ic = fgetc(fp);
if ( ic != EOF && bytesparsed != INT_MAX )
bytesparsed++;
unsigned char uc = ic; char c = uc; unsigned char uc = ic; char c = uc;
switch (scanmode) switch (scanmode)
{ {
@ -103,6 +108,8 @@ int vscanf_callback(void* fp,
if ( !*format ) if ( !*format )
{ {
ungetc(ic, fp); ungetc(ic, fp);
if ( ic != EOF )
bytesparsed--;
goto break_loop; goto break_loop;
} }
if ( isspace((unsigned char) *format) ) if ( isspace((unsigned char) *format) )
@ -118,10 +125,18 @@ int vscanf_callback(void* fp,
format++; format++;
scanmode = MODE_CONVSPEC; scanmode = MODE_CONVSPEC;
ungetc(ic, fp); ungetc(ic, fp);
if ( ic != EOF )
bytesparsed--;
continue; continue;
} }
escaped = false; escaped = false;
if ( *format != c ) { ungetc(ic, fp); goto break_loop; } if ( *format != c )
{
ungetc(ic, fp);
if ( ic != EOF )
bytesparsed--;
goto break_loop;
}
format++; format++;
break; break;
case MODE_CONVSPEC: case MODE_CONVSPEC:
@ -170,8 +185,12 @@ int vscanf_callback(void* fp,
string = false; scanmode = MODE_SCANSTRING; break; string = false; scanmode = MODE_SCANSTRING; break;
case 's': case 's':
string = true; scanmode = MODE_SCANSTRING; break; string = true; scanmode = MODE_SCANSTRING; break;
case 'n':
scanmode = MODE_SCANREPORT; break;
} }
ungetc(ic, fp); ungetc(ic, fp);
if ( ic != EOF )
bytesparsed--;
continue; continue;
case MODE_SCANINT: case MODE_SCANINT:
intparsed = 0; intparsed = 0;
@ -229,12 +248,17 @@ int vscanf_callback(void* fp,
if ( !intparsed ) if ( !intparsed )
{ {
while ( undoable ) while ( undoable )
{
ungetc(undodata[--undoable], fp); ungetc(undodata[--undoable], fp);
bytesparsed--;
}
goto break_loop; goto break_loop;
} }
scanmode = MODE_INIT; scanmode = MODE_INIT;
undoable = 0; undoable = 0;
ungetc(ic, fp); ungetc(ic, fp);
if ( ic != EOF )
bytesparsed--;
if ( discard ) { discard = false; continue; } if ( discard ) { discard = false; continue; }
uintmax_t uintmaxval = intvalue; uintmax_t uintmaxval = intvalue;
// TODO: Possible truncation of INTMAX_MIN! // TODO: Possible truncation of INTMAX_MIN!
@ -294,6 +318,8 @@ int vscanf_callback(void* fp,
(ic == EOF || isspace(ic) || strwritten == fieldwidth) ) (ic == EOF || isspace(ic) || strwritten == fieldwidth) )
{ {
ungetc(ic, fp); ungetc(ic, fp);
if ( ic != EOF )
bytesparsed--;
if ( !discard ) if ( !discard )
strdest[strwritten] = '\0'; strdest[strwritten] = '\0';
matcheditems++; matcheditems++;
@ -303,6 +329,8 @@ int vscanf_callback(void* fp,
if ( !string && strwritten == fieldwidth ) if ( !string && strwritten == fieldwidth )
{ {
ungetc(ic, fp); ungetc(ic, fp);
if ( ic != EOF )
bytesparsed--;
scanmode = MODE_INIT; scanmode = MODE_INIT;
continue; continue;
} }
@ -311,6 +339,14 @@ int vscanf_callback(void* fp,
if ( !discard ) if ( !discard )
strdest[strwritten++] = c; strdest[strwritten++] = c;
continue; continue;
case MODE_SCANREPORT:
ungetc(ic, fp);
if ( ic != EOF )
bytesparsed--;
if ( !discard )
*va_arg(ap, int*) = bytesparsed;
scanmode = MODE_INIT;
continue;
} }
} }
break_loop: break_loop: