mirror of
https://github.com/cc65/cc65.git
synced 2024-09-30 08:57:49 +00:00
Rewrote _scanf. It does need some tests and improvements, but it's a more
standard version than before, and it does support the necessary functionality to support scanf functions for files. Added vfscanf, fscanf and vfscanf. git-svn-id: svn://svn.cc65.org/cc65/trunk@3301 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
parent
e35b91ed3b
commit
b1d4e1613b
@ -14,6 +14,7 @@ fgets.s
|
|||||||
fputc.s
|
fputc.s
|
||||||
fputs.s
|
fputs.s
|
||||||
freopen.s
|
freopen.s
|
||||||
|
fscanf.s
|
||||||
fseek.s
|
fseek.s
|
||||||
fsetpos.s
|
fsetpos.s
|
||||||
ftell.s
|
ftell.s
|
||||||
@ -28,6 +29,7 @@ puts.s
|
|||||||
qsort.s
|
qsort.s
|
||||||
realloc.s
|
realloc.s
|
||||||
rewind.s
|
rewind.s
|
||||||
|
scanf.s
|
||||||
sleep.s
|
sleep.s
|
||||||
sscanf.s
|
sscanf.s
|
||||||
strftime.s
|
strftime.s
|
||||||
@ -35,4 +37,7 @@ strtok.s
|
|||||||
strxfrm.s
|
strxfrm.s
|
||||||
system.s
|
system.s
|
||||||
timezone.s
|
timezone.s
|
||||||
|
vfscanf.s
|
||||||
vsscanf.s
|
vsscanf.s
|
||||||
|
|
||||||
|
|
||||||
|
@ -44,6 +44,7 @@ C_OBJS = _afailed.o \
|
|||||||
fputc.o \
|
fputc.o \
|
||||||
fputs.o \
|
fputs.o \
|
||||||
freopen.o \
|
freopen.o \
|
||||||
|
fscanf.o \
|
||||||
fseek.o \
|
fseek.o \
|
||||||
fsetpos.o \
|
fsetpos.o \
|
||||||
ftell.o \
|
ftell.o \
|
||||||
@ -58,6 +59,7 @@ C_OBJS = _afailed.o \
|
|||||||
qsort.o \
|
qsort.o \
|
||||||
realloc.o \
|
realloc.o \
|
||||||
rewind.o \
|
rewind.o \
|
||||||
|
scanf.o \
|
||||||
sleep.o \
|
sleep.o \
|
||||||
sscanf.o \
|
sscanf.o \
|
||||||
strftime.o \
|
strftime.o \
|
||||||
@ -65,6 +67,7 @@ C_OBJS = _afailed.o \
|
|||||||
strtok.o \
|
strtok.o \
|
||||||
system.o \
|
system.o \
|
||||||
timezone.o \
|
timezone.o \
|
||||||
|
vfscanf.o \
|
||||||
vsscanf.o
|
vsscanf.o
|
||||||
|
|
||||||
|
|
||||||
|
@ -39,19 +39,18 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
static struct indesc* D; /* Copy of function argument */
|
static struct scanfdata* D; /* Copy of function argument */
|
||||||
static va_list ap; /* Copy of function argument */
|
static va_list ap; /* Copy of function argument */
|
||||||
static jmp_buf JumpBuf; /* Label that is used in case of EOF */
|
static jmp_buf JumpBuf; /* Label that is used in case of EOF */
|
||||||
static char C; /* Character from input */
|
static int C; /* Character from input */
|
||||||
static unsigned Width; /* Maximum field width */
|
static unsigned Width; /* Maximum field width */
|
||||||
static long IntVal; /* Converted int value */
|
static long IntVal; /* Converted int value */
|
||||||
static unsigned Conversions; /* Number of conversions */
|
static unsigned Conversions; /* Number of conversions */
|
||||||
|
static unsigned char IntBytes; /* Number of bytes-1 for int conversions */
|
||||||
|
|
||||||
/* Flags */
|
/* Flags */
|
||||||
static unsigned char Positive; /* Flag for positive value */
|
static unsigned char Positive; /* Flag for positive value */
|
||||||
static unsigned char NoAssign; /* Supppress assigment */
|
static unsigned char NoAssign; /* Supppress assigment */
|
||||||
static unsigned char IsShort; /* Short type */
|
|
||||||
static unsigned char IsLong; /* Long type */
|
|
||||||
static unsigned char Invert; /* Do we need to invert the charset? */
|
static unsigned char Invert; /* Do we need to invert the charset? */
|
||||||
static unsigned char CharSet[32]; /* 32 * 8 bits = 256 bits */
|
static unsigned char CharSet[32]; /* 32 * 8 bits = 256 bits */
|
||||||
static const unsigned char Bits[8] = {
|
static const unsigned char Bits[8] = {
|
||||||
@ -128,9 +127,22 @@ static void InvertCharSet (void)
|
|||||||
static void ReadChar (void)
|
static void ReadChar (void)
|
||||||
/* Get an input character, count characters */
|
/* Get an input character, count characters */
|
||||||
{
|
{
|
||||||
C = D->fin (D);
|
C = D->get (D->data);
|
||||||
|
if (C != EOF) {
|
||||||
++D->ccount;
|
++D->ccount;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void ReadCharWithCheck (void)
|
||||||
|
/* Get an input char, use longjmp in case of EOF */
|
||||||
|
{
|
||||||
|
ReadChar ();
|
||||||
|
if (C == EOF) {
|
||||||
|
longjmp (JumpBuf, RC_EOF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -171,33 +183,12 @@ static unsigned char HexVal (char C)
|
|||||||
if (isdigit (C)) {
|
if (isdigit (C)) {
|
||||||
return C - '0';
|
return C - '0';
|
||||||
} else {
|
} else {
|
||||||
return C - toupper (C) + ('A' + 10);
|
return toupper (C) - ('A' - 10);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void ReadInt (unsigned char Base)
|
|
||||||
/* Read an integer and store it into IntVal */
|
|
||||||
{
|
|
||||||
/* Value must start with a digit */
|
|
||||||
if (!isdigit (C)) {
|
|
||||||
longjmp (JumpBuf, RC_NOCONV);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Read the value */
|
|
||||||
IntVal = 0;
|
|
||||||
while (isxdigit (C) && Width-- > 0) {
|
|
||||||
IntVal = IntVal * Base + HexVal (C);
|
|
||||||
ReadChar ();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* One more conversion */
|
|
||||||
++Conversions;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void AssignInt (void)
|
static void AssignInt (void)
|
||||||
/* Assign the integer value in Val to the next argument. The function makes
|
/* Assign the integer value in Val to the next argument. The function makes
|
||||||
* several non portable assumptions to reduce code size:
|
* several non portable assumptions to reduce code size:
|
||||||
@ -216,10 +207,7 @@ static void AssignInt (void)
|
|||||||
asm ("stx ptr1+1");
|
asm ("stx ptr1+1");
|
||||||
|
|
||||||
/* Get the number of bytes-1 to copy */
|
/* Get the number of bytes-1 to copy */
|
||||||
asm ("ldy #3");
|
asm ("ldy %v", IntBytes);
|
||||||
asm ("lda %v", IsLong);
|
|
||||||
asm ("bne L1");
|
|
||||||
asm ("ldy #1");
|
|
||||||
|
|
||||||
/* Assign the integer value */
|
/* Assign the integer value */
|
||||||
asm ("L1: lda %v,y", IntVal);
|
asm ("L1: lda %v,y", IntVal);
|
||||||
@ -232,7 +220,80 @@ static void AssignInt (void)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
int _scanf (struct indesc* D_, register const char* format, va_list ap_)
|
static unsigned char ReadInt (unsigned char Base)
|
||||||
|
/* Read an integer and store it into IntVal. Returns the number of chars
|
||||||
|
* converted. Does NOT bump Conversions.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
unsigned char Val;
|
||||||
|
unsigned char CharCount = 0;
|
||||||
|
|
||||||
|
/* Read the integer value */
|
||||||
|
IntVal = 0;
|
||||||
|
while (isxdigit (C) && Width-- > 0 && (Val = HexVal (C)) < Base) {
|
||||||
|
++CharCount;
|
||||||
|
IntVal = IntVal * Base + Val;
|
||||||
|
ReadChar ();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we didn't convert anything, it's an error */
|
||||||
|
if (CharCount == 0) {
|
||||||
|
longjmp (JumpBuf, RC_NOCONV);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return the number of characters converted */
|
||||||
|
return CharCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void ScanInt (unsigned char Base)
|
||||||
|
/* Scan an integer including white space, sign and optional base spec,
|
||||||
|
* and store it into IntVal.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
/* Skip whitespace */
|
||||||
|
SkipWhite ();
|
||||||
|
|
||||||
|
/* Read an optional sign */
|
||||||
|
ReadSign ();
|
||||||
|
|
||||||
|
/* If Base is unknown (zero), figure it out */
|
||||||
|
if (Base == 0) {
|
||||||
|
if (C == '0') {
|
||||||
|
ReadChar ();
|
||||||
|
switch (C) {
|
||||||
|
case 'x':
|
||||||
|
case 'X':
|
||||||
|
Base = 16;
|
||||||
|
ReadChar ();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Base = 8;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Base = 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read the integer value */
|
||||||
|
ReadInt (Base);
|
||||||
|
|
||||||
|
/* Apply the sign */
|
||||||
|
if (!Positive) {
|
||||||
|
IntVal = -IntVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Assign the value to the next argument unless suppressed */
|
||||||
|
AssignInt ();
|
||||||
|
|
||||||
|
/* One more conversion */
|
||||||
|
++Conversions;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int _scanf (struct scanfdata* D_, register const char* format, va_list ap_)
|
||||||
/* This is the routine used to do the actual work. It is called from several
|
/* This is the routine used to do the actual work. It is called from several
|
||||||
* types of wrappers to implement the actual ISO xxscanf functions.
|
* types of wrappers to implement the actual ISO xxscanf functions.
|
||||||
*/
|
*/
|
||||||
@ -240,7 +301,6 @@ int _scanf (struct indesc* D_, register const char* format, va_list ap_)
|
|||||||
char F; /* Character from format string */
|
char F; /* Character from format string */
|
||||||
unsigned char Result; /* setjmp result */
|
unsigned char Result; /* setjmp result */
|
||||||
char* S;
|
char* S;
|
||||||
unsigned char Base; /* Integer base in %i */
|
|
||||||
unsigned char HaveWidth; /* True if a width was given */
|
unsigned char HaveWidth; /* True if a width was given */
|
||||||
char Start; /* Start of range */
|
char Start; /* Start of range */
|
||||||
|
|
||||||
@ -279,25 +339,25 @@ Again:
|
|||||||
/* Check for a match */
|
/* Check for a match */
|
||||||
if (isspace (F)) {
|
if (isspace (F)) {
|
||||||
|
|
||||||
/* Special white space handling: Any whitespace matches
|
/* Special white space handling: Any whitespace in the
|
||||||
* any amount of whitespace including none(!). So this
|
* format string matches any amount of whitespace including
|
||||||
* match will never fail.
|
* none(!). So this match will never fail.
|
||||||
*/
|
*/
|
||||||
SkipWhite ();
|
SkipWhite ();
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
} else if (F != C) {
|
} else if (F == C) {
|
||||||
|
|
||||||
|
/* A match. Read the next input character and start over */
|
||||||
|
goto Again;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
/* A mismatch. We will stop scanning the input and return
|
/* A mismatch. We will stop scanning the input and return
|
||||||
* the number of conversions.
|
* the number of conversions.
|
||||||
*/
|
*/
|
||||||
return Conversions;
|
return Conversions;
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
/* A match. Read the next input character and start over */
|
|
||||||
goto Again;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@ -305,15 +365,17 @@ Again:
|
|||||||
/* A conversion. Skip the percent sign. */
|
/* A conversion. Skip the percent sign. */
|
||||||
F = *format++;
|
F = *format++;
|
||||||
|
|
||||||
/* Initialize variables */
|
/* 1. Assignment suppression */
|
||||||
|
if (F == '*') {
|
||||||
|
F = *format++;
|
||||||
|
NoAssign = 1;
|
||||||
|
} else {
|
||||||
NoAssign = 0;
|
NoAssign = 0;
|
||||||
IsShort = 0;
|
}
|
||||||
IsLong = 0;
|
|
||||||
|
/* 2. Maximum field width */
|
||||||
Width = UINT_MAX;
|
Width = UINT_MAX;
|
||||||
HaveWidth = 0;
|
HaveWidth = 0;
|
||||||
|
|
||||||
/* Check for flags. */
|
|
||||||
while (1) {
|
|
||||||
if (isdigit (F)) {
|
if (isdigit (F)) {
|
||||||
HaveWidth = 1;
|
HaveWidth = 1;
|
||||||
Width = 0;
|
Width = 0;
|
||||||
@ -322,80 +384,63 @@ Again:
|
|||||||
Width = Width * 10 + (F & 0x0F);
|
Width = Width * 10 + (F & 0x0F);
|
||||||
F = *format++;
|
F = *format++;
|
||||||
} while (isdigit (F));
|
} while (isdigit (F));
|
||||||
} else {
|
}
|
||||||
|
|
||||||
|
/* 3. Length modifier */
|
||||||
|
IntBytes = sizeof(int) - 1;
|
||||||
switch (F) {
|
switch (F) {
|
||||||
case '*': NoAssign = 1; break;
|
case 'h':
|
||||||
case 'h': IsShort = 1; break;
|
if (*format == 'h') {
|
||||||
case 'l':
|
IntBytes = sizeof(char) - 1;
|
||||||
case 'L': IsLong = 1; break;
|
++format;
|
||||||
default: goto FlagsDone;
|
|
||||||
}
|
}
|
||||||
F = *format++;
|
F = *format++;
|
||||||
}
|
break;
|
||||||
}
|
|
||||||
FlagsDone:
|
|
||||||
|
|
||||||
/* Check for the actual conversion character */
|
case 'l':
|
||||||
|
if (*format == 'l') {
|
||||||
|
/* Treat long long as long */
|
||||||
|
++format;
|
||||||
|
}
|
||||||
|
/* FALLTHROUGH */
|
||||||
|
case 'j': /* intmax_t */
|
||||||
|
IntBytes = sizeof(long) - 1;
|
||||||
|
F = *format++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'z': /* size_t */
|
||||||
|
case 't': /* ptrdiff_t */
|
||||||
|
case 'L': /* long double - ignore this one */
|
||||||
|
F = *format++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 4. Conversion specifier */
|
||||||
switch (F) {
|
switch (F) {
|
||||||
|
|
||||||
case 'D':
|
/* 'd' and 'u' conversions are actually the same, since the
|
||||||
IsLong = 1;
|
* standard says that evene the 'u' modifier allows an
|
||||||
case 'd':
|
* optionally signed integer.
|
||||||
/* Optionally signed decimal integer */
|
*/
|
||||||
SkipWhite ();
|
case 'd': /* Optionally signed decimal integer */
|
||||||
ReadSign ();
|
case 'u':
|
||||||
ReadInt (10);
|
ScanInt (10);
|
||||||
if (!Positive) {
|
|
||||||
IntVal = -IntVal;
|
|
||||||
}
|
|
||||||
AssignInt ();
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'i':
|
case 'i':
|
||||||
/* Optionally signed integer with a base */
|
/* Optionally signed integer with a base */
|
||||||
SkipWhite ();
|
ScanInt (0);
|
||||||
ReadSign ();
|
|
||||||
if (C == '0') {
|
|
||||||
ReadChar ();
|
|
||||||
switch (C) {
|
|
||||||
case 'x':
|
|
||||||
case 'X':
|
|
||||||
Base = 16;
|
|
||||||
ReadChar();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
Base = 8;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Base = 10;
|
|
||||||
}
|
|
||||||
ReadInt (Base);
|
|
||||||
if (!Positive) {
|
|
||||||
IntVal = -IntVal;
|
|
||||||
}
|
|
||||||
AssignInt ();
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'o':
|
case 'o':
|
||||||
/* Unsigned octal integer */
|
/* Optionally signed octal integer */
|
||||||
SkipWhite ();
|
ScanInt (8);
|
||||||
ReadInt (8);
|
|
||||||
AssignInt ();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'u':
|
|
||||||
/* Unsigned decimal integer */
|
|
||||||
SkipWhite ();
|
|
||||||
ReadInt (10);
|
|
||||||
AssignInt ();
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'x':
|
case 'x':
|
||||||
case 'X':
|
case 'X':
|
||||||
/* Unsigned hexadecimal integer */
|
/* Optionally signed hexadecimal integer */
|
||||||
SkipWhite ();
|
ScanInt (16);
|
||||||
ReadInt (16);
|
|
||||||
AssignInt ();
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'E':
|
case 'E':
|
||||||
@ -435,12 +480,12 @@ FlagsDone:
|
|||||||
S = va_arg (ap, char*);
|
S = va_arg (ap, char*);
|
||||||
while (Width--) {
|
while (Width--) {
|
||||||
*S++ = C;
|
*S++ = C;
|
||||||
ReadChar ();
|
ReadCharWithCheck ();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Just skip as many chars as given */
|
/* Just skip as many chars as given */
|
||||||
while (Width--) {
|
while (Width--) {
|
||||||
ReadChar ();
|
ReadCharWithCheck ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
++Conversions;
|
++Conversions;
|
||||||
@ -526,8 +571,11 @@ FlagsDone:
|
|||||||
longjmp (JumpBuf, RC_NOCONV);
|
longjmp (JumpBuf, RC_NOCONV);
|
||||||
}
|
}
|
||||||
ReadChar ();
|
ReadChar ();
|
||||||
ReadInt (16);
|
if (ReadInt (16) != 4) { /* 4 chars expected */
|
||||||
|
longjmp (JumpBuf, RC_NOCONV);
|
||||||
|
}
|
||||||
AssignInt ();
|
AssignInt ();
|
||||||
|
++Conversions;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'n':
|
case 'n':
|
||||||
@ -542,20 +590,23 @@ FlagsDone:
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/* Skip the format char */
|
|
||||||
goto Again;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Push back the last unused character, provided it is not EOF */
|
||||||
|
if (C != EOF) {
|
||||||
|
D->unget (C, D->data);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (Result == RC_EOF) {
|
} else {
|
||||||
|
|
||||||
/* Jump via JumpBuf means EOF on input */
|
/* Jump via JumpBuf means an error. If this happens at EOF with no
|
||||||
if (D->ccount == 0) {
|
* conversions, it is considered an error, otherwise the number
|
||||||
|
* of conversions is returned (the default behaviour).
|
||||||
|
*/
|
||||||
|
if (C == EOF && D->ccount == 0) {
|
||||||
/* Special case: error */
|
/* Special case: error */
|
||||||
return -1;
|
Conversions = EOF;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -12,13 +12,11 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Forward */
|
|
||||||
struct indesc;
|
|
||||||
|
|
||||||
/* Type of the function that is called to input data. The function will
|
/* Type of the function that is called to input data. The function will
|
||||||
* return EOF if no more data is available.
|
* return EOF if no more data is available.
|
||||||
*/
|
*/
|
||||||
typedef char (*infunc) (struct indesc* desc);
|
typedef int __fastcall__ (*getfunc) (void* data);
|
||||||
|
typedef int __fastcall__ (*ungetfunc) (int c, void* data);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -26,21 +24,19 @@ typedef char (*infunc) (struct indesc* desc);
|
|||||||
* Beware: The low level functions will access the structure on the assembly
|
* Beware: The low level functions will access the structure on the assembly
|
||||||
* level, so check this when altering the structure.
|
* level, so check this when altering the structure.
|
||||||
*/
|
*/
|
||||||
struct indesc {
|
struct scanfdata {
|
||||||
infunc fin; /* Pointer to input routine */
|
getfunc get; /* Pointer to input routine */
|
||||||
|
ungetfunc unget; /* Pointer to pushback routine */
|
||||||
unsigned ccount; /* Number of chars read */
|
unsigned ccount; /* Number of chars read */
|
||||||
|
|
||||||
/* Fields used outside of _scanf */
|
/* Fields used outside of _scanf */
|
||||||
char* buf; /* Pointer to input buffer */
|
void* data; /* Caller data */
|
||||||
unsigned size; /* Size of input buffer */
|
|
||||||
unsigned fill; /* Fill mark of input buffer */
|
|
||||||
unsigned ridx; /* Read index of input buffer */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Internal scanning routine */
|
/* Internal scanning routine */
|
||||||
int _scanf (struct indesc* d, const char* format, va_list ap);
|
int _scanf (struct scanfdata* d, const char* format, va_list ap);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
36
libsrc/common/fscanf.c
Normal file
36
libsrc/common/fscanf.c
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* fscanf.c
|
||||||
|
*
|
||||||
|
* Ullrich von Bassewitz (uz@cc65.org), 2004-11-26
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Code */
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int fscanf (FILE* f, const char* format, ...)
|
||||||
|
/* Standard C function */
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
/* Setup for variable arguments */
|
||||||
|
va_start (ap, format);
|
||||||
|
|
||||||
|
/* Call vfscanf(). Since we know that va_end won't do anything, we will
|
||||||
|
* save the call and return the value directly.
|
||||||
|
*/
|
||||||
|
return vfscanf (f, format, ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
36
libsrc/common/scanf.c
Normal file
36
libsrc/common/scanf.c
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* scanf.c
|
||||||
|
*
|
||||||
|
* Ullrich von Bassewitz (uz@cc65.org), 2004-11-26
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Code */
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int scanf (const char* format, ...)
|
||||||
|
/* Standard C function */
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
/* Setup for variable arguments */
|
||||||
|
va_start (ap, format);
|
||||||
|
|
||||||
|
/* Call vfscanf(). Since we know that va_end won't do anything, we will
|
||||||
|
* save the call and return the value directly.
|
||||||
|
*/
|
||||||
|
return vfscanf (stdin, format, ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
39
libsrc/common/vfscanf.c
Normal file
39
libsrc/common/vfscanf.c
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* vfscanf.c
|
||||||
|
*
|
||||||
|
* Ullrich von Bassewitz (uz@cc65.org), 2004-11-26
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "_scanf.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Code */
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int __fastcall__ vfscanf (FILE* f, const char* format, va_list ap)
|
||||||
|
/* Standard C function */
|
||||||
|
{
|
||||||
|
struct scanfdata d;
|
||||||
|
|
||||||
|
/* Initialize the data struct. We do only need the given file as user data,
|
||||||
|
* since the get and ungetc are crafted so they match the standard fgetc
|
||||||
|
* and ungetc functions.
|
||||||
|
*/
|
||||||
|
d.get = (getfunc) fgetc,
|
||||||
|
d.unget = (ungetfunc) ungetc,
|
||||||
|
d.data = f;
|
||||||
|
|
||||||
|
/* Call the internal function and return the result */
|
||||||
|
return _scanf (&d, format, ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -12,21 +12,48 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Data */
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
struct sscanfdata {
|
||||||
|
const char* str; /* Pointer to input string */
|
||||||
|
unsigned index; /* Read index */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/* Code */
|
/* Code */
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static char get (struct indesc* d)
|
static int __fastcall__ get (struct sscanfdata* d)
|
||||||
/* Read a character from the input string and return it */
|
/* Read a character from the input string and return it */
|
||||||
{
|
{
|
||||||
char C;
|
char C;
|
||||||
if (C = d->buf[d->ridx]) {
|
if (C = d->str[d->index]) {
|
||||||
/* Increment index only if end not reached */
|
/* Increment index only if end not reached */
|
||||||
++d->ridx;
|
++d->index;
|
||||||
}
|
|
||||||
return C;
|
return C;
|
||||||
|
} else {
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static int __fastcall__ unget (int c, struct sscanfdata* d)
|
||||||
|
/* Push back a character onto the input stream */
|
||||||
|
{
|
||||||
|
/* We do assume here that the _scanf routine will not push back anything
|
||||||
|
* not read, so we can ignore c safely and won't check the index.
|
||||||
|
*/
|
||||||
|
--d->index;
|
||||||
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -34,17 +61,20 @@ static char get (struct indesc* d)
|
|||||||
int __fastcall__ vsscanf (const char* str, const char* format, va_list ap)
|
int __fastcall__ vsscanf (const char* str, const char* format, va_list ap)
|
||||||
/* Standard C function */
|
/* Standard C function */
|
||||||
{
|
{
|
||||||
struct indesc id;
|
struct sscanfdata sd;
|
||||||
|
struct scanfdata d;
|
||||||
|
|
||||||
/* Initialize the indesc struct. We leave all fields uninitialized that we
|
/* Initialize the data structs. The sscanfdata struct will be passed back
|
||||||
* don't need
|
* to the get and unget functions by _scanf.
|
||||||
*/
|
*/
|
||||||
id.fin = (infunc) get;
|
d.get = (getfunc) get;
|
||||||
id.buf = (char*) str;
|
d.unget = (ungetfunc) unget,
|
||||||
id.ridx = 0;
|
d.data = &sd;
|
||||||
|
sd.str = str;
|
||||||
|
sd.index = 0;
|
||||||
|
|
||||||
/* Call the internal function and return the result */
|
/* Call the internal function and return the result */
|
||||||
return _scanf (&id, format, ap);
|
return _scanf (&d, format, ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user