Fixed tab removal which somehow went wrong

git-svn-id: svn://svn.cc65.org/cc65/trunk@3382 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
cuz 2005-02-14 09:38:30 +00:00
parent bb66b590a9
commit bc5d046503
5 changed files with 381 additions and 381 deletions

View file

@ -36,42 +36,42 @@ extern void __fastcall__ _seterrno (unsigned char code);
/*****************************************************************************/ /*****************************************************************************/
/* SetJmp return codes */ /* SetJmp return codes */
/*****************************************************************************/ /*****************************************************************************/
enum { enum {
RC_OK, /* setjmp() call */ RC_OK, /* setjmp() call */
RC_NOCONV, /* No conversion possible */ RC_NOCONV, /* No conversion possible */
RC_EOF /* EOF reached */ RC_EOF /* EOF reached */
}; };
/*****************************************************************************/ /*****************************************************************************/
/* Data */ /* Data */
/*****************************************************************************/ /*****************************************************************************/
static const char* format; /* Copy of function argument */ static const char* format; /* Copy of function argument */
static const struct scanfdata* D_; /* Copy of function argument */ static const 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 for failures */ static jmp_buf JumpBuf; /* "Label" that is used for failures */
static char F; /* Character from format string */ static char F; /* Character from format string */
static unsigned CharCount; /* Characters read so far */ static unsigned CharCount; /* Characters read so far */
static int 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 int Assignments; /* Number of assignments */ static int Assignments; /* Number of assignments */
static unsigned char IntBytes; /* Number of bytes-1 for int conversions */ static unsigned char IntBytes; /* Number of bytes-1 for int conversions */
/* Flags */ /* Flags */
static bool Converted; /* Some object was converted */ static bool Converted; /* Some object was converted */
static bool Positive; /* Flag for positive value */ static bool Positive; /* Flag for positive value */
static bool NoAssign; /* Suppress assignment */ static bool NoAssign; /* Suppress assignment */
static bool Invert; /* Do we need to invert the charset? */ static bool Invert; /* Do we need to invert the charset? */
static unsigned char CharSet[(1+UCHAR_MAX)/CHAR_BIT]; static unsigned char CharSet[(1+UCHAR_MAX)/CHAR_BIT];
static const unsigned char Bits[CHAR_BIT] = { static const unsigned char Bits[CHAR_BIT] = {
0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80
@ -89,7 +89,7 @@ static const unsigned char Bits[CHAR_BIT] = {
/*****************************************************************************/ /*****************************************************************************/
/* Character sets */ /* Character sets */
/*****************************************************************************/ /*****************************************************************************/
@ -107,13 +107,13 @@ static unsigned FindBit (void)
*/ */
{ {
asm ("pha"); asm ("pha");
asm ("lsr a"); /* Divide by CHAR_BIT */ asm ("lsr a"); /* Divide by CHAR_BIT */
asm ("lsr a"); asm ("lsr a");
asm ("lsr a"); asm ("lsr a");
asm ("tax"); /* Byte's offset */ asm ("tax"); /* Byte's offset */
asm ("pla"); asm ("pla");
asm ("and #%b", CHAR_BIT-1); asm ("and #%b", CHAR_BIT-1);
asm ("tay"); /* Bit's offset */ asm ("tay"); /* Bit's offset */
asm ("lda %v,y", Bits); asm ("lda %v,y", Bits);
return (unsigned) __AX__; return (unsigned) __AX__;
} }
@ -139,7 +139,7 @@ static unsigned char IsCharInSet (void)
/* Get the character from C. */ /* Get the character from C. */
asm ("lda #$00"); asm ("lda #$00");
asm ("ldx %v+1", C); asm ("ldx %v+1", C);
asm ("bne L1"); /* EOF never is in the set */ asm ("bne L1"); /* EOF never is in the set */
asm ("lda %v", C); asm ("lda %v", C);
FindBit(); FindBit();
asm ("and %v,x", CharSet); asm ("and %v,x", CharSet);
@ -167,7 +167,7 @@ static void InvertCharSet (void)
/*****************************************************************************/ /*****************************************************************************/
/* Code */ /* Code */
/*****************************************************************************/ /*****************************************************************************/
@ -432,17 +432,17 @@ static void __fastcall__ ScanInt (unsigned char Base)
case 'x': case 'x':
case 'X': case 'X':
Base = 16; Base = 16;
Converted = true; Converted = true;
ReadChar (); ReadChar ();
break; break;
default: default:
Base = 8; Base = 8;
/* Restart at the beginning of the number because it might /* Restart at the beginning of the number because it might
* be only a single zero digit (which already was read). * be only a single zero digit (which already was read).
*/ */
PushBack (); PushBack ();
C = '0'; C = '0';
} }
} else { } else {
Base = 10; Base = 10;
@ -480,7 +480,7 @@ static char GetFormat (void)
int __fastcall__ _scanf (const struct scanfdata* D, int __fastcall__ _scanf (const struct scanfdata* D,
const char* format_, va_list ap_) 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.
*/ */
@ -518,72 +518,72 @@ Again:
/* Check for a conversion */ /* Check for a conversion */
if (F != '%') { if (F != '%') {
/* Check for a match */ /* Check for a match */
if ((bool) isspace ((int) F)) { if ((bool) isspace ((int) F)) {
/* Special white space handling: Any whitespace in the /* Special white space handling: Any whitespace in the
* format string matches any amount of whitespace including * format string matches any amount of whitespace including
* none(!). So this match will never fail. * none(!). So this match will never fail.
*/ */
SkipWhite (); SkipWhite ();
continue; continue;
} }
Percent: Percent:
/* ### Note: The opposite test (C == F) /* ### Note: The opposite test (C == F)
** would be optimized into buggy code! ** would be optimized into buggy code!
*/ */
if (C != (int) F) { if (C != (int) F) {
/* A mismatch -- we will stop scanning the input, /* A mismatch -- we will stop scanning the input,
* and return the number of assigned conversions. * and return the number of assigned conversions.
*/ */
goto NoConv; goto NoConv;
} }
/* A match -- get the next input character, and continue. */ /* A match -- get the next input character, and continue. */
goto Again; goto Again;
} else { } else {
/* A conversion. Skip the percent sign. */ /* A conversion. Skip the percent sign. */
/* 0. Check for %% */ /* 0. Check for %% */
if (GetFormat () == '%') { if (GetFormat () == '%') {
goto Percent; goto Percent;
} }
/* 1. Assignment suppression */ /* 1. Assignment suppression */
NoAssign = (F == '*'); NoAssign = (F == '*');
if (NoAssign) { if (NoAssign) {
GetFormat (); GetFormat ();
} }
/* 2. Maximum field width */ /* 2. Maximum field width */
Width = UINT_MAX; Width = UINT_MAX;
HaveWidth = (bool) isdigit (F); HaveWidth = (bool) isdigit (F);
if (HaveWidth) { if (HaveWidth) {
Width = 0; Width = 0;
do { do {
/* ### Non portable ### */ /* ### Non portable ### */
Width = Width * 10 + (F & 0x0F); Width = Width * 10 + (F & 0x0F);
} while ((bool) isdigit (GetFormat ())); } while ((bool) isdigit (GetFormat ()));
} }
if (Width == 0) { if (Width == 0) {
/* Invalid specification */ /* Invalid specification */
/* Note: This method of leaving the function might seem /* Note: This method of leaving the function might seem
* to be crude, but it optimizes very well because * to be crude, but it optimizes very well because
* the four exits can share this code. * the four exits can share this code.
*/ */
_seterrno (EINVAL); _seterrno (EINVAL);
Assignments = EOF; Assignments = EOF;
PushBack (); PushBack ();
return Assignments; return Assignments;
} }
/* Increment-and-test makes better code than test-and-decrement /* Increment-and-test makes better code than test-and-decrement
* does. So, change the width into a form that can be used in * does. So, change the width into a form that can be used in
* that way. * that way.
*/ */
Width = ~Width; Width = ~Width;
/* 3. Length modifier */ /* 3. Length modifier */
IntBytes = sizeof(int) - 1; IntBytes = sizeof(int) - 1;
@ -593,7 +593,7 @@ Percent:
IntBytes = sizeof(char) - 1; IntBytes = sizeof(char) - 1;
++format; ++format;
} }
GetFormat (); GetFormat ();
break; break;
case 'l': case 'l':
@ -604,108 +604,108 @@ Percent:
/* FALLTHROUGH */ /* FALLTHROUGH */
case 'j': /* intmax_t */ case 'j': /* intmax_t */
IntBytes = sizeof(long) - 1; IntBytes = sizeof(long) - 1;
/* FALLTHROUGH */ /* FALLTHROUGH */
case 'z': /* size_t */ case 'z': /* size_t */
case 't': /* ptrdiff_t */ case 't': /* ptrdiff_t */
/* Same size as int */ /* Same size as int */
case 'L': /* long double - ignore this one */ case 'L': /* long double - ignore this one */
GetFormat (); GetFormat ();
} }
/* 4. Conversion specifier */ /* 4. Conversion specifier */
switch (F) { switch (F) {
/* 'd' and 'u' conversions are actually the same, since the /* 'd' and 'u' conversions are actually the same, since the
* standard says that even the 'u' modifier allows an * standard says that even the 'u' modifier allows an
* optionally signed integer. * optionally signed integer.
*/ */
case 'd': /* Optionally signed decimal integer */ case 'd': /* Optionally signed decimal integer */
case 'u': case 'u':
ScanInt (10); ScanInt (10);
break; break;
case 'i': case 'i':
/* Optionally signed integer with a base */ /* Optionally signed integer with a base */
ScanInt (0); ScanInt (0);
break; break;
case 'o': case 'o':
/* Optionally signed octal integer */ /* Optionally signed octal integer */
ScanInt (8); ScanInt (8);
break; break;
case 'x': case 'x':
case 'X': case 'X':
/* Optionally signed hexadecimal integer */ /* Optionally signed hexadecimal integer */
ScanInt (16); ScanInt (16);
break; break;
case 's': case 's':
/* Whitespace-terminated string */ /* Whitespace-terminated string */
SkipWhite (); SkipWhite ();
CheckEnd (); /* Is it an input failure? */ CheckEnd (); /* Is it an input failure? */
Converted = true; /* No, conversion will succeed */ Converted = true; /* No, conversion will succeed */
if (NoAssign == false) { if (NoAssign == false) {
S = va_arg (ap, char*); S = va_arg (ap, char*);
} }
while (C != EOF while (C != EOF
&& (bool) isspace (C) == false && (bool) isspace (C) == false
&& ++Width) { && ++Width) {
if (NoAssign == false) { if (NoAssign == false) {
*S++ = C; *S++ = C;
} }
ReadChar (); ReadChar ();
} }
/* Terminate the string just read */ /* Terminate the string just read */
if (NoAssign == false) { if (NoAssign == false) {
*S = '\0'; *S = '\0';
++Assignments; ++Assignments;
} }
break; break;
case 'c': case 'c':
/* Fixed-length string, NOT zero-terminated */ /* Fixed-length string, NOT zero-terminated */
if (HaveWidth == false) { if (HaveWidth == false) {
/* No width given, default is 1 */ /* No width given, default is 1 */
Width = ~1u; Width = ~1u;
} }
CheckEnd (); /* Is it an input failure? */ CheckEnd (); /* Is it an input failure? */
Converted = true; /* No, at least 1 char. available */ Converted = true; /* No, at least 1 char. available */
if (NoAssign == false) { if (NoAssign == false) {
S = va_arg (ap, char*); S = va_arg (ap, char*);
/* ## This loop is convenient for us, but it isn't /* ## This loop is convenient for us, but it isn't
* standard C. The standard implies that a failure * standard C. The standard implies that a failure
* shouldn't put anything into the array argument. * shouldn't put anything into the array argument.
*/ */
while (++Width) { while (++Width) {
CheckEnd (); /* Is it a matching failure? */ CheckEnd (); /* Is it a matching failure? */
*S++ = C; *S++ = C;
ReadChar (); ReadChar ();
} }
++Assignments; ++Assignments;
} else { } else {
/* Just skip as many chars as given */ /* Just skip as many chars as given */
while (++Width) { while (++Width) {
CheckEnd (); /* Is it a matching failure? */ CheckEnd (); /* Is it a matching failure? */
ReadChar (); ReadChar ();
} }
} }
break; break;
case '[': case '[':
/* String using characters from a set */ /* String using characters from a set */
/* Clear the set */ /* Clear the set */
memset (CharSet, 0, sizeof (CharSet)); memset (CharSet, 0, sizeof (CharSet));
/* Skip the left-bracket, and test for inversion. */ /* Skip the left-bracket, and test for inversion. */
Invert = (GetFormat () == '^'); Invert = (GetFormat () == '^');
if (Invert) { if (Invert) {
GetFormat (); GetFormat ();
} }
if (F == ']') { if (F == ']') {
/* Empty sets aren't allowed; so, a right-bracket /* Empty sets aren't allowed; so, a right-bracket
* at the beginning must be a member of the set. * at the beginning must be a member of the set.
*/ */
AddCharToSet (F); AddCharToSet (F);
GetFormat (); GetFormat ();
} }
@ -716,16 +716,16 @@ Percent:
Start = F; Start = F;
++format; ++format;
switch (GetFormat ()) { switch (GetFormat ()) {
case '\0': case '\0':
case ']': case ']':
/* '-' as last char means: include '-' */ /* '-' as last char means: include '-' */
AddCharToSet (Start); AddCharToSet (Start);
AddCharToSet ('-'); AddCharToSet ('-');
break; break;
default: default:
/* Include all characters /* Include all characters
* that are in the range. * that are in the range.
*/ */
while (1) { while (1) {
AddCharToSet (Start); AddCharToSet (Start);
if (Start == F) { if (Start == F) {
@ -743,11 +743,11 @@ Percent:
GetFormat (); GetFormat ();
} }
} }
/* Don't go beyond the end of the format string. */ /* Don't go beyond the end of the format string. */
/* (Maybe, this should mean an invalid specification.) */ /* (Maybe, this should mean an invalid specification.) */
if (F == '\0') { if (F == '\0') {
--format; --format;
} }
/* Invert the set if requested */ /* Invert the set if requested */
if (Invert) { if (Invert) {
@ -758,90 +758,90 @@ Percent:
* store them into a string while they are part of * store them into a string while they are part of
* the set. * the set.
*/ */
Match = false; Match = false;
if (NoAssign == false) { if (NoAssign == false) {
S = va_arg (ap, char*); S = va_arg (ap, char*);
} }
while (IsCharInSet () && ++Width) { while (IsCharInSet () && ++Width) {
if (NoAssign == false) { if (NoAssign == false) {
*S++ = C; *S++ = C;
} }
Match = Converted = true; Match = Converted = true;
ReadChar (); ReadChar ();
} }
/* At least one character must match the set. */ /* At least one character must match the set. */
if (Match == false) { if (Match == false) {
goto NoConv; goto NoConv;
} }
if (NoAssign == false) { if (NoAssign == false) {
*S = '\0'; *S = '\0';
++Assignments; ++Assignments;
} }
break; break;
case 'p': case 'p':
/* Pointer, general format is 0xABCD. /* Pointer, general format is 0xABCD.
* %hhp --> zero-page pointer * %hhp --> zero-page pointer
* %hp --> near pointer * %hp --> near pointer
* %lp --> far pointer * %lp --> far pointer
*/ */
SkipWhite (); SkipWhite ();
if (CHAR (C) != '0') { if (CHAR (C) != '0') {
goto NoConv; goto NoConv;
}
Converted = true;
ReadChar ();
switch (CHAR (C)) {
case 'x':
case 'X':
break;
default:
goto NoConv;
} }
Converted = true;
ReadChar ();
switch (CHAR (C)) {
case 'x':
case 'X':
break;
default:
goto NoConv;
}
ReadChar (); ReadChar ();
ReadInt (16); ReadInt (16);
AssignInt (); AssignInt ();
break; break;
case 'n': case 'n':
/* Store the number of characters consumed so far /* Store the number of characters consumed so far
* (the read-ahead character hasn't been consumed). * (the read-ahead character hasn't been consumed).
*/ */
IntVal = (long) (CharCount - (C == EOF ? 0u : 1u)); IntVal = (long) (CharCount - (C == EOF ? 0u : 1u));
AssignInt (); AssignInt ();
/* Don't count it. */ /* Don't count it. */
if (NoAssign == false) { if (NoAssign == false) {
--Assignments; --Assignments;
} }
break; break;
case 'S': case 'S':
case 'C': case 'C':
/* Wide characters */ /* Wide characters */
case 'a': case 'a':
case 'A': case 'A':
case 'e': case 'e':
case 'E': case 'E':
case 'f': case 'f':
case 'F': case 'F':
case 'g': case 'g':
case 'G': case 'G':
/* Optionally signed float */ /* Optionally signed float */
/* Those 2 groups aren't implemented. */ /* Those 2 groups aren't implemented. */
_seterrno (ENOSYS); _seterrno (ENOSYS);
Assignments = EOF; Assignments = EOF;
PushBack (); PushBack ();
return Assignments; return Assignments;
default: default:
/* Invalid specification */ /* Invalid specification */
_seterrno (EINVAL); _seterrno (EINVAL);
Assignments = EOF; Assignments = EOF;
PushBack (); PushBack ();
return Assignments; return Assignments;
} }
} }
} }
} else { } else {
@ -852,7 +852,7 @@ NoConv:
* the number of assignments is returned (the default behaviour). * the number of assignments is returned (the default behaviour).
*/ */
if (C == EOF && Converted == false) { if (C == EOF && Converted == false) {
Assignments = EOF; /* Special case: error */ Assignments = EOF; /* Special case: error */
} }
} }

View file

@ -5,18 +5,18 @@
; 2004-12-31, Greg King ; 2004-12-31, Greg King
; ;
.export _scanf .export _scanf
.import _stdin, pushax, addysp, _vfscanf .import _stdin, pushax, addysp, _vfscanf
.import sp:zp, ptr1:zp .import sp:zp, ptr1:zp
.macpack generic .macpack generic
; ---------------------------------------------------------------------------- ; ----------------------------------------------------------------------------
; Code ; Code
; ;
_scanf: _scanf:
sty ArgSize ; Number of argument bytes passed in .Y sty ArgSize ; Number of argument bytes passed in .Y
; We are using a (hopefully) clever trick here to reduce code size. On entry, ; We are using a (hopefully) clever trick here to reduce code size. On entry,
; the stack pointer points to the last pushed argument of the variable ; the stack pointer points to the last pushed argument of the variable
@ -28,47 +28,47 @@ _scanf:
; * we will have the address of the Format argument which needs to ; * we will have the address of the Format argument which needs to
; be pushed next. ; be pushed next.
lda _stdin lda _stdin
ldx _stdin+1 ldx _stdin+1
jsr pushax jsr pushax
; Now, calculate the va_list pointer, which does point to Format. ; Now, calculate the va_list pointer, which does point to Format.
lda sp lda sp
ldx sp+1 ldx sp+1
add ArgSize add ArgSize
bcc @L1 bcc @L1
inx inx
@L1: sta ptr1 @L1: sta ptr1
stx ptr1+1 stx ptr1+1
; Push a copy of Format. ; Push a copy of Format.
ldy #1 ldy #1
lda (ptr1),y lda (ptr1),y
tax tax
dey dey
lda (ptr1),y lda (ptr1),y
jsr pushax jsr pushax
; Load va_list [last and __fastcall__ argument to vfscanf()]. ; Load va_list [last and __fastcall__ argument to vfscanf()].
lda ptr1 lda ptr1
ldx ptr1+1 ldx ptr1+1
; Call vfscanf(). ; Call vfscanf().
jsr _vfscanf jsr _vfscanf
; Clean up the stack. We will return what we got from vfscanf(). ; Clean up the stack. We will return what we got from vfscanf().
ldy ArgSize ldy ArgSize
jmp addysp jmp addysp
; ---------------------------------------------------------------------------- ; ----------------------------------------------------------------------------
; Data ; Data
; ;
.bss .bss
ArgSize: ArgSize:
.res 1 ; Number of argument bytes .res 1 ; Number of argument bytes

View file

@ -5,58 +5,58 @@
; 2005-01-01, Greg King ; 2005-01-01, Greg King
; ;
.export _cscanf .export _cscanf
.import pushax, addysp, _vcscanf .import pushax, addysp, _vcscanf
.macpack generic .macpack generic
.include "zeropage.inc" .include "zeropage.inc"
; ---------------------------------------------------------------------------- ; ----------------------------------------------------------------------------
; Code ; Code
; ;
_cscanf: _cscanf:
sty ArgSize ; Number of argument bytes passed in .Y sty ArgSize ; Number of argument bytes passed in .Y
dey ; subtract size of format pointer dey ; subtract size of format pointer
dey dey
tya tya
; Now, calculate the va_list pointer -- which points to format. ; Now, calculate the va_list pointer -- which points to format.
ldx sp+1 ldx sp+1
add sp add sp
bcc @L1 bcc @L1
inx inx
@L1: sta ptr1 @L1: sta ptr1
stx ptr1+1 stx ptr1+1
; Push a copy of the format pointer onto the stack. ; Push a copy of the format pointer onto the stack.
ldy #1 ldy #1
lda (ptr1),y lda (ptr1),y
tax tax
dey dey
lda (ptr1),y lda (ptr1),y
jsr pushax jsr pushax
; Load va_list [last and __fastcall__ argument for vcscanf()]. ; Load va_list [last and __fastcall__ argument for vcscanf()].
lda ptr1 lda ptr1
ldx ptr1+1 ldx ptr1+1
; Call vcscanf(). ; Call vcscanf().
jsr _vcscanf jsr _vcscanf
; Clean up the stack. We will return what we got from vcscanf(). ; Clean up the stack. We will return what we got from vcscanf().
ldy ArgSize ldy ArgSize
jmp addysp jmp addysp
; ---------------------------------------------------------------------------- ; ----------------------------------------------------------------------------
; Data ; Data
; ;
.bss .bss
ArgSize: ArgSize:
.res 1 ; Number of argument bytes .res 1 ; Number of argument bytes

View file

@ -4,20 +4,20 @@
; 2005-01-02, Greg King ; 2005-01-02, Greg King
; ;
.export _vcscanf .export _vcscanf
.import _cgetc, _cputc .import _cgetc, _cputc
.import popax, pushax, swapstk .import popax, pushax, swapstk
.include "../common/_scanf.inc" .include "../common/_scanf.inc"
; static bool pushed; ; static bool pushed;
; static char back; ; static char back;
; ;
.bss .bss
pushed: .res 1 pushed: .res 1
back: .res 1 back: .res 1
.code .code
; /* Call-back functions: ; /* Call-back functions:
@ -39,26 +39,26 @@ back: .res 1
; return (int)C; ; return (int)C;
; } ; }
; ;
get: ldx pushed get: ldx pushed
beq L1 beq L1
; Return the old, pushed-back character (instead of getting a new one). ; Return the old, pushed-back character (instead of getting a new one).
; ;
dex ; ldx #>0 dex ; ldx #>0
stx pushed stx pushed
lda back lda back
rts rts
; Directly read the keyboard. ; Directly read the keyboard.
; ;
L1: jsr _cgetc L1: jsr _cgetc
; Echo the character to the screen. ; Echo the character to the screen.
; ;
pha pha
jsr _cputc jsr _cputc
pla pla
ldx #>0 ldx #>0
rts rts
@ -68,10 +68,10 @@ L1: jsr _cgetc
; return back = c; ; return back = c;
; } ; }
; ;
unget: ldx #1 unget: ldx #1
stx pushed stx pushed
jsr popax ; get the first argument jsr popax ; get the first argument
sta back sta back
rts rts
@ -96,35 +96,35 @@ unget: ldx #1
; ;
; Beware: Because ap is a fastcall parameter, we must not destroy .XA. ; Beware: Because ap is a fastcall parameter, we must not destroy .XA.
; ;
.proc _vcscanf .proc _vcscanf
; ---------------------------------------------------------------------------- ; ----------------------------------------------------------------------------
; Static, constant scanfdata structure for the _vcscanf routine. ; Static, constant scanfdata structure for the _vcscanf routine.
; ;
.rodata .rodata
d: .addr get ; SCANFDATA::GET d: .addr get ; SCANFDATA::GET
.addr unget ; SCANFDATA::UNGET .addr unget ; SCANFDATA::UNGET
; .addr 0 ; SCANFDATA::DATA (not used) ; .addr 0 ; SCANFDATA::DATA (not used)
.code .code
pha ; Save low byte of ap pha ; Save low byte of ap
txa txa
pha ; Save high byte of ap pha ; Save high byte of ap
ldx #0 ldx #0
stx pushed stx pushed
; Put &d on the stack in front of the format pointer. ; Put &d on the stack in front of the format pointer.
lda #<d lda #<d
ldx #>d ldx #>d
jsr swapstk ; Swap .XA with top-of-stack jsr swapstk ; Swap .XA with top-of-stack
jsr pushax ; Put format pointer back on stack jsr pushax ; Put format pointer back on stack
; Restore ap, and jump to _scanf which will clean up the stack. ; Restore ap, and jump to _scanf which will clean up the stack.
pla pla
tax tax
pla pla
jmp __scanf jmp __scanf
.endproc .endproc

View file

@ -39,18 +39,18 @@ static const struct {
const char *input, *format; const char *input, *format;
int rvalue; int rvalue;
enum TYPE { enum TYPE {
INT, INT,
CHAR CHAR
} type1; } type1;
union { union {
int nvalue; int nvalue;
const char *svalue; const char *svalue;
} v1; } v1;
enum TYPE type2; enum TYPE type2;
union { union {
int nvalue; int nvalue;
const char *svalue; const char *svalue;
} v2; } v2;
} test_data[] = { } test_data[] = {
/* Input sequences for character specifiers must be less than 80 characters /* Input sequences for character specifiers must be less than 80 characters
** long. These format strings are allowwed a maximum of two assignment ** long. These format strings are allowwed a maximum of two assignment
@ -177,8 +177,8 @@ int main(void) {
*/ */
sscanf("% \r\n\f\v\t 0", "%%%i", &n1); sscanf("% \r\n\f\v\t 0", "%%%i", &n1);
if (n1 != 0) if (n1 != 0)
PRINTF("sscanf()'s \"%%%%%%i\" couldn't scan either a \"%%\" " PRINTF("sscanf()'s \"%%%%%%i\" couldn't scan either a \"%%\" "
"or a single zero digit.\r\n\n"); "or a single zero digit.\r\n\n");
/* Test scanf()'s return-value: EOF if input ends before the first /* Test scanf()'s return-value: EOF if input ends before the first
** conversion-attempt begins; an assignment-count, otherwise. ** conversion-attempt begins; an assignment-count, otherwise.
@ -188,60 +188,60 @@ int main(void) {
PRINTF("Testing scanf()'s return-value,\r\nconversions, and assignments...\r\n"); PRINTF("Testing scanf()'s return-value,\r\nconversions, and assignments...\r\n");
for (t = 0; t < ARRAYSIZE(test_data); ++t) { for (t = 0; t < ARRAYSIZE(test_data); ++t) {
/* Prefill the arguments with zeroes. */ /* Prefill the arguments with zeroes. */
n1 = n2 = 0; n1 = n2 = 0;
memset(s1, '\0', sizeof s1); memset(s1, '\0', sizeof s1);
memset(s2, '\0', sizeof s2); memset(s2, '\0', sizeof s2);
c=sscanf(test_data[t].input, test_data[t].format, c=sscanf(test_data[t].input, test_data[t].format,
/* Avoid warning messages about different /* Avoid warning messages about different
** pointer-types, by casting them to void-pointers. ** pointer-types, by casting them to void-pointers.
*/ */
test_data[t].type1 == INT ? (void *)&n1 : (void *)s1, test_data[t].type1 == INT ? (void *)&n1 : (void *)s1,
test_data[t].type2 == INT ? (void *)&n2 : (void *)s2); test_data[t].type2 == INT ? (void *)&n2 : (void *)s2);
if (c != test_data[t].rvalue) if (c != test_data[t].rvalue)
PRINTF("Test #%u returned %d instead of %d.\r\n", PRINTF("Test #%u returned %d instead of %d.\r\n",
t + 1, c, test_data[t].rvalue); t + 1, c, test_data[t].rvalue);
if (test_data[t].type1 == INT) { if (test_data[t].type1 == INT) {
if (test_data[t].v1.nvalue != n1) if (test_data[t].v1.nvalue != n1)
PRINTF("Test #%u assigned %i, instead of %i,\r\n" PRINTF("Test #%u assigned %i, instead of %i,\r\n"
"\tto the first argument.\r\n\n", "\tto the first argument.\r\n\n",
t + 1, n1, test_data[t].v1.nvalue); t + 1, n1, test_data[t].v1.nvalue);
} }
else { /* test_data[t].type1 == CHAR */ else { /* test_data[t].type1 == CHAR */
if (strcmp(test_data[t].v1.svalue, s1)) if (strcmp(test_data[t].v1.svalue, s1))
PRINTF("Test #%u assigned\r\n\"%s\",\r\n" PRINTF("Test #%u assigned\r\n\"%s\",\r\n"
"\tinstead of\r\n\"%s\",\r\n" "\tinstead of\r\n\"%s\",\r\n"
"\tto the first argument.\r\n\n", "\tto the first argument.\r\n\n",
t + 1, s1, test_data[t].v1.svalue); t + 1, s1, test_data[t].v1.svalue);
} }
if (test_data[t].type2 == INT) { if (test_data[t].type2 == INT) {
if (test_data[t].v2.nvalue != n2) if (test_data[t].v2.nvalue != n2)
PRINTF("Test #%u assigned %i, instead of %i,\r\n" PRINTF("Test #%u assigned %i, instead of %i,\r\n"
"\tto the second argument.\r\n\n", "\tto the second argument.\r\n\n",
t + 1, n2, test_data[t].v2.nvalue); t + 1, n2, test_data[t].v2.nvalue);
} }
else { /* test_data[t].type2 == CHAR */ else { /* test_data[t].type2 == CHAR */
if (strcmp(test_data[t].v2.svalue, s2)) if (strcmp(test_data[t].v2.svalue, s2))
PRINTF("Test #%u assigned\r\n\"%s\",\r\n" PRINTF("Test #%u assigned\r\n\"%s\",\r\n"
"\tinstead of\r\n\"%s\",\r\n" "\tinstead of\r\n\"%s\",\r\n"
"\tto the second argument.\r\n\n", "\tto the second argument.\r\n\n",
t + 1, s2, test_data[t].v2.svalue); t + 1, s2, test_data[t].v2.svalue);
} }
} }
Pause(); Pause();
/* Test the char, short, and long specification-modifiers. */ /* Test the char, short, and long specification-modifiers. */
PRINTF("Testing scanf()'s type-modifiers...\r\n"); PRINTF("Testing scanf()'s type-modifiers...\r\n");
for (t = 0; t < ARRAYSIZE(type_data); ++t) { for (t = 0; t < ARRAYSIZE(type_data); ++t) {
n0 = 0L; n0 = 0L;
sscanf(type_data[t].input, type_data[t].format, &n0); sscanf(type_data[t].input, type_data[t].format, &n0);
if (type_data[t].value != n0) if (type_data[t].value != n0)
PRINTF("Test #%u assigned %li instead of %li.\r\n", PRINTF("Test #%u assigned %li instead of %li.\r\n",
t + 1, n0, type_data[t].value); t + 1, n0, type_data[t].value);
} }
Pause(); Pause();
/* Test that the pointer specification /* Test that the pointer specification
@ -249,34 +249,34 @@ int main(void) {
*/ */
PRINTF("Testing \"%%p\"...\r\n"); PRINTF("Testing \"%%p\"...\r\n");
sprintf(s1, "%p %p %p %p", NULL, NULL, sprintf(s1, "%p %p %p %p", NULL, NULL,
Pause, /* static (program) storage */ Pause, /* static (program) storage */
&c); /* automatic (stack) storage */ &c); /* automatic (stack) storage */
sscanf(s1, "%p%p%p %p", &p1, &p2, &p3, &p4); sscanf(s1, "%p%p%p %p", &p1, &p2, &p3, &p4);
if (p1 != NULL || p2 != NULL || if (p1 != NULL || p2 != NULL ||
p3 != (void *)Pause || p4 != (void *)&c) p3 != (void *)Pause || p4 != (void *)&c)
PRINTF("p1 is %p, p2 is %p; they should be %p.\r\n" PRINTF("p1 is %p, p2 is %p; they should be %p.\r\n"
"scanf() assigned %p to p3, instead of %p.\r\n" "scanf() assigned %p to p3, instead of %p.\r\n"
"scanf() assigned %p to p4, instead of %p.\r\n", "scanf() assigned %p to p4, instead of %p.\r\n",
p1, p2, NULL, p1, p2, NULL,
p3, Pause, p3, Pause,
p4, &c); p4, &c);
/* Test that scanf() can scan typed input. /* Test that scanf() can scan typed input.
** Retest that "%i" can decode radix prefixxes. ** Retest that "%i" can decode radix prefixxes.
*/ */
do { do {
Pause(); Pause();
PRINTF("Type 3 signed numbers,\r\n" PRINTF("Type 3 signed numbers,\r\n"
"separated by white-space:\r\n" "separated by white-space:\r\n"
"octal decimal hexadecimal\r\n" "octal decimal hexadecimal\r\n"
"? "); "? ");
c = SCANF("%i %i %i", &n1, &n2, &n3); c = SCANF("%i %i %i", &n1, &n2, &n3);
PRINTF("\r\n\nscanf() returned %i.\r\n" PRINTF("\r\n\nscanf() returned %i.\r\n"
"The numbers are:\r\n" "The numbers are:\r\n"
" %+o octal,\r\n" " %+o octal,\r\n"
" %+d decimal,\r\n" " %+d decimal,\r\n"
" %+#X hexadecimal.\r\n", " %+#X hexadecimal.\r\n",
c, n1, n2, n3); c, n1, n2, n3);
} while (c > 0); } while (c > 0);
return 0; return 0;
} }