Add scanf(3) %n support.
This commit is contained in:
parent
0e78aec1c3
commit
0756a7ee96
|
@ -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:
|
||||||
|
|
Loading…
Reference in New Issue