Scanf improvements by Greg King

git-svn-id: svn://svn.cc65.org/cc65/trunk@3377 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
cuz 2005-02-14 09:19:59 +00:00
parent a4f6f14a6b
commit d406a9f677
8 changed files with 615 additions and 358 deletions

View file

@ -29,7 +29,6 @@ puts.s
qsort.s qsort.s
realloc.s realloc.s
rewind.s rewind.s
scanf.s
sleep.s sleep.s
strftime.s strftime.s
strtok.s strtok.s

View file

@ -1,5 +1,6 @@
# -*- makefile -*-
# #
# makefile for CC65 runtime library # makefile for CC65's common library
# #
.SUFFIXES: .o .s .c .SUFFIXES: .o .s .c
@ -26,9 +27,19 @@ CFLAGS = -Osir -g -T -t $(SYS) --forget-inc-paths -I . -I ../../include
%.o: %.s %.o: %.s
@$(AS) -g -o $@ $(AFLAGS) $< @$(AS) -g -o $@ $(AFLAGS) $<
#--------------------------------------------------------------------------
# Rules to help us see what code the compiler and assembler make.
%.s : %.c
@$(CC) $(CFLAGS) -S $<
%.lst : %.s
@$(AS) $(AFLAGS) -l -o /dev/null $<
#-------------------------------------------------------------------------- #--------------------------------------------------------------------------
# Object files # Object files
# From C source-files
C_OBJS = _afailed.o \ C_OBJS = _afailed.o \
_aligned_malloc.o \ _aligned_malloc.o \
_hextab.o \ _hextab.o \
@ -59,7 +70,6 @@ C_OBJS = _afailed.o \
qsort.o \ qsort.o \
realloc.o \ realloc.o \
rewind.o \ rewind.o \
scanf.o \
sleep.o \ sleep.o \
strftime.o \ strftime.o \
strxfrm.o \ strxfrm.o \
@ -67,7 +77,7 @@ C_OBJS = _afailed.o \
system.o \ system.o \
timezone.o timezone.o
# From assembly source-files
S_OBJS = _cwd.o \ S_OBJS = _cwd.o \
_fdesc.o \ _fdesc.o \
_file.o \ _file.o \
@ -134,6 +144,7 @@ S_OBJS = _cwd.o \
raise.o \ raise.o \
remove.o \ remove.o \
rename.o \ rename.o \
scanf.o \
setjmp.o \ setjmp.o \
signal.o \ signal.o \
sigtable.o \ sigtable.o \
@ -183,10 +194,10 @@ S_OBJS = _cwd.o \
all: $(C_OBJS) $(S_OBJS) all: $(C_OBJS) $(S_OBJS)
clean: clean:
@rm -f *~ @$(RM) *~ *.lst
@rm -f $(C_OBJS:.o=.s) @$(RM) $(C_OBJS:.o=.s)
@rm -f $(C_OBJS) @$(RM) $(C_OBJS)
@rm -f $(S_OBJS) @$(RM) $(S_OBJS)
zap: clean zap: clean

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,7 @@
/* /*
* _scanf.h * _scanf.h
* *
* (C) Copyright 2001 Ullrich von Bassewitz (uz@cc65.org) * (c) Copyright 2004, Ullrich von Bassewitz <uz@cc65.org>
* *
*/ */
@ -16,26 +16,26 @@
* return EOF if no more data is available. * return EOF if no more data is available.
*/ */
typedef int __fastcall__ (*getfunc) (void* data); typedef int __fastcall__ (*getfunc) (void* data);
/* Type of the function that is called to put back unused data */
typedef int __fastcall__ (*ungetfunc) (int c, void* data); 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: This structure is mirrored in the _scanf.inc assembler include * Beware: This structure is mirrored in the _scanf.inc assembler include
* file, 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 */
void* data; /* Pointer to struct. used outside of _scanf() */
/* Fields used outside of _scanf */
void* data; /* Caller data */
}; };
/* Internal scanning routine */ /* Internal scanning routine */
int __fastcall__ _scanf (struct scanfdata* d, const char* format, va_list ap); int __fastcall__ _scanf (const struct scanfdata* d, const char* format, va_list ap);
@ -44,4 +44,3 @@ int __fastcall__ _scanf (struct scanfdata* d, const char* format, va_list ap);

View file

@ -1,36 +0,0 @@
/*
* 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);
}

74
libsrc/common/scanf.s Normal file
View file

@ -0,0 +1,74 @@
;
; int scanf(const char* Format, ...);
;
; 2000-12-01, Ullrich von Bassewitz
; 2004-12-31, Greg King
;
.export _scanf
.import _stdin, pushax, addysp, _vfscanf
.import sp:zp, ptr1:zp
.macpack generic
; ----------------------------------------------------------------------------
; Code
;
_scanf:
sty ArgSize ; Number of argument bytes passed in .Y
; 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
; argument list. Adding the number of argument bytes, would result in a
; pointer that points _above_ the Format argument.
; Because we have to push stdin anyway, we will do that here, so:
;
; * we will save the subtraction of 2 (__fixargs__) later;
; * we will have the address of the Format argument which needs to
; be pushed next.
lda _stdin
ldx _stdin+1
jsr pushax
; Now, calculate the va_list pointer, which does point to Format.
lda sp
ldx sp+1
add ArgSize
bcc @L1
inx
@L1: sta ptr1
stx ptr1+1
; Push a copy of Format.
ldy #1
lda (ptr1),y
tax
dey
lda (ptr1),y
jsr pushax
; Load va_list [last and __fastcall__ argument to vfscanf()].
lda ptr1
ldx ptr1+1
; Call vfscanf().
jsr _vfscanf
; Clean up the stack. We will return what we got from vfscanf().
ldy ArgSize
jmp addysp
; ----------------------------------------------------------------------------
; Data
;
.bss
ArgSize:
.res 1 ; Number of argument bytes

View file

@ -1,14 +1,19 @@
; ;
; int __fastcall__ vfscanf (FILE* f, const char* format, va_list ap); ; int __fastcall__ vfscanf (FILE* f, const char* format, va_list ap);
; ;
; Ullrich von Bassewitz, 2004-11-27 ; 2004-11-27, Ullrich von Bassewitz
; 2004-12-21, Greg King
; ;
.export _vfscanf .export _vfscanf
.import _fgetc, _ungetc .import _fgetc, _ungetc, _ferror
.include "zeropage.inc" .include "zeropage.inc"
.include "_scanf.inc" .include "_scanf.inc"
.include "stdio.inc"
count := ptr3 ; Result of scan
; ---------------------------------------------------------------------------- ; ----------------------------------------------------------------------------
@ -25,23 +30,27 @@ d: .addr _fgetc ; GET
; int __fastcall__ vfscanf (FILE* f, const char* format, va_list ap) ; int __fastcall__ vfscanf (FILE* f, const char* format, va_list ap)
; /* Standard C function */ ; /* Standard C function */
; { ; {
; struct scanfdata d;
;
; /* Initialize the data struct. We do only need the given file as user data, ; /* 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 ; * because the (getfunc) and (ungetfunc) functions are crafted so that they
; * and ungetc functions. ; * match the standard-I/O fgetc() and ungetc().
; */ ; */
; d.get = (getfunc) fgetc, ; static struct scanfdata d = {
; d.unget = (ungetfunc) ungetc, ; ( getfunc) fgetc,
; d.data = f; ; (ungetfunc) ungetc
; };
; static int count;
; ;
; /* Call the internal function and return the result */ ; d.data = (void*) f;
; return _scanf (&d, format, ap); ;
; /* Call the internal function */
; count = _scanf (&d, format, ap);
;
; /* And, return the result */
; return ferror (f) ? EOF : count;
; } ; }
; ;
; Since _scanf has the same parameter stack as vfscanf, with f replaced by &d, ; Because _scanf() has the same parameter stack as vfscanf(), with f replaced
; we will do exactly that. _scanf will then clean up the stack, so we can jump ; by &d, we will do exactly that. _scanf() then will clean up the stack.
; directly there, no need to return.
; Beware: Since ap is a fastcall parameter, we must not destroy a/x. ; Beware: Since ap is a fastcall parameter, we must not destroy a/x.
; ;
@ -63,8 +72,27 @@ _vfscanf:
lda #>d lda #>d
sta (sp),y sta (sp),y
; Restore the low byte of ap and jump to the _scanf function ; Restore the low byte of ap, and call the _scanf function
pla pla
jmp __scanf jsr __scanf
sta count
stx count+1
; Return -1 if there was a read error during the scan
lda d + SCANFDATA::DATA ; Get f
ldx d + SCANFDATA::DATA+1
jsr _ferror
tay
beq L1
lda #<EOF
tax
rts
; Or, return the result of the scan
L1: lda count
ldx count+1
rts

View file

@ -2,10 +2,12 @@
; 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 */
; ;
; Ullrich von Bassewitz, 2004-11-28 ; 2004-11-28, Ullrich von Bassewitz
; 2004-12-21, Greg King
; ;
.export _vsscanf .export _vsscanf
.import popax, __scanf .import popax, __scanf
.importzp sp, ptr1, ptr2 .importzp sp, ptr1, ptr2
@ -25,14 +27,13 @@
; static int __fastcall__ get (struct sscanfdata* 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 = d->str[d->index];
; if (C = d->str[d->index]) { ; if (C == '\0') {
; /* Increment index only if end not reached */
; ++d->index;
; return C;
; } else {
; return EOF; ; return EOF;
; } ; }
; /* Increment index only if end not reached */
; ++d->index;
; return C;
; } ; }
; ;
@ -73,17 +74,17 @@
L1: tax ; Save return value L1: tax ; Save return value
tya ; Low byte of index tya ; Low byte of index
ldy #SSCANFDATA::INDEX ldy #SSCANFDATA::INDEX
add #1 add #<1
sta (ptr1),y sta (ptr1),y
iny iny
lda (ptr1),y lda (ptr1),y
adc #$00 adc #>1
sta (ptr1),y sta (ptr1),y
; Return the char just read ; Return the char just read
txa txa
ldx #$00 ldx #>0
rts rts
.endproc .endproc
@ -110,11 +111,11 @@ L1: tax ; Save return value
ldy #SSCANFDATA::INDEX ldy #SSCANFDATA::INDEX
lda (ptr1),y lda (ptr1),y
sub #1 sub #<1
sta (ptr1),y sta (ptr1),y
iny iny
lda (ptr1),y lda (ptr1),y
sbc #0 sbc #>1
sta (ptr1),y sta (ptr1),y
; Return c ; Return c
@ -127,15 +128,16 @@ L1: tax ; Save return value
; 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 sscanfdata sd;
; struct scanfdata d;
;
; /* Initialize the data structs. The sscanfdata struct will be passed back ; /* Initialize the data structs. The sscanfdata struct will be passed back
; * to the get and unget functions by _scanf. ; * to the get and unget functions by _scanf().
; */ ; */
; d.get = (getfunc) get; ; static struct sscanfdata sd;
; d.unget = (ungetfunc) unget, ; static const struct scanfdata d = {
; d.data = &sd; ; ( getfunc) get,
; (ungetfunc) unget,
; (void*) &sd
; };
;
; sd.str = str; ; sd.str = str;
; sd.index = 0; ; sd.index = 0;
; ;
@ -144,10 +146,10 @@ L1: tax ; Save return value
; } ; }
; ;
.data .bss
sd: .tag SSCANFDATA sd: .tag SSCANFDATA
.rodata
d: .addr get d: .addr get
.addr unget .addr unget
.addr sd .addr sd
@ -177,11 +179,10 @@ d: .addr get
sta sd + SSCANFDATA::INDEX sta sd + SSCANFDATA::INDEX
sta sd + SSCANFDATA::INDEX+1 sta sd + SSCANFDATA::INDEX+1
; Restore the low byte of ap and jump to _scanf which will cleanup the stacl ; Restore the low byte of ap, and jump to _scanf() which will clean up the stack
pla pla
jmp __scanf jmp __scanf
.endproc .endproc