📄 printff.asm
字号:
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 + -