
;
; Copyright (c) 1988 Commodore-Amiga, Inc.
;
; Executables based on this information may be used in software
; for Commodore Amiga computers.  All other rights reserved.
;
; This information is provided "as is"; no warranties are made.
; All use is at your own risk, and no liability or responsibility is assumed.
;

		SECTION	_printf,CODE
		XREF	_AbsExecBase,_LVOOpenLibrary,_LVOCloseLibrary
		XREF	_LVOOutput,_LVOWrite

;===========================================================================
; The actual code of the printf function.  Generates a formatted string with
; a maximum length of 512 bytes and then calls the appropriate text output
; function.  Text is output as a whole string to speed up the DOS write
; function which goes real slow on single character output.  Args passed on
; the stack as: format,arg1,arg2, ... arg8 and it is up to the caller to
; clean up the stack space used, this is handled by the printf macro.
;===========================================================================
		XDEF	_printf
_printf		movem.l	d0-d2/a0-a4/a6,-(sp)	save regs
		movea.l	40(sp),a3		a3 points to string
		lea.l	44(sp),a4		a4 points to args
		lea.l	-256(sp),sp		make room for output string
		movea.l	sp,a2			a2 points to output string

; The main loop, copy characters to the output buffer until a % or \ is
; encountered in which case interpret the characters following in the same
; manner as C's printf function and put the results into the output stream
; instead.  A null byte terminates the output.
_printloop	move.b	(a3)+,d0		get a copy of the byte
_possibleend	move.b	d0,(a2)			move to output string
		beq	_printdone		terminating byte
		cmpi.b	#'\',d0			special character byte ?
		beq.s	_specialchar		yes, go see what it is
		cmpi.b	#'%',d0			number or string byte ?
		beq.s	_introchar		yes, go process that
_bumpptr	addq.l	#1,a2			nothing special, bump ptr...
		bra.s	_printloop		...and go back for the next

; Found a backslash, replace character after with tab or newline (\t or \n)
_specialchar	move.b	(a3)+,d0		get the next character
		beq.s	_possibleend		that could have been nasty!!
		cmpi.b	#'\',d0			did caller want a backslash
		beq.s	_bumpptr		yes, so leave the other
		cmpi.b	#'t',d0			did user want a tab ?
		bne.s	_checkcr		nope, maybe a newline
		move.b	#9,(a2)+		yes, store tab and bump
		bra.s	_printloop		and go for the next char
_checkcr	cmpi.b	#'n',d0			did user want a newline ?
		bne.s	_printloop		nope, ignore all others
		move.b	#13,(a2)+		yes, store cr and bump
		move.b	#10,(a2)+
		bra.s	_printloop		and go for the next char

; Found a percent sign.  Must be introducing a number, string or character
_introchar	move.b	(a3)+,d0		get the next character
		beq.s	_possibleend		another possible oops!
		cmpi.b	#'%',d0			did caller want a percent?
		beq.s	_bumpptr		yes, so leave the last one
		cmpi.b	#'c',d0			print a character ?
		bne.s	_checkstring		nope!
		move.l	(a4)+,d0		get char from arg stack
		move.b	d0,(a2)+		store it and bump ptr
		bra.s	_printloop		and go for the next char
_checkstring	cmpi.b	#'s',d0			print a string ?
		bne.s	_checknumber		nope!
		movea.l	(a4)+,a0		get ptr from arg stack
10$		move.b	(a0)+,(a2)+		and copy the string
		bne.s	10$
		subq.l	#1,a2			went 1 byte too far
		bra.s	_printloop		go for the next char

; wasn't a string or character code so it has to be a number code here
_checknumber	moveq.l	#0,d2			flag, short (word) number
		cmpi.b	#'l',d0			long version of a number ?
		bne.s	_whatnumber		no, it was a short
		moveq.l	#1,d2			flag, longword number
		move.b	(a3)+,d0		and get the next letter
		beq.s	_possibleend		yet another nasty spot!
_whatnumber	cmpi.b	#'x',d0			hex character ?
		bne.s	_decnumber		nope, must be a decimal
		move.l	(a4)+,d0		get hex value to print
		movea.l	a2,a0			buffer to store to
		tst.w	d2			see what size
		bne.s	_dolonghex		it's a longword
		bsr	bin2hex16		it's a word
		bra.s	_findend		find where number ends
_dolonghex	bsr	bin2hex32
		bra.s	_findend		find where number ends

_decnumber	cmpi.b	#'d',d0			really want a decimal ?
		bne	_printloop		nope, illegal character!
		move.l	(a4)+,d0		get decimal value to print
		movea.l	a2,a0			and buffer to store to
		tst.w	d2			see what size
		bne.s	_dolongdec		it's a longword
		bsr	bin2asc16		it's a word
		bra.s	_findend		see what size
_dolongdec	bsr	bin2asc32

; A number has been stored into the buffer, find the end to update A2 ptr
_findend	tst.b	(a2)+			search for null byte
		bne.s	_findend		not there yet
		subq.l	#1,a2			went one byte too far
		bra	_printloop		go for the next char

; We got to the end of the format string and now have a formatted string on
; the stack that is terminated by a null byte.  Open the dos library to find
; the current output stream and write the string out.
_printdone	movea.l	_AbsExecBase,a6		need exec library node
		lea.l	DosName(pc),a1
		moveq.l	#0,d0			don't care what version
		jsr	_LVOOpenLibrary(a6)
		tst.l	d0
		beq.s	_cleanup		didn't get the library
		movea.l	d0,a6

		jsr	_LVOOutput(a6)		find output handle
		move.l	d0,d1			where we print to
		move.l	sp,d2			where we print from
		suba.l	sp,a2			find length of string
		move.l	a2,d3
		jsr	_LVOWrite(a6)		and write it out

		movea.l	a6,a1
		movea.l	_AbsExecBase,a6		finished with dos lib now
		jsr	_LVOCloseLibrary(a6)

_cleanup	lea.l	256(sp),sp		fix up the stack pointer
		movem.l	(sp)+,d0-d2/a0-a4/a6	restore regs
		rts				all done

		INCLUDE	"numbers.asm"

DosName		DC.B	'dos.library',0
		CNOP	0,2

		END

