; ; --- Version 2.2 91-02-08 11:56 --- ; ; 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, ; 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, ; 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 ; 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, ; 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, ; mov ax,ss mov es,ax lds bx,dest mov dx,ds lds si,fmt lea di,varg mov cx,offset @stringchar call @disprintf mov es,word ptr(dest) + 2 mov byte ptr es:[bx],0 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, ; lds bx,dest mov dx,ds lds si,fmt les di,varg mov cx,offset @stringchar call @disprintf mov es,word ptr(dest) + 2 mov byte ptr es:[bx],0 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, ; 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, ; 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, mov ax,chr call @dischar ret tsk_putc endp ; ; ; void tsk_puts (char far *s) ; ; Output string to console. ; Globalfunc tsk_puts, ; 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, ; 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, ; 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, ; 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, ; 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, ; 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, ; 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, ; 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, ; 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