NAME cczibm ; File CCZIBM.ASM page 60,132 ; Terminal emulator module for IBM PC's and compatibles. ; ;CHINESE ifdef MSDOS include mszibm.dat else include cczibm.dat endif code segment public 'code' extrn prtbout:near, prtnout:near, csrtype:near, trnmod:near extrn scrmod:near, scrseg:near, scrsync:near, scroff:near extrn scron:near, atsclr:near, vtscru:near, vtscrd:near extrn modwrt:near, telmsy:near, scrloc:near, pcwait:near extrn chgdsp:near, trnprs:near, cptchr:near, tekesc:near extrn pntchr:near, pntchk:near, pntflsh:near ; extrn procedures are all in module msyibm extrn tekini:near, tekemu:near, tekend:near, vtrmac:near,vtsmac:near assume cs:code, ds:datas, es:datas ; This routine initializes the VT100 setups at startup. It is called from ; procedure lclyini in module msyibm. vsinit proc near mov vtemu.vtflgst,vsdefaults ; Init to defaults in mssdef.h mov vtemu.vtflgop,vsdefaults ; Init runtime state to setup items mov insmod,0 ; turn off insert mode mov deftabs,0 ; Column 1 has no tab stop mov ansflgs,0 mov cl,crt_cols ; physical screen width (80) dec cl ; we count from column 0 mov ch,crt_lins ; physical screen length-1 dec ch ; we count from row 0 mov low_rgt,cx ; store active text area mov cx,131 mov di,1 ; Starting index for column 2 vsini1: mov al,0 ; Assume we will clear this one test di,0007H ; Index mod 8 equals 0? jnz vsini2 ; No, clear it mov al,0FFH ; Yes, set it vsini2: mov deftabs[di],al ; Set or clear a tab stop inc di ; Advance to next loop vsini1 ; Loop for all mov cx,slen ; clear linetype array mov di,0 vsini3: mov linetype[di],0 inc di loop vsini3 mov vtemu.vttbst,offset deftabs ; addrs of active tabs for STATUS mov vtemu.vttbs,offset deftabs ; addrs of tabs for setup (SET) mov vttabs,offset deftabs ; initial source of tabs call cpytabs ; copy default to active mov vtemu.att_ptr,offset att_normal ; ptr to video attributes mov ah,8 ; read current attributes xor bh,bh ; page 0 int screen mov scbattr,ah ; save video attributes mov att_normal,ah ; set att_normal to present colors call brkatt ; separate colors from blink/bold rol ah,1 ; reverse foreground & background rol ah,1 ; RGB bits rol ah,1 rol ah,1 call addatt ; reinsert bold/blink bits mov att_reverse,ah ; set att_reverse too mov ah,byte ptr low_rgt ; right most column (counted from 0) sub ah,8 ; place marker 9 columns from margin mov belcol,ah ; store column number to ring bell ret ; And return vsinit endp ; Initialization routine. ; ; Call: al/ yflags byte that was passed to Term routine ; dl/ index for baud rate table ; dh/ parity in bits 4-7, number of data bits in bits 0-3 ; ansini proc near mov yflags,al ; Always save flags mov ah,vtemu.vtflgst ; setup flags mov vtflags,ah mov vttabs,offset deftabs ; tab stop pointer mov vtemu.vttbst,offset tabs; store here for STATUS mov al,flags.vtflg ; get current terminal type mov oldterm,al ; remember it here for soft restarts mov insmod,0 ; turn off insert mode mov h19l25,0 ; clear Heath 25th line enable mov h19ctyp,1 ; set Heath cursor to underline, on mov anspflg,0 ; clear printer flag push ax mov ah,byte ptr low_rgt ; right most column (counted from 0) sub ah,8 ; place marker 9 columns from margin mov belcol,ah ; store column number to ring bell pop ax cmp dl,lbaudtab ; Wierd index? jb ansin1 ; No - OK - store it mov dl,lbaudtab-1 ; Yes - make it the maximum ansin1: mov baudidx,dl ; Save baud rate index mov al,dh ; Get parity/number of databits and al,0FH ; Isolate number of databits mov datbits,al ; Save mov cl,4 ; Isolate parity code shr dh,cl ; Isolate parity code cmp dh,lpartab ; Weird code? jb ansin2 ; No - OK - store it mov dh,lpartab-1 ; Yes - make it the maximum ansin2: mov parcode,dh ; Save call scrmod ; Get the screen mode, in MSYxxx mov cl,crt_cols ; physical screen number columns (80) dec cl ; we count from column 0 here mov ch,crt_lins ; physical screen number rows-1 (24) dec ch ; we count from row 0 here mov low_rgt,cx ; save as active text screen size mov oldscrn,cx ; remember old screen dimensions ansin3: call atreset ; Reset everything mov ttstate,offset atnrm ; Reset state to "normal" ret ; And return ansini endp ; Re-initialization routine. Called when Term was called but screen was ; restored from a previously saved screen, etc. ; ; Call: al/ yflags byte that was passed from msyibm module. ; ansrei proc near mov yflags,al ; Always save flags mov ah,vtemu.vtflgop ; get runtime flags mov tmpflags,ah call scrmod ; Get the screen mode call atsctyp ; set cursor type [rbv] mov ah,3 ; get cursor position from msy mov bh,0 ; Page zero int screen ; physical = logical cursor here mov cursor,dx ; dh = row, dl = column mov cl,crt_cols ; physical screen number columns (80) dec cl ; we count from column 0 here mov ch,crt_lins ; physical screen number rows-1 (24) dec ch ; we count from row 0 here mov low_rgt,cx ; save as active text screen size cmp linelen,79 ; want 80 cols? ja ansre2 ; a = no cmp byte ptr low_rgt,79 ; want 80 cols. Is active screen wider? jbe ansre2 ; be = no mov byte ptr low_rgt,79 ; narrow down to 80 columns ansre2: test vtemu.vtflgop,vswdir ; writing right to left? jz ansre4 ; z = no, left to right sub dl,byte ptr low_rgt ; reflect cursor from right side neg dl mov cursor,dx ; store as logical position ansre4: push cx ; save current physical screen size call stblmds ; Check settable modes, set flags pop cx cmp cx,oldscrn ; has screen size changed? je ansre3 ; e = no, same as last time mov oldscrn,cx ; remember new size mov mar_top,0 ; reset scrolling region mov al,byte ptr low_rgt+1 mov mar_bot,al jmp atres2 ; better do soft reset ansre3: ret ansrei endp ; This routine copies the new tab stops when they have changed. ; Copies all 132 columns. cpytabs proc near mov cx,swidth ; number of screen columns jcxz cpytab1 ; z = none to do mov si,vttabs ; Source mov di,offset tabs ; Destination push es ; save es push ds pop es ; set es to datas segment cld rep movsb ; Do the copy pop es ; recover es cpytab1:ret cpytabs endp ; This routine checks to see whether any of the settable modes have changed ; (things that can be changed in both SETUP and by host commands), and ; changes those that need to be changed. TMPFLAGS has the new VT100 setup ; flags, VTFLAGS has the old. This routine also updates VTFLAGS. ; Revised by [jrd] to allow MSY to reset scbattr when not in connect mode, ; to do "soft reset" if terminal type has changed, and to do a screen clear ; reset if the actual screen colors have changed. stblmds proc near mov al,flags.vtflg ; get current terminal type cmp al,oldterm ; same as before? je stblm10 ; e = yes, skip over soft reset mov oldterm,al ; remember current terminal type mov insmod,0 ; reset insert mode flag mov h19l25,0 ; reset heath-19 25th line enable mov mar_top,0 ; reset top scrolling margin mov al,byte ptr low_rgt+1 ; and scrolling margin mov mar_bot,al ; to last normal line on screen mov ah,byte ptr low_rgt ; right most column (counted from 0) sub ah,8 ; place marker 9 columns from margin mov belcol,ah ; store column number to ring bell and ansflgs,decckm+deckpam+decom+dececho ; save some flags push bx ; save this register around loop mov bx,offset linetype ; setup to clear double width chars mov cx,slen ; number of linetype slots to clear cmp flags.vtflg,ttvt100 ; VT100 now? jne stblm0 ; ne = no or ansflgs,decanm ; set ansi flag bit stblm0: mov byte ptr [bx],0 ; clear the linetype array to single inc bx ; width characters loop stblm0 ; do each line (1 byte per line) pop bx ; restore bx stblm10:mov al,tmpflags ; Get the new flags and ansflgs,not anslnm ; assume we do not want newline test al,vsnewline ; is newline mode desired? jz stblm1 ; No - continue or ansflgs,anslnm ; Yes - set corresponding mode flag stblm1: and ansflgs,not decawm ; assume not want wrap test al,vswrap ; Did wrap mode change? jz stblm2 ; No - continue or ansflgs,decawm ; Yes - set corresponding mode flag stblm2: ;; mov ah,vtflags ; old flags ;; xor ah,tmpflags ; new flags ;; test ah,vsshift3 ; pick out char set bit ;; jz stblm4 ; z = no change ;; mov ah,ascset ; assume US ASCII ;; test tmpflags,vsshift3 ; Want UK? ;; jz stblm3 ; No - guessed right ;; mov ah,ukset ; Yes - use UK set mov ah,vtemu.vtchset ; select char set from setup byte stblm3: mov chr_sg0,ah ; Set the sets mov chr_sg1,ah stblm4: mov ah,oldbatr ; get old screen background scbattr mov scbattr,ah ; and update working copy mov ah,att_normal ; get new attributes (Set Term Color) push bx mov bh,ah ; get new intensity bit of att_normal and bh,att_intensity and curattr,not att_intensity ; char attrs. clear intensity bit or curattr,bh ; set new intensity and mlbattr,not att_intensity ; mode line attrs. clear intensity and scbattr,not att_intensity ; screen background attribute or scbattr,bh ; set its intensity also mov bl,scbattr mov oldbatr,bl ; and save it here as well pop bx call brkatt ; separate color and blink/bold rol ah,1 ; reverse fore/back color fields rol ah,1 rol ah,1 rol ah,1 call addatt ; put back blink/bold push bx ; check on color change mov bh,ah ; new att_reverse pattern and bh,not(att_intensity+att_blink) ; look at just color bits mov bl,att_reverse ; previous att_reverse pattern and bl,not(att_intensity+att_blink) ; look at just color bits mov att_reverse,ah ; save new reverse pattern cmp bh,bl ; have any color bits changed? pop bx ; does not affect flags je stblm9 ; e = no mov cursor,0 ; reset cursor position jmp atres2 ; go to semi-reset stblm9: ; check on screen normal/reversed mov al,tmpflags xor al,vtflags ; Find which ones have changed test al,vsscreen ; How about screen background? jz stblm8 ; No - don't touch it test tmpflags,vsscreen ; Flag to be set? jnz stblm5 ; Yes - go to it and ansflgs,not decscnm ; No - cleared (normal video) and savflgs,not decscnm mov al,att_normal ; No - get new background jmp short stblm6 ; And reverse everything stblm5: or ansflgs,decscnm ; Set (reverse video) or savflgs,decscnm mov al,att_reverse ; No - set reverse video stblm6: call atrss2 ; Reverse screen and cursor attribute stblm7: mov al,scbattr ; Reset saved attribute also mov savecu+svattr_index,al mov oldbatr,al ; and save our attribute stblm8: mov al,tmpflags ; Get new flags mov vtflags,al ; Store them mov ah,2 ; set cursor mov bh,0 ; page 0 mov dx,cursor call direction ; set cursor for writing direction ret stblmds endp ; Return screen offset - given rol, col in dx, returns offset of the word ; for that character from the screen origin in ax. Preserves all other regs. ; Use same routine in msy to more closely track screen width. ;;scrloc proc near ;; push bx ; We will use bx ;; mov al,dh ; Get row ;; mov bl,swidth ; And length of a line ;; mul bl ; Offset for this row ;; mov dh,0 ; Clear row ;; add ax,dx ; Word offset for this position ;; sal ax,1 ; Make it a byte offset ;; pop bx ; Restore bx ;; ret ; And return ;;scrloc endp ; Fetch status/attributes routine. ; ; Call: al/ "yflags" byte from MSYxxx. ; ; Return: ah/ mode line background attribute ; al/ screen background attribute ; bl/ current cursor attribute ; bh/ ANSI (VT100) mode flags anstat proc near mov yflags,al ; Mostly for disleds mov ah,mlbattr ; Return them our attrs, flags, etc mov al,scbattr mov bl,curattr mov bh,ansflgs ret anstat endp ; Routine called when something is typed on the keyboard ; ; Call: No arguments ; anskbi proc near mov ttkbi,0FFH ; Just set a flag ret anskbi endp ; Routine to do keyclick if flag is set. ; ; Call: No arguments ; vclick proc near test vtflags,vskeyclick ; Is the flag on? jz vclick1 ; No - just return push bx ; Save some ACs push di mov di,500 ; 500 Hertz mov bx,1 ; For 1 millisecond call vtsound ; Do it pop di ; Restore the ACs pop bx vclick1:ret vclick endp ; Routine to do VT100-style bell. ; ; Call: No arguments ; vtbell proc near push di push bx mov di,880 ; 880 Hertz mov bx,40 ; For 40 ms call vtsound ; Do it pop bx pop di ret vtbell endp ; Routine to make noise of arbitrary frequency for arbitrary duration. ; Similar to routine (with typo removed) in "IBM PC Assembly Language: ; A Guide for Programmers", Leo J. Scanlon, 1983 Robert J. Brady Co., ; Bowie, MD., page 270. Modified by J R Doupnik to use 0.1 millsec interval. ; ; Call: di/ frequency in Hertz. ; bx/ duration in 1 millisecond units ; vtsound proc near push ax ; Save regs push cx push dx mov al,0B6H ; Write timer mode register out 43H,al mov dx,14H ; Timer divisor is mov ax,4F38H ; 1331000/frequency div di out 42H,al ; Write timer 2 count low byte mov al,ah out 42H,al ; Write timer 2 count high byte in al,61H ; Get current port B setting or al,3 ; Turn speaker on out 61H,al mov ax,bx ; number of milliseconds to wait call pcwait ; do the calibrated wait in al,61H ; Get current port B setting and al,0fch ; Turn off speaker and timer out 61H,al pop dx ; Restore regs pop cx pop ax ret vtsound endp ; Routine to toggle VT100/VT52/Heath-19 modes. No arguments. ; Use & update global byte flags.vtflg for terminal type and update local ; bit decanm. Note: shifting to Heath-19 here does Not reset the scrolling ; margins mar_top & mar_bot nor reset the double char linetype array. ; [jrd] ans52t proc near cmp tekflg,0 ; in Tek sub mode? jne ans52c ; ne = yes, get out now cmp flags.vtflg,ttvt100 ; in VT100 mode? jne ans52a ; ne = no and ansflgs,not decanm ; reset VT100 ansi mode mov flags.vtflg,ttvt52 ; say VT52 now (clears vt100 bit) mov oldterm,ttvt52 ; and remember it jmp ans52e ans52a: cmp flags.vtflg,ttvt52 ; in VT52 mode? jne ans52b ; ne = no mov flags.vtflg,ttheath ; say Heath-19 now mov oldterm,ttheath jmp ans52e ans52b: cmp flags.vtflg,ttheath ; in Heath-19 mode? jne ans52c ; ne = no test denyflg,tekxflg ; is Tek mode disabled? jz ans52f ; z = no, enabled mov flags.vtflg,ttvt100 ; say VT100 now mov oldterm,ttvt100 or ansflgs,decanm ; set, go to VT100 mode jmp short ans52e ans52f: call atsc ; save cursor and associated data mov flags.vtflg,tttek ; set Tek mode call tekini ; init Tek to switch screens jmp atnorm ; normal state and return ans52c: cmp flags.vtflg,tttek ; in Tek mode now? je ans52d ; e = yes cmp tekflg,0 ; doing Tek sub mode? jne ans52d ; ne = yes jmp atnorm ; else ignore this call ans52d: call tekend ; exit Tek graphics mode mov tekflg,0 ; end Tek sub mode (do after tekend) mov flags.vtflg,ttvt100 ; say VT100 now mov oldterm,ttvt100 or ansflgs,decanm ; set, go to VT100 mode call atrc ; restore cursor etc cmp flags.modflg,0 ; is mode line disabled? je ans52e ; e = yes, disabled test yflags,modoff ; Mode line off? jnz ans52e ; nz = yes - just return mov al,yflags ; get current flags or al,modoff ; say mode line is off call telmsy ; let msy hear the news call trnmod ; turn it on ans52e: call chrdef ; Set default character sets call atsc ; Save cursor etc call disleds ; Remove or redisplay "LEDs" jmp atnorm ; Say state is "normal" and return ans52t endp ; Display "LEDs" routine. Note that this routine ; is not used internally in this module (because it updates the flags from ; MSYIBM). Internally, disleds is used instead. The yflags from MSYIBM are ; needed because we have to know if the mode line is enabled. ; ; Call: al/ yflags from MSYIBM ; ; Return: Current state of "LEDs" displayed on line 25. ; ansdsl proc near ; Update flags and display "LEDs" mov yflags,al ; Update the flags call disleds ; Display LEDs ret ansdsl endp ; Internal routine to display LEDs. disleds:test yflags,modoff ; Mode line off? jnz disled2 ; Yes - just return cmp flags.modflg,1 ; mode line on and owned by us? ja disled2 ; a = no, leave it intact mov ah,2 ; Position cursor at (slen-1),70 mov bh,0 ; Page zero mov dh,byte ptr low_rgt+1 ; last screen line - 1 inc dh ; status line mov dl,led_col ; column for led display int screen mov cx,10 ; Length of byte array is ten mov si,offset ansleds ; The "LEDs" cmp flags.vtflg,ttvt100 ; VT100 mode? je disled1 ; e = yes mov si,offset v52leds ; try VT52 cmp flags.vtflg,ttvt52 ; VT52? je disled1 ; e = yes mov si,offset h19leds ; use Heath-19 disled1:lodsb ; Get a character mov ah,14 ; Write character function mov bh,0 ; Page zero int screen loop disled1 ; Loop for all chars mov ah,2 ; Reposition cursor when finished mov bh,0 ; Page zero mov dx,cursor call direction ; do Bios screen operation call atsctyp ; Reset right type of cursor disled2:ret ; ANSI terminal output routine. Call with character in al. anstty proc near ; ANSI terminal output mov dx,cursor ; Some routines need cursor in dx mov kbiflg,0 ; Clear old flag value test yflags,trnctl ; Debug mode? jz anstt1 ; z = no jmp atdeb ; Yes - just translate control chars anstt1: cmp ttkbi,0 ; New keyboard input? je anstt2 ; No - just continue mov kbiflg,1 ; Yes - set flag mov kbicsr,dx ; Save old cursor mov ttkbi,0 ; Clear this flag anstt2: test anspflg,vtcntp ; print controller on? jz anstt4 ; z = no test yflags,capt ; capturing output? jz anstt3 ; z = no, forget this part push ax ; save char call cptchr ; give it captured character pop ax ; restore character anstt3: jmp ansmc ; print transparently ; Set Display 7/8 bit filter anstt4: test flags.remflg,d8bit ; keep 8 bits for displays? jnz anstt5 ; nz = yes, 8 bits if possible and al,7fh ; remove high bit anstt5: cmp al,spc ; control char? jb anstt6 ; b = yes cmp ttstate,offset atnrm ; doing displayable text? jne anstt7 ; ne = no, no translation ; Set Translation filter anstt6: cmp rxtable+256,0 ; translation turned off? je anstt7 ; e = yes, no translation mov bx,offset rxtable ; address of translate table xlatb ; new char is in al anstt7: cmp al,DEL ; ANSI Delete char? je atdel ; e = yes, ignore it before logging cmp al,0 ; NUL char? je atign ; e = yes, ignore it before logging test yflags,capt ; capturing output? jz anstt8 ; z = no, forget this part push ax ; save char call cptchr ; give it captured character pop ax ; restore character and keep going ; Direct char to processor module anstt8: cmp al,20h ; Control character? jb atctrl ; b = yes, handle it anstt9: jmp ttstate ; Nope, dispatch according to state atign: ret ; Something to be ignored atctrl: mov ah,0 ; Make sure this is zero. cmp al,escape ; an escape sequence starting? je atctrl1 ; e = yes, don't print it test anspflg,vtautop+vtcntp ; printing desired? jz atctrl1 ; z = no call pntchr ; print char in al atctrl1:mov di,ax ; Put it in an index register shl di,1 ; Make it a word offset jmp ansspc[di] ; Dispatch atdel: jmp short atign ; ignore DEL char atdeb: test yflags,capt ; capturing output? jz atdeb3 ; z = no, forget this part push ax ; save char call cptchr ; give it captured character pop ax ; restore character and keep going atdeb3: mov bh,ansflgs ; Save flags and attribute mov bl,curattr push bx push word ptr mar_top ; Save limited scrolling region push ax ; Save character for a second mov ah,curattr ; Get attribute call brkatt ; Break it up and al,att_intensity ; clear attributes, except bold bit call addatt ; Put it back together mov curattr,ah ; Store or ansflgs,decawm ; Set autowrap temporarily mov mar_top,0 ; Set scrolling region to entire page mov al,byte ptr low_rgt+1 mov mar_bot,al pop ax ; Restore character test al,80h ; high bit set? jz atdeb0 ; z = not set push ax ; Save the character for a second mov al,7eh ; Output a tilde call atnrm2 pop ax ; Restore character and al,7fh ; and remove high bit atdeb0: cmp al,del ; A DELETE? je atdeb1 ; Yes - output "^?" cmp al,20h ; A control character? jnb atdeb2 ; No - just output char in al atdeb1: push ax ; Save the character for a second mov al,5eh ; Output a caret call atnrm2 pop ax ; Restore character add al,40h ; Make ^letter (or ^? for DELETE) and al,7fh ; Clear bit 7 (for DELETE) atdeb2: call atnrm2 ; Output translated character pop word ptr mar_top ; Restore scrolling region pop bx ; And flags and cursor attribute mov curattr,bl mov ansflgs,bh ret atnorm: mov ttstate,offset atnrm ; Reset state to "normal". ret ; Normal character processor atnrm: mov bx,chr_set ; Get character set cmp byte ptr [bx],ascset ; standard US ascii? je atnrm2 ; e = yes cmp byte ptr [bx],alcset ; Alternate character set? [bk] jne atnrm0b ; ne = no [bk] cmp al,('a'-1) ; replace a..z with 128d - (a..z) [bk] jb atnrm2 ; b = out of range cmp al,'z' ja atnrm2 ; a = out of range add al,(80h-('a'-1)) ; map up by 20h jmp short atnrm2 atnrm0b:cmp byte ptr [bx],sgrset ; "Special" set? jne atnrm1 ; No - check UK cmp flags.vtflg,ttheath ; Heath-19? je atnrm0a ; e = yes cmp al,137Q ; Yes - is it in the "special" range? jb atnrm2 ; No - just output the char in al mov bl,al ; Yes - compute index in bx mov bh,0 sub bx,137Q mov al,sgrtab[bx] ; Fetch translation jmp short atnrm2 ; Output it atnrm0a:cmp al,94 ; H-19, in range for special graphics? jb atnrm2 ; b = no cmp al,126 ; too large? ja atnrm2 ; a = too large sub bx,94 ; H-19, offset from caret mov bl,al mov bh,0 sub bx,94 mov al,hgrtab[bx] ; fetch translation jmp short atnrm2 atnrm1: cmp al,'#' ; This thing? jne atnrm2 ; No - just output it cmp byte ptr [bx],ukset ; Yes - UK set? jne atnrm2 ; No - just output it mov al,156 ; Yeah, show them our pound sign atnrm2: cmp al,9bh ; ANSI CSI char? jne atnrm2b ; ne = no jmp at9bh ; yes, process ANSI CSI as "ESC [" atnrm2b:mov dx,cursor ; get cursor virtual position push ax ; save character call atscur ; set cursor physical position pop ax cmp insmod,0 ; insert mode off? je atnrm3 ; e = yes push ax ; save char call inschr ; open a char space in this line push bx mov bx,cursor ; get current row mov bl,bh mov bh,0 cmp linetype [bx],0 ; single width line? je atnrm2a ; e = yes call inschr ; open second space for double width atnrm2a:pop bx pop ax ; restore char atnrm3: ; set cursor before writing char mov bl,dh ; check for double characteristic xor bh,bh ; bx = row, in bl test anspflg,vtautop ; printing desired? jz atnrm4d ; e = no call pntchr ; print char in al cmp linetype [bx],0 ; normal characteristic? je atnrm4d ; e = yes push ax ; save current char mov al,' ' ; add a space for double width call pntchr pop ax ; recover char to be processed atnrm4d: cmp linetype [bx],0 ; normal characteristic? je atnrm4a ; e = yes push ax ; save char shl dl,1 ; double the column number mov ah,2 ; set cursor (bh = 0 from above) call direction ; do Bios screen operation pop ax ; recover the char mov ah,9 ; Output char in al to screen mov bh,0 ; Page zero mov bl,curattr ; Current attribute mov cx,1 ; Only one character int screen inc dl ; next column mov ah,2 ; set cursor call direction ; do Bios screen operation mov al,' ' ; use a space for doubling mov ah,9 ; Output to screen mov bh,0 ; Page zero mov bl,curattr ; Current attribute mov cx,1 ; Only one character int screen shr dl,1 ; keep "cursor" in single units jmp atnrm4b ; check autowrap in double width mode atnrm4a:mov ah,9 ; Output to screen mov bh,0 ; Page zero mov bl,curattr ; Current attribute mov cx,1 ; Only one character int screen ; set physical cursor after this char atnrm4b:test ansflgs,decawm ; Autowrap? jz atnrm5 ; No, continue mov cx,low_rgt ; copy logical cursor margins to cx push bx mov bl,dh ; get row xor bh,bh cmp linetype[bx],0 ; single width line? pop bx ; pop preserves flags je atnrm4c ; e = yes, single shr cl,1 ; halve right column # for wide chars atnrm4c:cmp dl,cl ; wrote in right-most column? jb atnrm5 ; b = no inc dl ; say want to use next column cmp flags.vtflg,ttheath ; emulating a H-19? [uci] je atscur ; e = yes, show wrap now. [uci] mov cursor,dx ; virtual cursor position ret ; exit without moving cursor from eol atnrm5: mov dx,cursor ; Restore cursor position inc dl ; Bump cursor atscur: cmp dl,250 ; To left of column zero?(wide screen) jb atscu1 ; b = no, continue mov dl,0 ; Yes - set at column zero atscu1: mov cx,low_rgt ; copy logical margins; cl=right col push bx mov bl,dh ; get row xor bh,bh cmp linetype [bx],0 ; single width lines? pop bx je atscu1a ; e = yes, single width shr cl,1 ; halve column # for double wides atscu1a:cmp dl,cl ; To right of right margin? jbe atscu3 ; be = no, continue mov dl,cl ; Yes - assume no autowrap test ansflgs,decawm ; Autowrap? jz atscu3 ; No, continue mov dl,0 ; Yes - set to column zero cmp dh,byte ptr low_rgt+1 ; at bottom of screen? je atscu1b ; e = yes cmp dh,mar_bot ; At bottom of scrolling region? jl atscu2 ; l = No - bump cursor and continue atscu1b:mov scroll,1 ; scroll count = 1 line call atscru ; Scroll up dec dh ; offset inc dh below atscu2: inc dh ; Just bump it atscu3: cmp dh,0 ; Constrain row to valid range jge atscu4 ; ge = non-negative row, ok mov dh,0 atscu4: cmp dh,byte ptr low_rgt+1 ; 25th line? jle atscu5 ; le = no mov dh,byte ptr low_rgt+1 ; set to 24th line cmp flags.vtflg,ttheath ; emulating a Heath-19? jne atscu4a ; ne = no [hlk] cmp h19l25,0 ; Heath 25th line enabled? je atscu5 ; e = no atscu4a:inc dh ; yes, go to line 25 [hlk] test yflags,modoff ; is mode line off? jnz atscu8 ; nz = yes push dx ; save cursor position call trnmod ; no, turn it off now and yflags,not modoff ; now say it's on (owned by host) pop dx atscu8: mov flags.modflg,2 ; say mode line is owned by host mov al,yflags ; place to communicate call telmsy ; tell msy the news atscu5: push cx ; save cx around screen call mov cursor,dx ; Set cursor and return mov ah,2 ; setup for position cursor call mov bl,dh ; get row mov bh,0 cmp linetype [bx],0 ; single width line? je atscu5a ; e = yes shl dl,1 ; double the column number call direction ; do Bios screen operation shr dl,1 ; restore dl (logical column) jmp short atscu5b atscu5a:call direction ; do Bios screen operation atscu5b:pop cx cmp kbiflg,0 ; Is keyboard input flag set? je atscu6 ; No - just return test vtflags,vsmarginbell ; Yes - do we care? jz atscu6 ; Return if no margin bell mov dx,cursor ; Get new and old cursors mov bx,kbicsr cmp bh,dh ; Same row? jne atscu6 ; No - just return cmp bl,belcol ; Old cursor at or left of bell column? ja atscu6 ; a = no, just return cmp dl,belcol ; Yes - new cursor past bell column? jbe atscu6 ; be = no, just return call vtbell ; Yes - ring the bell atscu6: ret ; This routine is called to check the cursor position after any kind of cursor ; positioning command. Note that cursor positioning does NOT cause scrolling ; on a VT100 (hence the need for a routine separate from this for "indexing". ; ; Call: dx/ "new" cursor position (modified cursor) ; ; Return: dx/ "new" cursor position adjusted for screen limits (if ; decom is reset), or scrolling region (if decom is set). ; ; Preserves ax, bx, and cx. ; atccpc: push bx ; save bx and cx push cx atccp7: mov cx,low_rgt ; margins, cl = right margin mov bl,dh ; get row xor bh,bh cmp linetype [bx],0 ; single width line? je atccp0 ; e = yes, single width shr cl,1 ; halve right margin for double wides atccp0: cmp dl,250 ; To left of left margin?(wide screen) jb atccp1 ; b = no, go check right mov dl,0 ; No, set to left margin atccp1: cmp dl,cl ; To right of right margin jbe atccp2 ; be = yes, go check top mov dl,cl ; No, set to right margin atccp2: test ansflgs,decom ; Origin mode set? jnz atccp5 ; Yes, can't go out of scrolling region cmp dh,0 ; Above top of screen? jge atccp3 ; ge = no, check bottom mov dh,0 ; Yes, stop here atccp3: cmp dh,byte ptr low_rgt+1 ; Below bottom of screen? jle atccp4 ; le = no, return mov dh,byte ptr low_rgt+1 ; Yes, stop at bottom margin cmp flags.vtflg,ttheath ; Heath-19 mode? jne atccp4 ; ne = no cmp h19l25,0 ; 25th line enabled? je atccp4 ; e = no inc dh ; allow 25th line atccp4: pop cx pop bx ret atccp5: cmp dh,mar_top ; Above top of scrolling region? jge atccp6 ; ge = no, check bottom mov dh,mar_top ; Yes, stop there atccp6: cmp dh,mar_bot ; Below bottom perhaps? jle atccp4 ; le = no, return mov dh,mar_bot ; Yes, stop at the bottom margin pop cx pop bx ret ; This routine is called to adjust the cursor for the "indexing" like commands ; (e.g., index, reverse index, newline, etc.). It contrains the cursor, and ; indicates if scrolling is necessary, and if so, in which direction. ; ; Call: cursor/ "old" cursor position ; dx/ "new" cursor position ; ; Return: ax/ pointer to scrolling routine to call (or to a ret) ; bx/ "old" cursor position ; dx/ "new" cursor position adjusted for screen limits or ; scrolling region, depending on whether the original ; cursor position was inside or outside the scrolling ; region. ; ; On the VT100, a scroll does not occur unless the original cursor position ; was on the top or bottom margin. This routine assumes that when decom is ; set the cursor position is set to the new origin, and that no other routine ; allows the cursor to be positioned outside the scrolling region as long ; as decom is set (which is the way a real VT100 works). Note that for the ; normal case (no limited scrolling region defined) the margins are the same ; as the screen limits and scrolling occurs (as on a "normal" terminal) when ; an attempt is made to index off the screen. Preserves cx. ; Revised 16 June 1987 [jrd] atccic: push cx mov cx,low_rgt ; get margins, cl = right margin mov bl,dh ; get row xor bh,bh cmp bl,ch ; Below screen? ja atcci0 ; a = yes, use single width line cmp linetype[bx],0 ; single width chars? je atcci0 ; e = yes, single width shr cl,1 ; halve margin for double wides atcci0: mov ax,offset atign ; Assume no scrolling necessary mov bx,cursor ; Get old cursor cmp dl,250 ; To left of left margin?(wide screen) jb atcci1 ; b = no, go check right mov dl,0 ; No, set to left margin atcci1: cmp dl,cl ; To right of right margin jbe atcci2 ; be = yes, go check top mov dl,cl ; No, set to right margin atcci2: cmp bh,mar_top ; was old pos at scrolling top margin? jne atcci5 ; ne = no, check other end cmp dh,mar_top ; want to go above top margin? jge atcci7 ; ge = no mov scroll,1 mov ax,offset atscrd ; Yes, indicate scroll down required mov dh,mar_top ; Set to top margin jmp atcci7 atcci5: cmp bh,mar_bot ; Was old position at bottom margin? jne atcci7 ; ne = no, so don't trap cursor cmp dh,mar_bot ; want to go below? jb atcci7 ; b = no, nothing to worry about mov scroll,1 ; 1 line mov ax,offset atscru ; Yes, indicate scroll up required atcci6: mov dh,mar_bot ; Set to bottom margin pop cx ret atcci7: pop cx ; old pos was outside scrolling region jmp atccpc ; do full screen check and return ; This routine picks an attribute apart into its component "parts" - the ; base attribute for the screen and the "extras" - i.e., blink, intensity ; and underline. ; ; Call: ah/ a cursor attribute ; ; Return: ah/ base attribute for screen (07H normal, 70H reverse). ; al/ "extra" attributes ; ; Note that there is a complementary routine, addatt, for putting attributes ; back together. ; brkatt: mov al,0 ; Clear returned "extra" attributes cmp crt_mode,7 ; monochrome display adapter mode? jne brkat2 ; ne = no. cut this short for color test ah,att_low_mask ; Any of these on? jnz brkat1 ; Yes, can't be underline test ah,att_underline ; Underline? jz brkat2 ; No, some kind of reverse video or al,att_underline ; Yes, say underline test ah,70h ;;att_reverse ; Reverse video + underline? jz brkat1 ; No, fix up low nibble and ah,not att_underline ; Yes, clear the underline bit in ah jmp short brkat2 ; And forge on brkat1: or ah,att_normal ; Normal - turn on all normal bits brkat2: test ah,att_intensity ; Intensity attribute on? jz brkat3 ; No - check blink or al,att_intensity ; Yes - turn on the bit brkat3: test ah,att_blink ; Blink on? jz brkat4 ; No - forge on or al,att_blink ; Yes - turn on the bit brkat4: and ah,not(att_intensity+att_blink) ;strip blink/bold, leave color ret ; This routine builds a cursor attribute given the base attribute for the ; screen background and the "extra" attributes we want (blink, etc.). ; ; Call: ah/ base attribute for background (07H or 70H) ; al/ "extra" attributes (89H for all three) ; ; Return: ah/ base combined with "extras". ; addatt: test al,att_underline ; Want underline? jz addat1 ; No - no need for hack and ah,not att_low_mask ; Yes - clear these bits addat1: or ah,al ; Or in the attributes ret ; This routine is called when we want to reverse everything on the screen ; from normal to reverse video, or vice versa. It is called only when ; the decscnm attribute is changed. ; ; Call: no arguments. ; ; This routine may destroy ax-dx ; revscn: mov dh,byte ptr low_rgt+1 ; Compute last screen offset in ax inc dh ; One more row to catch mode line mov dl,crt_cols ; physical width dec dl ; and we count from 0 call scrloc mov cx,ax ; Save it in cx for a minute mov dx,0 ; Compute first screen offset in ax call scrloc sub cx,ax ; Compute number of locs to change. add cx,2 sar cx,1 ; In 16-bit words please push di ; Save some more acs push es push cx ; save word count for Topview push ax ; save screen displacement call scrseg ; Get address of screen in ax, es:di pop ax ; recover displacement add di,ax ; displacement addr of start of change call scroff ; Turn screen off if color card revsc1: mov ax,es:[di] ; Fetch a word mov bl,al ; Save the character call brkatt ; Break up the attributes rol ah,1 ; Reverse the video rol ah,1 ; Reverse the video rol ah,1 ; Reverse the video rol ah,1 ; Reverse the video call addatt ; Put attributes back together mov al,bl ; Restore character mov es:[di],ax ; Stuff into screen memory add di,2 ; Point di to next word of screen mem loop revsc1 ; Loop for entire screen pop cx ; recover word count for Topview call scrsync ; synch with Topview call scron ; Turn screen back on if color card pop es ; Restore segment register pop di ; And destination index ret ; Reset-everything routine. atreset:mov al,0 ; Make cursor disappear for a while ;; call csrtype mov cursor,0 ; Cursor is at 0,0 mov ansflgs,0 ; reset these flags mov escdec,0 cmp flags.vtflg,ttvt100 ; VT100? jne atres7 ; ne = no mov ansflgs,decanm ; turn on ANSI mode flag atres7: mov mar_top,0 ; Reset scrolling region mov al,byte ptr low_rgt+1 mov mar_bot,al mov ah,vtemu.vtflgst mov vtemu.vtflgop,ah mov vtflags,ah mov insmod,0 ; reset insert mode mov h19l25,0 ; clear heath 25th line enable mov h19ctyp,1 ; Heath-19 cursor to underline mov anspflg,0 ; clear printer flag mov cx,4 ; Initialize the "LEDs" mov al,led_off ; Turn them all off mov di,offset ansleds+6 ; Point to the "LEDs" push es ; save es push ds pop es ; use datas segment for es:di below cld ; set forward direction rep stosb ; Do it pop es call disleds ; update mode line mov vttabs,offset deftabs call cpytabs ; Initialize tab stops call chrdef ; Set default character set call vtbell ; Ding bell like VT100 test vtflags,vsnewline ; Want ANSI newline mode? jz atres1 ; No or ansflgs,anslnm ; Yes - set it in the mode flags atres1: test vtflags,vswrap ; How about autowrap? jz atres2 ; No or ansflgs,decawm ; Yes - set it in the mode flags atres2: mov ah,att_normal ; get present normal coloring call brkatt ; separate color and blink/bold rol ah,1 ; reverse fore/back color fields rol ah,1 rol ah,1 rol ah,1 call addatt ; put back blink/bold mov att_reverse,ah ; this is the reverse video code mov al,att_normal ; Assume normal video test vtflags,vsscreen ; Want reverse video? jz atres3 ; No or ansflgs,decscnm ; Yes - turn on the mode flag xchg al,ah ; And reverse the video atres3: mov cx,slen ; typically 24 but do max lines mov di,0 atres8: mov linetype[di],0 ; clear the linetype array to single inc di ; width/height characters loop atres8 mov curattr,al ; Give cursor and screen nice mov scbattr,al ; attributes. mov oldbatr,al ; place to remember long term mov mlbattr,ah ; Give the other to the mode line and mlbattr,not att_intensity ; turn off intensity bit mov video_state,0 ; say normal video mov ax,0 ; Clear entire screen mov bx,low_rgt mov bl,crt_cols dec bl ; do physical screen call atsclr mov dx,cursor ; Set cursor to 0,0 call atscu5 call atsc ; Give saved cursor reasonable values call atsctyp ; Set right cursor type mov al,yflags call telmsy ; update msy about ansflgs state test yflags,modoff ; is mode line off? jnz atres9 ; nz = yes push dx ; save cursor position call trnmod ; toggle off then on again so we call trnmod ; use it with current coloring pop dx atres9: ret ; Routine to set cursor type (block, underline). atsctyp:cmp flags.vtflg,ttheath ; Heath-19? jne atsct0 ; ne = no mov al,h19ctyp ; get cursor kind and on/off bit test al,4 ; is cursor to be off? jz atsct1 ; z = no, al has kind mov al,0 ; turn off cursor jmp short atsct1 ; do it atsct0: mov al,1 ; Assume underline test vtemu.vtflgop,vscursor ; Want block? jnz atsct1 ; nz = no, underline mov al,2 ; Yes atsct1: call csrtype ; Do it ret ; Routine to set default character set. chrdef: mov al,vtemu.vtchset ; get setup default character set chrde1: mov chr_sg0,al ; reset character sets mov chr_sg1,al mov ax,offset chr_sg0 ; select character set zero mov chr_set,ax ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; end of part one ;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; start of part two ;;;;;;;;;;;;;;;;;;;;;;;;;; ; Routine to set special graphics character set (used in VT52 mode). chrsgs: mov al,sgrset ; Select "graphics" set jmp chrde1 ; Do it and return ; Control-character handling routines atbel: call vtbell ; Just ring bell and return ret atbs: cmp dl,0 ; Backspace. too far? je atbs1 ; e = at column 0 already dec dl ; Backup cursor atbs1: call atccpc ; Check range jmp atscu5 ; Set cursor and return atht: cmp flags.vtflg,ttheath ; Heath-19 mode? je atht2 ; e = yes. handle specially mov ch,0 mov cl,byte ptr low_rgt cmp dl,cl ; At or beyond last column? jae atbs1 ; Yes, check range, set cursor and ret mov bh,0 ; Make an index mov bl,dl ; For column sub cl,dl ; number of columns to examine atht1: inc bx ; Tab always moves at least one space cmp tabs[bx],0 ; Look for non-zero loopz atht1 mov dl,bl ; Get the new row index jmp atbs1 ; Check range, set cursor, and return atht2: mov dx,cursor ; Heath-19. get cursor position add dl,8 ; tabs are every 8 columns and dl,not 7 ; do modulo 8 cmp dl,byte ptr low_rgt ; check against right edge jae atht3 ; ae = out of range jmp atscu5 ; set cursor and return atht3: test ansflgs,decawm ; doing line wrapping? jnz atht4 ; nz = yes. wrap to next line mov dl,byte ptr low_rgt ; else go to right margin jmp atscu5 ; set cursor and return atht4: inc dh ; say want next line down xor dl,dl ; and left margin call atccic ; index check call ax ; do any needed scrolling atht4a: jmp atscu5 ; reset cursor atlf: cmp flags.vtflg,ttheath ; Heath-19 mode? je atlf2 ; e = yes test ansflgs,anslnm ; New-line mode? jz atlf2 ; No - just move to next line down mov dl,0 ; Yes - move to left margin also atlf2: inc dh ; Index line down call atccic ; Check indexing call ax ; Call scrolling routine jmp atscu5 ; Set cursor atcr: mov dl,0 ; Go to left margin jmp atscu5 ; Set cursor and return atff: cmp ttstate,offset atescf ; parsing escape sequence? jne atlf ; ne = no, do as line feed test denyflg,200h ; is auto Tek mode disabled? jnz atlf ; nz = yes, treat as line feed call atsc ; save cursor and associated data JMP TEKESC ; Jump to Tektronix Emulator, al=FF atso: mov ax,offset chr_sg1 ; Select set G1 and return mov chr_set,ax ret atsi: mov ax,offset chr_sg0 ; Select set G0 and return mov chr_set,ax ret atcan: cmp ttstate,offset atnrm ; doing normal chars (vs esc seq)? jne atcan1 ; ne = no, assume esc seq jmp atign ; ignore ^X, ^Z in normal mode atcan1: mov ttstate,offset atnrm ; Reset state to "normal" mov al,sgrtab+2 ; replace CAN (^X) by checkerboard jmp atnrm ; Process char as a normal one atesc: mov nansarg,0 ; Clear ANSI arguments mov al,0 mov cx,lansarg mov di,offset ansargs push es push ds pop es ; use datas segment for es:di below cld ; set direction forward rep stosb pop es and escdec,not decmode ; Clear "DEC modes" flag mov h19mod,0 ; clear Heath-19 mode flag mov ttstate,offset atescf ; Next state is escape follower ret atescf: cmp flags.vtflg,ttvt100 ; VT100? jne atv52f ; ne = not VT100, try others atescf0:mov cx,lansesc ; Escape follower - get table length mov di,offset ansesc ; Point di at table push es push ds pop es ; use datas segment for es:di below cld ; set direction forward repne scasb ; Find it pop es je atescf1 ; Found - now go do something with it jmp atnorm ; Not there - just ignore it atescf1:mov di,lansesc - 1 ; Compute word index into jump table sub di,cx shl di,1 jmp ansejt[di] ; Dispatch to the routine atv52f: cmp flags.vtflg,ttheath ; Heath-19? je ath19f ; e = yes. Use Heath esc seqs mov ttstate,offset atnrm ; Assume state "normal" on return mov cx,lv52esc ; Get table length mov di,offset v52esc ; Point di at table push es push ds pop es ; use datas segment for es:di below cld ; set direction forward repne scasb ; Find it pop es je atv52f1 ; Found - do something with it ret ; Not there - just ignore it atv52f1:mov di,lv52esc - 1 ; Compute word index into jump table sub di,cx shl di,1 jmp v52ejt[di] ; Dispatch to the routine ath19f: mov ttstate,offset atnrm ; Assume state "normal" on return test ansflgs,decanm ; ansi mode? jnz atescf0 ; nz = yes, use ansi table mov cx,lh19esc ; Get table length mov di,offset h19esc ; Point di at table push es push ds pop es ; use datas segment for es:di below cld ; set direction forward repne scasb ; Find it pop es je ath19f1 ; Found - do something with it ret ; Not there - just ignore it ath19f1:mov di,lh19esc - 1 ; Compute word index into jump table sub di,cx shl di,1 jmp h19ejt[di] ; Dispatch to the routine at9bh: call atesc ; 9bH char (ANSI CSI == ESC [) mov ttstate,offset atpaa ; next state is parse ansi sequences ret ; Escape follower routines. atcsi: mov ttstate,offset atpaa ; Next state is parse ansi args ret atpaa: test al,80h ; high bit set? jz atpaa6 ; z = no and al,7fh ; strip high bit cmp al,' ' ; control code remainder? jae atpaa6 ; ae = no, use 7 bit result mov ttstate,offset atnrm ; reset state to normal text jmp atctrl ; execute 7 bit control code atpaa6: cmp al,'0' ; A digit? jb atpaa1 ; No - just ignore it cmp al,'9' ; Maybe - A separator or final char? ja atpaa2 ; Perhaps - go check it out mov cl,al ; A digit - convert ASCII to binary sub cl,'0' mov ch,0 mov bl,nansarg ; put index in bx [dlk] xor bh,bh mov al,ansargs[bx] ; Pick up what we've done so far [dlk] shl al,1 ; multiply by 10. 2 * al mov ah,al ; save shl al,1 ; 4 * al shl al,1 ; 8 * al add al,ah ; 10 * al mov ah,0 ; clear high field add ax,cx ; add in this digit [dlk] cmp ax,0feh ; max value is 0ffh [dlk] jbe atpaa0 ; be = ok [dlk] mov al,0ffh ; set to max value [dlk] atpaa0: mov ansargs[bx],al ; Put result back for next time [dlk] atpaa1: ret ; And return atpaa2: cmp al,'?' ; The deadly question mark? jne atpaa2a ; No - check further or escdec,decmode ; Yes - say DEC modes are coming ret ; And return atpaa2a:cmp al,'>' ; Heath private mode? jne atpaa3 ; ne = no cmp flags.vtflg,ttheath ; emulating a Heath-19? jne atpaa3 ; ne = no, ignore this sequence mov h19mod,1 ; say Heath mode sequence follows ret atpaa3: cmp al,';' ; Argument separator? jne atpaa4 ; No - check for final char mov al,nansarg ; Get argument index inc al ; Bump it cmp al,lansarg ; Too many? jl atpa3a ; l = no, continue mov ttstate,offset atnrm ; Reset state to "normal" ret ; and pretend all is well ; [jrd] jmp atcan ; Yes - abandon sequence on error atpa3a: mov nansarg,al ; Save it ret atpaa4: mov cx,lanstab mov di,offset anstab ; Look for it in the table push es push ds pop es ; use datas segment for es:di below cld ; set direction forward repne scasb pop es je atpaa5 ; Found it - go dispatch cmp al,40h ; in range for a legal terminator? jb atpaa4a ; b = not in range, ignore cmp al,7eh ; other end of the range ja atpaa4a ; a = out of range, ignore ; in range, absorb and become normal mov ttstate,offset atnrm ; Put state back to normal atpaa4a:ret ; Just return if it is unknown atpaa5: mov ttstate,offset atnrm ; Put state back to normal mov di,lanstab - 1 ; Compute word index into jump table sub di,cx shl di,1 jmp ansjmp[di] ; Off into the wild blue atind: inc dh ; Index - move cursor down one atind1: call atccic ; Check cursor position call ax ; Scroll if necessary mov ttstate,offset atnrm ; Reset state jmp atscu5 ; Set cursor, etc. and return atnel: mov dl,0 ; Next line - sort of like CRLF inc dh ; ... all in one command jmp atind1 ; Check cursor, etc., and return atri: dec dh ; Reverse index jmp atind1 ; Check cursor, etc., and return athts: call atccpc ; Make sure we have valid column number mov dh,0 ; Zap row mov al,0FFH ; Indicates a tab stop mov di,dx ; Dumb specialized registers mov tabs[di],al ; Store it jmp atnorm ; Reset state and return atsc: mov si,offset curattr ; Save cursor, attribute, char set etc mov di,offset savecu ; Place to save the stuff mov cx,lsavecu ; Length of save area push es ; save es push ds pop es ; set es to datas segment cld rep movsb ; Save it pop es mov cl,ansflgs ; Save a copy of the flags mov savflgs,cl jmp atnorm ; Reset state and return atrc: mov si,offset savecu ; Restore cursor, attributes, etc. mov di,offset curattr ; Where stuff goes mov cx,lsavecu ; Length of save area push es ; save es push ds pop es ; set es to datas segment cld rep movsb ; Put the stuff back pop es mov al,savflgs ; Get saved flags xor al,ansflgs ; Exclusive-or with current flags test al,decscnm ; Did screen mode change? jz atrc1 ; No, just reset saved flags and leave mov ah,curattr ; Get cursor attribute that was saved call brkatt ; Break into background & extra stuff rol ah,1 ; Reverse the background rol ah,1 ; Reverse the background rol ah,1 ; Reverse the background rol ah,1 ; Reverse the background call addatt ; Put it all back together mov curattr,ah ; Store atrc1: mov al,ansflgs ; Reset flags in case called again and al, not(decckm+deckpam+decom) ; remove old bits [dlk] and savflgs,(decckm+deckpam+decom) ; remove all but new bits [dlk] or al,savflgs ; restore saved bits [dlk] mov ansflgs,al ; update these flags [dlk] mov savflgs,al mov dx,cursor ; Get cursor mov kbiflg,0 ; Don't bother them with beeps here call atscu5 ; Set cursor jmp atnorm ; Reset state and return atkpam: or ansflgs,deckpam ; Turn on the bit mov al,yflags call telmsy ; inform msy of new state jmp atnorm ; Reset state and return atkpnm: and ansflgs,not deckpam ; Turn off the bit mov al,yflags call telmsy ; inform msy of new state jmp atnorm ; Reset state and return atris: call atreset ; Reset everything jmp atnorm ; And state too, return, etc atsg0: mov ttstate,offset atsg01 ; Setup to get last character ret atsg01: call atscs ; Get code for character set mov chr_sg0,al ; Store it jmp atnorm ; Reset state etc. and return atsg1: mov ttstate,offset atsg11 ; Setup to get last character ret atsg11: call atscs ; Get code for character set mov chr_sg1,al ; Store it jmp atnorm ; Reset state etc. and return atscs: cmp al,'A' ; UK ASCII set? jne atscs1 ; No mov al,ukset ; Yes - give them that and return ret atscs1: cmp al,'B' ; US ASCII set? jne atscs3 ; No atscs2: mov al,ascset ; Yes - give them that and return ret atscs3: cmp al,'0' ; Special graphics set? jne atscs4 ; ne = no mov al,sgrset ; Yes - say that's what it is ret atscs4: cmp al,'1' ; alt char ROM, std char set? jne atscs5 ; ne = no mov al,alcset ; use Alternate character set ret atscs5: cmp al,'2' ; alt char ROM, special graphics? jne atscs2 ; ne = no, use US ASCII mov al,sgrset ; set graphics ret ; ESC # Pn series atsdhl: mov ttstate,offset atsdbl ; set up to parse argument ret atsdbl: cmp al,'3' ; Double high lines. Top half? je atsdh2 ; e = yes cmp al,'4' ; bottom half? je atsdh2 ; e = yes cmp al,'5' ; restore line to single width? je atsdh1 ; e = yes cmp al,'6' ; double width single height? je atsdh2 ; e = yes cmp al,'8' ; screen alignment? je atsdh8 ; e = yes jmp atnorm ; else ignore atsdh1: call linesgl ; set line to single width jmp atnorm atsdh2: call linedbl ; expand the line to double width jmp atnorm ; set state to normal and ret atsdh8: call atalign ; do screen alignment jmp atnorm atpriv: mov ttstate,offset atnorm ; ignore next char ret ; and return to normal afterward atalign proc near ; Fill screen with 'E' call atreset ; clear system or ansflgs,decawm ; set wrap mov cl,byte ptr low_rgt ; number of columns-1 inc cl mov al,byte ptr low_rgt+1 ; number of rows-1 inc al mul cl ; ax = number of chars on screen mov cx,ax atalig1:push cx mov al,'E' ; write screen full of E's call atnrm ; write the 'E' pop cx loop atalig1 ; cx times ret atalign endp ; This routine may be used to repeat a call to a selected action routine ; for all of the ANSI parameters given in a call. When the action routine ; is called, si will contain the index for the current ANSI parameter (i.e., ; the current ANSI parameter may be gotten using ansargs[si] for an effective ; address). The action routine may modify any ACs it wants, but cx, si, ; and di are preserved over the call to the action routine, so these may ; not be used for building return values for the original caller. Note that ; if there are no ANSI parameters, the effect is the same as if one ANSI ; parameter with a value of zero was given. ; ; Call: di/ offset of action routine in code seqment ; atreps: mov cl,nansarg ; Pick up number of parameters inc cl ; Zero parms is same as 1 zero parm mov ch,0 mov si,0 ; Init parm index atrep1: push cx ; Save important acs push si push di call di ; Call indicated routine pop di ; Restore acs pop si pop cx inc si ; Advance to next parameter loop atrep1 ; Loop for all ret ; And return ; Final char (ANSI) routines. atcup: mov dh,ansargs ; Get the two arguments mov dl,ansargs+1 cmp dh,0 ; Zero line number? jne atcup1 ; No - continue mov dh,1 ; Yes - default to one atcup1: cmp dl,0 ; Ditto for row jne atcup2 mov dl,1 atcup2: dec dh ; Now normalize dec dl test ansflgs,decom ; Origin mode? jz atcup4 ; No - skip this stuff add dh,mar_top ; Yes - it was relative to top margin jno atcup4 ; If no overflow, continue mov dh,byte ptr low_rgt+1 ; Otherwise just set to screen bottom atcup4: cmp dh,byte ptr low_rgt+1 ; going to 25th line? [hlk] jbe atcup5 ; be = no [dlk] cmp flags.vtflg,ttheath ; emulating a Heath-19? jne atcup6 ; ne = no [hlk] cmp h19l25,0 ; Heath 25th line enabled? je atcup5 ; e = no atcup6: mov dh,byte ptr low_rgt+1 ; bottom normal line inc dh ; the 25th line jmp atscu4 ; set cursor position and return atcup5: call atccpc ; Check position jmp atscu5 ; Set cursor position and return atcuarg:mov al,ansargs ; Get a cursor move argument cmp al,0 ; Zero? jne atcua1 ; No - return mov al,1 ; Yes - default to one atcua1: ret ; Return ; Disallow movement to 25th line atcuu: call atcuarg ; Get cursor move argument in al sub dh,al ; Compute new cursor position jnc atcuu1 ; nc = ok [dlk] xor dh,dh ; overflow, restrict range. [dlk] atcuu1: call atccic ; check indexing, ignore action in ax jmp atscu5 ; set the cursor at its new position atcud: call atcuarg ; Get the argument add dh,al ; Compute new cursor position jnc atcud1 ; nc = ok [dlk] mov dh,byte ptr low_rgt+1 ; default bottom [dlk] atcud1: call atccic ; check indexing, ignore action in ax jmp atscu5 ; set the cursor at its new position ; Allow horiz movement on 25th line atcuf: call atcuarg ; Get the argument add dl,al ; Compute new cursor position jnc atcup4 ; If no carry, continue [dlk] mov dl,byte ptr low_rgt ; Else set to right margin jmp atcup4 ; Check/set cursor, return atcub: call atcuarg ; Get the argument sub dl,al ; Compute new cursor position jnc atcup4 ; If no carry, continue [dlk] mov dl,0 ; Else set to left margin jmp atcup4 ; Check/set cursor, return ated: mov di,offset ated0 ; Routine to process parm call atreps ; Do all selected parms ret ated0: cmp ansargs[si],0 ; Was arg zero? jne ated2 ; No - continue mov ax,dx ; Yes - erase from cursor to end of screen cmp dx,0 ; cursor at home position? je atedcom ; e = yes, roll screen before clear push dx ; save dx mov bl,dh ; get row number xor bh,bh cmp linetype [bx],0 ; single width line? je ated0a ; e = yes shl dl,1 ; physical column is twice logical ated0a: or dl,dl ; starting at left margin? je ated0b ; e = yes, this goes to single width inc bl ; else start on next line ated0b: cmp bl,byte ptr low_rgt+1 ; at the end of the screen? ja ated0c ; a = yes, stop singling-up mov byte ptr linetype [bx],0 ; set to single width inc bx jmp short ated0b ; loop, reset lines to end of screen ated0c: mov bx,low_rgt ; erase from cursor to end of screen mov bl,crt_cols dec bl ; do physical screen width call vtsclr ; Clear it pop dx ; restore dx ated1: ret ated2: cmp ansargs[si],1 ; Was arg one? jne ated3 ; No - continue mov ax,0 ; Yes - erase from start of screen ; to cursor, inclusive xor bx,bx ; start at top row (0) ated2b: cmp bl,dh ; check rows from the top down jae ated2c ; ae = at or below current line mov byte ptr linetype [bx],0; set line to single width inc bx ; inc row jmp short ated2b ; look at next line ated2c: or dl,dl ; at left margin of current line? jne ated2d ; ne = no, leave line width intact mov byte ptr linetype [bx],0 ; convert to single width ated2d: mov bl,dh ; get row number xor bh,bh cmp linetype [bx],0 ; single width line? je ated2a ; e = yes shl dl,1 ; physical column is twice logical ated2a: mov bx,dx ; cursor position to bx call vtsclr ; Clear it ret ated3: cmp ansargs[si],2 ; Was arg two? jne ated1 ; ne = no, else erase entire screen ; entry to roll screen before erasing atedcom:mov al,byte ptr low_rgt+1 ; number of lines on screen mov scroll,al call atscru ; scroll them up before erasure ; removes double w/h lines too. mov ax,0 ; erase from here (home) mov bx,low_rgt mov bl,crt_cols dec bl ; physical width (to here) call vtsclr ; clear screen ret atel: mov di,offset atel0 ; Get routine to call call atreps ; Repeat for all parameters ret atel0: cmp ansargs[si],0 ; Was arg zero? jne atel2 ; No - continue mov ax,dx ; Yes - erase from cursor mov bh,dh ; ...to end of line, inclusive push bx mov bl,bh ; get row mov bh,0 cmp linetype [bx],0 ; single width line? je atel0a ; e = yes shl al,1 ; physical column is twice logical atel0a: pop bx mov bl,byte ptr low_rgt call vtsclr ; Clear it atel1: ret atel2: cmp ansargs[si],1 ; Was arg one? jne atel3 ; No - continue mov ah,dh ; Yes - erase from start of line mov al,0 mov bx,dx ; ...to cursor, inclusive push bx mov bl,dh ; get row mov bh,0 cmp linetype [bx],0 ; single width line? pop bx ; pop does not affect flags je atel2a ; e = yes shl bl,1 ; physical column is twice logical atel2a: call vtsclr ; Clear it ret atel3: cmp ansargs[si],2 ; Was arg two? jne atel1 ; No - ignore it mov ah,dh ; Yes - erase entire line mov al,0 mov bh,dh mov bl,byte ptr low_rgt mov bl,crt_cols dec bl ; physical line call vtsclr ; Clear it ret atsgr: mov ah,curattr ; Get current cursor attribute call brkatt ; Break it apart mov di,offset atsgr1 ; Routine to call call atreps ; Repeat for all parms call addatt ; Put the attributes back together mov curattr,ah ; Store ret atsgr1: mov bl,ansargs[si] ; Fetch an argument cmp bl,0 ; Zero? jne atsgr2 ; No mov al,0 ; Yes - clear the "extras" mov ah,scbattr ; And reset background and ah,77h ; clear blink/bold here mov video_state,0 ; say normal video now ret atsgr2: cmp bl,1 ; One? jne atsgr3 ; No or al,att_intensity ; Yes - set bold ret atsgr3: cmp bl,4 ; Four? Underline. Mods by [jrd] jne atsgr4 ; ne = no or al,att_underline ; Yes, set underscore cmp crt_mode,7 ; monochrome display adapter mode? je atsgr3a ; e = yes. Otherwise reverse video ; use reversed video rather than blue on black and al,not att_underline ; clear underline and rol ah,1 ; reverse the colors rol ah,1 rol ah,1 rol ah,1 atsgr3a:ret atsgr4: cmp bl,5 ; Five? jne atsgr5 ; No or al,att_blink ; Yes - set blink ret atsgr5: cmp bl,7 ; Seven? jne atsgr6 ; No - just ignore it cmp video_state,0 ; is video normal? jne atsgr6 ; ne = no, reversed already, ignore rol ah,1 ; reverse the colors rol ah,1 rol ah,1 rol ah,1 mov video_state,1 ; say reversed now ret atsgr6: cmp bl,30 ; ANSI color series? jb atsgrx ; b = no cmp bl,37 ; foreground set (30-37)? ja atsgr7 ; a = no, try background set sub bl,30 ; take away the bias and ah,not 07H ; clear foreground bits test bl,1 ; ANSI red? jz atsgr6a ; z = no or ah,4 ; IBM red foreground bit atsgr6a:test bl,2 ; ANSI & IBM green? jz atsgr6b ; z = no or ah,2 ; IBM green foreground bit atsgr6b:test bl,4 ; ANSI blue? jz atsgr6c ; z = no or ah,1 ; IBM blue foreground bit atsgr6c:ret atsgr7: cmp bl,40 ; background color set? jb atsgrx ; b = no cmp bl,47 ; background set is 40-47 ja atsgrx ; nb = no, not a color command sub bl,40 ; take away the bias and ah,not 70H ; clear background bits test bl,1 ; ANSI red? jz atsgr7a ; z = no or ah,40h ; IBM red background bit atsgr7a:test bl,2 ; ANSI & IBM green? jz atsgr7b ; z = no or ah,20h ; IBM green background bit atsgr7b:test bl,4 ; ANSI blue? jz atsgrx ; z = no or ah,10h ; IBM blue background bit atsgrx: ret attbc: call atccpc ; Make sure cursor is kosher mov di,offset attbc0 ; Routine to call call atreps ; Do for all parms ret attbc0: cmp ansargs[si],0 ; Was argument zero? jne attbc2 ; No - check further mov dh,0 ; Zap row for indexing mov di,dx mov tabs[di],0 ; clear tab stop attbc1: ret attbc2: cmp ansargs[si],3 ; Was arg 3 (clear all tab stops)? jne attbc1 ; No - just ignore it mov cx,swidth ; Get ready to zap swidth columns mov di,offset tabs ; Point to the tab stop table mov al,0 ; zero indicates no tab stop push es ; save es push ds pop es ; use datas segment for es:di below cld ; set direction forward rep stosb ; Blit full of zeros pop es ret atstbm: mov al,ansargs ; Get the two line number args mov ah,ansargs+1 cmp al,0 ; Was first zero? jne atstb1 ; No - continue mov al,1 ; Yes - default is one atstb1: cmp ah,0 ; Was second zero? jne atstb2 ; No - continue mov ah,byte ptr low_rgt+1 ; Yes - default is last line on screen inc ah atstb2: dec al ; Normalize to our coord. system dec ah cmp ah,al ; Is size of region at least two lines? jbe atstb3 ; be = if not, indicate an error cmp al,0 ; Check against screen limits jl atstb3 cmp ah,byte ptr low_rgt+1 ja atstb3 mov mar_top,al ; Set the limits mov mar_bot,ah mov dx,0 ; Home cursor call atccpc ; Check cursor (get it inside window) jmp atscu5 ; Set cursor position and return atstb3: ret ; ignore bad requests ;;; jmp atcan ; Indicate error and return atda: cmp ansargs,0 ; Was argument zero? je decid ; Yes - send the i.d. string ret ; No - only an echo at52id: mov ttstate,offset atnrm ; ensure state is correct decid: mov cx,20 ; assumed length of asciiz string mov si,offset dastr ; Point to the string cmp flags.vtflg,ttvt100 ; VT100? je decid1 ; e = yes mov si,offset v52str ; No - try VT52 i.d. cmp flags.vtflg,ttvt52 ; Heath-19 mode? je decid1 ; e = yes mov si,offset h19str ; say Heath-19 decid1: cld lodsb ; Get a byte cmp al,0 ; end of string? je decid2 ; e = yes push cx ; Save the important registers push si call prtbout ; Send it to port with no local echo pop si pop cx loop decid1 ; Loop for all characters decid2: ret atll: mov di,offset atleds ; Get pointer to routine to call call atreps ; Repeat for selective parameters ret atleds: cmp ansargs[si],0 ; Zero argument? jne atled3 ; No - check further mov cx,4 ; Reset the "LEDs" mov al,led_off ; to all off mov di,offset ansleds+6 ; Point to the "LEDs" push es ; save es push ds pop es ; make es:di point to datas seg cld ; move forward rep stosb pop es atled1: call disleds ; Update "LEDs" display and return atled2: ret atled3: mov al,ansargs[si] ; Get the argument cmp al,1 ; Must be .GE. 1 jb atled2 ; If not just ignore it. [dlk] cmp al,4 ; Must be .LE. 4 ja atled2 ; Ignore if not so. [dlk] dec al ; Zero base it cbw ; Convert to index in ax mov di,ax ; Dumb specialized registers add al,'1' ; add ascii offset for digit mov ansleds[di+6],al ; Turn the "LED" on by storing digit jmp atled1 ; Update display and return atreqt: cmp ansargs,0 ; Want report? je atreq1 ; Yes - give report cmp ansargs,1 ; Want report? je atreq1 ; Yes - give the report ret ; Gee, must have been an echo atreq1: mov al,escape ; Send an escape to start off call prtbout mov al,'[' ; Then one of these call prtbout mov al,'3' ; We only report on request cmp ansargs,0 ; was argument a zero? jne atreq1a ; ne = no mov al,'2' ; yes atreq1a:call prtbout mov al,';' ; Separate call prtbout mov bl,parcode ; Get the parity code mov bh,0 mov al,partab[bx] ; Get VT100 parity code push ax ; save parity code call prtnout ; Send number to the port. mov al,';' ; Separate call prtbout mov al,'2' ; Assume 7 data bits pop bx ; get parity code into bl cmp bl,1 ; is parity none? jne atreq2 ; ne = no, so 7 data bits test flags.remflg,d8bit ; 8 bit display? jz atreq2 ; z = no mov al,'1' ; must be eight atreq2: call prtbout ; Send it to the port mov al,';' ; Separate call prtbout mov bl,baudidx ; Baud rate index mov bh,0 mov al,baudtab[bx] ; Get DEC baud rate code push ax call prtnout ; Send it to the port mov al,';' ; Separate call prtbout ; Send it to the port pop ax call prtnout ; Send it to the port mov al,';' ; Separate call prtbout mov al,'1' ; Clock rate multiplier is always 1 call prtbout mov al,';' ; Separate (gasp - for the last time) call prtbout mov al,'0' ; Flags are always zero (no STP) call prtbout mov al,'x' ; Finally, say what this all was call prtbout ret atdsr: mov di,offset atdsr1 ; Routine to call call atreps ; Do for all parms ret atdsr1: cmp ansargs[si],5 ; Want status? je rpstat ; Yes - report status cmp ansargs[si],6 ; Want cursor position? je rpcup ; Yes - do it cmp ansargs[si],15 ; Printer status? je rpstap ; e = yes, do so ret ; No - must have been an echo rpstat: mov al,escape ; Tell them we think we are OK call prtbout mov al,'[' call prtbout mov al,'0' call prtbout mov al,'n' call prtbout ret rpstap: test escdec,decmode ; Printer status report from jz rpstap3 ; ESC [ ? 15 n request mov al,escape call prtbout mov al,'[' call prtbout mov al,'?' call prtbout mov al,'1' call prtbout mov ah,ioctl ; get printer status, via DOS mov al,7 ; status for output push bx mov bx,4 ; std handle for system printer int dos pop bx jc rpstap1 ; c = call failed cmp al,0ffh ; code for Ready jne rpstap1 ; ne = not ready mov al,'0' ; ready, send final digit jmp rpstap2 rpstap1:mov al,'3' ; not ready, say printer disconnected rpstap2:call prtbout mov al,'n' ; final char of response call prtbout rpstap3:ret rpcup: mov al,escape ; Cursor position - send an escape call prtbout mov al,'[' ; And one of these call prtbout mov al,byte ptr cursor+1 ; Get row inc al ; They use coords that start at 1 test ansflgs,decom ; Origin mode set? jz rpcup1 ; No - continue sub al,mar_top ; Yes - subtract off top margin rpcup1: call prtnout ; Output the number mov al,';' ; Separate call prtbout mov al,byte ptr cursor ; Now get the column number inc al ; Their coords start at 1 call prtnout ; Send it off to the port mov al,'R' ; Finally end it with this call prtbout ret ; ESC [ ? xxx h/l series atrm: mov modeset,0 ; Say we are resetting modes mov di,offset atrsm ; Reset/set modes call atreps ; Repeat for all parms test ansflgs,decanm ; Did this get reset? jnz atrm1 ; No - return cmp flags.vtflg,ttheath ; were we a Heath-19? je atrm0 ; e = yes, don't change terminal types mov flags.vtflg,ttvt52 ; Yes. Say VT52 now atrm0: call chrdef ; Yes - set default char sets call atsc ; Save cursor status call disleds ; update terminal type atrm1: ret atsm: mov modeset,1 ; Say we are setting modes mov di,offset atrsm ; Reset/set modes call atreps ; Repeat for all parms ret atrsm: mov al,ansargs[si] ; Pick up the argument test escdec,decmode ; Is this DEC private mode ([ ?)stuff? jnz atrsm1 ; nz = yes - go check it out cmp h19mod,0 ; Heath-19 private mode ([ >)? je atrsma ; e = no jmp htrsm1 ; yes, do Heath specific things atrsma: cmp al,20 ; No - ANSI new-line mode? jne atrsm0 ; but try insert mode and vtemu.vtflgop,not vsnewline ; assume resetting cmp modeset,0 ; resetting? je atrsmb ; e = yes or vtemu.vtflgop,vsnewline ; setting atrsmb: mov al,anslnm ; Yes - get the bit call atrsflg ; Set or reset it ret atrsm0: cmp al,4 ; toggle insert mode? jne atrsmc ; ne = no mov al,modeset ; set/reset insert mode mov insmod,al ; store it ret atrsmc: cmp al,12 ; 12? Control local echo jne atrsmx ; ne = no cmp modeset,0 ; resetting mode (ESC [ 12 l)? jne atrsmc1 ; ne = no or ansflgs,dececho ; remember state here too or yflags,lclecho ; (l) turn on local echoing jmp short atrsmc2 atrsmc1:and yflags,not lclecho ; (h) turn off local echoing and ansflgs,not dececho atrsmc2:mov al,yflags call telmsy ; inform msy about echoing state test yflags,modoff ; is mode line off? jnz atrsmx ; nz = yes push dx ; save cursor position call trnmod ; toggle off then on again so we call trnmod ; use it with current coloring pop dx atrsmx: ret atrsm1: cmp al,1 ; Cursor keys mode? jne atrsm2 ; No - check some more mov al,decckm ; Yes - get the bit jmp atrsflg ; Set or reset it and return atrsm2: cmp al,7 ; Auto-wrap? jne atrsm3 ; No - check some more and vtemu.vtflgop,not vswrap ; assume resetting line wrap cmp modeset,0 ; resetting? je atrsm2a ; e = yes or vtemu.vtflgop,vswrap ; set the bit atrsm2a:mov al,decawm ; Yes - get the bit jmp atrsflg ; Set or reset it and return atrsm3: cmp al,6 ; Origin mode? jne atrsm4 ; No - check for video change jmp atrsom ; Yes - change decom and return atrsm4: cmp al,5 ; Change the video? jne atrsm5 ; No - check for VT52 mode set/reset jmp atrsscnm ; Yes - change it if we have to and ret atrsm5: cmp al,2 ; Change VT52 compatibility mode? jne atrsm6 ; No - ignore unknown DEC private modes cmp flags.vtflg,ttheath ; Heath-19 mode? je atrsm5a ; e = yes, handle specially mov al,ascset ; return to US ascii graphics sets mov chr_sg0,al ; Store it mov chr_sg1,al ; Store it mov al,decanm ; Yes - get the flag jmp atrsflg ; Set or reset it and return atrsm5a:mov modeset,0 ; Heath-19 ESC [ ? 2 h, reset ansi mov al,decanm ; the flag needing adjustment jmp atrsflg ; reset the flag and return atrsm6: cmp al,3 ; 132/80 column mode change? jne atrsm7 ; ne = no push chr_set ; save character set pointer push word ptr chr_sg0 ; and the G0/G1 values mov al,ansflgs ; these flags mov ah,vtflags push ax mov al,curattr ; and current video attributes push ax mov al,modeset ; pass set/reset request to chgdsp[dlk] call chgdsp ; call Change Display proc in msy [dlk] call scrmod ; get current screen mode cmp modeset,1 ; want 132 cols? jne atrsm6n ; ne = no, so use 80 columns mov al,crt_cols ; get current physical screen width dec al ; we count from column 0 here mov byte ptr low_rgt,al ; screen capability mov linelen,131 ; say using wide screen, if possible jmp short atrsm6e atrsm6n:mov linelen,79 ; say using 80 columns cmp byte ptr low_rgt,79 ; want 80 cols, is it wider? jbe atrsm6e ; be = no mov byte ptr low_rgt,79 ; narrow down to 80 columns atrsm6e:CALL ATRES2 ; do partial reset of emulator pop ax mov curattr,al ; restore saved items pop ax mov ansflgs,al mov vtflags,ah pop word ptr chr_sg0 ; restore the G0/G1 values pop chr_set ; and character set pointer mov dl,byte ptr low_rgt+1 ; text lines (leave status line intact) mov mar_top,0 mov mar_bot,dl ; reset scrolling region xor dx,dx ; new cursor position is 0,0 mov cursor,dx jmp atscu5 ; place it there and return atrsm7: cmp al,18 ; 18? 18 & 19 = printer support jne atrsm8 ; ne = no cmp modeset,0 ; resetting? jne atrsm7a ; ne = no, setting and anspflg,not vtffp ; no form feed after printing ret atrsm7a:or anspflg,vtffp ; use form feed after printing ret atrsm8: cmp al,19 ; 19? jne atrsm9 ; ne = no cmp modeset,0 ; resetting? jne atrsm8a ; ne = no, setting and anspflg,not vtextp ; reset print region to scrolling reg ret atrsm8a:or anspflg,vtextp ; set print region to whole screen ret atrsm9: cmp al,34 ; ESC [ ? 34 h/l? Invoke special macro jne atrsm10 ; ne = no cmp modeset,0 ; resetting? jne atrsm9a ; ne = no, setting jmp vtrmac ; jump to perform on-line macro ; code is located in file msy atrsm9a:jmp vtsmac ; do set macro atrsm10:cmp al,38 ; 38? Enter Tek sub-mode. VT340 seq jne atrsm11 ; ne = no cmp modeset,1 ; setting mode (ESC [ ? 38 h)? jne atrsm11 ; ne = no, ignore sequence test denyflg,200h ; is auto Tek mode disabled? jnz atrsm11 ; nz = yes, just ignore command call atsc ; save cursor and associated data mov al,0 ; enter with this received character JMP TEKEMU ; Jump to Tektronix Emulator, al=null atrsm11:ret ; Heath-19 ESC [ > Ps h or l where Ps = 1, 4, 7, or 9 htrsm1: cmp al,1 ; 25th line? jne htrsm4 ; ne = no mov al,modeset ; set/reset flag mov h19l25,al cmp al,0 ; resetting? Mods from Dave Tweten jne htrsmx ; ne = no, enabling. we are done mov ah,byte ptr low_rgt+1 ; point to status (25th) line inc ah ; which is here xor al,al ; from column 0 mov bh,ah ; to same line mov bl,crt_cols ; physical width dec bl ; we count from 0 jmp vtsclr ; disabling status line clears it htrsm4: cmp al,4 ; block/line cursor? jne htrsm5 ; ne = no and h19ctyp,4 ; save on/off bit (4) cmp modeset,0 ; reset? je htrsm4a ; e = yes or h19ctyp,2 ; remember block kind here jmp atsctyp htrsm4a:or h19ctyp,1 ; remember underline kind here jmp atsctyp htrsm5: cmp al,5 ; on/off cursor? jne htrsm7 ; ne = no cmp modeset,0 ; on? je htrsm5a ; e = yes or h19ctyp,4 ; remember off state in this bit jmp atsctyp htrsm5a:and h19ctyp,not 4 ; set cursor on jmp atsctyp htrsm7: cmp al,7 ; alternate application keypad? jne htrsm9 ; ne = no mov al,deckpam ; get keypad application mode bit jmp atrsflg ; set or reset appl keypad mode htrsm9: cmp al,9 ; auto newline mode? (add cr to lf) jne htrsmx ; ne = no mov al,anslnm ; get the bit jmp atrsflg ; set or reset newline mode htrsmx: ret ; ignore the code atrsflg:cmp modeset,0 ; Want to reset je atrsf1 ; Yes - reset it or ansflgs,al ; No, set. OR in the flag test al,decanm ; Changing terminal type? jz atrsfx ; z = no cmp flags.vtflg,ttheath ; in Heath-19 mode? je atrsfx ; e = yes, don't flip terminal kinds mov flags.vtflg,ttvt100 ; say VT100 now jmp short atrsfx atrsf1: not al ; Complement and ansflgs,al ; Clear the bit not al ; recover the bit test al,decanm ; Changing terminal type? jz atrsfx ; z = no cmp flags.vtflg,ttheath ; in Heath-19 mode? je atrsfx ; e = yes, don't flip terminal kinds mov flags.vtflg,ttvt52 ; say VT52 now atrsfx: push ax mov al,yflags call telmsy ; tell msy file about new state pop ax ret atrsom: cmp modeset,0 ; Clearing DEC origin mode? jne atrsom1 ; ne = no, setting and ansflgs,not (decom) ; clear the bit mov dx,0 ; go to the home position jmp atscu5 ; set cursor and return atrsom1:or ansflgs,decom ; Set Origin mode mov dx,cursor ; Get the cursor mov dl,0 ; go to right margin mov dh,mar_top ; go to home of scrolling region jmp atscu5 ; Set the cursor and return atrsscnm: cmp modeset,0 ; Setting or resetting? je atrss1 ; Do reset test ansflgs,decscnm ; Setting. Is it set already? jnz atrss3 ; Yes. Don't do it again or ansflgs,decscnm ; No. Set it or vtemu.vtflgop,vsscreen ; tell Status display or vtflags,vsscreen ; and our local flags mov al,att_reverse ; Want reverse video jmp short atrss2 ; Do it atrss1: test ansflgs,decscnm ; Resetting. Is it reset already? jz atrss3 ; Yes. Don't do it again and ansflgs,not decscnm ; No. Clear it and vtemu.vtflgop,not vsscreen ; tell Status display and vtflags,not vsscreen ; and our local flags mov al,att_normal ; Want normal video ; Fall through to atrss2 ; Note: This is also called from the stblmds initialization routine. atrss2: push ax mov scbattr,al ; Set screen background attribute mov oldbatr,al ; update long term memory too mov ah,al ; place where brkatt works call brkatt ; separate color and specials rol ah,1 ; Reverse the reversal (sic.) rol ah,1 ; Reverse the reversal (sic.) rol ah,1 ; Reverse the reversal (sic.) rol ah,1 ; Reverse the reversal (sic.) call addatt ; put blink/bold bits back in mov mlbattr,ah ; For mode line background mov ah,curattr ; Get current cursor attribute call brkatt ; Break it up rol ah,1 ; Reverse its background rol ah,1 ; Reverse its background rol ah,1 ; Reverse its background rol ah,1 ; Reverse its background call addatt ; Put it back together mov curattr,ah ; And store it pop ax call revscn ; Reverse everything on the screen atrss3: ret atctst: mov al,0 ; Init test weight mov di,offset atcts2 ; Routine to call call atreps ; Repeat for all parms test al,80H ; Want to reset? jz atcts1 ; No - return call atreset ; Yes - reset everything atcts1: ret atcts2: mov ah,ansargs[si] ; Pick up an argument cmp ah,0 ; Zero? jne atcts3 ; No - ignore others or al,80H ; Yes - say we want reset atcts3: ret ; VT52 compatibility mode routines. ; Return to ANSI mode. v52ans: or ansflgs,decanm ; Turn ANSI flag back on mov flags.vtflg,ttvt100 ; Say VT100 now call chrdef ; Set default char sets call atsc ; Save cursor status call disleds ; Put "LEDs" back jmp atnorm ; Reset state to normal and return ; Reset VT52 (does NOT cause return to VT100 mode) v52ris: call atreset ; Reset everything call disleds ; Put "LEDs" back ret ; Enter VT52 "graphics" mode. v52egm: call chrsgs ; Set "graphics" char set jmp atnorm ; Reset state to normal and return ; Exit VT52 "graphics" mode. v52xgm: call chrdef ; Set default character set jmp atnorm ; Reset state to normal and return ; VT52 cursor positioning. v52pos: mov ttstate,offset v52pc1 ; Next state ret v52pc1: sub al,' '-1 ; Minus offset mov ansargs,al ; Stash it here mov ttstate,offset v52pc2 ; Next state ret v52pc2: sub al,' '-1 ; Minus offset mov ansargs+1,al ; Stash here call atnorm ; Reset state to "normal" jmp atcup ; Position and return ; VT52 print controls v52apb: mov ansargs,5 ; Enter auto print mode or escdec,decmode ; simulate ESC [ ? 5 i jmp ansprt ; process command v52ape: mov ansargs,4 ; Exit auto print mode or escdec,decmode ; simulate ESC [ ? 4 i jmp ansprt ; process command v52pcb: mov ansargs,5 ; Enter printer controller on or escdec,decmode ; simulate ESC [ ? 5 i jmp ansprt ; process command v52pce: mov ansargs,4 ; Exit printer controller on or escdec,decmode ; simulate ESC [ ? 4 i jmp ansprt ; process command v52ps: mov ansargs,0 ; print screen and escdec,not decmode ; simulate ESC [ 0 i jmp ansprt ; process command v52pl: mov ansargs,1 ; print line or escdec,decmode ; simulate ESC [ ? 1 i jmp ansprt ; process command ; Heath-19 special functions h19ans: or ansflgs,decanm ; Turn on ANSI flag. ESC < call chrdef ; Set default char sets jmp atnorm ; Reset state to normal and return ; do several "ESC [" ANSI commands ; but don't change terminal types h19ansa:jmp atcsi ; parse ansi arguments ; clear screen and go home h19clrs:mov dx,0 ; go to upper left corner call atscu5 ; do it mov ax,0 ; clear screen from (0,0) mov bh,byte ptr low_rgt+1 ; to lower right corner mov bl,crt_cols ; physical width dec bl ; we count from 0 jmp vtsclr ; Clear it ; cursor down (scrolls) h19cud: mov dx,cursor ; get cursor position inc dh ; say next row down call atccic ; check position cursor (scrolls) mov cursor,dx call ax ; do scrolling jmp atscu5 ; cursor forward (right). ESC C h19cuf: mov dx,cursor ; get cursor position inc dl ; move cursor right cmp dl,byte ptr low_rgt ; beyond right margin jb h19cuf1 ; b = no. do it test ansflgs,decawm ; wrap mode on? jz h19cuf2 ; z = no. just ignore movement xor dl,dl ; set to left margin inc dh ; and down a row call atccic ; adjust position call ax ; call scrolling routine h19cuf1:jmp atscu5 ; do positioning and return h19cuf2:ret ; just return ; set line wrap on h19wrap:or ansflgs,decawm ; turn on the flag jmp atnorm ; turn off line wrap h19nowrp:and ansflgs,not decawm ; turn off the flag jmp atnorm h19erb: mov bx,cursor ; erase home to cursor, incl xor ax,ax ; home jmp vtsclr ; clear the area, cursor stays put??? h19erl: mov bx,cursor ; erase whole line mov ax,bx ; get row xor al,al ; column 0 mov bl,crt_cols ; physical width dec bl ; we count from 0 jmp vtsclr ; erase whole line, cursor stays put h19ero: mov bx,cursor ; erase start of line to cursor mov ax,bx xor al,al ; start in column 0 jmp vtsclr ; clear that part of line h19herv:cmp video_state,0 ; is video normal? ESC p jne h19hrv1 ; ne = no, reversed already, ignore mov ah,curattr ; current cursor attributes call brkatt ; breakup attributes byte rol ah,1 ; reverse foreground to background rol ah,1 rol ah,1 rol ah,1 call addatt ; put things together again mov curattr,ah ; and store it mov video_state,1 ; say we are reversed h19hrv1:ret h19hxrv:cmp video_state,0 ; is video normal? ESC q je h19hxr1 ; e = yes, so just ignore mov ah,curattr ; current cursor attributes call brkatt ; breakup attributes byte rol ah,1 ; reverse foreground to background rol ah,1 rol ah,1 rol ah,1 call addatt ; put things together again mov curattr,ah ; and store it mov video_state,0 ; say we are normal h19hxr1:ret h19mbr: mov ttstate,offset hmbr ; Modify baud rate ESC r char ret ; setup to parse next char hmbr: jmp atnorm ; discard char (in al) htsc: cmp flags.vtflg,ttheath ; Heath-19? ESC [ s jne htscx ; ne = no, ignore call atsc ; store cursor position and attr htscx: jmp atnorm ; reset state & return htrc: cmp flags.vtflg,ttheath ; Heath-19? ESC [ u jne htrcx ; ne = no, ignore call atrc ; restore cursor pos and attr htrcx: jmp atnorm ; reset state & return ; Heath-19 set mode "ESC x " h19smod:mov ttstate,offset hsmod ; setup to parse rest of seq ret hsmod: mov modeset,1 ; say set mode mov ttstate,offset atnrm sub al,'0' ; remove ascii bias jmp htrsm1 ; perform mode set h19cmod:mov ttstate,offset hcmod ; setup to parse rest of seq ret hcmod: mov modeset,0 ; say reset mode mov ttstate,offset atnrm sub al,'0' ; remove ascii bias jmp htrsm1 ; perform mode reset htrest: cmp flags.vtflg,ttheath ; Heath-19? ESC [ z jne htrestx ; ne = no, ignore call atreset ; do a hard reset htrestx:jmp atnorm ; reset state and return hrcup: mov al,escape ; send "ESC Y row col" cursor report call prtbout ; send with no local echo mov al,'Y' call prtbout mov al,byte ptr cursor+1 ; get row add al,' ' ; add ascii bias call prtbout ; send it mov al,byte ptr cursor ; get column add al,' ' ; add ascii bias call prtbout ; and send it too jmp atnorm ; return to terminal mode ; Heath-19 and VT102 additions inslin: cmp ansargs,0 ; insert line(s). Any args? jne insli1 ; ne = yes. If no arg use 1 mov ansargs,1 ; insert one line insli1: mov dl,ansargs mov scroll,dl mov dx,cursor ; current position cmp dh,mar_bot ; below bottom margin? jae insli3 ; ae = at or below bottom margin push word ptr mar_top mov mar_top,dh ; call present position the top insli2: call atscrd ; scroll down pop word ptr mar_top ; restore margins xor dl,dl ; go to left margin jmp atscu5 ; reposition cursor and return insli3: ret dellin: cmp ansargs,0 ; delete line(s). Any args? jne delli1 ; no arg; use 1 mov ansargs,1 ; insert one line delli1: mov dl,ansargs mov scroll,dl ; line count mov dx,cursor ; where we are presently cmp dh,mar_bot ; at or below bottom margin? jae delli3 ; ae = yes push word ptr mar_top ; save current scrolling margins mov mar_top,dh ; temp top margin is here delli2: call atscru ; scroll up pop word ptr mar_top ; restore scrolling margins jmp atscu5 ; restore cursor and return delli3: ret ; Delete character(s) atdelc: cmp ansargs,0 ; zero becomes one operation jne atdelc1 mov ansargs,1 ; delete one char. Heath ESC N atdelc1:mov cl,byte ptr low_rgt ; number of columns on screen mov dx,cursor ; get present cursor position push bx mov bl,dh ; get row mov bh,0 cmp linetype [bx],0 ; single width line? je atdelc5 ; e = yes shl dl,1 ; double the column number mov bl,ansargs shl bl,1 ; double # chars to delete mov ansargs,bl atdelc5:pop bx sub cl,dl ; end of screen - current column # xor ch,ch ; cx = number of chars to move cmp cx,0 ; zero means just this char ja atdelc4 inc cx ; say one, this one atdelc4:push es push cx ; save word count for Topview cld test vtemu.vtflgop,vswdir ; writing left to right? jz atdelc4a ; z = yes sub dl,byte ptr low_rgt ; reflect about logical right column neg dl ; convert to positive value atdelc4a: call scrloc ; compute current cursor location mov di,ax ; temporary storage places mov si,ax mov al,ansargs ; get delete count xor ah,ah ; clear high byte of delete count cmp al,cl ; clear more than rest of line? jb atdelc2 ; b = no. some chars left at end mov al,cl ; say delete all to right, inclusive atdelc2:cmp al,0 ; zero? jne atdelc3 inc al ; none or 0 implies one atdelc3:shl ax,1 ; double: char and its attribute byte push di ; destination offset cld ; assume forward for left to right test vtemu.vtflgop,vswdir ; writing left to right jz atdelc3a ; z = yes neg ax ; minus ax, work the other way std ; movement reverses too atdelc3a: add ax,si ; src offset = dest + # deleted words push ax ; save it call scroff call scrseg ; pick up screen segment mov si,di ; align memory addresses pop ax ; recover source offset add si,ax ; add to starting memory address pop ax ; recover destination offset add di,ax ; add to destination memory address push ds ; save ds around the move push es ; move es into ds to pop ds ; make ds point to screen memory too rep movsw cld ; reset direction to forward pop ds ; recover normal ds pop cx ; count for Topview test vtemu.vtflgop,vswdir ; writing left to right? jz atdelc6 ; z = yes sub di,cx ; get correct es:di ending address sub di,cx ; for scrsync atdelc6:call scrsync ; synch Topview pop es call scron mov ax,cursor ; get current row mov bx,cursor mov bl,byte ptr low_rgt ; last col on screen mov al,bl sub al,ansargs ; minus number of locations cleared inc al test vtemu.vtflgop,vswdir ; writing left to right? jz atdelc7 ; z = yes mov cl,byte ptr low_rgt ; reflect about logical right margin sub cl,al mov bl,cl ; end of line to be cleared mov al,0 ; start of line to be cleared atdelc7:call atsclr ; clear end of line atdelcx:mov dx,cursor jmp atscu5 ; reposition cursor inschr: mov dx,cursor ; open one char space in current line push bx mov bl,dh ; get row mov bh,0 cmp linetype [bx],0 ; single width line? je insch2 ; e = yes shl dl,1 ; double the column number insch2: pop bx mov ch,0 mov cl,byte ptr low_rgt ; number of columns on screen push dx mov dh,0 sub cx,dx ; compute distance to end pop dx or cx,cx jle insch1 ; le = nothing to move [dlk] mov dl,byte ptr low_rgt dec dl ; last col to move push ax ; save regs push es ; ditto push cx ; save count for Topview test vtemu.vtflgop,vswdir ; writing left to right? jz insch3 ; z = yes mov dl,1 ; right-to-left physical EOL-1 call scrloc ; compute position of end of line-1 push ax ; save offset cld ; remember to move forward call scroff ; turn off color screen call scrseg ; get memory address in es:di pop ax ; recover offset add di,ax ; source memory address mov si,di ; align addresses. destination sub di,2 ; is one char over jmp short insch4 ; join common code insch3: ; do normal left to right material call scrloc ; compute position of end of line-1 push ax ; save offset std ; remember to move backward call scroff ; turn off color screen call scrseg ; get memory address in es:di pop ax ; recover offset add di,ax ; source memory address mov si,di ; align addresses. destination add di,2 ; is one char over insch4: push di push ds ; save ds around move push es ; put es into ds pop ds ; ds points to screen memory too rep movsw pop ds ; recover normal ds cld ; reset direction to be forward pop di pop cx ; count for Topview test vtemu.vtflgop,vswdir ; writing left to right? jz insch5 ; z = yes add di,cx ; get correct es:di ending address add di,cx ; for scrsync insch5: call scrsync ; synch Topview pop es ; restore regs pop ax ; ditto call scron ; turn on screen again cld ; reset direction insch1: mov dx,cursor jmp atscu5 ; position cursor noins: mov insmod,0 ; turn off insert mode jmp atnorm ; and return entins: mov insmod,0ffh ; enter insert mode jmp atnorm ; and return ansich proc near ; ANSI insert characters ESC [ Pn @ cmp ansargs,0 ; any arguments? jne ansic1 ; ne = no, ignore mov ansargs,1 ; use one ansic1: push dx ; save cursor mov insmod,1 ; enter insert mode push cx mov cl,ansargs ; get count of inserts mov ch,0 mov ah,ansflgs ; save flags in ah and ansflgs,not decawm ; turn off autowrap push ax ; save char ansic2: push cx ; save counter mov al,' ' ; character to write call atnrm ; do display pop cx ; recover counter loop ansic2 ; do cx times pop ax ; restore char mov ansflgs,ah ; recover flags mov ah,0 ; clear register pop cx mov insmod,0 ; turn off insert mode pop dx ; get original cursor jmp atscu5 ; set cursor ansich endp ; routines supporting scrolling and double width/height chars ; scroll has number of lines to scroll atscru proc near ; scroll screen up one line push ax ; assumes dx holds cursor position push bx ; returns with dx = old row, new col push cx push si xor bh,bh mov bl,mar_top ; top line to move xor ch,ch mov cl,scroll ; number of lines to move jcxz atscru5 ; cx = 0. nothing to do mov al,mar_bot ; bottom line to scroll sub al,bl ; number of lines minus 1 inc al ; number of lines cmp al,cl ; scrolling region smaller than scroll? jge atscru1 ; ge = no, is ok mov scroll,al ; limit to region cmp al,1 ; at least one line to scroll? jge atscru1 ; ge = yes mov scroll,1 ; no, force one atscru1:push bx mov bl,dh ; get row of cursor mov bh,0 cmp linetype[bx],0 ; single width? pop bx je atscru7 ; e = yes shr dl,1 ; reindex to single width columns atscru7:mov al,scroll xor ah,ah cmp al,byte ptr low_rgt+1 ; number of lines on screen jbe atscru8 ; be = scrolling not more than that mov al,byte ptr low_rgt+1 ; limit to screen length mov scroll,al atscru8:mov si,ax ; scroll interval mov bl,mar_top mov cl,mar_bot sub cl,bl inc cl ; number of lines in region sub cl,scroll ; cx = those needing movement jcxz atscru3 atscru2:mov al,linetype[bx+si] ; get old type mov linetype[bx],al ; copy to new higher position inc bx loop atscru2 atscru3:mov bl,mar_bot ; set fresh lines to single attribute mov cl,scroll mov ch,0 inc cx atscru4:mov linetype[bx],0 dec bx loop atscru4 ; clear old bottom lines atscru5:pop si pop cx pop bx pop ax test anspflg,vtcntp ; controller print active? jz atscru6 ; z = no, ok to change screen ret ; else keep screen intact atscru6:jmp vtscru ; call & ret the msy scroll routine atscru endp atscrd proc near ; scroll screen down one line push ax ; assumes dx holds cursor position push bx ; returns with dx = old row, new col push cx push si xor ch,ch mov cl,scroll ; number of lines to scroll jcxz atscrd5 ; cx = 0. nothing to do xor bh,bh mov bl,mar_bot ; bottom line to move mov al,bl mov ah,0 sub al,mar_top ; number of lines minus 1 inc al ; number of lines cmp al,cl ; scrolling region smaller than scroll? jge atscrd1 ; ge = no, is ok mov scroll,al ; limit to region cmp al,1 ; at least one line to scroll? jge atscrd1 ; ge = yes mov scroll,1 ; no, force one atscrd1:push bx mov bl,dh ; get row of cursor mov bh,0 cmp linetype[bx],0 ; single width? pop bx je atscrd7 ; e = yes shr dl,1 ; reindex to single wide columns atscrd7:mov al,scroll mov si,ax ; si = scroll sub bl,scroll ; si + this bx will be new bottom line mov cl,bl sub cl,mar_top inc cl ; number of movements jcxz atscrd3 atscrd2:mov al,linetype[bx] ; get old line's type mov linetype[bx+si],al ; copy to new lower position dec bx loop atscrd2 atscrd3:mov bl,mar_top mov bh,0 mov cl,scroll mov ch,0 inc cx atscrd4:mov linetype[bx],0 ; clear new top lines inc bx loop atscrd4 atscrd5:pop si pop cx pop bx pop ax test anspflg,vtcntp ; controller print active? jz atscrd6 ; z = no, ok to change screen ret ; else keep screen intact atscrd6:jmp vtscrd ; call & ret the msy scroll routine atscrd endp linesgl proc near ; convert line to single width char push ax push bx push cx push dx mov bx,cursor mov bl,bh xor bh,bh ; bx now holds row cmp linetype [bx],0 ; is line already single width? je linsglx ; e = yes mov linetype [bx],0 ; say will be single now call scroff ; turn off video mov dx,cursor mov dl,0 ; start in column 0 mov cl,byte ptr low_rgt ; number of columns on screen inc cl shr cl,1 ; number of columns to do mov ch,0 push cx ; save around loop below linsgl1:push cx ; save loop counter shl dl,1 ; double column number mov ah,2 ; set cursor xor bh,bh ; page 0 call direction ; do Bios screen operation mov ah,8 ; read char and attribute int screen push ax ; save char and attribute shr dl,1 ; restore column mov ah,2 ; set cursor call direction ; do Bios screen operation pop ax ; recover char and attribute mov bl,ah ; set attribute mov cx,1 ; one char mov ah,9 ; write char and attribute int screen inc dl ; next column pop cx loop linsgl1 pop cx ; recover column counter mov dl,cl linsgl2:push cx ; save counter mov ah,2 ; set cursor call direction ; do Bios screen operation mov bh,0 mov bl,scbattr ; screen background mov al,' ' mov ah,9 ; write char mov cx,1 ; do one character call direction ; do Bios screen operation inc dl ; next column pop cx loop linsgl2 ; repeat for all characters call scron ; turn on the video linsglx:pop dx pop cx pop bx pop ax jmp atscur ; update cursor and return linesgl endp linedbl proc near ; convert line to double width char push ax ; must reset physical cursor push bx ; to same char as before expansion push cx ; but does not modify variable cursor push dx mov bx,cursor mov bl,bh xor bh,bh ; bx now holds row cmp linetype [bx],0 ; is line single width? jne lindblx ; ne = no. nothing to do mov linetype [bx],1 ; say will be double width now mov dx,cursor mov cl,byte ptr low_rgt ; number of columns on the screen inc cl mov ch,0 shr cl,1 ; number of items to do mov dl,cl dec dl call scroff ; turn off the video lindbl1:push cx ; save loop counter mov ah,2 ; set cursor mov bh,0 ; page 0 call direction ; do Bios screen operation mov ah,8 ; read char and attribute int screen push ax ; save char and attribute shl dl,1 ; double the column number mov ah,2 ; set cursor call direction ; do Bios screen operation pop ax ; recover char and attribute mov bl,ah ; set attribute mov cx,1 ; one char mov ah,9 ; write char and attribute int screen inc dl ; move to second column of double mov ah,2 ; set cursor call direction ; do Bios screen operation mov al,' ' ; space as filler mov ah,9 ; write that char int screen dec dl shr dl,1 dec dl pop cx loop lindbl1 call scron ; turn on the video lindblx:pop dx pop cx pop bx pop ax jmp atscur ; update the cursor and return linedbl endp anstty endp ansprt proc near ; printer support routines mov di,offset ansprt0 ; routine to process arguments call atreps ; Repeat for all parms ret ansprt0:mov ah,ansargs[si] ; Pick up the argument cmp ah,0 ; 0 (print all/part of screen)? jne ansprt1 ; ne = no call pntchk ; check printer jc ansprtx ; c = printer not ready call pntext ; do whole screen or scrolling extent jmp atscu5 ; reposition cursor and return ansprt1:cmp ah,1 ; 1 (print current line)? jne ansprt4 ; ne = no call pntchk ; check for printer ready jc ansprtx ; c = printer not ready call pntlin ; print current line call pntflsh ; flush printer buffer anspr1a:jmp atscu5 ; reposition cursor and return ansprt4:cmp ah,4 ; 4 (auto print disable)? jne ansprt5 ; ne = no test escdec,decmode ; was it ESC [ ? 4 i jz anspr4a ; z = no, so it was ESC [ 4 i test anspflg,vtautop ; check state of print flag jz anspr4a ; z = off already and anspflg,not vtautop ; auto-print disable call trnprs ; toggle mode line PRN indicator anspr4a:jmp ansprtx ansprt5:cmp ah,5 ; 5 (auto print enable)? jne ansprtx ; ne = no call pntchk ; check printer, ignore carry ret jc ansprtx ; c = printer not ready test escdec,decmode ; was it ESC [ ? 5 i jz anspr5a ; z = no test anspflg,vtautop ; is print already enabled? jnz ansprtx ; nz = yes, leave trnprs intact or anspflg,vtautop ; auto-print enabled jmp short anspr5b anspr5a:test anspflg,vtcntp ; controller print already enabled? jnz ansprtx ; nz = yes or anspflg,vtcntp ; controller print enabled anspr5b:call trnprs ; toggle on mode line PRN indicator ansprtx:jmp atnorm ansprt endp ; State machine active while Media Copy On (Print Controller ON). Copies all ; chars to the printer until (and excluding) Media Copy Off (ESC [ 4 i) has ; been received or the emulator reset. New char is in al. 6 March 1987 [jrd] ansmc proc near mov ah,al ; copy active character and ah,7fh ; strip high bit cmp ah,escape ; start of MC Off sequence? jne ansmc1 ; ne = no call ansmc6 ; playback previously matched chars mov mccnt,1 ; count matched chars (one now) mov mcoffs,al ; save full character, with high bit mov ansargs,0 ; clear first ansi argument mov nansarg,0 ; number of arguments ret ansmc1: mov bx,mccnt ; number of chars matched in MC Off cmp bx,0 ; have first? jne ansmc1a ; ne = yes, one or more jmp pntchr ; print it, ignore errors ansmc1a:mov mcoffs[bx],al ; save this char, with high bit inc mccnt ; count saved characters and al,7fh ; strip high bit cmp al,'0' ; A digit? jge ansmc2 ; ge = maybe jmp ansmc6 ; b = out of range for everything ansmc2: cmp al,'9' ; maybe, separator or final char? ja ansmc3 ; a = perhaps, go check it out mov cl,al ; digit, convert ASCII to binary sub cl,'0' mov ch,0 mov bl,nansarg ; put index in bx xor bh,bh mov al,ansargs[bx] ; Pick up what we've done so far [dlk] shl al,1 ; multiply by 10. 2 * al mov ah,al ; save shl al,1 ; 4 * al shl al,1 ; 8 * al add al,ah ; 10 * al mov ah,0 ; clear high field add ax,cx ; add in this digit [dlk] cmp ax,0feh ; max value is 0ffh [dlk] jbe ansmc2a ; be = ok [dlk] mov al,0ffh ; set to max value [dlk] ansmc2a:mov ansargs[bx],al ; Put result back for next time [dlk] ret ; And return ansmc3: cmp al,'[' ; ANSI sequence? jne ansmc4 ; ne = no, check further cmp mccnt,2 ; is it the second character? je ansmc3a ; e = yes, accept and continue jmp ansmc6 ; no, end match ansmc3a:ret ; continue ansmc4: cmp al,';' ; Argument separator? jne ansmc5 ; ne = no, check for final char inc nansarg ; yes, count it mov bl,nansarg ; get argument index mov bh,0 mov ansargs[bx],0 ; clear next arg field cmp bl,lansarg ; too many? jl ansmc4a ; l = no, continue dec nansarg ; yes, do not add more jmp ansmc6 ; end match now ansmc4a:ret ; accept separator and continue ansmc5: cmp al,'i' ; sequence terminator? jne ansmc6 ; ne = no, end match mov bx,-1 mov cl,nansarg ; number of argument values mov ch,0 inc cx ; no args is same as one ansmc5a:inc bx mov al,ansargs[bx] ; get ansi argument mov ansargs[bx],0ffh ; and zap it to absorb early values cmp al,4 ; MC OFF value? loopne ansmc5a ; ne = no, examine all non-matches jne ansmc6 ; ne = no match, end matching ; MC OFF sequence discovered mov mccnt,0 ; clear counter call pntflsh ; flush printer buffer test anspflg,vtcntp ; was printing active? jz ansmc5b ; z = no, do nothing and anspflg,not vtcntp ; yes, disable print controller call trnprs ; toggle mode line PRN indicator ansmc5b:jmp ansprt ; done, process arguments in order ; MC OFF sequence not found, playback ansmc6: push ax ; save break char (in al) push cx ; playback partial sequence to printer mov cx,mccnt ; number of chars matched before break jcxz ansmc6b ; z = none push si mov si,offset mcoffs ; string to be played back cld ansmc6a:lodsb ; get a char into al call pntchr ; print it, ignore errors loop ansmc6a ; do all that came in previously pop si ansmc6b:pop cx pop ax ; recover break char mov mccnt,0 ; reset to no match and exit mov nansarg,0 ret ansmc endp pntlin proc near ; print whole line given by dx push ax push bx push cx push dx xor ch,ch mov cl,byte ptr low_rgt ; number of columns mov dl,cl ; Bios column counter, dh = row inc cl ; actual line length, count it down test vtemu.vtflgop,vswdir ; writing right to left? jnz pntlin2 ; nz = yes, do not trim spaces pntlin1:mov ah,2 ; set cursor xor bh,bh ; page 0 int screen mov ah,8 ; read char (al) and attribute (ah) int screen cmp al,' ' ; is this a space? jne pntlin2 ; no, we have the end of the line dec dl ; else move left one column loop pntlin1 ; and keep looking for non-space pntlin2:jcxz pntlin4 ; z = empty line xor dl,dl ; start in column 0, do cl chars pntlin3:mov ah,2 ; set cursor xor bh,bh ; page 0 int screen mov ah,8 ; read char and attribute int screen inc dl ; inc to next column call pntchr ; print the char (in al) jc pntlin5 ; c = printer error loop pntlin3 ; do cx columns pntlin4:mov al,cr ; add trailing cr/lf for printer call pntchr jc pntlin5 mov al,lf call pntchr pntlin5:pop dx pop cx pop bx pop ax ret ; C bit controlled by pntchr pntlin endp pntext proc near ; print an extent of lines, depending push ax ; on flag bit vtextp push bx push dx xor dx,dx ; assume starting at top left mov bx,low_rgt ; and extending to lower right test anspflg,vtextp ; full screen wanted? jnz pntext1 ; nz = yes, else scrolling region mov dh,mar_top ; top of scrolling region mov bh,mar_bot ; bottom of scrolling region pntext1:call pntlin ; print a line jc pntext2 ; c = printer error inc dh cmp dh,bh ; done all requested lines? jbe pntext1 ; be = not yet, do another test anspflg,vtffp ; form feed needed at end? jz pntext2 ; z = no mov al,ff call pntchr ; print the form feed char pntext2:pop dx pop bx pop ax ret pntext endp ; Do Bios screen operation with consideration for writing direction. ; Enter with normal registers set, preserves register dx. direction proc near push dx test vtemu.vtflgop,vswdir ; writing left to right? jz direct1 ; z = yes, do Bios function sub dl,byte ptr low_rgt ; right margin column number neg dl ; make a positive value again direct1:int screen pop dx ret direction endp ; Clear screen from AX to BX, where AH = row, AL = column, ditto for BX. ; This routine accomodates right to left writing. BX >= AX. vtsclr proc near test vtemu.vtflgop,vswdir ; writing left to right? jz vtsclr4 ; z = yes cmp bh,ah ; same row? je vtsclr2 ; e = yes push ax ; multiple lines push bx ; save both coordinates mov bl,byte ptr low_rgt ; get right most logical column mov bh,ah ; pick just top line call vtsclr2 ; delete fraction of top line pop bx ; recover ending position push bx inc ah ; omit top row, now done dec bh ; omit last line, could be fractional cmp bh,ah ; any whole lines remaining to delete? jb vtsclr1 ; b = no, finish up mov bl,byte ptr low_rgt ; get right most physical column mov al,0 ; to end of line (on left) call atsclr ; clear top line and whole remainders vtsclr1:pop bx ; setup for last line to be cleared push bx ; get last row again mov al,0 ; start at logical left margin jmp short vtsclr3 ; ax and bx are already pushed vtsclr2:push ax ; erase single line, whole or part push bx vtsclr3:mov ah,byte ptr low_rgt ; borrow reg ah (same as bh) sub ah,bl ; reflect right to left mov bl,ah or bl,bl ; overflow? jns vtsclr5 ; ns = no, is ok mov bl,0 ; limit to logical screen vtsclr5:mov ah,byte ptr low_rgt sub ah,al mov al,ah jns vtsclr6 mov al,byte ptr low_rgt ; limit to logical screen vtsclr6:mov ah,bh ; restore ah xchg al,bl ; reverse to get physical ax < bx call atsclr ; erase part/all of single line pop bx pop ax ret ; for writing left to right vtsclr4:jmp atsclr ; do normal erasure and return vtsclr endp code ends if1 %out [End of pass 1] else %out [End of assembly] endif end