1
0
mirror of https://github.com/cc65/cc65.git synced 2025-01-14 00:32:08 +00:00

Added assembler include function for _scanf

git-svn-id: svn://svn.cc65.org/cc65/trunk@3304 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
cuz 2004-11-27 14:45:49 +00:00
parent 7cf5f27ec6
commit dbb003c9ac
3 changed files with 144 additions and 57 deletions

View File

@ -12,6 +12,7 @@
#include <stdio.h>
#include <stdarg.h>
#include <stddef.h>
#include <string.h>
#include <setjmp.h>
#include <ctype.h>
@ -39,9 +40,10 @@
static struct scanfdata* D; /* Copy of function argument */
static va_list ap; /* Copy of function argument */
static struct scanfdata* D_; /* 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 unsigned CharCount; /* Characters read so far */
static int C; /* Character from input */
static unsigned Width; /* Maximum field width */
static long IntVal; /* Converted int value */
@ -57,6 +59,15 @@ static const unsigned char Bits[8] = {
0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80
};
/* We need C to be 16 bits since we cannot check for EOF otherwise.
* Unfortunately, this causes the code to be quite larger, even if for most
* purposes, checking the low byte would be enough, since if C is EOF, the
* low byte will not match any useful character anyway (at least for the
* supported platforms - I know that this is not portable). So the following
* macro is used to access just the low byte of C.
*/
#define CHAR(c) (*((unsigned char*)&(c)))
/*****************************************************************************/
@ -124,13 +135,57 @@ static void InvertCharSet (void)
static void __fastcall__ Error (unsigned char Code)
/* Does a longjmp using the given code */
{
longjmp (JumpBuf, Code);
}
static void ReadChar (void)
/* Get an input character, count characters */
{
C = D->get (D->data);
if (C != EOF) {
++D->ccount;
}
/* Move D to ptr1 */
asm ("lda %v", D_);
asm ("ldx %v+1", D_);
asm ("sta ptr1");
asm ("stx ptr1+1");
/* Copy the get vector to jmpvec */
asm ("ldy #%b", offsetof (struct scanfdata, get));
asm ("lda (ptr1),y");
asm ("sta jmpvec+1");
asm ("iny");
asm ("lda (ptr1),y");
asm ("sta jmpvec+2");
/* Load D->data into __AX__ */
asm ("ldy #%b", offsetof (struct scanfdata, data)+1);
asm ("lda (ptr1),y");
asm ("tax");
asm ("dey");
asm ("lda (ptr1),y");
/* Call the get routine */
asm ("jsr jmpvec");
/* Assign the result to C */
asm ("sta %v", C);
asm ("stx %v+1", C);
/* If C is not EOF, bump the character counter. */
asm ("inx");
asm ("bne %g", Done);
asm ("cmp #$FF");
asm ("bne %g", Done);
/* Must bump CharCount. */
asm ("inc %v", CharCount);
asm ("bne %g", Done);
asm ("inc %v+1", CharCount);
Done:
}
@ -140,7 +195,7 @@ static void ReadCharWithCheck (void)
{
ReadChar ();
if (C == EOF) {
longjmp (JumpBuf, RC_EOF);
Error (RC_EOF);
}
}
@ -161,17 +216,27 @@ static void ReadSign (void)
* positive, store 0 otherwise.
*/
{
switch (C) {
case '-':
ReadChar ();
Positive = 0;
break;
case '+':
ReadChar ();
/* FALLTHROUGH */
default:
Positive = 1;
}
/* We can ignore the high byte of C here, since if it is EOF, the lower
* byte won't match anyway.
*/
asm ("lda %v", C);
asm ("cmp #'-'");
asm ("bne %g", NotNeg);
/* Negative value */
asm ("jsr %v", ReadChar);
asm ("lda #$00"); /* Flag as negative */
asm ("beq %g", Store);
/* Positive value */
NotNeg:
asm ("cmp #'+'");
asm ("bne %g", Pos);
asm ("jsr %v", ReadChar); /* Skip the + sign */
Pos:
asm ("lda #$01"); /* Flag as positive */
Store:
asm ("sta %v", Positive);
}
@ -210,10 +275,10 @@ static void AssignInt (void)
asm ("ldy %v", IntBytes);
/* Assign the integer value */
asm ("L1: lda %v,y", IntVal);
Loop: asm ("lda %v,y", IntVal);
asm ("sta (ptr1),y");
asm ("dey");
asm ("bpl L1");
asm ("bpl %g", Loop);
}
}
@ -238,7 +303,7 @@ static unsigned char ReadInt (unsigned char Base)
/* If we didn't convert anything, it's an error */
if (CharCount == 0) {
longjmp (JumpBuf, RC_NOCONV);
Error (RC_NOCONV);
}
/* Return the number of characters converted */
@ -247,7 +312,7 @@ static unsigned char ReadInt (unsigned char Base)
static void ScanInt (unsigned char Base)
static void __fastcall__ ScanInt (unsigned char Base)
/* Scan an integer including white space, sign and optional base spec,
* and store it into IntVal.
*/
@ -260,9 +325,9 @@ static void ScanInt (unsigned char Base)
/* If Base is unknown (zero), figure it out */
if (Base == 0) {
if (C == '0') {
if (CHAR (C) == '0') {
ReadChar ();
switch (C) {
switch (CHAR (C)) {
case 'x':
case 'X':
Base = 16;
@ -293,14 +358,15 @@ static void ScanInt (unsigned char Base)
int _scanf (struct scanfdata* D_, register const char* format, va_list ap_)
int __fastcall__ _scanf (register 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
* types of wrappers to implement the actual ISO xxscanf functions.
*/
{
char F; /* Character from format string */
register char F; /* Character from format string */
unsigned char Result; /* setjmp result */
char* S;
char* S;
unsigned char HaveWidth; /* True if a width was given */
char Start; /* Start of range */
@ -308,12 +374,12 @@ int _scanf (struct scanfdata* D_, register const char* format, va_list ap_)
* nice, but on a 6502 platform it gives better code, since the values
* do not have to be passed as parameters.
*/
D = D_;
D_ = D;
ap = ap_;
/* Initialize variables */
Conversions = 0;
D->ccount = 0;
CharCount = 0;
/* Set up the jump label. The get() routine will use this label when EOF
* is reached.
@ -429,7 +495,7 @@ Again:
case 'i':
/* Optionally signed integer with a base */
ScanInt (0);
ScanInt (0);
break;
case 'o':
@ -448,13 +514,13 @@ Again:
case 'f':
case 'g':
/* Optionally signed float */
longjmp (JumpBuf, RC_NOCONV);
Error (RC_NOCONV);
break;
case 's':
/* Whitespace terminated string */
SkipWhite ();
if (!NoAssign) {
if (!NoAssign) {
S = va_arg (ap, char*);
}
while (!isspace (C) && Width--) {
@ -465,34 +531,34 @@ Again:
}
/* Terminate the string just read */
if (!NoAssign) {
*S = '\0';
}
*S = '\0';
}
++Conversions;
break;
break;
case 'c':
/* Fixed length string, NOT zero terminated */
if (!HaveWidth) {
/* No width given, default is 1 */
Width = 1;
}
if (!NoAssign) {
S = va_arg (ap, char*);
/* Fixed length string, NOT zero terminated */
if (!HaveWidth) {
/* No width given, default is 1 */
Width = 1;
}
if (!NoAssign) {
S = va_arg (ap, char*);
while (Width--) {
*S++ = C;
ReadCharWithCheck ();
}
} else {
} else {
/* Just skip as many chars as given */
while (Width--) {
ReadCharWithCheck ();
}
}
++Conversions;
++Conversions;
break;
case '[':
/* String using characters from a set */
/* String using characters from a set */
Invert = 0;
/* Clear the set */
memset (CharSet, 0, sizeof (CharSet));
@ -563,16 +629,16 @@ Again:
case 'p':
/* Pointer, format is 0xABCD */
SkipWhite ();
if (C != '0') {
longjmp (JumpBuf, RC_NOCONV);
if (CHAR (C) != '0') {
Error (RC_NOCONV);
}
ReadChar ();
if (C != 'x' && C != 'X') {
longjmp (JumpBuf, RC_NOCONV);
if (CHAR (C) != 'x' && CHAR (C) != 'X') {
Error (RC_NOCONV);
}
ReadChar ();
if (ReadInt (16) != 4) { /* 4 chars expected */
longjmp (JumpBuf, RC_NOCONV);
Error (RC_NOCONV);
}
AssignInt ();
++Conversions;
@ -580,13 +646,13 @@ Again:
case 'n':
/* Store characters consumed so far */
IntVal = D->ccount;
IntVal = CharCount;
AssignInt ();
break;
default:
/* Invalid conversion */
longjmp (JumpBuf, RC_NOCONV);
Error (RC_NOCONV);
break;
}
@ -604,7 +670,7 @@ Again:
* conversions, it is considered an error, otherwise the number
* of conversions is returned (the default behaviour).
*/
if (C == EOF && D->ccount == 0) {
if (C == EOF && CharCount == 0) {
/* Special case: error */
Conversions = EOF;
}
@ -617,3 +683,4 @@ Again:

View File

@ -21,13 +21,12 @@ typedef int __fastcall__ (*ungetfunc) (int c, void* data);
/* Control structure passed to the low level worker function.
* Beware: The low level functions will access the structure on the assembly
* level, so check this when altering the structure.
* Beware: This structure is mirrored in the _scanf.inc assembler include
* file, so check this when altering the structure.
*/
struct scanfdata {
getfunc get; /* Pointer to input routine */
ungetfunc unget; /* Pointer to pushback routine */
unsigned ccount; /* Number of chars read */
/* Fields used outside of _scanf */
void* data; /* Caller data */
@ -36,7 +35,7 @@ struct scanfdata {
/* Internal scanning routine */
int _scanf (struct scanfdata* d, const char* format, va_list ap);
int __fastcall__ _scanf (struct scanfdata* d, const char* format, va_list ap);

21
libsrc/common/_scanf.inc Normal file
View File

@ -0,0 +1,21 @@
;
; Ullrich von Bassewitz, 2004-11-27
;
;----------------------------------------------------------------------------
; Structure passed to _scanf
.struct SCANFDATA
GET .addr
UNGET .addr
DATA .addr
.endstruct
;----------------------------------------------------------------------------
; Global data
.global _scanf