;
-; int vsnprintf (char* Buf, size_t size, const char* Format, va_list ap);
+; int __fastcall__ vsnprintf (char* Buf, size_t size, const char* Format, va_list ap);
;
-; Ullrich von Bassewitz, 2009-09-26
+; 2009-09-26, Ullrich von Bassewitz
+; 2015-07-17, Greg King
;
- .export _vsnprintf
- .import ldaxysp, popax, incsp2, incsp6
- .import _memcpy, __printf
- .importzp sp, ptr1
+ .export _vsnprintf, vsnprintf
+ .import ldaxysp, popax, incsp2, incsp6
+ .import _memcpy, __printf
+ .importzp sp, ptr1
- .macpack generic
+ .include "errno.inc"
+
+ .macpack generic
.data
; Static data for the _vsnprintf routine
;
-outdesc: ; Static outdesc structure
- .word 0 ; ccount
- .word out ; Output function pointer
- .word 0 ; ptr
- .word 0 ; Buffer size
+outdesc: ; Static outdesc structure
+ccount: .word 0 ; ccount
+func: .word out ; Output function pointer
+bufptr: .word 0 ; ptr
+bufsize:.word 0 ; Buffer size
.code
-; ----------------------------------------------------------------------------
-; Callback routine used for the actual output.
-;
-; static void out (struct outdesc* d, const char* buf, unsigned count)
-; /* Routine used for writing */
-;
-; Since we know, we're called with a pointer to our static outdesc structure,
-; we don't need the pointer passed on the stack.
-
-out:
-
-; Calculate the space left in the buffer. If no space is left, don't copy
-; any characters
-
- lda outdesc+6 ; Low byte of buffer size
- sec
- sbc outdesc+0 ; Low byte of bytes already written
- sta ptr1
- lda outdesc+7
- sbc outdesc+1
- sta ptr1+1
- bcs @L0 ; Space left
- lda #0
- sta ptr1
- sta ptr1+1
-
-; Replace the pointer to d by a pointer to the write position in the buffer
-; for the call to memcpy that follows.
-
-@L0: lda outdesc+0
- clc
- adc outdesc+4
- ldy #4
- sta (sp),y
-
- lda outdesc+1
- adc outdesc+5
- iny
- sta (sp),y
-
-; Get Count from stack
-
- jsr popax
-
-; outdesc.ccount += Count;
-
- pha
- clc
- adc outdesc+0
- sta outdesc+0
- txa
- adc outdesc+1
- sta outdesc+1
- pla
-
-; if (Count > Left) Count = Left;
-
- cmp ptr1
- bne @L1
- cpx ptr1+1
-@L1: bcs @L2
- lda ptr1
- ldx ptr1+1
-
-; Jump to memcpy, which will cleanup the stack and return to the caller
-
-@L2: jmp _memcpy
-
-
; ----------------------------------------------------------------------------
; vsprintf - formatted output into a buffer
;
;
_vsnprintf:
- pha ; Save low byte of ap
+ pha ; Save ap
+ txa
+ pha
-; Setup the outdesc structure
+; Setup the outdesc structure. This is also an additional entry point for
+; vsprintf with ap on stack
- lda #0
- sta outdesc
- sta outdesc+1 ; Clear ccount
+vsnprintf:
+ lda #0
+ sta ccount+0
+ sta ccount+1 ; Clear ccount
; Get the size parameter and replace it by a pointer to outdesc. This is to
-; build a stack frame for the call to _printf.
-; If size is zero, there's nothing to do.
+; build a stack frame for the call to _printf. The size must not be greater
+; than INT_MAX because the return type is int. If the size is zero,
+; then nothing will be written into the buffer; but, the arguments still will
+; be formatted and counted.
ldy #2
lda (sp),y
sta ptr1
+
lda #<outdesc
sta (sp),y
+
iny
lda (sp),y
+ bmi L9 ; More than $7FFF
sta ptr1+1
- ora ptr1
- beq L9
lda #>outdesc
sta (sp),y
-; Write size-1 to the outdesc structure
+; Write size-1 to outdesc.uns. It will be -1 if there is no buffer.
- ldx ptr1
ldy ptr1+1
- dex
+ ldx ptr1
bne L1
dey
-L1: stx outdesc+6
- sty outdesc+7
+L1: dex
+ stx bufsize+0
+ sty bufsize+1
-; Copy buf to the outdesc structure
+; Copy buf to the outdesc.ptr
ldy #5
jsr ldaxysp
- sta outdesc+4
- stx outdesc+5
+ sta bufptr+0
+ stx bufptr+1
-; Restore low byte of ap and call _printf
+; There must be a buffer if its size is non-zero.
- pla
- jsr __printf
+ bit bufsize+1
+ bmi L5
+ ora bufptr+1
+ bze L0 ; The pointer shouldn't be NULL
-; Terminate the string
+; Restore ap and call _printf
- lda outdesc+0
- ldx outdesc+1
- cpx outdesc+7
+L5: pla
+ tax
+ pla
+ jsr __printf
+
+; Terminate the string if there is a buffer. The last char. is at either
+; bufptr+bufsize or bufptr+ccount, whichever is smaller.
+
+ ldx bufsize+1
+ bmi L4 ; -1 -- No buffer
+ lda bufsize+0
+ cpx ccount+1
bne L2
- cmp outdesc+6
+ cmp ccount+0
L2: bcc L3
- lda outdesc+6
- ldx outdesc+7
+ lda ccount+0
+ ldx ccount+1
clc
-L3: adc outdesc+4
+L3: adc bufptr+0
sta ptr1
txa
- adc outdesc+5
+ adc bufptr+1
sta ptr1+1
lda #0
; Return the number of bytes written and drop buf
- lda outdesc ; ccount
- ldx outdesc+1
- jmp incsp2
+L4: lda ccount+0
+ ldx ccount+1
+ jmp incsp2
-; Bail out if size is zero
+; Bail out if size is too high.
-L9: lda #0
- tax
+L9: ldy #ERANGE
+ .byte $2C ;(bit $xxxx)
+
+; NULL buffer pointers usually are invalid.
+
+L0: ldy #EINVAL
+ pla ; Drop ap
+ pla
+ tya
+ jsr __directerrno ; Return -1
jmp incsp6 ; Drop parameters
+; ----------------------------------------------------------------------------
+; Callback routine used for the actual output.
+;
+; static void __cdecl__ out (struct outdesc* d, const char* buf, unsigned count)
+; /* Routine used for writing */
+;
+; Since we know, we're called with a pointer to our static outdesc structure,
+; we don't need the pointer passed on the stack.
+
+out:
+
+; Calculate the space left in the buffer. If no space is left, don't copy
+; any characters
+
+ lda bufsize+0 ; Low byte of buffer size
+ sec
+ sbc ccount+0 ; Low byte of bytes already written
+ sta ptr1
+ lda bufsize+1
+ bmi @L9 ; -1 -- No buffer
+ sbc ccount+1
+ sta ptr1+1
+ bcs @L0 ; Branch if space left
+@L9: lda #$0000
+ sta ptr1
+ sta ptr1+1 ; No space left
+
+; Replace the pointer to d by a pointer to the write position in the buffer
+; for the call to memcpy that follows.
+
+@L0: lda bufptr+0
+ clc
+ adc ccount+0
+ ldy #4
+ sta (sp),y
+
+ lda bufptr+1
+ adc ccount+1
+ iny
+ sta (sp),y
+
+; Get Count from stack
+
+ jsr popax
+
+; outdesc.ccount += Count;
+
+ pha
+ clc
+ adc ccount+0
+ sta ccount+0
+ txa
+ adc ccount+1
+ sta ccount+1
+ pla
+
+; if (Count > Left) Count = Left;
+
+ cpx ptr1+1
+ bne @L1
+ cmp ptr1
+@L1: bcc @L2
+ lda ptr1
+ ldx ptr1+1
+
+; Jump to memcpy, which will cleanup the stack and return to the caller
+
+@L2: jmp _memcpy
+
+
+