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