1
0
mirror of https://github.com/cc65/cc65.git synced 2024-12-23 19:29:37 +00:00
cc65/libsrc/common/vsscanf.s

189 lines
4.2 KiB
ArmAsm

;
; int __fastcall__ vsscanf (const char* str, const char* format, va_list ap);
; /* Standard C function */
;
; 2004-11-28, Ullrich von Bassewitz
; 2014-09-10, Greg King
;
.export _vsscanf
.import popax, __scanf
.importzp sp, ptr1, ptr2
.macpack generic
; ----------------------------------------------------------------------------
; Structure used to pass data to the callback functions
.struct SSCANFDATA
STR .addr
INDEX .word
.endstruct
; ----------------------------------------------------------------------------
; static int __fastcall__ get (struct sscanfdata* d)
; /* Read a character from the input string and return it */
; {
; char C = d->str[d->index];
; if (C == '\0') {
; return EOF;
; }
; /* Increment index only if end not reached */
; ++d->index;
; return C;
; }
;
.code
.proc get
sta ptr1
stx ptr1+1 ; Save d
; Get d->str adding the high byte of index to the pointer, so we can access
; the byte in the string with just the low byte as index
ldy #SSCANFDATA::STR
lda (ptr1),y
sta ptr2
iny
lda (ptr1),y
ldy #SSCANFDATA::INDEX+1
add (ptr1),y
sta ptr2+1
; Load the low byte of the index and fetch the byte from the string
dey ; = SSCANFDATA::INDEX
lda (ptr1),y
tay
lda (ptr2),y
; Return EOF if we are at the end of the string
bne L1
lda #<-1
tax
rts
; Bump the index (beware: A contains the char we must return)
L1: tax ; Save return value
tya ; Low byte of index
ldy #SSCANFDATA::INDEX
add #<$0001
sta (ptr1),y
iny
lda (ptr1),y
adc #>$0001
sta (ptr1),y
; Return the char just read
txa
ldx #>$0000
rts
.endproc
; ----------------------------------------------------------------------------
; 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;
; }
;
.code
.proc unget
sta ptr1
stx ptr1+1 ; Save d
; Decrement the index
ldy #SSCANFDATA::INDEX
lda (ptr1),y
sub #<$0001
sta (ptr1),y
iny
lda (ptr1),y
sbc #>$0001
sta (ptr1),y
; Return c
jmp popax
.endproc
; ----------------------------------------------------------------------------
; int __fastcall__ vsscanf (const char* str, const char* format, va_list ap)
; /* Standard C function */
; {
; /* Initialize the data structs. The sscanfdata struct will be passed back
; ** to the get and unget functions by _scanf().
; */
; static struct sscanfdata sd;
; static const struct scanfdata d = {
; ( getfunc) get,
; (ungetfunc) unget,
; (void*) &sd
; };
;
; sd.str = str;
; sd.index = 0;
;
; /* Call the internal function and return the result */
; return _scanf (&d, format, ap);
; }
;
.bss
sd: .tag SSCANFDATA
.rodata
d: .addr get
.addr unget
.addr sd
.code
.proc _vsscanf
; Save the low byte of ap (which is passed in a/x)
pha
; Initialize sd and at the same time replace str on the stack by a pointer
; to d
ldy #2 ; Stack offset of str
lda (sp),y
sta sd + SSCANFDATA::STR
lda #<d
sta (sp),y
iny
lda (sp),y
sta sd + SSCANFDATA::STR+1
lda #>d
sta (sp),y
lda #$00
sta sd + SSCANFDATA::INDEX
sta sd + SSCANFDATA::INDEX+1
; Restore the low byte of ap, and jump to _scanf() which will clean up the stack
pla
jmp __scanf
.endproc