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:
@@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
#include <stddef.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <setjmp.h>
|
#include <setjmp.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
@@ -39,9 +40,10 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
static struct scanfdata* 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 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 */
|
||||||
@@ -57,6 +59,15 @@ static const unsigned char Bits[8] = {
|
|||||||
0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80
|
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)
|
static void ReadChar (void)
|
||||||
/* Get an input character, count characters */
|
/* Get an input character, count characters */
|
||||||
{
|
{
|
||||||
C = D->get (D->data);
|
/* Move D to ptr1 */
|
||||||
if (C != EOF) {
|
asm ("lda %v", D_);
|
||||||
++D->ccount;
|
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 ();
|
ReadChar ();
|
||||||
if (C == EOF) {
|
if (C == EOF) {
|
||||||
longjmp (JumpBuf, RC_EOF);
|
Error (RC_EOF);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,17 +216,27 @@ static void ReadSign (void)
|
|||||||
* positive, store 0 otherwise.
|
* positive, store 0 otherwise.
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
switch (C) {
|
/* We can ignore the high byte of C here, since if it is EOF, the lower
|
||||||
case '-':
|
* byte won't match anyway.
|
||||||
ReadChar ();
|
*/
|
||||||
Positive = 0;
|
asm ("lda %v", C);
|
||||||
break;
|
asm ("cmp #'-'");
|
||||||
case '+':
|
asm ("bne %g", NotNeg);
|
||||||
ReadChar ();
|
|
||||||
/* FALLTHROUGH */
|
/* Negative value */
|
||||||
default:
|
asm ("jsr %v", ReadChar);
|
||||||
Positive = 1;
|
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);
|
asm ("ldy %v", IntBytes);
|
||||||
|
|
||||||
/* Assign the integer value */
|
/* Assign the integer value */
|
||||||
asm ("L1: lda %v,y", IntVal);
|
Loop: asm ("lda %v,y", IntVal);
|
||||||
asm ("sta (ptr1),y");
|
asm ("sta (ptr1),y");
|
||||||
asm ("dey");
|
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 we didn't convert anything, it's an error */
|
||||||
if (CharCount == 0) {
|
if (CharCount == 0) {
|
||||||
longjmp (JumpBuf, RC_NOCONV);
|
Error (RC_NOCONV);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return the number of characters converted */
|
/* 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,
|
/* Scan an integer including white space, sign and optional base spec,
|
||||||
* and store it into IntVal.
|
* 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 is unknown (zero), figure it out */
|
||||||
if (Base == 0) {
|
if (Base == 0) {
|
||||||
if (C == '0') {
|
if (CHAR (C) == '0') {
|
||||||
ReadChar ();
|
ReadChar ();
|
||||||
switch (C) {
|
switch (CHAR (C)) {
|
||||||
case 'x':
|
case 'x':
|
||||||
case 'X':
|
case 'X':
|
||||||
Base = 16;
|
Base = 16;
|
||||||
@@ -293,12 +358,13 @@ 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
|
/* 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.
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
char F; /* Character from format string */
|
register char F; /* Character from format string */
|
||||||
unsigned char Result; /* setjmp result */
|
unsigned char Result; /* setjmp result */
|
||||||
char* S;
|
char* S;
|
||||||
unsigned char HaveWidth; /* True if a width was given */
|
unsigned char HaveWidth; /* True if a width was given */
|
||||||
@@ -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
|
* nice, but on a 6502 platform it gives better code, since the values
|
||||||
* do not have to be passed as parameters.
|
* do not have to be passed as parameters.
|
||||||
*/
|
*/
|
||||||
D = D_;
|
D_ = D;
|
||||||
ap = ap_;
|
ap = ap_;
|
||||||
|
|
||||||
/* Initialize variables */
|
/* Initialize variables */
|
||||||
Conversions = 0;
|
Conversions = 0;
|
||||||
D->ccount = 0;
|
CharCount = 0;
|
||||||
|
|
||||||
/* Set up the jump label. The get() routine will use this label when EOF
|
/* Set up the jump label. The get() routine will use this label when EOF
|
||||||
* is reached.
|
* is reached.
|
||||||
@@ -448,7 +514,7 @@ Again:
|
|||||||
case 'f':
|
case 'f':
|
||||||
case 'g':
|
case 'g':
|
||||||
/* Optionally signed float */
|
/* Optionally signed float */
|
||||||
longjmp (JumpBuf, RC_NOCONV);
|
Error (RC_NOCONV);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 's':
|
case 's':
|
||||||
@@ -563,16 +629,16 @@ Again:
|
|||||||
case 'p':
|
case 'p':
|
||||||
/* Pointer, format is 0xABCD */
|
/* Pointer, format is 0xABCD */
|
||||||
SkipWhite ();
|
SkipWhite ();
|
||||||
if (C != '0') {
|
if (CHAR (C) != '0') {
|
||||||
longjmp (JumpBuf, RC_NOCONV);
|
Error (RC_NOCONV);
|
||||||
}
|
}
|
||||||
ReadChar ();
|
ReadChar ();
|
||||||
if (C != 'x' && C != 'X') {
|
if (CHAR (C) != 'x' && CHAR (C) != 'X') {
|
||||||
longjmp (JumpBuf, RC_NOCONV);
|
Error (RC_NOCONV);
|
||||||
}
|
}
|
||||||
ReadChar ();
|
ReadChar ();
|
||||||
if (ReadInt (16) != 4) { /* 4 chars expected */
|
if (ReadInt (16) != 4) { /* 4 chars expected */
|
||||||
longjmp (JumpBuf, RC_NOCONV);
|
Error (RC_NOCONV);
|
||||||
}
|
}
|
||||||
AssignInt ();
|
AssignInt ();
|
||||||
++Conversions;
|
++Conversions;
|
||||||
@@ -580,13 +646,13 @@ Again:
|
|||||||
|
|
||||||
case 'n':
|
case 'n':
|
||||||
/* Store characters consumed so far */
|
/* Store characters consumed so far */
|
||||||
IntVal = D->ccount;
|
IntVal = CharCount;
|
||||||
AssignInt ();
|
AssignInt ();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
/* Invalid conversion */
|
/* Invalid conversion */
|
||||||
longjmp (JumpBuf, RC_NOCONV);
|
Error (RC_NOCONV);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -604,7 +670,7 @@ Again:
|
|||||||
* conversions, it is considered an error, otherwise the number
|
* conversions, it is considered an error, otherwise the number
|
||||||
* of conversions is returned (the default behaviour).
|
* of conversions is returned (the default behaviour).
|
||||||
*/
|
*/
|
||||||
if (C == EOF && D->ccount == 0) {
|
if (C == EOF && CharCount == 0) {
|
||||||
/* Special case: error */
|
/* Special case: error */
|
||||||
Conversions = EOF;
|
Conversions = EOF;
|
||||||
}
|
}
|
||||||
@@ -617,3 +683,4 @@ Again:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -21,13 +21,12 @@ typedef int __fastcall__ (*ungetfunc) (int c, void* data);
|
|||||||
|
|
||||||
|
|
||||||
/* Control structure passed to the low level worker function.
|
/* Control structure passed to the low level worker function.
|
||||||
* Beware: The low level functions will access the structure on the assembly
|
* Beware: This structure is mirrored in the _scanf.inc assembler include
|
||||||
* level, so check this when altering the structure.
|
* file, so check this when altering the structure.
|
||||||
*/
|
*/
|
||||||
struct scanfdata {
|
struct scanfdata {
|
||||||
getfunc get; /* Pointer to input routine */
|
getfunc get; /* Pointer to input routine */
|
||||||
ungetfunc unget; /* Pointer to pushback routine */
|
ungetfunc unget; /* Pointer to pushback routine */
|
||||||
unsigned ccount; /* Number of chars read */
|
|
||||||
|
|
||||||
/* Fields used outside of _scanf */
|
/* Fields used outside of _scanf */
|
||||||
void* data; /* Caller data */
|
void* data; /* Caller data */
|
||||||
@@ -36,7 +35,7 @@ struct scanfdata {
|
|||||||
|
|
||||||
|
|
||||||
/* Internal scanning routine */
|
/* 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
21
libsrc/common/_scanf.inc
Normal 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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user