⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 printff.asm

📁 汇编编程艺术
💻 ASM
📖 第 1 页 / 共 2 页
字号:
StdGrp		group	stdlib,stddata
stddata		segment	para public 'sldata'
		extrn	fpacc:word
stddata		ends
;
stdlib		segment	para public 'slcode'
		assume	cs:stdgrp
;
		extrn	sl_Putc:far, sl_Puti:far, sl_ISize:far
		extrn	sl_Putw:far, sl_Puth:far
		extrn	sl_Putu:far, sl_PutUL:far, sl_ULSize:far
		extrn	sl_LSize:far, sl_USize:far, sl_PutL:far
		extrn	sl_pute:far, sl_putf:far
		extrn	sl_LSFPA:far, sl_LDFPA:far, sl_LEFPA:far
;
;
putc		equ	sl_putc
puti		equ	sl_puti
ISize		equ	sl_ISize
putw		equ	sl_putw
puth		equ	sl_puth
putu		equ	sl_putu
putul		equ	sl_putul
ulsize		equ	sl_ulsize
lsize		equ	sl_lsize
usize		equ	sl_usize
putl		equ	sl_putl
putf		equ	sl_putf
pute		equ	sl_pute
;
;
; Printff- Like Printf except this guy supports floating point values too.
;	   A program should not include both printf and printff.  Printff
;	   includes everything printf does an more.  Including them both
;	   would waste a lot of memory.  There are two routines because
;	   most people don't need floating point I/O and printff links in
;	   the floating point package which is quite large.
;
;               call    printf
;               db      "format string",0
;               dd      item1, item2, ..., itemn
;
; The format string is identical to "C".  Item1..Itemn are pointers to
; values to print for this string.  Each item must be matched by the
; corresponding "%xxx" item in the format string.
;
; Format string format:
;
; 1)    All characters, except the following, are printed to the standard
;       output as-is.
;
; 2)    "\" is the escape character.  Anything following it is printed
;       as-is except standard "C" values like \r, \n, \b, \t, etc.  If
;       a decimal digit follows the back-slash, printf assumes that this
;       is a hexadecimal number and converts following three digits to
;       an ASCII character and prints it.  Other back-slash operators are
;       just like those for "C".
;
; 3)	Format Control Strings:
;
;	General format:  "%s\cn^f" where:
;				s = -
;				n = a decimal integer or two integers
;				    separated by a period (for fp).
;				c = a fill character
;				^ = ^
;				f = a format character
;
;			All fields except "%" and "f" are optional.
;
;	s = -   	Left justify value and use fill character.
;	\c present	Use "c" as fill character.
;	n present	Use "n" as the minimum field width.
;	^ present	The address associated with f is the address of a
;				pointer to the object, not the address of
;				the object itself.  The pointer is a far ptr.
;
;	f is one of the following
;
;		d -	Print signed integer in decimal notation.
;		i -	Print signed integer in decimal notation.
;		x -	Print word value in hexadecimal notation.
;		h -	Print byte value in hexadecimal notation.
;		u -	Print unsigned integer in decimal notation.
;		c -	Print character.
;		s -	Print string.
;		f -	Print floating point number in decimal form.
;	 	e -	Print floating point number in scientific notation.
;
;		ld-	Print long signed integer.
;		li-	Print long unsigned integer.
;		lx-	Print long hexadecimal number.
;		lu-	Print long unsigned number.
;		lf-	Print dbl prec fp number in decimal form.
;		le-	Print dbl prec fp number in scientific notation.
;
;		gf-	Print extended precision fp number in decimal form.
;		ge-	Print extended precision fp number in sci not form.
;
;
;	Calling Sequence:
;
;		call	Printf
;		db	"Format String",0
;		dd	adrs1, adrs2, ..., adrsn
;
;	Where the format string is ala "C" (and the descriptions above)
;	and adrs1..adrsn are addresses (far ptr) to the items to print.
;	Unless the "^" modifier is present, these addresses are the actual
;	addresses of the objects to print.
;
;
;
cr		equ	0dh
ff		equ	0ch
lf		equ	0ah
tab		equ	09h
bs		equ	08h
;
RtnAdrs		equ	2[bp]
;
		public  sl_printff
sl_printff	proc    far
		push	bp
		mov	bp, sp
		pushf
		push	ax
		push	bx
		push	cx
		push	dx
		push	di
		push	si
		push	es
		push	ds
;
; Get pointers to the return address (format string).
		cld
		les	di, RtnAdrs
		lds	si, RtnAdrs
;
; Okay, search for the end of the format string.  After these instructions,
; di points just beyond the zero byte at the end of the format string.  This,
; of course, points at the first address beyond the format string.
;
		mov	al, 0
		mov	cx, 65535
	repne	scasb
;
PrintItems:	lodsb			;Get char si points at.
		cmp	al, 0		;EOS?
		jz	PrintfDone
		cmp	al, "%"		;Start of a format string?
		jz	FmtItem
		cmp	al, "\"		;Escape character?
		jnz	PrintIt
		call	GetEscChar
PrintIt:	call	Putc
		jmp	PrintItems
;
FmtItem:	call	GetFmtItem	;Process the format item here.
		jmp	PrintItems
;
PrintfDone:	mov	RtnAdrs, di	;Put out new return address.
		pop	ds
		pop	es
		pop	si
		pop	di
		pop	dx
		pop	cx
		pop	bx
		pop	ax
		popf
		pop	bp
		ret
sl_printff      endp
;
;
;
;
; GetEscChar- Handles items immediately following the escape character "\".
;
;	Special escape characters (upper/lower case is acceptable):
;
;		n	Newline (cr/lf)
;		t	tab
;		b	backspace
;		r	return
;		l	line feed
;		f	formfeed
;		\	\
;		%	&
;		0xhh	Char with hex character code hh.  Must have exactly
;			two hexadecimal digits.
;
GetEscChar	proc	near
		lodsb			;Get next character
		cmp	al, 'n'
		je	RtnNL
		cmp	al, 'N'
		je	RtnNL
		cmp	al, 't'
		je	RtnTab
		cmp	al, 'T'
		je	RtnTab
		cmp	al, 'b'
		je	RtnBS
		cmp	al, 'B'
		je	RtnBS
		cmp	al, 'r'
		je	RtnRtn
		cmp	al, 'R'
		je	RtnRtn
		cmp	al, 'l'
		je	RtnLF
		cmp	al, 'L'
		je	RtnLF
		cmp	al, 'f'
		je	RtnFF
		cmp	al, 'F'
		je	RtnFF
;
; Check for the presence of a 0xhh value here:
;
		cmp	al, '0'
		jne	RtnChar
		cmp	byte ptr [si], 'x'
		je	GetHex
		cmp	byte ptr [si], 'X'
		jne	RtnChar
;
; Okay, process the hex value here.  Note that exactly two hex digits must
; follow the 0x.
;
GetHex:		inc	si		;Point at first hex digit.
		lodsb			;Get first hex digit.
		and	al, 05fh	;l.c. -> u.c.
		cmp	al, 'A'
		jb	GotIt
		sub	al, '7'
GotIt:		shl	al, 1		;Put into H.O. nibble.
		shl	al, 1
		shl	al, 1
		shl	al, 1
		mov	ah, al		;Save for later
		lodsb			;Get next char.
		and	al, 05fh
		cmp	al, 'A'
		jb	GotIt2
		sub	al, '7'
GotIt2:		and	al, 0fh
		or	al, ah
		ret			;Return hex constant.
;
; RtnNL (return Newline) cheats.  It needs to return two characters.
; Since GetEscChar only returns a single character, this code goes ahead
; and calls putc to output the CR and the returns the LF.
;
RtnNL:		mov	al, cr
		call	Putc
		mov	al, lf
		ret
;
RtnTab:		mov	al, tab
		ret
;
RtnBS:		mov	al, bs
		ret
;
RtnRtn:		mov	al, cr
		ret
;
RtnLF:		mov	al, lf
		ret
;
RtnFF:		mov	al, ff
RtnChar:	ret
;
GetEscChar	endp
;
;
;
GetFmtItem	proc	near
		lodsb				;Get char beyond "%"
;
		mov	cx, 1			;Default field width is 1.
		mov	dl, 0			;Default is right justified
		mov	dh, ' '			;Default fill char is space.
		mov	ah, ' '			;Assume straight ptr, not handle.
;
; See if the user wants the value left justified:
;
		cmp	al, '-'
		jne	NotLeftJust
		inc	dl			;Set to right justified
		lodsb				;Get next character.
;
; See if the user wants to change the padding character.
;
NotLeftJust:	cmp	al, '\'
		jne	NoPadChange
		lodsb				;Get Padding Character.
		mov	dh, al			;Save padding character.
		lodsb				;Get next character
;
; See if the user wants a different field width:
;
NoPadChange:	cmp	al, '0'
		jb	NoFldWidth
		cmp	al, '9'
		ja	NoFldWidth
		call	GetDecVal
;
; See if the user wants to specify a handle rather than a straight pointer
;
NoFldWidth:	cmp	al, '^'
		jne     ChkFmtChars
		mov	ah, al
		lodsb				;Skip "^" character
;
; Okay, process the format characters down here.
;
ChkFmtChars:	and	al, 05fh		;l.c. -> U.C.
		cmp	al, 'D'
		je	PrintDec2
		cmp	al, 'I'
		je	PrintDec2
		cmp	al, 'C'
		je	PrintChar2
;
		cmp	al, 'X'
		jne	TryH
		jmp	PrintHexWord
;
PrintDec2:	jmp	PrintDec
PrintChar2:	jmp	PrintChar
TryH:		cmp	al, 'H'
		jne	TryU
		jmp	PrintHexByte
;
TryU:		cmp	al, 'U'
		jne	TryString
		jmp	PrintUDec
;
TryString:	cmp	al, 'S'
		jne	TryFloat
		jmp	PrintString
;
TryFloat:	cmp	al, 'F'
		jne	TrySci
		jmp	PrintSPFP
;
TrySci:		cmp	al, 'E'
		jne	TryExt
		jmp	PrintSPFPE
;
TryExt:		cmp	al, 'G'
		jne	TryLong
		lodsb			;If it's the "G" modifier, look for F/E
		and	al, 05fh	;l.c. -> U.C.
		cmp	al, 'F'		;See if GF (ext prec., dec out).
		jne	TryEE
		jmp	PrintDPFP
;
TryEE:		cmp	al, 'E'		;See if GE (ext prec, sci not out).
		jne	Default
		jmp	PrintDPFPE
;
;
;
TryLong:	cmp	al, 'L'
		jne	Default
;
; If we've got the "L" modifier, this is a long value to print, get the
; data type character as the next value:
;
		lodsb
		and	al, 05fh		;l.c. -> U.C.
		cmp	al, 'D'
		je	JmpDec
		cmp	al, 'I'
		jne	TryLU
JmpDec:		jmp	LongDec
;
TryLU:		cmp	al, 'U'
		jne	TryX
		jmp	LongU
;
TryX:		cmp	al, 'X'
		jne	TryLF
		jmp	LongX
;
TryLF:		cmp	al, 'F'
		jne	TryLE
		jmp     PrintEPFP
;
TryLE:		cmp	al, 'E'
		jne	Default
		jmp	PrintEPFPE
;
;
; If none of the above, simply return without printing anything.
;
Default:	ret
;
;
;
PrintSPFP:      call	GetPtr
		xchg	di, bx
		call	sl_LSFPA
DoTheRestf:	mov	ax, cx
		call	putf
		xchg	di, bx
		ret
;
PrintSPFPE:     call	GetPtr
		xchg	di, bx

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -