home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The C Users' Group Library 1994 August
/
wc-cdrom-cusersgrouplibrary-1994-08.iso
/
vol_300
/
330_03
/
tskprf.asm
< prev
next >
Wrap
Assembly Source File
|
1990-10-12
|
30KB
|
1,659 lines
;
; --- Version 2.2 90-10-12 10:38 ---
;
; CTask - Printf replacement
;
; Public Domain Software written by
; Thomas Wagner
; Ferrari electronic Gmbh
; Beusselstrasse 27
; D-1000 Berlin 21
; Germany
;
; This file is new with Version 2.1.
;
; This module contains substitutes for the standard C printf
; family formatting routines. It uses no helper routines, and
; thus can be called from Assembler programs and is model
; independent. It is smaller and faster (up to 5 times) than
; the standard C printf, and supports all output options except
; floating point and some esoteric flags.
;
; Also supported is output to the second monitor in a dual-
; monitor system.
;
; The routines in this module are reentrant in the sense that nothing
; will crash if routines are re-entered concurrently. No protection
; against a garbled screen is built in, however, so external
; resource request/release calls are still necessary to make
; sure output to the display stays in proper order. The sprintf
; routines need no protection.
;
; No CTask specific stuff is used to allow use of the routines
; even when CTask is not installed.
;
; Note that the tsk_fprintf routine takes a different parameter
; than the standard fprintf. You have to pass an integer file
; handle, not a FILE *.
;
;---------------------------------------------------------------------------
;
; Conversion format:
;
; % [flags] [width] [.precision] [indirection] [size] conversion
;
; Flags supported:
;
; - Left-justify output
;
; the +, blank, and # flags are not supported.
;
; Width and precision are handled like in standard C, i.e.
; the * specification is supported. The only exception is
; that numeric output will not be suppressed for an explicit
; 0 precision.
;
; Size modifiers supported:
;
; N Near pointer
; F Far pointer
; h Short
; l Long
;
; Conversion characters supported:
;
; c single character
; s zero-terminated string
; x unsigned hex word, a-f
; X unsigned hex word, A-F
; d signed decimal int
; u unsigned decimal int
; p hex pointer, a-f
; P hex pointer, A-F
; n store converted length at int pointer
;
; In addition, two indirection operators are supported. Both
; can be repeated, but they should not normally be mixed.
;
; ^ Near indirection (param is DS-based near pointer)
; @ Far indirection (param is far pointer)
;
; Example:
; %d Displays the word parameter
; %^d Displays the word at DS:parameter
; %@d Displays the word at the far address
; given as parameter
;
;---------------------------------------------------------------------------
;
name tskprf
;
include tsk.mac
;
.tsk_model
;
public tsk_regen ; far pointer to regen buffer
public tsk_regen_s ; regen buffer segment
public tsk_regen_o ; current regen buffer offset
public tsk_disport ; display controller I/O port
;
Pubfunc tsk_putc ; put char to screen
Pubfunc tsk_puts ; put string to screen
Pubfunc tsk_rputc ; put char to regen
Pubfunc tsk_rputs ; put string to regen
;
CPubfnc tsk_printf ; print to screen
Pubfunc tsk_vprintf ; print to screen with arg pointer
CPubfnc tsk_fprintf ; print to file handle
Pubfunc tsk_vfprintf ; print to file handle w. argptr
CPubfnc tsk_sprintf ; print to string
Pubfunc tsk_vsprintf ; print to string w. argptr
CPubfnc tsk_rprintf ; print to regen
Pubfunc tsk_vrprintf ; print to regen w. argptr
;
Pubfunc tsk_setpos ; set regen cursor position
Pubfunc tsk_set_regen ; set regen address
Pubfunc tsk_set_dualdis ; init secondary monitor
Pubfunc tsk_set_currdis ; init primary monitor
Pubfunc tsk_set_colour ; init colour monitor
Pubfunc tsk_set_mono ; init mono monitor
Pubfunc tsk_set_attr ; set display attribute
Pubfunc tsk_set_clreol ; CR clears to EOL when set
;
;
; Configuration options:
;
; FILE_BUFSIZE Is the local buffer size for tsk_fprintf and tsk_vfprintf.
; The buffer is allocated on the stack, so it should
; not be chosen too large to avoid stack overflows.
; It must be a power of 2, and less than or equal to 256.
;
FILE_BUFSIZE = 64 - 1
;
;
; DFLT_FAR If set, pointers (%p and %n) and strings (%s) are assumed
; far by default, near pointers must use the N size
; modifiers.
; If clear, the default is near, so the F size modifier
; must be used for far pointers.
;
DFLT_FAR = 1 ; by default, pointers and strings are Far
;
;
; The local variables used in the main formatter.
; Those variables are relative to BP, and are accessed by
; several routines in this module (the local routines do not
; use the standard stack discipline, they should be viewed as
; Pascal-like nested routines within the scope of @disprintf).
;
dislocrec struc
convbuf db 11 dup(?) ; conversion buffer (hex/dec)
prflags db ? ; formatting flags
prhexch db ? ; Hex format offset for upper/lower case
prfcnt db ? ; file output counter
procnt dw ? ; output char counter
prwidth dw ? ; field width
prec dw ? ; precision
arglen dw ? ; argument length in bytes
prproc dw ? ; output routine offset
prargbx dw ? ; output routine BX argument
prargdx dw ? ; output routine DX argument
dislocrec ends
;
; formatting flags
;
F_LONGARG = 01h ; argument is long/far (4 bytes)
F_SHORTARG = 02h ; argument is single byte
F_PADZERO = 04h ; pad with zeros
F_LEFTADJ = 08h ; left adjust output
F_SIGNED = 10h ; signed number
F_WIDTH = 20h ; width is valid
F_PREC = 40h ; precision is valid
F_INDIR = 80h ; indirection was used
;
biosdata segment at 40h
org 4ah
bios_cols dw ?
org 63h
bios_chipad dw ?
org 84h
bios_rows db ?
biosdata ends
;
.tsk_data
;
tsk_regen label dword
tsk_regen_o dw 0
tsk_regen_s dw 0b000h ; default mono screen
;
tsk_disport dw 3b4h ; default mono 6845
tsk_attrib db 07h ; default white on black
;
sc_clreol db 0 ; default is don't clear
;
sc_cols dw 80 * 2
sc_end dw 25 * 80 * 2
;
sc_proc dw offset @nodis
;
.tsk_edata
.tsk_code
;
ctdataseg dw @CTASK_DATA
;
; setcsr - local routine to set the cursor to the current position
; on the regen display.
;
@setcsr proc near
;
push dx
mov dx,tsk_disport
or dx,dx
jz no_cursor
mov al,0eh
out dx,al
jmp $+2
mov ax,tsk_regen_o
shr ax,1
xchg ah,al
inc dx
out dx,al
jmp $+2
dec dx
mov al,0fh
out dx,al
jmp $+2
mov al,ah
inc dx
out dx,al
;
no_cursor:
pop dx
ret
;
@setcsr endp
;
;
; disregen - local routine to write char directly into the display
; regen buffer. The following control characters
; are handled special:
; 08 \b (BS) backspace one position (no erase)
; 09 \t (TAB) tab to next 8th column
; 0D \r (CR) carriage return
; 0A \n (LF) line feed
; Note: the printf routines will not pass
; a single line feed unchanged.
; 0B \v (VT) clear to end of line
; 0C \f (FF) clear to end of screen
;
;
; Entry: AL = char to display
; Uses: AX
;
@disregen proc near
;
push ds
mov ds,cs:ctdataseg ; allow access to local vars
;
; First, check for control characters
;
cmp al,0eh ; 08-0D are special
jae no_special
cmp al,08h
jb no_special
je dis_bs ; 08 = Backspace
cmp al,0ah
jb dis_tab ; 09 = Tab
je dis_lf ; 0A = Linefeed
cmp al,0ch
jb dis_vt ; 0B = Clear to eol
jne dis_cr ; 0D = Carriage return
jmp dis_ff ; 0C = Clear screen
;
; Carriage return
;
dis_cr:
cmp sc_clreol,0
jne dis_vt
discr1:
push dx
cli
mov ax,tsk_regen_o ; current offset
xor dx,dx ; make into doubleword
div sc_cols ; divide by number of columns
sub tsk_regen_o,dx ; subtract remainder
sti
pop dx
jmp disreg_end
;
no_special:
jmp disregen_ok
;
; Backspace
;
dis_bs:
cli
cmp tsk_regen_o,0 ; Handle wraparound
je dis_bs2
sub tsk_regen_o,2
sti
jmp disreg_end
dis_bs2:
mov ax,sc_end ; Wrap to end of screen
sub ax,2
mov tsk_regen_o,ax
sti
jmp disreg_end
;
; Tab
;
dis_tab:
cli
mov ax,tsk_regen_o
add ax,16
and ax,0fff0h ; Tabs every 8 cols
mov tsk_regen_o,ax
sti
jmp disreg_end
;
; Linefeed
;
dis_lf:
cli
mov ax,tsk_regen_o
add ax,sc_cols ; Add one line
mov tsk_regen_o,ax
sti
cmp ax,sc_end ; did we get past the end?
jae dislf_sc
jmp disreg_end
;
dislf_sc:
push es ; then setup regs and go scroll
push di
mov es,tsk_regen_s
mov di,ax
jmp short disreg_scroll
;
; Vertical tab (clear to end of line)
;
dis_vt:
push es
push di
push cx
push ax
les di,tsk_regen
mov cx,sc_cols ; number of columns
mov ax,di ; current offset
xor dx,dx ; make into doubleword
div cx ; divide by number of columns
sub cx,dx ; subtract remainder
shr cx,1 ; number of words
mov ah,tsk_attrib
mov al,' '
rep stosw
pop ax
pop cx
cmp al,0dh
jne disreg_ok
pop di
pop es
jmp discr1
;
; Formfeed (clear to end of screen)
;
dis_ff:
push es
push di
push cx
les di,tsk_regen
mov cx,sc_end ; total number of chars
sub cx,di ; minus current offset
shr cx,1 ; number of words
mov ah,tsk_attrib
mov al,' '
rep stosw
pop cx
jmp short disreg_ok
;
; Normal character output
;
disregen_ok:
push es
push di
cli
les di,tsk_regen ; load current regen buffer addr
mov ah,tsk_attrib
stosw
mov tsk_regen_o,di ; new offset
sti
cmp di,sc_end ; past the end?
jb disreg_ok
;
; Scroll up one line
;
disreg_scroll:
sub di,sc_cols ; one line up
mov tsk_regen_o,di
push cx
push si
push ds
mov si,sc_cols ; second line
mov cx,sc_end
sub cx,si ; screen len minus one line
shr cx,1 ; no. of words
mov di,es
mov ds,di
mov di,0 ; first line
rep movsw
pop ds
;
mov cx,sc_cols ; number of columns
shr cx,1 ; number of words
mov ah,tsk_attrib
mov al,' '
rep stosw
;
pop si
pop cx
;
disreg_ok:
pop di
pop es
;
disreg_end:
call @setcsr
pop ds
ret
;
@disregen endp
;
;
; nodis - local dummy output routine.
; This routine is called if the regen buffer adddress has not
; been set, or if there is no secondary monitor.
;
@nodis proc near
ret
@nodis endp
;
;
; dischar - local screen output routine.
; This routine uses INT 10 TTY output to display the character.
; Entry: AL = char to display
; Uses: AX
;
@dischar proc near
IF IBM
push bx
push bp
mov bl,7
mov ah,14
int 10h
pop bp
pop bx
ELSE
push dx
mov dl,al
mov ah,2
int 21h
pop dx
ENDIF
ret
@dischar endp
;
;
; filechar - local file output routine.
; Write character to file
; Entry: AL = char to display
; Uses: AX
;
@filechar proc near
push bx
push si
mov si,prargdx[bp]
mov bl,ss:[si]
xor bh,bh
inc bx
mov ss:[si+bx],al
cmp bx,FILE_BUFSIZE - 1
jb fcharend
xchg si,dx
inc dx
push ds
push ax
push cx
mov cx,bx
mov bx,prargbx[bp]
mov ax,ss
mov ds,ax
mov ah,40h
int 21h
pop cx
pop ax
pop ds
xchg dx,si
dec si
xor bl,bl
fcharend:
mov ss:[si],bl
pop si
pop bx
ret
@filechar endp
;
;
; stringchar - local string output routine.
; Entry: AL = char to write to string
; prargbx/dx set to point to destination
;
; Uses: AX
;
@stringchar proc near
push di
push es
les di,dword ptr prargbx[bp]
stosb
mov prargbx[bp],di
pop es
pop di
ret
@stringchar endp
;
;
; hexdigbp - put hex digit in AL to SS:DI, increment DI and BL.
;
@hexdigbp proc near
;
push ax
and al,0fh
add al,'0'
cmp al,'9'
jbe hexbp1
add al,prhexch[bp]
hexbp1:
mov byte ptr ss:[di],al
inc di
inc bl
pop ax
ret
;
@hexdigbp endp
;
;
; hexconv - convert hex
; Entry: DX,AX = number
; SS:DI = Buffer pointer
; Exit: BX = converted length
; SS:DI = string start + 1
; Uses: CX
;
@hexconv proc near
xor bl,bl
mov cl,4
mov bh,4
or dx,dx
jnz hchiword
;
hclp1:
call @hexdigbp
shr ax,cl
jz hcend
dec bh
jnz hclp1
;
hcend:
xor bh,bh
ret
;
hchiword:
call @hexdigbp
shr ax,cl
dec bh
jnz hchiword
mov ax,dx
jmp hclp1
;
@hexconv endp
;
;
; decconv - convert decimal
;
; Entry: DX,AX = number
; SS:DI = Buffer top pointer
; Exit: BX = converted length
; SS:DI = string start + 1
; Uses: CX
;
@decconv proc near
xor bx,bx
mov cx,10
or dx,dx
jnz dchiword
;
dclp1:
xor dx,dx
div cx
add dl,'0'
mov byte ptr ss:[di],dl
inc di
inc bx
or ax,ax
jnz dclp1
ret
;
dchiword:
push si
mov si,dx
;
dchilp:
xchg ax,si
xor dx,dx
div cx
xchg ax,si
div cx
add dl,'0'
mov byte ptr ss:[di],dl
inc di
inc bx
or si,si
jnz dchilp
;
pop si
jmp dclp1
;
@decconv endp
;
;
; getint - read integer at DS:SI
; Entry: AL = first char
; Exit: AX = integer
; Uses: BX,DX
;
@getint proc near
;
and ax,0fh
mov bl,10
getintlp:
xchg ax,dx
lodsb
cmp al,'0'
jb getint_end
cmp al,'9'
ja getint_end
and ax,0fh
xchg ax,dx
mul bl
add ax,dx
jmp getintlp
;
getint_end:
dec si
mov ax,dx
ret
;
@getint endp
;
;
; padleft - local routine to pad output on the left side.
;
@padleft proc near
;
push cx
push dx
xor dx,dx
test prflags[bp],F_PREC
jz padleft_noprec
cmp bx,prec[bp]
jae padleft_noprec
;
mov dx,prec[bp]
sub dx,bx
test prflags[bp],F_WIDTH
jz padleft_noprec
sub prwidth[bp],dx
jnc padleft_noprec
and prflags[bp],NOT F_WIDTH
;
padleft_noprec:
test prflags[bp],F_LEFTADJ
jnz padleft_end
test prflags[bp],F_WIDTH
jz padleft_end
cmp bx,prwidth[bp]
jae padleft_end
;
mov cx,prwidth[bp]
sub cx,bx
add procnt[bp],cx
mov al,' '
test prflags[bp],F_PADZERO
jz padleftlp
mov al,'0'
;
padleftlp:
push ax
call prproc[bp]
pop ax
loop padleftlp
;
padleft_end:
mov cx,dx
jcxz padleft_exit
add procnt[bp],cx
;
padleftprec:
mov al,'0'
call prproc[bp]
loop padleftprec
;
padleft_exit:
pop dx
pop cx
ret
;
@padleft endp
;
; padright - local routine to pad output on the right side
;
@padright proc near
;
test prflags[bp],F_LEFTADJ
jz padright_end
test prflags[bp],F_WIDTH
jz padright_end
cmp bx,prwidth[bp]
jae padright_end
;
push cx
mov cx,prwidth[bp]
sub cx,bx
add procnt[bp],cx
;
padrightlp:
mov al,' '
call prproc[bp]
loop padrightlp
pop cx
;
padright_end:
ret
;
@padright endp
;
;
; disprintf: display formatted string.
;
; Entry: DS:SI = format string
; ES:DI = parameter pointer
; CX = output routine address
; BX,DX = output routine parameter
;
; Uses: AX,BX,DX
;
; Usually, the parameter pointer will point to the first
; parameter on the stack. For added flexibility, ES:DI is
; used here, so that the parameter list may be anywhere in
; memory. This allows vprintf-style parameters.
;
;
@disprintf proc near
push bp
sub sp,TYPE dislocrec
mov bp,sp
mov prproc[bp],cx
mov prargbx[bp],bx
mov prargdx[bp],dx
mov procnt[bp],0
;
disploop:
lodsb
or al,al
jz dispend ; end of string
cmp al,'%'
je dispformat ; jump if format character
cmp al,0ah
jne dispchar
mov al,0dh
call prproc[bp] ; translate LF into CR+LF
inc procnt[bp]
mov al,0ah
;
dispchar:
call prproc[bp]
inc procnt[bp]
jmp disploop
;
dispend:
mov bx,prargbx[bp]
add sp,TYPE dislocrec
pop bp
ret
;
disploop1:
pop di
pop es
add di,arglen[bp]
jmp disploop
;
; Format character found, process conversion
;
dispformat:
lodsb
cmp al,'%' ; %% means print single %
je dispchar
;
push es
push di ; save parameter pointer
mov prflags[bp],0
mov arglen[bp],2
;
cmp al,'-'
jne no_flags
or prflags[bp],F_LEFTADJ
lodsb
;
no_flags:
cmp al,'0'
jne no_zero
or prflags[bp],F_PADZERO
lodsb
;
no_zero:
cmp al,'*'
je loadwidth
cmp al,'9'
ja no_width
cmp al,'0'
jb no_width
call @getint
jmp short haswidth
;
loadwidth:
mov ax,word ptr es:[di]
add di,2
add arglen[bp],2
;
haswidth:
or prflags[bp],F_WIDTH
mov prwidth[bp],ax
lodsb
;
no_width:
cmp al,'.'
jne no_prec
lodsb
cmp al,'*'
je loadprec
cmp al,'9'
ja no_prec
cmp al,'0'
jb no_prec
call @getint
jmp short hasprec
;
loadprec:
mov ax,word ptr es:[di]
add di,2
add arglen[bp],2
;
hasprec:
or prflags[bp],F_PREC
mov prec[bp],ax
lodsb
;
; Process indirection.
;
no_prec:
mov dx,ds
cmp al,'^'
je indir_near
cmp al,'@'
jne no_indir
add arglen[bp],2
;
indir_near:
or prflags[bp],F_INDIR
;
indir_loop:
cmp al,'^'
je is_indir
cmp al,'@'
jne no_indir
mov dx,word ptr es:2[di]
is_indir:
mov di,word ptr es:[di]
mov es,dx
lodsb ; next conversion char
jmp indir_loop
;
; Indirection finished, check for size modification
;
no_indir:
IF DFLT_FAR
cmp al,'s'
je dfltsize0
cmp al,'n'
je dfltsize0
cmp al,'p'
je dfltsize0
cmp al,'P'
jne dfltsize1
;
dfltsize0:
or prflags[bp],F_LONGARG
jmp short no_sizemod
;
dfltsize1:
ENDIF
cmp al,'F'
je sizemodl
cmp al,'N'
jne sizemod2
lodsb
jmp short no_sizemod
;
sizemod2:
cmp al,'h'
jne sizemod3
or prflags[bp],F_SHORTARG
lodsb
jmp short no_sizemod
;
sizemod3:
cmp al,'l'
jne no_sizemod
;
sizemodl:
or prflags[bp],F_LONGARG
lodsb
;
no_sizemod:
xor dx,dx
test prflags[bp],F_LONGARG
jz loadsingle
mov dx,word ptr es:2[di]
test prflags[bp],F_INDIR
jnz loadsingle
add arglen[bp],2
;
loadsingle:
mov bl,al
mov ax,word ptr es:[di]
test prflags[bp],F_SHORTARG
jz noshort
xor ah,ah
;
noshort:
cmp bl,'n'
jne convc0
test prflags[bp],F_LONGARG
jz gostorelen
mov ds,dx
gostorelen:
mov bx,ax
mov ax,procnt[bp]
mov [bx],ax
jmp disploop1
;
convc0:
lea di,convbuf[bp]
;
cmp bl,'c'
jne convc1
mov byte ptr ss:[di],al
inc di
mov bx,1
and prflags[bp],NOT (F_PREC OR F_PADZERO)
jmp out_conv
;
convc1:
cmp bl,'s'
jne convc2
test prflags[bp],F_LONGARG
jnz gofmtstring
mov dx,ds
gofmtstring:
and prflags[bp],NOT F_PADZERO
jmp fmtstring
;
convc2:
cmp bl,'x'
je fmthex
cmp bl,'X'
je fmthex
cmp bl,'p'
je fmtptr
cmp bl,'P'
je fmtptr
cmp bl,'u'
je fmtdec
cmp bl,'d'
jne badconv
test prflags[bp],F_LONGARG
jnz signedlong
test prflags[bp],F_SHORTARG
jz signedint
cbw
;
signedint:
test ah,80h
jz fmtdec
or prflags[bp],F_SIGNED
neg ax
jmp short fmtdec
;
signedlong:
test dh,80h
jz fmtdec
or prflags[bp],F_SIGNED
mov cx,dx
xor dx,dx
neg ax
sbb dx,cx
jmp short fmtdec
;
; Invalid conversion. Reset parameter pointer and output the
; char.
;
badconv:
pop di
pop es
mov al,bl
jmp dispchar
;
;
fmtdec:
call @decconv
test prflags[bp],F_SIGNED
jz fmtdnosign
mov byte ptr ss:[di],'-'
inc di
inc bx
fmtdnosign:
jmp short out_conv
;
fmthex:
mov prhexch[bp],'a'-10-'0'
cmp bl,'x'
je fmthex1
mov prhexch[bp],'A'-10-'0'
fmthex1:
call @hexconv
jmp short out_conv
;
fmtptr:
mov prhexch[bp],'a'-10-'0'
cmp bl,'p'
je fmtptr1
mov prhexch[bp],'A'-10-'0'
fmtptr1:
and prflags[bp],NOT (F_PREC OR F_PADZERO)
mov cl,4
mov bh,cl
xor bl,bl
;
fmtplo:
call @hexdigbp
shr ax,cl
dec bh
jnz fmtplo
test prflags[bp],F_LONGARG
jz out_conv
;
mov byte ptr ss:[di],':'
inc di
inc bl
mov bh,cl
mov ax,dx
;
fmtphilp:
call @hexdigbp
shr ax,cl
dec bh
jnz fmtphilp
;
;
out_conv:
mov cx,bx
call @padleft
add procnt[bp],cx
outc_out:
dec di
mov al,byte ptr ss:[di]
call prproc[bp]
loop outc_out
call @padright
jmp disploop1
;
;
fmtstring:
push si
push ds
mov ds,dx
mov si,ax
;
mov es,dx
mov di,ax
xor ax,ax
mov cx,-1
repne scasb
not cx
dec cx
test prflags[bp],F_PREC
jz fmtstr_np
cmp cx,prec[bp]
jbe fmtstr_np
mov cx,prec[bp]
;
fmtstr_np:
and prflags[bp],NOT F_PREC
mov bx,cx
call @padleft
jcxz fmtstr_end
add procnt[bp],cx
fmtstr_out:
lodsb
call prproc[bp]
loop fmtstr_out
fmtstr_end:
call @padright
pop ds
pop si
jmp disploop1
;
;
@disprintf endp
;
;
; void tsk_printf (char far *format, ...)
;
; Formatted output to console.
;
CGlobalfunc tsk_printf,<uses ds si di, fmt: far ptr, varg: word>
;
mov ax,ss
mov es,ax
lds si,fmt
lea di,varg
mov cx,offset @dischar
call @disprintf
ret
tsk_printf endp
;
;
; void tsk_vprintf (char far *format, void far *arg)
;
; Formatted output to console.
;
Globalfunc tsk_vprintf,<uses ds si di, fmt: far ptr, varg: far ptr>
;
lds si,fmt
les di,varg
mov cx,offset @dischar
call @disprintf
ret
tsk_vprintf endp
;
;
; void tsk_fprintf (int handle, char far *format, ...)
;
; Formatted output to file.
;
CGlobalfunc tsk_fprintf <uses ds si di, handle: word, fmt: far ptr, varg: word>
;
mov ax,ss
mov es,ax
lds si,fmt
lea di,varg
sub sp,FILE_BUFSIZE
mov dx,sp
mov bx,sp
mov byte ptr ss:[bx],0
mov cx,offset @filechar
mov bx,handle
call @disprintf
mov si,sp
mov cl,ss:[si]
xor ch,ch
jcxz fprintfend
mov dx,si
inc dx
mov bx,handle
mov ax,ss
mov ds,ax
mov ah,40h
int 21h
fprintfend:
add sp,FILE_BUFSIZE
ret
tsk_fprintf endp
;
;
; void tsk_vfprintf (int handle, char far *format, void far *arg)
;
; Formatted output to file.
;
Globalfunc tsk_vfprintf,<uses ds si di, handle: word, fmt: far ptr, varg: far ptr>
;
lds si,fmt
les di,varg
sub sp,FILE_BUFSIZE
mov dx,sp
mov bx,sp
mov byte ptr ss:[bx],0
mov cx,offset @filechar
mov bx,handle
call @disprintf
mov si,sp
mov cl,ss:[si]
xor ch,ch
jcxz vfprintfend
mov dx,si
inc dx
mov bx,handle
mov ax,ss
mov ds,ax
mov ah,40h
int 21h
vfprintfend:
add sp,FILE_BUFSIZE
ret
tsk_vfprintf endp
;
;
; void tsk_sprintf (char far *dest, char far *format, ...)
;
; Formatted output to string.
;
CGlobalfunc tsk_sprintf,<uses ds si di, dest: far ptr, fmt: far ptr, varg: word>
;
mov ax,ss
mov es,ax
lds bx,dest
mov dx,ds
lds si,fmt
lea di,varg
mov cx,offset @stringchar
call @disprintf
sub bx,word ptr(dest)
mov ax,bx
ret
tsk_sprintf endp
;
;
; void tsk_vsprintf (char far *dest, char far *format, void far *arglist)
;
; Formatted output to string.
;
Globalfunc tsk_vsprintf,<uses ds si di, dest: far ptr, fmt: far ptr, varg: far ptr>
;
lds bx,dest
mov dx,ds
lds si,fmt
les di,varg
mov cx,offset @stringchar
call @disprintf
sub bx,word ptr(dest)
mov ax,bx
ret
tsk_vsprintf endp
;
;
; void tsk_rprintf (char far *format, ...)
;
; Formatted output to regen buffer (second display).
;
CGlobalfunc tsk_rprintf,<uses ds si di, fmt: far ptr, varg: word>
;
IFDEF LOAD_DS
mov ds,cs:ctdataseg
ENDIF
mov cx,sc_proc
mov ax,ss
mov es,ax
lds si,fmt
lea di,varg
call @disprintf
ret
tsk_rprintf endp
;
;
; void tsk_vrprintf (char far *format, void far *arglist)
;
; Formatted output to regen buffer (second display).
;
Globalfunc tsk_vrprintf,<uses ds si di, fmt: far ptr, varg: far ptr>
;
IFDEF LOAD_DS
mov ds,cs:ctdataseg
ENDIF
mov cx,sc_proc
lds si,fmt
les di,varg
call @disprintf
ret
tsk_vrprintf endp
;
;
; void tsk_putc (char c)
;
; Output character to console.
;
Globalfunc tsk_putc,<chr: word>
mov ax,chr
call @dischar
ret
tsk_putc endp
;
;
; void tsk_puts (char far *s)
;
; Output string to console.
;
Globalfunc tsk_puts,<uses ds si, dstr: far ptr>
;
lds si,dstr
putslp:
lodsb
or al,al
jz putsend
call @dischar
jmp putslp
;
putsend:
mov al,0dh
call @dischar
mov al,0ah
call @dischar
ret
tsk_puts endp
;
;
; void tsk_rputc (char c)
;
; Output character to regen buffer (second display).
;
Globalfunc tsk_rputc,<chr: word>
;
mov ax,chr
IFDEF LOAD_DS
push ds
mov ds,cs:ctdataseg
call sc_proc
pop ds
ELSE
call sc_proc
ENDIF
ret
tsk_rputc endp
;
;
; void tsk_rputs (char far *s)
;
; Output string to regen buffer.
;
Globalfunc tsk_rputs,<uses si, dstr: far ptr>
;
IFDEF LOAD_DS
push ds
mov ds,cs:ctdataseg
ENDIF
les si,dstr
rputslp:
lods es:prflags
or al,al
jz rputsend
call sc_proc
jmp rputslp
;
rputsend:
mov al,0dh
call sc_proc
mov al,0ah
call sc_proc
IFDEF LOAD_DS
pop ds
ENDIF
ret
tsk_rputs endp
;
;
; void tsk_setpos (int row, int col)
;
; Set cursor position for regen output.
; First position on screen is (0, 0).
;
Globalfunc tsk_setpos,<row: word, col: word>
;
IFDEF LOAD_DS
push ds
mov ds,cs:ctdataseg
ENDIF
mov ax,row
mul sc_cols
add ax,col
add ax,col
mov tsk_regen_o,ax
call @setcsr
IFDEF LOAD_DS
pop ds
ENDIF
ret
tsk_setpos endp
;
;
; void tsk_set_regen (int segment, int port, int rows, int cols)
;
; Set regen buffer address and size, and display controller port.
; This routine can be used to force regen output to the
; primary screen for single-screen systems, and to modify
; the output parameters (number of rows and columns).
;
Globalfunc tsk_set_regen,<reg: word, port: word, rows: word, cols: word>
;
IFDEF LOAD_DS
push ds
mov ds,cs:ctdataseg
ENDIF
mov ax,reg
mov tsk_regen_s,ax
mov ax,port
mov tsk_disport,ax
mov tsk_regen_o,0
mov ax,cols
add ax,ax
mov sc_cols,ax
mul rows
mov sc_end,ax
mov sc_proc,offset @disregen
IFDEF LOAD_DS
pop ds
ENDIF
ret
tsk_set_regen endp
;
;
; int tsk_set_dualdis (void)
;
; Determine regen buffer address on second monitor.
; This routine first checks the current video mode. If it's
; mode 7, the regen buffer is set to B800 (the colour screen).
; For all other modes, the regen buffer is B000 (mono).
; Then a check is done to make sure that the secondary card
; exists. If it does, the regen output is initialized. Otherwise,
; any output through the regen routines will be discarded.
;
; Returns 0 if there is no secondary monitor, else the
; regen buffer address.
;
; No attempt is made to initialize the secondary monitor,
; the monitor must be in alpha mode.
;
Globalfunc tsk_set_dualdis
;
IFDEF LOAD_DS
push ds
mov ds,cs:ctdataseg
ENDIF
mov ah,0fh
push bp
int 10h ; get video mode
pop bp
mov bx,0b800h ; colour regen buffer
mov dx,3d4h ; CGA 6845 I/O addr
cmp al,7 ; only mode 7 has regen at B000
je ddis_checks
mov bx,0b000h ; mono regen buffer
mov dx,3b4h ; mono 6845 I/O addr
;
ddis_checks:
mov tsk_regen_s,bx
mov tsk_regen_o,0
mov tsk_disport,dx
mov sc_cols,80 * 2
mov sc_end,25 * 80 * 2
mov al,0fh
out dx,al
inc dx
in al,dx
mov ah,al
mov al,56h
out dx,al
mov cx,100h
ddis_wait:
loop ddis_wait
in al,dx
xchg ah,al
out dx,al
cmp ah,56h
je ddis_ok
mov sc_proc,offset @nodis
xor ax,ax
mov tsk_regen_s,ax
jmp short ddis_end
;
ddis_ok:
mov sc_proc,offset @disregen
mov ax,bx
;
ddis_end:
IFDEF LOAD_DS
pop ds
ENDIF
ret
;
tsk_set_dualdis endp
;
;
; int tsk_set_currdis (void)
;
; Determine regen buffer address on current monitor.
; This routine checks the current video mode. If it's
; mode 7, the regen buffer is set to B000 (the mono screen).
; For all other modes, the regen buffer is B800 (colour).
;
; Returns the regen buffer address.
;
; No attempt is made to initialize the monitor, or to check for
; special modes with different regen address. The monitor must
; be in alpha mode.
;
Globalfunc tsk_set_currdis
;
IFDEF LOAD_DS
push ds
mov ds,cs:ctdataseg
ENDIF
mov ah,0fh
push bp
int 10h ; get video mode
pop bp
mov bx,0b800h ; colour regen buffer
cmp al,7 ; only mode 7 has regen at B000
jne curdis_ready
mov bx,0b000h ; mono regen buffer
;
curdis_ready:
mov tsk_regen_s,bx
mov tsk_regen_o,0
mov ax,SEG biosdata
mov es,ax
assume es:biosdata
mov ax,bios_chipad
mov tsk_disport,ax
mov ax,bios_cols
add ax,ax
mov sc_cols,ax
mov dl,bios_rows
xor dh,dh
mul dx
mov sc_end,ax
mov sc_proc,offset @disregen
mov ax,bx
IFDEF LOAD_DS
pop ds
ENDIF
ret
;
tsk_set_currdis endp
;
;
; void tsk_set_colour (int rows, int cols)
;
; Set regen buffer address to colour monitor.
;
Globalfunc tsk_set_colour,<rows: word, cols: word>
;
IFDEF LOAD_DS
push ds
mov ds,cs:ctdataseg
ENDIF
mov tsk_regen_s,0b800h ; colour regen buffer
mov tsk_regen_o,0
mov tsk_disport,3d4h ; CGA 6845 I/O addr
mov ax,cols
add ax,ax
mov sc_cols,ax
mul rows
mov sc_end,ax
mov sc_proc,offset @disregen
IFDEF LOAD_DS
pop ds
ENDIF
ret
;
tsk_set_colour endp
;
;
; void tsk_set_mono (int rows, int cols)
;
; Set regen buffer address to monochrome monitor.
;
Globalfunc tsk_set_mono,<rows: word, cols: word>
;
IFDEF LOAD_DS
push ds
mov ds,cs:ctdataseg
ENDIF
mov tsk_regen_s,0b000h ; mono regen buffer
mov tsk_regen_o,0
mov tsk_disport,3b4h ; mono 6845 I/O addr
mov ax,cols
add ax,ax
mov sc_cols,ax
mul rows
mov sc_end,ax
mov sc_proc,offset @disregen
IFDEF LOAD_DS
pop ds
ENDIF
ret
;
tsk_set_mono endp
;
;
; void tsk_set_attr (int attr)
;
; Set regen display attributes
;
Globalfunc tsk_set_attr,<attr: word>
;
IFDEF LOAD_DS
push ds
mov ds,cs:ctdataseg
ENDIF
mov ax,attr
mov tsk_attrib,al
IFDEF LOAD_DS
pop ds
ENDIF
ret
;
tsk_set_attr endp
;
;
; void tsk_set_clreol (int clr)
;
; Set special handling of CR. If "clr" is nonzero, CR will clear
; to end of line before returning to the home position.
;
Globalfunc tsk_set_clreol,<clr: word>
;
IFDEF LOAD_DS
push ds
mov ds,cs:ctdataseg
ENDIF
mov ax,clr
mov sc_clreol,al
IFDEF LOAD_DS
pop ds
ENDIF
ret
;
tsk_set_clreol endp
;
.tsk_ecode
end