NAME msyibm ; File MSYIBM.ASM include mssdef.h ; edit history: ; Last edit 16 Jan 1990 ; 9 May 1989 Add Bert Tyler's (NIH) new screen rollback routines. ; 21 Jan 1989 be more tolerate of propriatary video modes above 18 when ; determining screen segment, Tnx to Terry Kennedy. Add check for IBM ; 85xx monitors on Video 7 boards, no 132 columns if it is the monitor. ; Retain 43 rows on Video 7 boards. ; 30 Nov 1988 Add SET TERM CLEAR screen clearing support. ; 28 Nov 1988 Accomodate Tseng Labs UltraPAK mono/Herc board w/132 cols. ; 132 column mode is 18h. Requires Tseng's BIGSCR.COM (use BIGSCR /R:25 ; to enable 132x25 feature). Thanks to Tseng Labs for technical support. ; 21 Nov 1988 Version 2.32 ; 14 Nov 1988 Write a space during lclini to obtain default screen colors. ; 12 Nov 1988 Add procs vtrmac and vtsmac to allow exit from Connect mode and ; invokation of macros TERMINALR and TERMINALS by reception of escape seqs ; in file mszibm.asm or by keyboard verbs. ; 7 Oct 1988 Reverse left/right arrow key codes when writing right to left. ; 24 Sept 1988 Make output to printer be buffered and flow controlled. ; 1 July 1988 Version 2.31 ; 19 June 1988 Add Everex EVGA support, from Terry Kennedy. ; 10 June 1988 Add oldsp and procedure endcon to exit Connect mode if output ; fails, mostly for networking (but we don't know that here). ; 23 May 1988 Add Everex EV-659 ega board test from Alex Zliu. Fixed incorrect ; screen width assumption at startup. ; 29 March 1988 Include flag ttyact to group string bytes into one net packet, ; thanks to Paul Fox of AT&T. ; 23 March 1988 Add "fairness" word to let serial port deliver max chars ; between kbd reads, for connect mode only. [jrd] ; 10 Feb 1988 Revise getcirc and vtscrX routines to do proper scrolling with ; MS Window 1.0x/2.0x [jrd]. ; 9 Feb 1988 Mode line again. Make flags.modflg 0 for off, 1 for on and owned ; by Kermit, and 2 for on and owned by remote host (toggling suppressed). ; 25 Jan 1988 Add global byte SCROLL, set in msz, to control emulator screen ; scrolling for higher speeds. [jrd] ; 5 Jan 1988 Restore cursor codes broken by Tek code additions. [jrd] ; 1 Jan 1988 version 2.30 public term, lclyini ; entry points public prtbout, prtnout, csrtype, scrseg public atsclr, vtscru, vtscrd, trnmod, out8bit, vclick, vtbell public chgdsp, vtroll, crt_lins, crt_cols, tv_mode, vtclear ; action verb procedures for keyboard translator public uparrw, dnarrw, rtarr, lfarr, pf1, pf2, pf3, pf4 public kp0, kp1, kp2, kp3, kp4, kp5, kp6, kp7, kp8, kp9 public kpminus, kpcoma, kpenter, kpdot, chrout, cstatus, cquit public cquery, dmpscn, vtans52, vtinit, dnwpg, upwpg, endwnd, homwnd public upone, dnone, trnprs, dumpscr, modlin, snull public klogon, klogof, cdos, chang, khold, vtrmac, vtsmac public decf6,decf7,decf8,decf9,decf10,decf11,decf12,decf13,decf14 public dechelp,decdo,decf17,decf18,decf19,decf20, udkclear public decfind, decinsert, decremove, decselect, decprev public decnext, setudk public vtemu, crt_mode, scbattr, refresh, low_rgt ; data public savescr, restscr, pntchr, pntchk, pntflsh ; code public setpos, getpos, getatch, setatch, putchar, yflags public getbold, setbold, clrbold, getblink, setblink, clrblink public getunder, setunder, clrunder, revideo, revscn, setcolor public setrev, clrrev, insdecom public vts, vtstat, termtb ; terminal emulation ; some definitions ; hardware crt_status equ 3dah ; CGA crt status port disp_enb equ 8 ; CGA display enable bit crtmset equ 3D8H ; CGA CRT mode set port screen equ 10h ; Bios screen interrupt biostty equ 0eh ; Bios screen tty write mode modfrm struc ; format of mode (status) line db 'Esc-chr: ' ; do not write in last column m_echr db 2 dup (?) db ' help: ' m_hlp db 2 dup (?) db '? port:' m_prt db 1 dup (?) db ' speed:' m_baud db 5 dup (?) db ' parity:' m_par db 4 dup (?) db ' echo:' m_echo db 3 dup (?) m_term db 13 dup (' ') ; 13 bytes for term type m_prn db 3 dup (' ') ; show PRN when printer is on db '$' ; terminator modfrm ends ; structure for status information table sttab. stent struc sttyp dw ? ; type (actually routine to call) msg dw ? ; message to print val2 dw ? ; needed value: another message, or tbl addr tstcel dw ? ; address of cell to test, in data segment basval dw 0 ; base value, if non-zero stent ends data segment public 'data' extrn flags:byte, mar_top:byte, mar_bot:byte, portval:word extrn filtst:byte, dmpname:byte, kbdflg:byte, rxtable:byte extrn anspflg:byte, tekflg:byte, scroll:byte, ttyact:byte extrn holdscr:byte, taklev:byte, takadr:word, mcctab:byte extrn video_state:byte, trans:byte, npages:word, comand:byte extrn denyflg:word, tekgraf:byte, rdbuf:byte, dupflg:byte extrn chcontrol:byte, kbcodes:byte ; stuff for screen routines yflags db 0 ; status flags flags1 db 0 ; internal flags (but used in mszibm) prtscr equ 1 ; print screen pressed inited equ 08h ; been here before vtinited db 0 ; flag for emulator having been inited vtclear db 0 ; nonzero to redo emulator screen cursor dw 0 parmsk db 0 ; 8/7 bit parity mask, for reception argadr dw ? ; address of arg blk skip dw 0 vid7id db 'VEGA BIOS Code, ' ; Video 7 Vega version string subset vid7len equ $-vid7id ; length of string vid7id2 db 'Video Seven BIOS Code, ' ; Video 7 VGA board vid7len2 equ $-vid7id2 atiwid db 'ATI EGA Wonder Bios,' ; ATI EGA wonder version string subset atilen equ $-atiwid ; length of string, inc terminator tsngid db 'Tseng' ; Tseng Labs EVA (& Orchid Designer) tsnglen equ $-tsngid stbvid db 'TVGA' ; STB VGA/EM (also Tseng TVGA) stbvlen equ $-stbvid ; evrxid db 'Everex' ; Everex Micro Enhancer Deluxe EGA evrxlen equ $-evrxid evgid db 'VGA EV673' ; Everex EVGA EV-673 evglen equ $-evgid attvdc6 db '003116' ; AT&T video board, at c000:35h attvdlen equ $-attvdc6 attvdc7 db 'C02000' ; AT&T video board, at e000:10h cols80 db 'COLS80.BAT',0 ; to 80 column mode batch file cols132 db 'COLS132.BAT',0 ; to 132 column mode batch file ega_mode db 0 ; non-zero if IBM EGA is in use tvhere equ 0feh ; Topview active query tvsynch equ 0ffh ; Topview resynch request tv_segs dw 0 ; Topview virtual screen, segment tv_sego dw 0 ; and offset tv_mode db 0 ; flag, 0 = no Topview savadr dw 2 dup (0) ; offset then segment of saved screen savflg dw 0 ; low_rgt at time of screen save att_low_mask equ 06H ; Various attribute-related equates att_underline equ 01H att_intensity equ 08H att_blink equ 80H att_normal equ 07h ; The following are used to turn the display back on (after scrolling etc.) msets db 2CH,28H,2DH,29H,2AH,2EH,1EH,29H vtemu emulst <> ; emulator flags trmtyp db 0 ; most recent terminal type mtty db ' TTY ' ; no terminal type (mode line) belltype db 0 ; 0 = aural bell, 1 = visual fairness dw 0 fairprn dw 0 lincur dw ? ; cursor type save area scbattr db ? ; screen background attribute dosattr db ? ; screen attributes at init time userbold db 0 ; screen bold attribute at start up savattr db ? ; current emulator attributes oldsp dw 0 ; offset to longjmp to for i/o failure ten db 10 ; byte constant for key defines temp dw 0 ; scratch storage captrtn dw 0 ; routine to call for captured output dmphand dw -1 ; screen dump file handle dumplen equ 132 dumpbuf db dumplen dup (?), cr, lf ; 134 byte dump work buffer dumpsep db FF,cr,lf ; screen image separators dmperr db ' Cannot open file to save screen to disk $' memerr db cr,lf,'Not enough memory for terminal emulator$' crlf db cr,lf,'$' flowon db 0 ; flow control chars xon flowoff db 0 ; and xoff (or both null if none) pntmsg db 'Printer not ready, printing request skipped$' pntptr dw dumpbuf ; pointer to next free byte in buffer ; some static data for mode line modbuf modfrm <> ; mode line buffer unkbaud db 'unkwn' ; must be 5 chars baudn db ' 45.5',' 50 ',' 75 ',' 110 ','134.5',' 150 ',' 300 ',' 600 ' db ' 1200',' 1800',' 2000',' 2400',' 4800',' 9600','19200','38400' db '57.6K','115 K' baudnsiz equ 18 ; # of baud rates known (tbl size / 4) parnams db 'even','mark','none','odd ','spc ' lclmsg db 'loc' remmsg db 'rem' portno db 0 ; storage for multi-window stuff swidth equ 80 ; max screen width slen equ 24 ; and length of text crt_norm db 3 ; video mode for normal screen crt_mode db 3 ; video mode (typ 3, must be text) crt_cols db 80 ; number of screen columns (typ 80) crt_lins db 24 ; number of screen rows - 1 (typ 24) low_rgt dw 174fh ; lower right corner of text window ; high = row address (typ 23) ; low = column address (typ 79) inipara dw 0 ; initial paragraphs of scroll memory refresh db 0 ; screen refresh (0=wait for retrace) vtroll db 0 ; auto roll back allowed (0 = no) vtrname db 'TERMINALR' ; a macro name, must be Upper Case vtrlen equ $-vtrname vtsname db 'TERMINALS' ; a macro name, must be Upper Case vtslen equ $-vtsname vtmacname dw vtrname ; pointer to selected macro name vtmaclen db vtrlen udkseg dw 18 dup (0) ; segment of user definable key defs even ; screen rollback material iniseg dw ? ; (BDT) initial seg of scroll memory ppl dw 0 ; (BDT) paragraphs per line lcnt dw 0 ; (BDT) number of "filled" buffer lines linef dw 0 ; (BDT) "first" filled line is here linec dw 0 ; (BDT) "current" screen line number linee dw 0 ; (BDT) total # of lines in the buffer lmax dw 0 ; (BDT) max lines in buff (less 1 scrn) lxtra dw 0 ; (BDT) "extra" lines rqd for screen ; begin Terminal emulator data set termtb db tttypes ; entries for Status, not Set mkeyw 'Heath-19',ttheath mkeyw 'none',ttgenrc mkeyw 'Tek4010',tttek mkeyw 'VT320',ttvt320 mkeyw 'VT102',ttvt100 mkeyw 'VT52',ttvt52 vttbl db 23 ; number of entries mkeyw 'Bell',8800h ; note 8800 flag for decoding mkeyw 'Character-set',chaval+8300h mkeyw 'Clear-screen',8500h ; 8500h = marker here mkeyw 'Color',8200H ; screen fore/back colors; 200H=marker mkeyw 'Controls',cntlval mkeyw 'Cursor-style',curval mkeyw 'Direction',dirval mkeyw 'Graphics',8600h ; Tek graphics board, 800h=marker mkeyw 'Heath-19',ttheath+8100H; note 8100H flag for decoding here mkeyw 'Keyclick',keyval mkeyw 'Keypad',kpamval mkeyw 'Margin-bell',marval mkeyw 'None',ttgenrc+8100H mkeyw 'Newline',newval mkeyw 'Replay',8700h ; note 8700H flag for file replaying mkeyw 'Rollback',8400h ; note 8400H flag for decoding mkeyw 'Screen-background',scrval mkeyw 'Tabstops',tabval mkeyw 'Tek4010',tttek+8100H mkeyw 'VT320',ttvt320+8100H mkeyw 'VT102',ttvt100+8100H mkeyw 'VT52',ttvt52+8100H mkeyw 'Wrap',wraval ontab db 2 ; two entries mkeyw 'off',0 mkeyw 'on',1 beltab db 2 ; bell type mkeyw 'audible',0 mkeyw 'visual',1 scrtab db 2 ; screen attributes mkeyw 'normal',0 mkeyw 'reverse',1 dirtab db 2 ; writing direction mkeyw 'left-to-right',0 mkeyw 'right-to-left',1 curtab db 2 ; cursor attributes mkeyw 'block',0 mkeyw 'underline',1 chatab db 17 ; National Replacement Character sets mkeyw 'ASCII',0 ; ASCII is default (0, no NRC) mkeyw 'British',1 ; start NRC set (1-12) mkeyw 'Dutch',2 mkeyw 'Finnish',3 mkeyw 'French',4 mkeyw 'Fr-Canadian',5 mkeyw 'German',6 mkeyw 'Italian',7 mkeyw 'Norwegian/Danish',8 mkeyw 'Portuguese',9 mkeyw 'Spanish',10 mkeyw 'Swedish',11 mkeyw 'Swiss',12 ; end of NRC proper mkeyw 'Alternate-ROM',13 ; Alternate-ROM character set mkeyw 'Transparent',14 ; use native display adapter hardware mkeyw 'Latin-1',15 ; Latin-1 in GR mkeyw 'DEC-MCS',16 ; DEC Supplemental Graphics in GR graftab db 10 mkeyw 'auto-sensing',0 ; autosensing mkeyw 'CGA',1 mkeyw 'EGA',2 mkeyw 'VGA',3 mkeyw 'Hercules',4 mkeyw 'ATT',5 mkeyw 'WyseA(1280x800)',6 ; Wyse-700 1280 x 800 mode mkeyw 'WyseH(1280x780)',7 ; Wyse-700 1280 x 780 mode mkeyw 'WyseT(1024x780)',8 ; Wyse-700 1024 x 780 mode mkeyw 'character-writing',101h gchrtab db 2 ; set term graphics char-writing mkeyw 'opaque',1 mkeyw 'transparent',0 disatab db 2 ; Tek disable/enable table mkeyw 'disable',1 mkeyw 'enable',0 tabtab db 2 ; label says it all! mkeyw 'at',0FFH ; For setting tab stops mkeyw 'Clear',0 ; For clearing tab stops alltab db 2 ; more tab command decoding mkeyw 'all',0 mkeyw 'at',1 cntltab db 2 ; 8-bit controls mkeyw '7-bit',0 mkeyw '8-bit',1 kpamtab db 2 ; keypad, application mkeyw 'Numeric',0 mkeyw 'Application',1 vtable dw ontab, ontab, chatab, dirtab ,ontab, ontab, curtab, scrtab dw cntltab, kpamtab, 0 ; which are newline wrap char direct key margin cursor screen ; controls key-app vtsflg equ this word ; define small digits xxxval newval equ $-vtsflg ; 0 and mask for bit in byte dw vsnewline ; 1 wraval equ $-vtsflg ; 2 dw vswrap ; 2 chaval equ $-vtsflg ; 4 dw vsnrcm ; 4 dirval equ $-vtsflg ; 6 dw vswdir ; 8 keyval equ $-vtsflg ; 8 dw vskeyclick ; 10h marval equ $-vtsflg ; 10 dw vsmarginbell ; 20h curval equ $-vtsflg ; 12 dw vscursor ; 40h scrval equ $-vtsflg ; 14 dw vsscreen ; 80h cntlval equ $-vtsflg ; 16 dw vscntl ; 100h kpamval equ $-vtsflg ; 18 dw deckpam ; 400h numflgs equ ($-vtsflg)/2 ; 10 tabval equ $-vtsflg ; 20 dw 0 vtrtns dw numflgs dup (flgset), tabmod ; dispatch table for vtsflg colortb db 0,4,2,6,1,5,3,7 ; color reversed-bit setting bytes clrset db ? ; Temp for SET Term Tabstops xxx erms41 db cr,lf,'?More parameters are needed$' vthlp db ' one of the following:',cr,lf db ' terminal types of: None, Heath-19, VT52, VT102, VT320,' db ' or Tek4010',cr,lf db ' Newline-mode Cursor-style Character-set' db cr,lf db ' Keyclick Margin-bell Screen-background' db ' (normal, reverse)',cr,lf db ' Tabstops Wrap (long lines) Color (fore & background)' db cr,lf,' Bell audible or visual' db cr,lf,' Clear-screen (clears old startup screen)' db cr,lf,' Controls 7-bit or 8-bit (permits VT320 to use' db ' 8-bit control sequences (C1))' db cr,lf,' Direction Left-to-right or Right-to-left' db ' (screen writing direction)' db cr,lf,' Graphics (type of display adapter when in Tek4010' db ' mode)' db cr,lf,' Keypad numeric (normal) or application mode' db cr,lf,' Replay filespec (display a file through the emulator)' db cr,lf,' Rollback (undo screen roll back before writing new' db ' chars, default=off)' db cr,lf,' TEK ENABLE or DISABLE (activation by host command)$' clrhlp db ' one of the following:' db cr,lf,' AT #s (to set tabs at column #s) or' db ' AT start-column:spacing' db cr,lf,' Clear AT #s (clears individual tabs) or' db ' AT start-column:spacing' db cr,lf,' Clear ALL (to clear all tabstops)' db cr,lf,' Ex: Set term tab at 10, 20, 34 sets tabs' db cr,lf,' Ex: Set term tab at 1:8 sets tabs at 1, 9,' db cr,lf,' Ex: Set term tab clear at 9, 17, 65 clears tabs' db cr,lf,' Ex: Set term tab clear at 1:8 clears tabs at 1, 9,' db ' 17,...$' tbserr db cr,lf,'?Column number is not in range 1 to screen width-1$' colhlp db cr,lf,' Set Term Color value, value, value, ...' db cr,lf,' 0 no-snow mode on an IBM CGA and white on black' db cr,lf,' 1 for high intensity foreground' db cr,lf,' 10 for fast CGA screen updating (may cause snow)' db cr,lf,' Foreground color (30-37) = 30 + sum of colors' db cr,lf,' Background color (40-47) = 40 + sum of colors' db cr,lf,' where colors are 1 = red, 2 = green, 4 = blue' db cr,lf,' Ex: 0, 1, 37, 44 IBM CGA(0), bright(1) white(37)' db ' chars on a blue(44) field' db cr,lf,' Attributes are applied in order of appearance.$' colerr db cr,lf,'?Value not in range of 0, 1, 10, 30-37, or 40-47$' vtwrap db 'Term wrap-lines: $' vtbellm db 'Term margin-bell: $' vtnewln db 'Term newline: $' vtcur db 'Term cursor-style: $' vtcset db 'Term character-set: $' vtclik db 'Term key-click: $' vtscrn db 'Term screen-background: $' colst1 db 'Term color foregnd:3$' colst2 db ' backgnd:4$' vtgraf db 'Term graphics: $' vtrolst db 'Term rollback: $' vtdir db 'Term direction: $' vtcntst db 'Term controls: $' vtkpst db 'Term keypad: $' vtbset db 'Term bell: $' vtgchst db 'Term graph char: $' ; terminal emulator vtstbl stent ; char set stent ; keyclick stent ; colors stent ; line wrap stent ; controls stent ;margin bell stent ; cursor type stent ; bell stent ; write direct stent ; newline stent ; graphics stent ; rollback stent ; chr cntrl stent ; keypad stent ; screen stent ; VT320 tab status - needs one whole line dw 0 ; end of table ; end of Terminal data set data ends code2 segment public 'code2' extrn tekini:far,tekemu:far,tekend:far,tekrint:far ;in msgibm code2 ends code segment public 'code' extrn prtchr:near, outchr:near, sbrk:near, pcwait:near extrn isfile:near ; in mssfil extrn anstty:near,ansini:near,ansrei:near ; in mszibm extrn anskbi:near,ansdsl:near ; in mszibm extrn ans52t:near, vsinit:near ; in mszibm extrn msuinit:near, keybd:near, kbhold:near ; in msuibm extrn clrmod:near, putmod:near extrn telnet:near, tabset:near, tabclr:near, istabs:near extrn atoi:near, strlen:near, srchkb:near, srchkw:near extrn prompt:near, comnd:near, statc:near, replay:near extrn crun:near, serini:near, spath:near, strcpy:near, tekdmp:near assume cs:code, ds:data, es:nothing ; do initialization local to this module ; Dynamically allocates 4000 bytes for screen save/restore buffer plus ; 320 to 38400 bytes for screen scroll back buffers. Tries to leave space ; for Command.com before enlarging buffers. [jrd] lclyini proc near call msuinit ; initialize keyboard module msuxxx mov ah,conout ; write a space to determine mov dl,' ' ; DOS's default cursor coloring int dos call getpos ; get current cursor position into dx mov lincur,cx ; save cursor type (scan line #'s) dec dl ; backup to last char or dl,dl jns lclyin5 ; ns = no problem xor dl,dl ; else set cursor back to left margin lclyin5:call setpos ; set cursor position call getatch ; read current attributes into AH mov scbattr,ah ; save video attributes mov dosattr,ah ; and here too and ah,att_intensity ; select intensity bit mov userbold,ah ; save bit for user Bold control mov ega_mode,0 ; assume no EGA mov ax,1200H ; EGA: Bios alternate select mov bl,10H ; Ask for EGA info mov bh,0ffH ; Bad info, for testing mov cl,0fH ; Reserved switch settings int screen ; EGA, are you there? cmp cl,0cH ; Test reserved switch settings jge lclyin1 ; ge = no EGA in use push es mov ax,40h ; check Bios 40:87h for ega being mov es,ax ; the active display adapter test byte ptr es:[87h],8 ; is ega active? pop es jnz lclyin1 ; nz = no mov ega_mode,1 ; yes, set flag to say so mov crt_norm,3 ; assume color monitor is attached cmp bh,0 ; is color mode in effect? je lclyin1 ; e = yes mov crt_norm,7 ; else use mode 7 for mono lclyin1:call scrseg ; test running in an Environment call scrmod ; read video state, get crt_mode mov ax,low_rgt ; lower right corner of screen mov al,crt_mode mov crt_norm,al ; save as normal mode mov savflg,ax ; screen roll back buffers mov al,crt_lins ; physical length of user area mul crt_cols ; physical width add ax,7 ; round up mov cl,3 shr ax,cl ; bytes/screen to paragraphs/screen mov si,ax ; save a copy in si mov bx,npages ; number of roll back screens wanted inc bx ; include current screen in count mul bx ; total number of screens wanted mov cx,ax ; save total wanted paragraphs in cx mov bx,0ffffh ; ask for all of memory, to get size mov ah,alloc ; allocate all of memory (must fail) int dos ; bx has # free paragraphs mov ax,bx ; ax has copy of number free paragraphs sub bx,26000D/16 ; space for Command.com copy #2 jc lclyin2 ; c = not enough for it cmp bx,si ; minimum roll back space left over? jle lclyin2 ; le = not even that much cmp bx,cx ; got vs wanted paras for roll back jle lclyin3 ; le = enough but not more than needed mov bx,cx ; limit to our actual needs jmp short lclyin3 ; ask for all we really want lclyin2:xor bx,bx ; use no space at all mov cx,bx ; remember this new request lclyin3:mov ah,alloc int dos mov iniseg,ax ; (BDT) memory segment, window area mov inipara,bx ; save for later resizing of buffers cmp cx,bx ; paragraphs wanted vs delivered jae lclyin4 ; ae = enough mov ah,prstr mov dx,offset memerr ; say not enough memory to operate int dos mov flags.extflg,1 ; set Kermit exit flag lclyin4:call bufadj ; set roll back buffer parameters call vsinit ; init terminal emulator module MSZ mov bx,vtemu.att_ptr ; attributes pointer mov ah,dosattr ; startup video attributes and ah,not att_intensity ; emulation intensity to normal or ah,userbold mov [bx],ah ; set initial emulation attributes ret lclyini endp ; Determine screen roll back buffer parameters depending on current screen ; dimensions and available memory. Each rollback screen line has its own ; segment (lines start on segment boundaries for rollback). bufadj proc near push bx push cx push dx mov lxtra,0 ; assume no storage for "extra" lines xor bh,bh ; (BDT) get bytes / line mov bl,crt_cols ; (BDT) physical line width add bx,7 ; (BDT) round up to paragraph boundary mov cl,3 ; (BDT) now convert to shr bx,cl ; (BDT) paragraphs / line mov ppl,bx ; (BDT) save this in buffer area mov ax,inipara ; (BDT) compute the number of lines xor dx,dx div bx ; (BDT) in the buffer mov lmax,ax ; max line capacity of the buffer mov linee,ax ; (BDT) save as number of total lines or ax,ax ; is this zero? je bufadj1 ; e = yes, no space at all xor bh,bh ; (BDT) get lines / screen mov bl,byte ptr low_rgt+1 ; (BDT) rows on user/host screen inc bx ; (BDT) adjust for counting from 0 mov lxtra,bx ; (BDT) save as "extra" lines sub lmax,bx ; (BDT) deduct "extra" lines req'd cmp lmax,0 ; down to no rollback space? jg bufadj1 ; g = no, have some mov lmax,0 ; say none mov lxtra,0 ; say none of these too bufadj1:mov lcnt,0 ; (BDT) # of lines filled in buffer mov linef,0 ; (BDT) first filled in line mov linec,0 ; (BDT) last filled in line pop dx pop cx pop bx ret bufadj endp ; begin Terminal set & status code ; SET Term parameters, especially for use with VT100 emulator. [jrd] ; Taken from work done originally by James Harvey IUPUI. ; VTS is called only by mssset to set terminal type and characteristics. ; Enter via direct jmp. Exit rskp for success, ret for failure. VTS proc near ; SET TERM whatever mov ah,cmkey ; Parse another keyword mov bx,offset vthlp ; Use this help mov dx,offset vttbl ; Use this table call comnd jnc vset1 ; nc = success ret ; failure vset1: cmp bh,81H ; marker for terminal type? je vsetu0 ; e = yes cmp bh,82h ; marker for set term color? jne vset1a ; ne = no jmp vsetu2 ; e = yes vset1a: cmp bh,83h ; marker for character set? jne vset1f ; ne = no jmp vsetu3 ; e = yes vset1f: cmp bh,84h ; marker for roll back control? jne vset1g ; ne = no jmp vsetu4 ; e = yes vset1g: cmp bh,85h ; marker for clear-screen? jne vset1b ; ne = no mov ah,cmeol ; yes call comnd jc vset1h ; c = failure mov vtclear,2 ; set trigger for emulator clear scn clc ; success vset1h: ret vset1b: cmp bh,86h ; marker for graphics type? jne vset1c ; ne = no jmp vsetu8 ; yes vset1c: cmp bh,87h ; marker for REPLAY? jne vset1d ; ne = no jmp REPLAY ; yes, do REPLAY vset1d: cmp bh,88h ; marker for BELL? jne vset1e ; ne = no jmp vsetu10 ; yes, do BELL setup vset1e: jmp vsetu1 ; ne = no, dispatch on bl vsetu0: mov byte ptr temp,bl ; set terminal type mov byte ptr temp+1,-1 ; assume no enable/disable Tek cmp bl,tttek ; set term tek? jne vsetu0a ; ne = no mov dx,offset disatab ; disable/enable keyword table mov bx,0 ; help is the table mov comand.cmcr,1 ; allow bare CR's mov ah,cmkey ; get enable/disable keyword call comnd mov comand.cmcr,0 ; no more bare CR's jc vsetu0e ; c = no such keyword mov byte ptr temp+1,bl ; save enable/disable keyword value mov bl,flags.vtflg ; get current terminal type mov byte ptr temp,bl ; and force it here vsetu0a:mov ah,cmeol call comnd ; get a confirm jc vsetu0d ; c = failure vsetu0e:mov bx,temp mov flags.vtflg,bl ; Set the terminal emulation type mov tekflg,0 ; clear Tek sub mode cmp bl,tttek ; adjusting Tek? je vsetu0b ; e = yes cmp bh,-1 ; just enable/disable tek? je vsetu0c ; e = no vsetu0b:and denyflg,not tekxflg ; enable Tek cmp bh,1 ; ought we disable? jne vsetu0c ; ne = no or denyflg,tekxflg ; disable Tek vsetu0c:clc ; success vsetu0d:ret vsetu1: ;;;xor bh,bh ; remove marker bits in bh jmp vtrtns[bx] ; Dispatch vsetu3: mov ah,cmkey ; Set Term character set xor bx,bx ; Use character set table for help mov dx,offset chatab ; Use character set table call comnd jc vsetu3a ; c = failure mov temp,bx mov ah,cmeol ; get a confirm call comnd jc vsetu3a ; failure mov ax,temp ; recover value mov vtemu.vtchset,al ; set default character set clc vsetu3a:ret vsetu4: mov ah,cmkey ; Set Term Roll On/Off, auto roll back xor bx,bx ; Use on/off table as help mov dx,offset ontab ; Use on/off table call comnd jc vsetu4a ; c = failure mov temp,bx mov ah,cmeol ; get a confirm call comnd jc vsetu4a ; c = failure mov bx,temp mov vtroll,bl ; set roll state (0=no auto rollback) clc vsetu4a:ret ; Set Term Color foreground, background vsetu2: mov ah,cmline ; get number(s) after set term color mov dx,offset colhlp ; use this help mov bx,offset rdbuf ; temp buffer mov rdbuf,0 ; clear the buffer call comnd jc vsetu2b ; c = failure cmp ah,0 ; text given? jne vsetu2a ; ne = yes mov ah,prstr mov dx,offset erms41 ; say need more parameters int dos stc ; failure ret vsetu2a:mov bx,vtemu.att_ptr ; get address of attributes byte mov bl,[bx] ; get attributes mov byte ptr temp,bl ; save in work temp mov si,offset rdbuf ; si = place where atoi wants text jmp vsetu2b ; analyze colbad: mov ah,prstr ; not in range - complain and exit mov dx,offset colerr int dos stc ret vsetu2x:mov al,byte ptr temp ; get current attributes mov bx,vtemu.att_ptr ; get address of attributes byte mov [bx],al ; store attributes clc ; success ret vsetu2b:mov dx,si ; analyze values call strlen ; current length of text to cx jcxz vsetu2x ; z = nothing left vsetu2c:cmp byte ptr[si],' ' ; scan off leading spaces jne vsetu2d ; ne = non-blank text found inc si ; look at next char loop vsetu2c ; cx characters to examine jcxz vsetu2x ; z = nothing left vsetu2d:mov ah,cl ; put length where atoi wants it call atoi ; convert text to numeric in ax jc colbad ; c = no value available cmp ax,0 ; reset all? regular IBM CGA refresh je vsetu2j ; e = yes cmp ax,1 ; high intensity? je vsetu2k ; e = yes cmp ax,10 ; fast refresh? je vsetu2l ; e = yes cmp ax,30 ; check range jb colbad ; b = too small. complain cmp ax,37 jna vsetu2f ; 30-37 is foreground color cmp ax,40 jb colbad cmp ax,47 ; compare as unsigned jna vsetu2g ; 40-47 is background jmp colbad ; else error vsetu2h:inc si ; skip separator cmp byte ptr[si-1],0 ; ended on null? jne vsetu2b ; ne = no, do more jmp vsetu2x ; e = yes, exit vsetu2f:sub al,30 ; remove foreground bias and byte ptr temp,not 07H ; clear foreground bits mov bx,ax mov al,colortb[bx] ; get reversed bit pattern or byte ptr temp,al ; load new bits mov vtclear,2 ; set trigger for emulator clear scn jmp vsetu2h vsetu2g:sub al,40 ; remove background bias and byte ptr temp,not 70H ; clear background bits mov bx,ax mov al,colortb[bx] ; get reversed bit pattern mov cl,4 ; rotate 4 positions rol al,cl or byte ptr temp,al ; load new bits mov vtclear,2 ; set trigger for emulator clear scn jmp vsetu2h vsetu2j:mov refresh,0 ; Regular (slow) screen refresh mov byte ptr temp,07h ; clear all, set white on black mov vtclear,2 ; set trigger for emulator clear scn jmp vsetu2h ; get next value vsetu2k:or byte ptr temp,08h ; set high intensity mov vtclear,1 ; set trigger for emulator keep screen jmp vsetu2h ; get next value vsetu2l:mov refresh,1 ; Fast screen refresh jmp vsetu2h vsetu8: mov ah,cmkey ; Set Term graphics xor bx,bx ; Use graphics table as help mov dx,offset graftab ; Use graphics table call comnd jc vsetu8a ; c = failure mov temp,bx cmp bx,100h ; in the special options area? ja vsetu8b ; a = yes mov ah,cmeol ; get a confirm call comnd jc vsetu8a ; c = failure mov bx,temp mov tekgraf,bl ; set Tek graphics board type clc vsetu8a:ret vsetu8b:mov ah,cmkey ; Set Term graphics char-writing xor bx,bx ; no help mov dx,offset gchrtab ; opaque/transparent table call comnd jc vsetu8a ; c = failure push bx mov ah,cmeol ; get a confirm call comnd pop bx jc vsetu8a mov chcontrol,bl ; set/reset opaque char control clc ret vsetu10:mov ah,cmkey ; SET TERM BELL xor bx,bx ; use table as help mov dx,offset beltab ; use Bell table call comnd jc vsetu10a ; c = failure mov temp,bx mov ah,cmeol ; get a confirm call comnd jc vsetu10a ; c = failure mov bx,temp mov belltype,bl ; set bell type vsetu10a:ret ; return carry clear or set ; SET Term flags. These are the (near) equivalent of VT100 Setup mode values. flgset: push bx ; save index (newval etc) mov ah,cmkey ; Another keyword mov dx,vtable[bx] ; The table to use xor bx,bx ; Use default help call comnd mov temp,bx ; save switch value pop bx ; recover index jc flgse0 ; c = failure push bx mov ah,cmeol ; get confirm call comnd pop bx jc flgse0 ; c = failure mov dx,temp ; Restore switch value mov ax,vtsflg[bx] ; get the flag or dx,dx ; set or clear? je flgse1 ; e = clear it or vtemu.vtflgst,ax ; set the flag or vtemu.vtflgop,ax ; in runtime flags too clc ; success flgse0: ret flgse1: not ax ; Complement and vtemu.vtflgst,ax ; clear the indicated setup flag and vtemu.vtflgop,ax ; clear the indicated runtime flag clc ; success ret ; SET Term Tabstops Clear ALL ; SET Term Tabstops Clear AT n1, n2, ..., nx ; SET Term Tabstops At n1, n2, ..., nx tabmod: mov ah,cmkey ; parse keyword mov bx,offset clrhlp ; help text mov dx,offset tabtab ; table call comnd jc tabmo2 ; c = failure mov clrset,2 ; 2 = code for set a tab cmp bl,0 ; clear? jne tabmo3 ; ne = no, SET. parse column number(s) mov clrset,1 ; code for clear at/all tab(s) mov ah,cmkey ; CLEAR, parse ALL or AT mov bx,offset clrhlp ; help text mov dx,offset alltab ; parse ALL or AT call comnd jc tabmo2 ; c = failure cmp bx,0 ; ALL? jne tabmo3 ; ne = AT, clear at specific places mov ah,cmeol ; confirm the ALL call comnd jc tabmo2 ; c = failure mov cx,132 ; ALL, means clear all tab stops tabmo1: mov dx,cx dec dl ; column number, starting with 0 push si mov si,vtemu.vttbs ; the cold-start buffer call tabclr ; clear the tab pop si loop tabmo1 ; do all columns jmp tabcpy ; update active tabs tabmo2: ret tabmo3: mov dx,offset clrhlp ; tell them we want a column number mov ah,cmline ; get line of text mov bx,offset rdbuf ; temp buffer call comnd jc tabmo2 ; c = failure cmp ah,0 ; anything given? jne tabmo4 ; ne = yes mov ah,prstr mov dx,offset erms41 ; say need more parameters int dos clc ret tabmo4: mov si,offset rdbuf ; si = place where atoi wants text tabmo5: mov dx,si call strlen ; cx = current length of text jcxz tabcpy ; z = nothing left mov ah,cl ; put length where atoi wants it call atoi ; convert text to numeric in ax jc tabcpy ; c = no number available mov dx,ax ; column (1-132 style) dec dx ; put column in range 0-131 cmp dx,0 ; check range (1-132 --> 0-131) jl tbsbad ; l = too small. complain cmp dl,132-1 ; more than the right most column? jna tabmo6 ; na = no, is ok tbsbad: mov ah,prstr ; not in range - complain and exit mov dx,offset tbserr int dos jmp short tabmo5 ; get next command value tabmo6: cmp byte ptr [si],':' ; "start-column:spacing" notation? jne tabmo9 ; ne = no, do individual tabstops inc si ; skip colon, do start:space analysis mov temp,dx ; save reg around atoi call mov dx,si ; string address for strlen call strlen ; get remaining string length into cx jcxz tabcpy ; z = no space value, all done here mov ah,cl ; ah = string length for atoi call atoi ; get space value into ax jc tabcpy ; c = no number available mov dx,temp mov cx,ax ; "space" value cmp cx,0 ; zero spacing? jne tabmo7 ; ne = no inc cx ; don't get caught with zero spacing tabmo7: cmp dx,132-1 ; largest tab stop ja tabcpy ; a = done largest tab stop push si mov si,vtemu.vttbs ; the cold-start buffer cmp clrset,2 ; set? jne tabmo8 ; ne = no, clear call tabset ; set tabstop in column DL jmp short tabmo8a tabmo8: call tabclr ; clear tabstop in column DL tabmo8a:pop si add dx,cx ; new column value jmp short tabmo7 ; finish spacing loop ; individual tabstops tabmo9: push si mov si,vtemu.vttbs ; the cold-start buffer cmp clrset,2 ; set? jne tabmo10 ; ne = no, clear call tabset ; set tabstop in column DL pop si jmp short tabmo5 ; get next command value tabmo10:call tabclr ; clear tabstop in column DL pop si jmp tabmo5 ; get next command value tabcpy: mov cx,(132+7)/8 ; update all active tab stops mov di,vtemu.vttbst ; in terminal emulator's active buffer mov si,vtemu.vttbs ; from the cold-start buffer push es push ds pop es cld rep movsb pop es clc ; success ret VTS endp ; end of Set Term things ; Terminal Status display, called within STAT0: in MSSSET VTSTAT proc near ; enter with di within sttbuf, save bx mov bx,offset vtstbl ; table of things to show jmp statc ; status common code, in mssset colstat proc near ; foreground/background color status push si mov si,offset colst1 cld colstd1:lodsb cmp al,'$' ; end of string? je colstd2 ; e = yes stosb jmp short colstd1 colstd2:mov bx,vtemu.att_ptr ; pointer to attributes byte mov bl,byte ptr[bx] xor bh,bh push bx and bx,7 ; get foreground set mov al,colortb[bx] ; get reversed bit pattern add al,'0' ; add ascii bias stosb pop bx mov si,offset colst2 colstd3:lodsb cmp al,'$' je colstd4 stosb jmp short colstd3 colstd4:mov cl,4 ; rotate 4 positions shr bl,cl and bx,7 ; get background set mov al,colortb[bx] ; get reversed bit pattern add al,'0' ; add ascii bias stosb pop si ret colstat endp ; Tabs Status display tabstat proc near ; display tabs ruler for Status push dx cld mov al,cr stosb cmp cl,10 ; are we on a new line? jb tabsta0 ; b = no, do a lf now mov al,lf stosb tabsta0:xor cl,cl ; column index xor ax,ax ; ah = tens, al = units counter tabsta1:mov dl,'.' ; default position symbol inc al cmp al,10 ; time to roll over? jb tabsta2 ; b = not yet xor al,al ; modulo 10 inc ah mov dl,ah ; display a tens-digit add dl,'0' cmp dl,'9' ; larger than 90? jbe tabsta2 ; be = no sub dl,10 ; roll over to 0, 1, etc tabsta2:push dx push si mov dl,cl ; column number, counted from 0 mov si,vtemu.vttbst ; the active buffer call istabs ; is tab set here? pop si pop dx jnc tabsta3 ; nc = no mov dl,'T' ; yes, display a 'T' tabsta3:push ax mov al,dl stosb pop ax inc cl cmp cl,byte ptr low_rgt ; done yet? jb tabsta1 ; b = not yet pop dx ret tabstat endp filler proc near ; use space mov cx,20 mov al,' ' cld rep stosb ret filler endp VTSTAT endp ; end of Terminal set & status code scrini proc near ; init screen stuff mov ega_mode,0 ; assume no EGA mov ax,1200H ; EGA: Bios alternate select mov bl,10H ; Ask for EGA info mov bh,0ffH ; Bad info, for testing mov cl,0fH ; Reserved switch settings int screen ; EGA, are you there? cmp cl,0cH ; Test reserved switch settings jge scrin1 ; ge = no EGA in use push es mov ax,40h ; check Bios 40:87h for ega being mov es,ax ; the active display adapter test byte ptr es:[87h],8 ; is ega active? pop es jnz scrin1 ; nz = no mov ega_mode,1 ; yes, set flag to say so mov crt_norm,3 ; assume color monitor is attached cmp bh,0 ; is color mode in effect? je scrin1 ; e = yes mov crt_norm,7 ; else use mode 7 for mono scrin1: call scrseg ; update screen segment tv_seg(s/o) call scrmod ; get screen mode, low_rgt call getpos ; get cursor position and type jcxz scrin2 ; z = nothing there, skip this mov lincur,cx ; save cursor type (scan line #'s) scrin2: mov bx,vtemu.att_ptr mov ah,[bx] and ah,att_intensity mov userbold,ah mov ax,low_rgt ; present screen text size cmp ax,savflg ; vs size of saved screen je scrin3 ; e = same, do not re-initialize ; call bufadj ; re-initialize screen buffers mov cursor,0 ; cursor to upper left corner cmp flags.vtflg,0 ; terminal type of None? ja scrin3 ; a = no, emulating mov dh,byte ptr low_rgt+1 inc dh ; bottom xor dl,dl ; left corner mov cursor,dx ; non-emulating cursor ; Common finish code scrin3: mov ah,savattr ; saved emulator attributes mov scbattr,ah ; restore active value mov dx,cursor ; use old cursor, if any call setpos ; set cursor position call restscr ; restore screen, if any saved or flags1,inited ; remember we've run already cmp flags.vtflg,0 ; current terminal type = None? je scrin13 ; e = yes, nothing to init cmp vtclear,2 ; screen need clearing? jae scrin10 ; ae = yes, do emulator reinit now cmp vtinited,inited ; inited emulator yet? je scrin11 ; e = yes scrin10:call vtinit ; init it now jmp short scrin13 scrin11:call ansrei ; reinit the emulator cmp flags.vtflg,tttek ; Tek mode? je scrin12 ; e = yes test tekflg,1 ; Tek mode? jz scrin13 ; z = no scrin12:call tekini scrin13:mov al,flags.vtflg ; current terminal type mov trmtyp,al ; place to remember it til next time mov vtclear,0 ; say screen is updated ret scrini endp ; Routine to initialize VT102/52/Heath-19 terminal emulator. vtinit proc near mov holdscr,0 ; clear holdscreen call kbhold ; tell DEC LK250 the state, in msuibm or vtinited,inited cmp flags.vtflg,0 ; doing emulation? je vtinix ; e = no cmp flags.vtflg,tttek ; doing full Tek mode? je vtini2 ; e = yes, skip text emulator mov bx,argadr ; address of argument block mov dl,[bx].flgs and dl,lclecho ; local echo flag and yflags,not lclecho or yflags,dl mov dl,[bx].baudb ; baud rate code in dl mov dh,[bx].parity ; parity code in bits mov cl,4 ; 0-3 of dh shl dh,cl or dh,07H ; just say 7 data bits test flags.remflg,d8bit ; eight bit display? jz vtini1 ; z = no inc dh ; set low four bits to value 8 vtini1: test tekflg,1 ; Tek sub-mode active? jnz vtini2 ; nz = yes, do it's reinit call ansini ; call startup routine in mszibm cmp flags.vtflg,tttek ; full Tek mode? je vtini2 ; e = yes vtinix: clc ret vtini2: call tekrint ; reinitialize Tek emulator clc ret vtinit endp argini proc near ; read passed arguments mov bx,argadr ; base of argument block mov al,[bx].flgs ; get flags and al,capt+emheath+trnctl+lclecho+modoff mov yflags,al ; mask for allowable and save mov al,[bx].prt mov portno,al ; update port number mov crt_lins,24 ; init # of rows mov ax,[bx].captr mov captrtn,ax ; buffer capture routine mov parmsk,0ffh ; parity mask, assume parity = None cmp [bx].parity,parnon ; is parity None? je argini1 ; e = yes, keep all 8 bits mov parmsk,07fh ; else keep lower 7 bits argini1:ret ; that's it argini endp term proc near ; terminal mode entry point mov argadr,ax ; save argument ptr call argini ; init options from arg address call scrini ; init screen stuff or kbcodes,80h ; set need-to-init flg for kbd xtlator mov bx,portval ; port data structure address mov bx,[bx].flowc ; get flow control chars (bl=xoff) mov flowon,bh mov flowoff,bl ; save for later mov oldsp,sp ; remember stack for i/o failure, ; used by procedure endcon mov fairprn,0 ; set printer buffer flush counter lp: call prtchr ; char at port? jnc short lpinp ; nc = yes, go handle push bx mov bx,portval ; port structure address cmp [bx].portrdy,0 ; is port ready for business? pop bx jne lpkbd ; ne = ready jmp endcon ; end the communications now lpkbd: mov fairness,0 ; say kbd was examined inc fairprn ; inc printer dump counter cmp fairprn,1000 ; been here enough times now? jb lpkbd1 ; b = no call pntflsh ; flush printer buffer mov fairprn,0 ; reset for next time lpkbd1: call keybd ; call keyboard translator in msu jnc lp ; nc = no char or have processed it jmp short quit ; carry set = quit connect mode lpinp: and al,parmsk ; apply 8/7 bit parity mask call outtty ; print on terminal inc fairness ; say read port but not kbd, again cmp fairness,100 ; this many port reads before kbd? jb lp ; b = no, read port again jmp short lpkbd ; yes, let user have a chance too quit: mov ah,scbattr ; current emulator attributes mov savattr,ah ; save them here call pntflsh ; flush printer buffer call tekend ; cleanup Tektronix mode [bjh] call getpos ; get cursor position into dx mov cursor,dx ; save position mov al,1 call csrtype ; turn on underline cursor cmp flags.vtflg,0 ; terminal type of none? je quit1 ; e = yes cmp flags.modflg,2 ; is modeline owned by remote host? je quit1 ; e = yes call clrmod ; clear it before storing screen quit1: call savescr ; save screen mov ah,dosattr ; attributes at init time mov scbattr,ah ; background = original state call clrmod ; clear mode line with old attributes ; for ega in non-standard # lines cmp ega_mode,0 ; ega board active? je quit2 ; e = no cmp byte ptr low_rgt+1,23 ; is screen standard length? je quit2 ; e = yes, so regular cursor set is ok push es ; turn off ega cursor emulation mov ax,40h ; byte 40:87H is ega Info byte mov es,ax push es:[87h] ; save info byte around call or byte ptr es:[87h],1 ; set emulation off (low bit = 1) mov cx,lincur ; cursor shape to set mov ah,1 ; set the shape int screen ; back to starting value pop es:[87h] ; recover original Info byte pop es ; and our work reg jmp short quit3 ; skip regular mode cursor setting quit2: ; for regular sized screen mov cx,lincur ; cursor type at startup mov ah,1 int screen ; restore cursor type quit3: mov dh,byte ptr low_rgt+1 ; bottom line inc dh ; status line position xor dl,dl ; left most column call setpos ; set cursor position mov al,yflags and al,not lclecho ; don't copy host's echo flag mov bx,argadr mov ah,[bx].flgs ; get user's flag settings and ah,lclecho ; clear all but local echo bit or [bx].flgs,al ; update flags in arg block ret term endp ; put the character in al to the screen outtty proc near test flags.remflg,d8bit ; keep 8 bits for displays? jnz outtt1 ; nz = yes, 8 bits if possible and al,7fh ; remove high bit outtt1: cmp flags.vtflg,0 ; emulating a terminal? je outnp10 ; e = no cmp vtroll,0 ; auto roll back allowed? je outem1 ; e = no, leave screen as is cmp tekflg,0 ; Tek mode active? jne outem1 ; ne = yes, skip screen rolling cmp flags.vtflg,tttek ; doing Tektronix emulation? je outem2 ; e = yes, use Tek emulator push ax ; (BDT) save this for a tad mov ax,linec ; (BDT) are we at the buffer end? cmp ax,lcnt ; (BDT) ... pop ax ; (BDT) restore the register je outem1 ; (BDT) e = yes push ax ; (BDT) save AX again call endwnd ; (BDT) restore screen [dlk] pop ax ; (BDT) restore the register outem1: cmp flags.vtflg,tttek ; doing Tektronix emulation? je outem2 ; e = yes, use Tek emulator cmp tekflg,0 ; Tek submode active for input? jne outem2 ; ne = yes, use Tek emulator jmp anstty ; call terminal emulator routine & ret outem2: call tekemu ; use Tek emulator and return ret ; use DOS for screen output outnp10:test flags.remflg,d8bit ; keep 8 bits for displays? jnz outnp9 ; nz = yes, 8 bits if possible and al,7fh ; remove high bit outnp9: cmp rxtable+256,0 ; translation turned off? je outnp7 ; e = yes, no translation push bx mov bx,offset rxtable ; address of translate table xlatb ; new char is in al pop bx outnp7: test anspflg,prtscr ; should we be printing? jz outnp8 ; no, keep going call pntchr ; queue char for printer jnc outnp8 ; nc = successful print push ax call vtbell ; else make a noise and call trnprs ; turn off printing pop ax outnp8: test yflags,capt ; capturing output? jz outnp6 ; no, forget this part push ax ; save char call captrtn ; give it captured character pop ax ; restore character and keep going outnp6: test yflags,trnctl ; debug? if so use Bios tty mode jz outnp4 ; z = no mov ah,conout ; DOS screen write cmp al,7fh ; Ascii Del char or greater? jb outnp1 ; b = no je outnp0 ; e = Del char push ax ; save the char mov dl,7eh ; output a tilde for 8th bit int dos pop ax ; restore char and al,7fh ; strip high bit outnp0: cmp al,7fh ; is char now a DEL? jne outnp1 ; ne = no and al,3fH ; strip next highest bit (Del --> '?') jmp outnp2 ; send, preceded by caret outnp1: cmp al,' ' ; control char? jae outnp3 ; ae = no add al,'A'-1 ; make visible outnp2: push ax ; save char mov dl,5eh ; caret int dos ; display it pop ax ; recover the non-printable char outnp3: push ax mov dl,al int dos pop ax ret outnp4: cmp al,bell ; bell (Control G)? jne outnp5 ; ne = no jmp vtbell ; use short beep, avoid char loss outnp5: mov dl,al ; write without intervention mov ah,conout int dos ; else let dos display char ret outtty endp ;[IU2] Here to output an unsigned 8-bit number (in al) to the port without ; echoing. Used by terminal emulator escape sequence output. prtnout proc near mov bl,10 ; Output in base 10 jmp prtno2 ; Ensure at least a zero prtno1: cmp al,0 jne prtno2 ; ne = yes, do more digits ret ; no, return from recursive call prtno2: xor ah,ah ; clear previous remainder div bl ; divide off a digit push ax ; push remainder (in ah) on stack call prtno1 ; recurse pop ax ; pop off a digit add ah,'0' ; make it ASCII mov al,ah ; send to port, in ah call outprt jc prtno3 ; failure, end connection ret prtno3: jmp endcon prtnout endp ; send the character in al out to the serial port; handle echoing. ; Can send an 8 bit char while displaying only 7 bits locally. outprt proc near prtbout label near ; label used in msz test yflags,lclecho ; echoing? jz outpr3 ; z = no, forget it push ax ; save char call outtty ; print it pop ax ; restore outpr3: mov ah,al ; this is where outchr expects it call outchr ; output to the port jc outpr4 ; c = failure ret outpr4: jmp endcon ; failure, end connection outprt endp ; Jump here to exit Connect mode and execute macros 'TERMINALR' (vtrmac) or ; 'TERMINALS' (vtsmac). Does nothing if macro does not exist. ; Preserves registers except ax. Returns to TELNET caller with 'C' in kbdflg. vtrmac proc near ; RESET macro mov ax,offset vtrname ; select macro name mov vtmacname,ax mov vtmaclen,vtrlen ; and its length jmp short vtmacro ; finish in common code vtrmac endp vtsmac proc near ; SET macro mov ax,offset vtsname mov vtmacname,ax mov vtmaclen,vtslen jmp short vtmacro vtsmac endp ; ; Reference Macro structure for db number of entries (mac names) ; is file table mcctab |-> db length of macroname, excl '$' ; mssset.asm each entry |-> db 'macroname','$' ; where these |-> dw segment:0 of definition string ; are stored. (offset part is always 0) ; Definition string in db length of ; buffer macbuf db 'string with trailing null' ; vtmacro proc near ; common code for macros vtsmac,vtrmac push bx push cx push si mov bx,offset mcctab ; table of macro names mov cl,[bx] ; number of names in table xor ch,ch jcxz vtmacx ; z = empty table, do nothing inc bx ; point to length of first name vtmac2: mov al,[bx] ; length of this name xor ah,ah cmp al,vtmaclen ; length same as desired keyword? jne vtmac3 ; ne = no, search again mov si,bx inc si ; point at first char of name push cx ; save name counter push di ; save reg mov cl,vtmaclen ; length of name, excluding '$' xor ch,ch mov di,vtmacname ; point at desired macro name push es ; save reg push ds pop es ; make es use data segment cld repe cmpsb ; match strings pop es ; need current si below pop cx pop di ; recover saved regs je vtmac4 ; e = matched vtmac3: add bx,ax ; step to next name, add name length add bx,4 ; + count, dollar sign, def word ptr loop vtmac2 ; try next name vtmacx: pop si ; no macro, return to Connect mode pop cx pop bx ret vtmac4: cmp taklev,maxtak ; room in Take level? jge vtmacx ; ge = no, exit with no action inc taklev ; increment take level add takadr,size takinfo ; make a new Take entry/macro mov bx,takadr ; point to current macro structure inc si ; skip dollar sign after name mov si,[si] ; get definition address (segment) mov [bx].takbuf,si ; address of definition string struc push es mov es,si ; segment of definition string struc xor si,si mov cl,es:[si] ; length byte of definition xor ch,ch mov [bx].takcnt,cx ; number of chars in definition pop es inc si ; offset of definition text proper mov [bx].takptr,si ; where to read next command char mov [bx].taktyp,0ffh ; flag as a macro pop si pop cx pop bx jmp endcon ; exit Connect mode vtmacro endp ; Error recovery routine used when outchr reports unable to send character ; or when vtmacro requests exiting Connect mode. ; Exit Connect mode cleanly, despite layers of intermediate calls. endcon proc near mov kbdflg,'C' ; report 'C' to TERM's caller mov sp,oldsp ; recover startup stack pointer ; TERM caller's return address is now ; on the top of stack. A longjmp. jmp quit ; exit Connect mode cleanly endcon endp ;;; Action routines (verbs) for keyboard translator KEYBD in msuibm. ; These are invoked by a jump instruction. Return carry clear for normal ; processing, return carry set for invoking Quit (kbdflg has transfer char). uparrw: mov al,'A' ; cursor keys jmp short comarr dnarrw: mov al,'B' jmp short comarr rtarr: mov al,'C' test vtemu.vtflgop,vswdir ; writing left to right? jz comarr ; z = yes mov al,'D' ; reverse sense of keys jmp short comarr lfarr: mov al,'D' test vtemu.vtflgop,vswdir ; writing left to right? jz comarr ; z = yes mov al,'C' ; reverse sense of keys comarr: push ax ; save final char mov ttyact,0 ; network, group chars for packet test vtemu.vtflgop,decanm ; ANSI mode? jz comar2 ; z = no mov al,CSI ; CSI character test vtemu.vtflgop,decckm ; cursor key mode reset? jz comar1 ; z = yes mov al,SS3 ; SS3 character comar1: call out8bit ; send in 7 or 8 bit form jmp short comar3 comar2: mov al,escape ; do Heath/VT52 mode "ESC char" call prtbout comar3: pop ax ; recover final char mov ttyact,1 ; network, restore tty active flag call prtbout ret pf1: mov al,'P' ; keypad function keys PF1-4 jmp short compf pf2: mov al,'Q' jmp short compf pf3: mov al,'R' jmp short compf pf4: mov al,'S' compf: push ax ; save final char mov ttyact,0 ; network, group chars for packet test vtemu.vtflgop,decanm ; ansi mode? jz short compf1 ; z = no mov al,SS3 call out8bit ; send 7 or 8 bit version jmp short compf2 compf1: mov al,escape ; output ESC call prtbout compf2: pop ax ; get the saved char mov ttyact,1 ; network, restore tty active flag call prtbout ret kp0: mov al,'p' ; keypad numeric keys jmp short comkp kp1: mov al,'q' jmp short comkp kp2: mov al,'r' jmp short comkp kp3: mov al,'s' jmp short comkp kp4: mov al,'t' jmp short comkp kp5: mov al,'u' jmp short comkp kp6: mov al,'v' jmp short comkp kp7: mov al,'w' jmp short comkp kp8: mov al,'x' jmp short comkp kp9: mov al,'y' jmp short comkp kpminus:mov al,'m' jmp short comkp kpcoma: mov al,'l' jmp short comkp kpenter:mov al,'M' jmp short comkp kpdot: mov al,'n' comkp: test vtemu.vtflgop,deckpam ; keypad application mode active? jnz comkp1 ; nz = yes, use escape sequences sub al,40h ; deduct offset to numeric symbols push ax ; save final char jmp comkp3 ; and send that single char comkp1: push ax mov ttyact,0 ; network, group chars for packet test vtemu.vtflgop,decanm ; ANSI mode? jz comkp2 ; z = no mov al,SS3 ; SS3 character call out8bit ; send 7 or 8 bit version jmp comkp3 comkp2: mov al,escape ; output "ESC ?" call prtbout mov al,'?' call prtbout comkp3: pop ax ; recover final char mov ttyact,1 ; network, restore tty active flag call prtbout ; send it ret klogon proc near ; resume logging (if any) test flags.capflg,logses ; session logging enabled? jz klogn ; z = no, forget it or argadr.flgs,capt ; turn on capture flag or yflags,capt ; set local msy flag as well klogn: clc ret klogon endp klogof proc near ; suspend logging (if any) and argadr.flgs,not capt ; stop capturing and yflags,not capt ; reset local msy flag as well clc ret klogof endp snull proc near ; send a null byte xor al,al ; the null jmp prtbout ; send without logging and local echo snull endp khold: xor holdscr,1 ; toggle Hold screen byte for msx call kbhold ; tell DEC LK250 the hold kbd state clc ; kbhold is in file msuibm.asm ret ; DEC LK201 keyboard keys and "User Definable Keys" in VT3xx mode decfind:mov al,1 ; Find jmp udkout decinsert:mov al,2 ; Insert jmp udkout decremove:mov al,3 ; Remove jmp udkout decselect:mov al,4 ; Select jmp udkout decprev:mov al,5 ; Previous screen jmp udkout decnext:mov al,6 ; Next screen jmp udkout decf6: mov al,17 ; key ident for DEC F6 jmp udkout ; process it decf7: mov al,18 ; key ident for DEC F7 jmp udkout ; process it decf8: mov al,19 ; key ident for DEC F8 jmp udkout ; process it decf9: mov al,20 ; key ident for DEC F9 jmp udkout ; process it decf10: mov al,21 ; key ident for DEC F10 jmp udkout ; process it decf11: mov al,23 ; key ident for DEC F11 jmp udkout ; process it decf12: mov al,24 ; key ident for DEC F12 jmp udkout ; process it decf13: mov al,25 ; key ident for DEC F13 jmp udkout ; process it decf14: mov al,26 ; key ident for DEC F14 jmp udkout ; process it dechelp:mov al,28 ; key ident for DEC HELP jmp udkout ; process it decdo: mov al,29 ; key ident for DEC DO jmp udkout ; process it decf17: mov al,31 ; key ident for DEC F17 jmp udkout ; process it decf18: mov al,32 ; key ident for DEC F18 jmp udkout ; process it decf19: mov al,33 ; key ident for DEC F19 jmp udkout ; process it decf20: mov al,34 ; key ident for DEC F20 jmp udkout ; process it ; common worker to output contents of User Definable Key definition strings ; Enter with al = key ident (17 - 34) udkout proc near push ax push bx push cx push es cmp flags.vtflg,ttvt320 ; VT320? je udkout3 ; e = yes, else use VT100/VT52 default cmp flags.vtflg,tttek ; Tek? je udkout3 ; try this cmp al,23 ; F11 sends ESC jne udkou1a ; ne = not F11 mov al,escape call prtbout jmp udkoutx udkou1a:cmp al,24 ; F12 sends BS jne udkou1b ; ne = not F12 mov al,BS call prtbout jmp udkoutx udkou1b:cmp al,25 ; F13 sends LF jne udkou1c ; ne = not F13, ignore mov al,LF call prtbout udkou1c:jmp udkoutx udkout3:mov bl,al ; VT3XX key ident, UDK style (17-34) cmp al,6 ; is this the CSI 1-6 set? jbe udkout4 ; be = yes, do separately sub bl,17 ; minus starting offset of 17 xor bh,bh cmp bl,17 ; out of range? ja udkoutx ; a = yes, ignore shl bx,1 ; index words mov bx,udkseg[bx] ; segment of definition cmp bx,0 ; anything there? je udkout4 ; e = no, use DEC defaults below mov es,bx ; definition segment xor bx,bx ; and offset mov cl,es:[bx] ; get string length byte xor ch,ch ; use cx as a counter jcxz udkout4 ; z = empty, use defaults udkou3a:inc bx ; es:bx is now the string text mov al,es:[bx] ; get a char push bx push cx push es call prtbout ; output, no echo, no log pop es pop cx pop bx loop udkou3a jmp short udkoutx ; done udkout4:push ax ; VT320, use default definitions mov al,CSI ; char to send call out8bit ; send lead-in char in 7/8-bit form pop ax call prtnout ; key ident (17-34) as ascii digits mov al,7eh ; tilde terminator call prtbout udkoutx:pop es pop cx pop bx pop ax clc ret udkout endp ; Set (define) the DEC "User Definable Keys". Inserts text definitions for ; keyboard verbs \KdecF6 ...\KdecF14, \KdecHELP, \KdecDO, \KdecF17...\KdecF20. ; Enter with the DCS definition string as key-number/hex-chars. UDK key number ; is 17 for \KdecF6, et seq, the definition are pairs of hex digits converted ; here to a single byte per pair. The DCS definition string is pointed at by ; DS:SI, and the byte count is in CX. ; Example: 17/54657374204636 means key \KdecF6 sends string "Test F6" setudk proc near push ax push bx push cx push si push di push es cld lodsb ; get key ident first byte sub al,'0' ; ascii to binary mul ten ; times 10 xchg ah,al ; to ah lodsb ; get key ident second byte sub al,'0' ; ascii to binary add al,ah ; plus high order part xor ah,ah mov bx,ax ; key ident, 17 - 34 lodsb ; skip slash separator sub cx,3 ; three less bytes in the string sub bx,17 ; remove key ident bias of 17 cmp bx,17 ; out of range? ja setudkx ; a = yes, ignore shl bx,1 ; index words cmp udkseg[bx],0 ; has a segment been allocated for it? je setudk1 ; e = no mov ax,udkseg[bx] ; get segment to es mov es,ax mov ah,freemem ; deallocate old memory block, es:0 int dos mov udkseg[bx],0 ; clear table entry too setudk1:jcxz setudkx ; z = no definition, clear entry push bx ; save index BX mov bx,cx ; get string length shr bx,1 ; two hex digits per final byte add bx,15+1 ; round up plus length byte shr bx,1 ; convert to paragraphs shr bx,1 shr bx,1 shr bx,1 mov di,bx ; remember request mov ah,alloc ; allocate BX paragraphs int dos jc setudkx ; c = failure cmp di,bx ; requested vs allocated pop bx ; recover bx je setudk2 ; e = enough mov ah,freemem ; return the memory, es is ptr int dos jmp short setudkx ; exit failure setudk2:mov es,ax ; segment of allocated memory mov udkseg[bx],es ; segment:0 of definition string xor di,di cld mov al,cl ; length of string shr al,1 ; two hex bytes per stored byte xor ch,ch stosb ; store length byte jcxz setudkx ; z = empty string setukd3:lodsb ; get first hex digit dec cx ; adjust count remaining or al,20h ; to lower case cmp al,'9' ; digit? jbe setudk4 ; be = yes sub al,'a'-'9'-10 ; hex letter to column three setudk4:sub al,'0' ; ascii to binary shl al,1 ; times 16 shl al,1 shl al,1 shl al,1 mov ah,al ; save in ah lodsb ; get second hex digit or al,20h ; to lower case cmp al,'9' ; digit? jbe setudk5 ; be = yes sub al,'a'-'9'-10 ; hex letter to column three setudk5:sub al,'0' ; ascii to binary add al,ah ; join both parts stosb ; store final byte loop setukd3 setudkx:pop es pop di pop si pop cx pop bx pop ax clc ret setudk endp ; Clear all User Definable Keys, deallocate memory for their definitions udkclear proc near push ax push bx push cx push es mov cx,17 ; 17 entries xor bx,bx udkcle1:mov ax,udkseg[bx] ; segment of definition or ax,ax ; segment defined? jz udkcle2 ; z = no, try next key mov es,ax mov udkseg[bx],0 ; clear the entry mov ah,freemem ; release the memory int dos udkcle2:add bx,2 ; word index loop udkcle1 ; do all pop es pop cx pop bx pop ax clc ret udkclear endp ; general character out for emulator chrout: cmp flags.vtflg,0 ; emulating? je chrou5 ; e = no call anskbi ; say we had keyboard input cmp al,cr ; CR? jne chrou5 ; ne = no, just output it and return test vtemu.vtflgop,anslnm ; ANSI new-line mode set? jz chrou5 ; z = no, just send the cr cmp dupflg,0 ; full duplex? je chrou4 ; e = yes cmp al,trans.seol ; End of Line char? jne chrou5 ; ne = no chrou4: mov ah,trans.seol ; save eol char push ax ; save on stack mov trans.seol,lf ; make LF the eol char call outprt ; output a carriage-return mov al,lf ; followed by a line feed call outprt ; send the LF pop ax mov trans.seol,ah ; restore eol char ret chrou5: jmp outprt ; output, no echo, 8-bit control chars as literals or "ESC char" form out8bit proc near mov ttyact,0 ; network, group chars for packet cmp flags.vtflg,ttvt320 ; VT320? jne out8bi1 ; ne = no cmp parmsk,7fh ; using parity? je out8bi1 ; e = yes test vtemu.vtflgop,vscntl ; doing 8-bit controls? jnz out8bi2 ; nz = yes, send 8-bit control char out8bi1:test al,80h ; in range for C1 controls? jz out8bi2 ; z = no cmp al,9fh ja out8bi2 ; a = no push ax mov al,escape ; send ESCAPE call prtbout pop ax sub al,40h ; compose second char out8bi2:mov ttyact,1 ; network, restore single char mode jmp prtbout ; send final char out8bit endp ; these commands invoke Quit cdos: mov al,'P' ; Push to DOS jmp short cmdcom cstatus:mov al,'S' ; Status jmp short cmdcom cquit: mov al,'C' ; Exit Connect mode jmp short cmdcom cquery: mov al,'?' ; Help jmp short cmdcom chang: mov al,'H' ; Hangup, drop DTR & RTS jmp short cmdcom cmdcom: mov kbdflg,al ; pass char to msster.asm via kbdflg stc ; signal that Quit is needed ret ; Screen dump entry from keyboad xlat dmpscn proc near ; dump screen to file cmp flags.vtflg,tttek ; doing Tektronix emulation? je dmpscn2 ; e = yes, use Tek emulator test tekflg,1 ; emulation a Tektronix? jz dmpscn1 ; z = no dmpscn2:call tekdmp ; near-call Tek screen dump utility clc ret dmpscn1:call savescr ; save screen to buffer call dumpscr ; do buffer to file clc ; do not exit Connect mode ret dmpscn endp ;[IU2] Routine to toggle VT100/VT52/Heath-19 modes in VT100 emulator. vtans52 proc near cmp flags.vtflg,0 ; emulating? je vtans5 ; e = no call ans52t ; call MSZ toggle-it routine clc ; clear c bit so don't exit Connect vtans5: ret vtans52 endp ; Toggle Mode Line trnmod proc near cmp flags.modflg,1 ; mode line enabled and owned by us? jne trnm1 ; ne = no, don't touch it cmp flags.vtflg,tttek ; Tek mode? je trnm3 ; e = yes cmp tekflg,0 ; Tek submode? jne trnm3 ; ne = yes, no mode line changes test yflags,modoff ; mode line already off? jnz trnm2 ; nz = yes, go turn on or yflags,modoff ; say modeline is toggled off call clrmod ; clear mode line trnm1: clc ; clear c bit so don't exit Connect ret trnm2: cmp flags.vtflg,0 ; emulating a terminal? jne trnm3 ; ne = yes push dx ; scroll screen to save bottom line mov ah,prstr ; for terminal type none mov dx,offset crlf int dos pop dx trnm3: call modlin ; turn on modeline and yflags,not modoff ; say modeline is not toggled off clc ret trnmod endp modlin proc near ; turn on mode line mov al,trans.escchr ; Connect mode escape character mov modbuf.m_echr,' ' ; first char is initial space mov modbuf.m_hlp,' ' ; goes here too cmp al,32 ; printable? jnb modl1 ; yes, keep going add al,40h ; made printable mov modbuf.m_echr,5eh ; caret, note control char mov modbuf.m_hlp,5eh modl1: mov modbuf.m_echr+1,al ; fill in character mov modbuf.m_hlp+1,al mov bx,argadr ; get argument block mov al,[bx].baudb ; get baud bits mov si,offset unkbaud ; assume unknown baud mov cx,size m_baud ; length of baud space cmp al,baudnsiz ; too big? jnb modl2 ; nb = yes, use default mul cl xor ah,ah add ax,offset baudn mov si,ax modl2: mov di,offset modbuf.m_baud push es ; save es push ds pop es ; set es to data segment cld rep movsb ; copy in baud rate mov al,[bx].parity ; get parity code shl al,1 ; each is 4 bytes long shl al,1 xor ah,ah add ax,offset parnams ; names of parity settings mov si,ax mov cx,4 ; each is 4 long mov di,offset modbuf.m_par rep movsb mov si,offset remmsg ; assume remote echoing test yflags,lclecho ; local echo on? jz modl4 ; z = no mov si,offset lclmsg ; say echo is local modl4: mov cx,3 ; size of on/off mov di,offset modbuf.m_echo rep movsb mov al,portno ; communications port cmp al,' ' ; binary (non-printable)? jae modl5 ; ae = no, ascii add al,'0' ; convert to ascii modl5: mov modbuf.m_prt,al ; fill in port number mov cx,8 ; blank out terminal id field mov si,offset mtty ; assume no terminal emulation mov di,offset modbuf.m_term ; destination rep movsb ; copy it in pop es mov word ptr modbuf.m_prn,' '; assume not printing the screen mov modbuf.m_prn+2,' ' test anspflg,prtscr+2 ; print the screen? (msz uses 1 & 2) jz modl5a ; z = no mov word ptr modbuf.m_prn,'RP' ; yes. display PRN at end of line mov modbuf.m_prn+2,'N' modl5a: call getpos ; get cursor position mov cursor,dx ; save cursor position mov dx,offset modbuf ; mode line image ptr for putmod call putmod ; display mode line cmp flags.vtflg,0 ; emulating? je modl7 ; e = no and yflags,not modoff ; update local flags (mode line on) call ansdsl ; get extras from emulator modl7: mov dx,cursor jmp setpos ; reposition cursor modlin endp trnprs: push ax ; toggle ^ PrtSc screen to printer test anspflg,prtscr ; are we currently printing? jnz trnpr2 ; nz = yes, its on and going off mov ah,ioctl mov al,7 ; get output status of printer push bx mov bx,4 ; file handle for system printer int dos pop bx jc trnpr1 ; c = printer not ready cmp al,0ffh ; Ready status? je trnpr2 ; e = Ready trnpr1: call vtbell ; Not Ready, complain jmp trnpr3 ; and ignore request trnpr2: xor anspflg,prtscr ; flip the flag test yflags,modoff ; mode line off? jnz trnpr3 ; nz = yes call modlin ; else rewrite mode line trnpr3: pop ax clc ; return carry clear (don't quit) ret ; Print on PRN the char in register al. On success return with C bit clear. ; On failure do procedure pntchk and return its C bit (typically C set). ; Uses buffer dumpbuf (screen dump). pntchr proc near push bx ; buffer the character mov bx,pntptr ; offset of next free byte in buffer mov [bx],al ; store the character inc bx ; update pointer mov pntptr,bx ; save pointer cmp bx,offset dumpbuf+dumplen ; buffer full yet? pop bx jb pntchrx ; b = no, just return jmp pntflsh ; go flush the buffer pntchrx:clc ; clear carry bit ret pntchr endp ; Flush printer buffer. Return carry clear if success. ; On failure do procedure pntchk and return its C bit (typically C set). ; Uses buffer dumpbuf (screen dump). pntflsh proc near cmp pntptr,offset dumpbuf ; any text in buffer? jne pntfls1 ; ne = yes ret ; else nothing to do pntfls1:push ax push bx push cx push dx mov bx,portval mov bx,[bx].flowc ; get flow control chars (bl=xoff) mov flowon,bh mov flowoff,bl ; save for later mov al,bl ; get flow control char cmp al,0 ; flow control active? je pntfls2 ; e = no, not using xoff call prtbout ; output xoff (al), no echo pntfls2:mov ah,write2 mov bx,4 ; file handle for DOS printer PRN mov cx,pntptr ; next free byte in buffer mov dx,offset dumpbuf ; start of buffer mov pntptr,dx ; reset buffer pointer sub cx,dx ; cx = current byte count jcxz pntfls3 ; z = empty, do nothing int dos ; write buffer to printer pntfls3:pushf ; save carry status bit mov al,flowon cmp al,0 ; flow control active? je pntfls4 ; e = no, not using xon call prtbout ; output xon (al), no echo pntfls4:popf pop dx pop cx pop bx pop ax jc pntchk ; c = error (printer not ready) ret ; nc = success pntflsh endp ; Check for PRN (DOS's printer) being ready. If ready, return with C clear ; Otherwise, write Not Ready msg on mode line and return with C bit set. ; N.B. DOS Critical Error will occur here if PRN is not ready. [jrd] pntchk proc near push dx push cx push ax mov cx,10 ; ten retries before declaring error pntchk0:mov ah,ioctl ; get printer status, via DOS mov al,7 ; status for output push bx mov bx,4 ; std handle for DOS system printer int dos pop bx jc pntchk1 ; c = call failed cmp al,0ffh ; code for Ready? je pntchk3 ; e = yes, assume printer is ready pntchk1:push cx ; save counter, just in case mov ax,100 ; wait 100 millisec call pcwait pop cx loop pntchk0 ; and try a few more times ; get here when printer is not ready test yflags,modoff ; is mode line off? jnz pntchk2 ; nz = off, skip msg push bx mov dx,offset pntmsg ; say printer not ready call putmod ; write on mode line pop bx pntchk2:pop ax pop cx pop dx stc ; say printer not ready ret pntchk3:pop ax pop cx pop dx clc ; say printer is ready ret pntchk endp ;;;;; General screen management routines for IBM PC ; computes screen location to ax, given row and col in [dh,dl], resp. scrloc proc near mov al,dh ; get row mul crt_cols ; multiply by number of columns add al,dl ; plus current column number adc ah,0 ; ripple carry shl ax,1 ; double for attributes ret scrloc endp ; Routine to set cursor type. Pass cursor type in al: 0 = No cursor, ; 1 = Underline cursor, 2 = Block cursor. All cursors blink due to hardware. ; Routine frags any ac that video ints frag. ; For EGA boards running in non-25 line mode the cursor emulation is turned ; off during cursor shape changing and restored afterward. It's another ; ega Feature. [jrd] ; Sense crt_mode 18h as Tseng Labs UltraPAK mono board in 132 column mode. csrtype proc near push cx ; save the reg mov cx,0F00H ; assume no cursor or al,al ; no cursor? jz csrty2 ; z = yes, no cursor cmp crt_mode,7 ; B&W card? je csrty3 ; e = yes, different sizes cmp crt_mode,18h ; Tseng UltraPAK mono board? je csrty3 ; e = yes, use mono cursor mov cx,0607H ; No, use CGA underline cursor cmp al,2 ; Block? jne csrty2 ; ne = no, set it now csrty1: xor ch,ch ; make cursor a block csrty2: cmp ega_mode,0 ; ega board active? je csrty4 ; e = no cmp byte ptr low_rgt+1,23 ; standard screen length? je csrty4 ; e = yes, use regular cursor setting push es ; EGA. turn off cursor emulation mov ax,40h ; 40:87h is ega Info byte mov es,ax push es:[87h] ; save Info byte around call or byte ptr es:[87h],1 ; set emulation off (low bit = 1) mov ah,1 ; video function for set cursor type int screen pop es:[87h] ; restore Info byte pop es ; and our work register pop cx ret csrty4: mov ah,1 ; video function for set cursor type int screen ; regular cursor shape setting pop cx ret csrty3: mov cx,0B0CH ; assume B&W underline cursor cmp al,2 ; Block? jne csrty2 ; ne = no, set it now jmp short csrty1 ; make it a block csrtype endp ; Save the entire screen in a buffer so we can restore and/or dump it. ; Saves regular (80x25) screens to memory buffer allocated dynamically from ; DOS or if insufficient space then to video memory page 1. Save address is ; savadr+2:savadr (seg:offset). A memory buffer is deallocated and reallocated ; if it's size needs to change, otherwise it is reused as is. ; Current low_rgt size info is saved in savflg for restscr. Note, some ; Environments (TopView/Windows etc) may not permit use of page 1 and we ; will not save the screen if video page 1 is required under Environments. savescr proc near push es push ds push ax push cx push dx push si push di call scrmod ; ascertain video mode and screen call scrseg ; get screen segment in ax and es:di mov di,ax ; save screen seg in di mov ax,low_rgt ; text screen lower right (typ 23,79) inc al ; number of columns add ah,2 ; plus status line = number of rows mul ah ; times rows = characters on screen shl ax,1 ; times two for attributes = page 1 mov dx,ax ; save number of screen bytes in dx mov ax,savadr+2 ; seg of saved memory, if any or ax,ax ; none? jz savsc1 ; z = yes, none cmp ax,0a000h ; in video memory? jae savsc1 ; ae = yes mov ax,low_rgt ; text screen lower right (typ 23,79) cmp ax,savflg ; same as saved screen? je savsc4 ; e = yes, no allocation needed mov ax,savadr+2 ; get old allocation mov es,ax mov ah,freemem ; free old memory int dos mov savadr+2,0 ; clear old segment ; allocate and use DOS memory for save savsc1: mov bx,dx ; bytes to do add bx,15 ; round up mov cl,4 shr bx,cl ; bytes/screen to paragraphs/screen mov ah,alloc ; allocate memory int dos ; bx has # free paragraphs jc savsc2 ; c = not enough for it, use video mov savadr+2,ax ; working seg address for restore mov savadr,0 ; and no offset for memory buffer jmp short savsc4 ; use video page 1 as save area savsc2: cmp di,0a000h ; screen segment is in DOS (Environ)? jae savsc3 ; ae = no mov savadr+2,0 ; then say no seg because no save jmp savsc5 ; exit without saving screen savsc3: mov cx,dx ; number of screen bytes and cx,000fh ; get lower four bits for offset part mov savadr,cx ; save offset in this word mov ax,dx ; number of screen bytes mov cl,4 shr ax,cl ; compute number of paragraphs add ax,di ; add paragraphs, point ax to page 1 mov savadr+2,ax ; and save segment in this word ; save the screen savsc4: push low_rgt ; current screen dimensions pop savflg ; save it for screen restore mov cx,dx ; number of screen bytes shr cx,1 ; do as words push di ; preserve di around call call scroff ; turn off screen [dt] pop di mov ax,savadr+2 ; destination segment mov es,ax ; segment of storage area push di ; screen memory segment from di mov di,savadr ; offset of storage pop ds ; put into ds xor si,si cld rep movsw ; save the screen savsc5: pop di pop si pop dx pop cx pop ax pop ds call scron ; turn on screen pop es ret savescr endp ; Restore screen from buffer (savadr+2:savadr, with screen size in savflg). ; Restores all screen lines. restscr proc near push es push si push di cmp savadr+2,0 ; saved anything yet? jne restsc1 ; ne = yes xor ax,ax mov bx,low_rgt ; clear the screen to current colors call atsclr jmp restsc2 restsc1:mov ax,savflg ; saved low_rgt text screen coord add ah,2 ; number of screen lines inc al ; number of screen columns mul ah ; columns time lines = # characters mov cx,ax ; save this in counter cx push cx ; save count call scrseg ; get address of screen in es:di call scroff ; turn off screen [dt] push ds ; save original data segment mov si,savadr ; offset of storage area push savadr+2 ; segment of same pop ds ; put storage segment into ds cld rep movsw ; restore data to screen pop ds ; recover original data segment call scron ; turn on screen [dt] pop cx ; recover count call scrsync ; synch Topview with new screen restsc2:pop di pop si pop es ret restscr endp ; Save the screen to a buffer and then append buffer to a disk file. [jrd] ; Default filename is Kermit.scn; actual file can be a device too. Filename ; is determined by mssset and is passed as pointer dmpname. ; Dumpscr reads the screen image saved by savescr so call savescr call first. dumpscr proc near cmp savadr+2,0 ; any save area? jne dmp6 ; ne = yes clc ; else ignore and return success ret dmp6: push ax push bx push cx push dx mov dmphand,-1 ; preset illegal handle mov dx,offset dmpname ; name of disk file, from mssset mov ax,dx ; where isfile wants name ptr call isfile ; what kind of file is this? jc dmp5 ; c = no such file, create it test byte ptr filtst.dta+21,1fh ; file attributes, ok to write? jnz dmp0 ; nz = no. mov al,1 ; writing mov ah,open2 ; open existing file int dos jc dmp0 ; c = failure mov dmphand,ax ; save file handle mov bx,ax ; need handle here mov cx,0ffffh ; setup file pointer mov dx,-1 ; and offset mov al,2 ; move to eof minus one byte mov ah,lseek ; seek the end int dos jmp dmp1 dmp5: test filtst.fstat,80h ; access problem? jnz dmp0 ; nz = yes mov ah,creat2 ; file did not exist mov cx,20h ; attributes, archive bit int dos mov dmphand,ax ; save file handle jnc dmp1 ; nc = ok dmp0: call getpos ; get cursor position push dx ; save it mov dh,byte ptr low_rgt+1 ; go to status line inc dh xor dl,dl ; left most column call setpos ; position cursor mov dx,offset dmperr ; say no can do mov ah,prstr int dos pop dx ; get original cursor position call setpos ; position cursor pop dx pop cx pop bx pop ax clc ret dmp1: mov ah,ioctl ; is destination ready for output? mov al,7 ; test output status mov bx,dmphand ; handle int dos jc dmp0 ; c = error cmp al,0ffh ; ready? jne dmp0 ; ne = not ready push di ; read screen buffer, write lines push si push es mov cl,byte ptr low_rgt+1 ; number of lines - 2 add cl,2 ; number of line on screen xor ch,ch mov si,savadr ; offset in storage area dmp2: push cx ; save outer loop counter mov es,savadr+2 ; get storage segment mov di,offset dumpbuf ; data segment memory mov cl,byte ptr savflg ; number of columns on screen - 1 inc cl ; number of columns on screen xor ch,ch dmp3: mov ax,word ptr es:[si] ; read char + attribute or al,al ; is it a null? jnz dmp3c ; nz = no mov al,' ' ; replace null with space dmp3c: mov byte ptr [di],al ; store just char, don't use es: inc si ; update pointers inc si inc di loop dmp3 ; do for each column std ; set scan backward mov cl,byte ptr savflg ; number of columns on screen - 1 inc cl ; number of columns on screen xor ch,ch push es mov ax,ds mov es,ax ; set es to data segment for es:di mov di,offset dumpbuf ; start of line add di,cx ; plus length of line dec di ; minus 1 equals end of line mov al,' ' ; thing to scan over repe scasb ; scan until non-space cld ; set direction forward pop es jz dmp3a ; z = all spaces inc cx inc di dmp3a: mov word ptr [di+1],0A0Dh ; append cr/lf add cx,2 ; line count + cr/lf mov dx,offset dumpbuf ; array to be written mov bx,dmphand ; need file handle mov ah,write2 ; write the line int dos pop cx ; get line counter again jc dmp3b ; c = error loop dmp2 ; do next line mov dx,offset dumpsep ; put in formfeed/cr/lf mov cx,3 ; three bytes overall mov ah,write2 ; write them dmp3b: mov bx,dmphand ; file handle int dos mov ah,close2 ; close the file now int dos pop es pop si pop di pop dx pop cx pop bx pop ax clc ret dumpscr endp ; Get CRT mode - returns mode in variable crt_mode, ; updates crt_cols and low_rgt. ; For EGA active it looks in Bios work memory 40:84H for number of rows scrmod proc near push ax push dx mov ah,15 ; get current video state int screen mov crt_mode,al ; store CRT mode value mov crt_cols,ah ; store # of cols mov dl,ah ; # of cols again mov dh,crt_lins ; and # of rows (constant from msster) cmp ega_mode,0 ; ega active? je scrmod4 ; e = no push es ; yes, permit different lengths mov ax,40h ; refer to 40:84h for # ega rows mov es,ax mov ah,es:[84h] ; get number of rows - 1 (typ 24) cmp ah,20 ; less than 20 rows? jb scrmod3 ; b = yes, ignore this length cmp ah,80 ; more than 80 rows? ja scrmod3 ; a = yes, ignore this length mov dh,ah ; use this length mov crt_lins,dh ; update our working constant scrmod3:pop es scrmod4:dec dl ; max text column, count from zero dec dh ; max text row, count from zero mov low_rgt,dx ; save away window address pop dx pop ax ret scrmod endp ; Get screen segment - returns screen segment in ax, and full address in es:di scrseg proc near xor di,di ; start at beginning of screen (0,0) mov ax,0B000H ; Assume B&W card cmp crt_mode,7 ; Is it? je scrse1 ; e = yes cmp crt_mode,18h ; Tseng UltraPAK mono in 132 col? je scrse1 ; e = yes, use seg B000H mov ax,0B800H ; No - video memory is here on color cmp crt_mode,12 ; graphics set? jb scrse1 ; b = no cmp crt_mode,18 ; end of ordinary 640x480 graphics ja scrse1 ; a = no, assume CGA segment mov ax,0A000H ; graphics scrse1: mov es,ax ; tell Topview our hardware address needs mov tv_segs,es ; save our hardware screen address mov tv_sego,di ; segment and offset form mov tv_mode,1 ; assume we're running under Topview mov ah,tvhere ; query Topview for its presence int screen mov ax,es ; get its new segment for screen work cmp ax,tv_segs ; same as hardware? jne scrse2 ; ne = no, we are being mapped cmp di,tv_sego ; check this too jne scrse2 ; ne = no too. Use TV's work buf as screen mov tv_mode,0 ; else no Topview or no mapping scrse2: mov tv_segs,es ; save segment mov tv_sego,di ; and offset ret scrseg endp ; Synchronize a Topview provided virtual screen buffer with the image ; seen by the user. Requires cx = number of words written to screen ; (char & attribute bytes) and es:di = ENDING address of screen write. ; Changes ax and di. scrsync proc near cmp tv_mode,0 ; Topview mode active? je scrsyn1 ; e = no, skip DOS call below sub di,cx ; backup to start byte (cx = words) sub di,cx ; after storing words to screen mov ah,tvsynch ; tell Topview we have changed screen int screen ; so user sees updated screen scrsyn1:ret scrsync endp ; The following two routines are used to turn off the display while we ; are reading or writing the screen in one of the color card modes. ; Turn screen off for (known) color card modes only. All regs preserved. ; Includes code for old procedure scrwait. 16 June 1987 [jrd] scroff proc near cmp ega_mode,0 ; Extended Graphics Adapter in use? jne scrofx ; ne = yes, no waiting cmp tv_mode,0 ; Topview mode? jne scrofx ; ne = yes, no waiting cmp crt_mode,7 ; B&W card? jnb scrofx ; nb = yes - just return cmp refresh,0 ; slow refresh? jne scrofx ; ne = no wait push ax ; save ax and dx push dx mov dx,crt_status ; CGA: Wait for vertical retrace scrof1: in al,dx test al,disp_enb ; display enabled? jnz scrof1 ; yes, keep waiting scrof2: in al,dx test al,disp_enb ; now wait for it to go off jz scrof2 ; so can have whole cycle mov dx,crtmset ; output to CRT mode set port mov al,25H ; this shuts down the display out dx,al pop dx ; restore regs pop ax scrofx: ret scroff endp ; Turn screen on for (known) color card modes only ; All registers are preserved. scron proc near cmp ega_mode,0 ; Extended Graphics Adapter in use? jne scronx ; ne = yes, no waiting cmp tv_mode,0 ; Topview mode? jne scronx ; ne = yes, no waiting cmp crt_mode,7 ; B&W card? jnb scronx ; nb = yes - just return cmp refresh,0 ; slow refresh? jne scronx ; ne = no wait push ax ; save ax, dx, and si push dx push si mov al,crt_mode ; convert crt_mode to a word xor ah,ah mov si,ax ; get it in a usable register mov al,msets[si] ; fetch the modeset byte mov dx,crtmset ; this port out dx,al ; flash it back on pop si pop dx pop ax scronx: ret scron endp ; Screen clearing routine. [IU] ; ; Call: ax/ coordinates of first screen location to be cleared. ; bx/ coordinates of last location to be cleared. ; Coord: ah = row [0-24], al = column [0-79]. Preserves all registers. [jrd] atsclr: push ax ; save regs push cx push dx mov dx,bx ; compute last screen offset in ax push ax call scrmod ; update column length pop ax ; scrmod zaps ax push ax call scrloc ; get screen start address in ax mov cx,ax ; save it in cx for a minute pop dx ; compute first screen offset in ax call scrloc sub cx,ax ; compute number of locs to clear add cx,2 sar cx,1 ; make byte count a word count jle atscl2 ; If nothing to clear, then vamos push di ; save regs push es ; save es push ax ; save displacement call scrseg ; get address of screen into es:di pop di ; displacement memory address into di mov ah,scbattr ; use current screen background attr mov al,' ' ; use space for fill call scroff ; turn screen off if color card atscl1: push cx ; save word count for Topview cld rep stosw ; Blit... (excuse PDP-10ese please) pop cx ; recover word count call scrsync ; synch Topview call scron ; Turn screen back on if color card pop es ; Restore segment register pop di ; And destination index atscl2: pop dx ; restore regs pop cx pop ax ret ; Scrolling routines. vtscru scrolls up, vtscrd scrolls down 'scroll' ; rows. Top lines are saved in the circular buffer before scrolling up. ; When running under an Environment control number of line positions moved ; to be less than scrolling region. ; All registers are preserved. ; ; Screen-roll down. Move text down one line, for terminal emulator only. ; vtscrd: push ax push bx push cx push dx mov ax,0700h ; scroll down whole region mov ch,mar_top ; top margin line xor cl,cl ; left most column mov dh,mar_bot ; bottom margin line mov dl,byte ptr low_rgt ; right most column mov bh,scbattr ; attributes mov bl,dh sub bl,ch ; region size - 1 line jz vscrd1 ; z = region is 1 line, do one scroll mov al,scroll ; number of lines to scroll, from msz vscrd1: cmp al,bl ; want to scroll more that than? jbe vscrd2 ; be = no push ax mov al,bl ; limit to region-1 for Windows int screen ; and do in parts pop ax sub al,bl ; get remainder jmp short vscrd1 ; do next part vscrd2: int screen ; scroll it down pop dx pop cx pop bx pop ax ret ; Screen scroll up one line (text moves up) for terminal emulator use. ; When running under an Environment control number of line positions moved ; to be less than scrolling region. vtscru: push ax push bx push cx push dx xor ch,ch mov cl,scroll ; number of lines to scroll or cl,cl jnz vscru5 jmp vscru3 ; z = nothing to do vscru5: cmp mar_top,0 ; scrolling the top screen line? ja vscru2 ; a = no. don't save anything push si push di push cx ; (BDT) save this around the call call putcirc ; put screen lines in circular buffer pop cx ; (BDT) restore the register add linec,cx ; (BDT) increment the current line mov cx,linec ; new current line number sub cx,lcnt ; minus # in buf = qty new lines added jc vscru4 ; c = not extending buffer add lcnt,cx ; (BDT) increment the line counter vscru4: mov cx,lcnt ; (BDT) check: are we cmp cx,lmax ; (BDT) beyond the end? jbe vscru1b ; (BDT) be = no sub cx,lmax ; (BDT) compute overflow count add linef,cx ; (BDT) adjust the "first" line mov cx,linef ; (BDT) check: time to wrap? cmp cx,linee ; (BDT) ... jb vscru1 ; (BDT) b = no sub cx,linee ; (BDT) yup mov linef,cx ; (BDT) adjust it vscru1: mov cx,lmax ; (BDT) get the maximum line count mov lcnt,cx ; (BDT) reset the line counter mov linec,cx ; (BDT) reset the current line vscru1b: pop di pop si ; now scroll the visible screen vscru2: mov ax,0600h ; scroll up whole region mov dh,mar_bot ; bottom row mov dl,byte ptr low_rgt ; right most column mov ch,mar_top ; top row of scrolling region xor cl,cl ; left most column mov bh,scbattr ; attributes mov bl,dh sub bl,ch ; region size - 1 line jz vscru2b ; z = region is 1 line, do one scroll mov al,scroll ; number of lines to scroll, from msz vscru2a:cmp al,bl ; want to scroll more that than? jbe vscru2b ; be = no push ax mov al,bl ; limit to region - 1 for Windows int screen ; and do in parts pop ax sub al,bl jmp short vscru2a ; do next part vscru2b:int screen ; scroll up that region vscru3: pop dx ; restore the rest of the regs pop cx pop bx pop ax ret ; (BDT) new screen-scrolling routines. Single, circular buffer homwnd proc near ; "home" to start of the buffer push cx ; save registers mov cx,lxtra ; save this many lines call putcirc ; save them mov linec,0 ; reset the current pointer call getcirc ; now get the new screen pop cx ; restore registers clc ret homwnd endp endwnd proc near ; "end" to end of the buffer push cx ; save registers mov cx,lxtra ; save this many lines call putcirc ; save them mov cx,lcnt ; reset the current pointer mov linec,cx ; save the results call getcirc ; now get the new screen pop cx ; restore registers clc ret endwnd endp dnwpg proc near ; scroll down 1 page push cx ; save registers mov cx,lxtra ; save this many lines call putcirc ; save them mov cx,linec ; reset the current pointer add cx,lxtra ; to the next page cmp cx,lcnt ; did we go past the end? jbe dnwpg1 ; be = no, we're OK mov cx,lcnt ; yup, back up dnwpg1: mov linec,cx ; save the results call getcirc ; now get the new screen pop cx ; restore registers clc ret dnwpg endp dnone proc near ; scroll down 1 line push cx ; save registers mov cx,lxtra ; save this many lines call putcirc ; save them mov cx,linec ; reset the current pointer inc cx ; to the next line cmp cx,lcnt ; oops, did we go past the end? jbe dnone1 ; be = no, we're OK mov cx,lcnt ; yup, back up dnone1: mov linec,cx ; save the results call getcirc ; now get the new screen pop cx ; restore registers clc ret dnone endp upwpg proc near ; scroll up 1 page push cx ; save registers mov cx,lxtra ; save this many lines call putcirc ; save them mov cx,linec ; reset the current pointer sub cx,lxtra ; to the previous page cmp cx,0 ; oops, did we go past the end? jge upwpg1 ; ge = no, we're OK xor cx,cx ; yup, back up upwpg1: mov linec,cx ; save the results call getcirc ; now get the new screen pop cx ; restore registers clc ret upwpg endp upone proc near ; scroll up 1 line push cx ; save registers mov cx,lxtra ; save this many lines call putcirc ; save them mov cx,linec ; reset the current pointer dec cx ; to the previous line cmp cx,0 ; oops, did we go past the end? jge upone1 ; ge = no, we're OK xor cx,cx ; yup, back up upone1: mov linec,cx ; save the results call getcirc ; now get the new screen pop cx ; restore registers clc ret upone endp ; Put cx lines into the circular buffer. ; Source is tv_segs:si which is the current screen address. putcirc proc near ; put lines in the circular buffer jcxz putcir9 ; z = no lines to save push es ; save ES for a tad call scroff ; turn off the screen mov si,tv_sego ; initial screen offset mov ax,linef ; get the first line pointer add ax,linec ; add the current line counter dec ax ; get a running start putcir1:inc ax ; increment the current line pointer cmp ax,linee ; fallen off the end of the buffer? jb putcir2 ; b = no, proceed sub ax,linee ; back up to the buffer start putcir2:push ax ; save the current line pointer mul ppl ; compute the paragraph offset add ax,iniseg ; add the initial segment mov es,ax ; now we have the segment pointer xor di,di ; initial buffer offset is 0 push cx ; save the number of lines xor ch,ch ; get the number of characters to move mov cl,crt_cols push ds ; get the offset of the screen mov ds,tv_segs ; get the segment of the screen rep movsw ; move them pop ds ; restore DS pop cx ; restore the line count pop ax ; restore the buffer counter loop putcir1 ; go back for more call scron ; turn the screen back on pop es ; restore ES putcir9:ret putcirc endp ; Get CX lines from the circular buffer, non destructivly. ; Destination preset in es:di which is the current screen address. getcirc proc near ; get lines from the circular buffer mov cx,lxtra ; restore this many lines jcxz getcir3 ; z = nothing to do call scroff ; turn off the screen push es ; save ES for a tad mov es,tv_segs ; get the segment of the screen mov di,tv_sego ; initial screen offset mov ax,linef ; get the first line pointer add ax,linec ; add the current line counter dec ax ; get a running start getcir1:inc ax ; increment the current line pointer cmp ax,linee ; fallen off the end of the buffer? jb getcir2 ; b = no, proceed sub ax,linee ; back up to the buffer start getcir2:push ax ; save the current line pointer mul ppl ; compute the paragraph offset add ax,iniseg ; add the initial segment xor si,si ; initial offset is 0 push cx ; save the number of lines xor ch,ch ; get the number of characters to move mov cl,crt_cols ; ... push ds ; save DS for a tad mov ds,ax ; now we have the segment pointer rep movsw ; move them pop ds ; restore DS pop cx ; restore the line count push di ; save around update call call scrsync ; synch Topview pop di pop ax ; restore the buffer counter loop getcir1 ; go back for more call scron ; turn the screen back on pop es ; restore ES getcir3:ret getcirc endp ; ; CHKDSP - procedure to check for hardware support of 132 cols [dlk] ; ; Supported hardware: EVA board from Tseng Labs w/132-col kit installed ; Tseng Labs UltraPAK mono/Herc board w/132 column modes. ; Video 7 Vega Deluxe w/ 132X25.COM driver installed [tmk] ; and VGA board, ATI EGA Wonder, Everex ev-659 and fvga-673. ; The routine checks for the presence of a 132-column-capable adapter. If ; one is found its handler executes the desired mode setting and returns ; carry clear; it returns carry set otherwise. ; Adding new boards - place an identification string in the data segment, ; construct a mode setting routine and insert it in the call list below ; (setting 132 column mode is byte ptr temp non-zero). ; chgdsp proc near push es ; save all we use push ax push bx push cx push dx push si push di mov temp,ax ; save set/reset flag from msz cmp crt_cols,80 ; are we narrow? jbe chgds3 ; be = narrow width now cmp al,0 ; resetting to narrow width? je chgds4 ; e = yes, do it jmp chgdsx1 ; else we are there now chgds3: cmp al,0 ; resetting to narrow width? je chgdsx1 ; e = yes, we are there now chgds4: mov ah,flowoff ; get xoff cmp ah,0 ; flow control? je chgds0 ; e = none call outchr ; send it call savescr ; save current screen mov ax,500 ; wait 500 millisec before video tests call pcwait ; so don't mix screen and port intrpts chgds0: call ckteva ; try Tseng Labs EVA jnc chgds1 ; nc = found call ckstbv ; try STB VEGA/EM jnc chgds1 ; nc = found call ckv7vd ; try Video 7 EGA Deluxe and VGA jnc chgds1 ; nc = found call ckatiw ; try ATI EGA Wonder jnc chgds1 ; nc = found call ckevrx ; try Everex Micro Enhancer Deluxe jnc chgds1 ; nc = found call ckevga ; try Everex EVGA-673 jnc chgds1 ; nc = found call ckatt ; ATT boards jnc chgds1 ; nc = not found mov si,offset cols80 ; name of 80 column file cmp byte ptr temp,0 ; setting 80 cols? je chgdsx2 ; e = yes mov si,offset cols132 ; use 132 column file chgdsx2:mov di,offset dumpbuf ; a temp buffer for path= usage call strcpy mov ax,di ; spath wants ptr in ax call spath jc chgdsx ; c = file not found mov si,ax ; crun wants ptr in si call crun ; run the batch file, si = filespec call serini ; reengage serial port, mode changes ; Perform mode change chgds1: cmp flags.modflg,1 ; is mode line enabled? jbe chgds2 ; be = yes, and off or locally owned mov flags.modflg,1 ; remove foreign ownership chgds2: call scrini ; reset parameters chgdsx: mov ah,flowon ; get flowon byte cmp ah,0 ; using flow control? je chgdsx1 ; e = no call outchr ; send it chgdsx1:pop di ; restore what we saved pop si pop dx pop cx pop bx pop ax pop es ret ; return to caller ; Individual tests for various 132-column boards ; Tseng LABS EVA and UltraPAK ckteva: mov ax,0c000h ; seg addr for EVA mov es,ax ; set into es register mov di,76h ; offset of board's string lea si,tsngid ; validation string mov cx,tsnglen ; length of validiation string cld repe cmpsb ; compare strings je ckteva2 ; e = strings match mov ax,4d00h ; check for UltraPAK mono driver int screen cmp ax,5aa5h ; driver signature? jne ckteva3 ; ne = no mov ax,7 ; default to mono (7) for this board cmp byte ptr temp,0 ; setting 132 columns? je ckteva1 ; e = resetting to normal mov ax,18h ; set to 132 cols (Set Mode 18H) ckteva1:int screen clc ; carry clear means success ret ; an EVA board - check for 132 col kit ckteva2:cmp byte ptr es:099h,0 ; check 132 col kit installed jne catfnd ; ne = installed, do the mode change ckteva3:stc ; indicate adapter not present ret ; and exit ; ckstbv: mov ax,0c000h ; STB's VGA/EM and VGA/EM-16 mov es,ax ; mov di,70h ; where to look for signature lea si,stbvid ; the signature mov cx,stbvlen ; cld ; repe cmpsb ; test je catfnd ; e = found stc ; else say not there ret ; ; ATI EGA Wonder ckatiw: mov ax,0c000h ; seg addr for EGA Wonder mov es,ax ; set into es register mov di,012fh ; offset of message in ROM lea si,atiwid ; offset of message here mov cx,atilen ; length of validation string cld repe cmpsb ; compare strings je catfnd ; e = they match stc ; strings differ ret catfnd: mov ax,0003h ; prepare to reset video mode cmp byte ptr temp,0 ; are we setting or resetting? je catfnd1 ; e is reset, exit mov ax,0023h ; set to 132 cols (Set Mode 23H) catfnd1:int screen clc ; carry clear means success ret ; Video 7 Vega Deluxe ckv7vd: mov ax,0c000h ; seg addr for Vega rom bios mov es,ax ; set into es register mov di,002ah ; offset of message in ROM lea si,vid7id ; offset of message here mov cx,vid7len cld repe cmpsb ; compare strings je cnv7fn1 ; e = same mov di,002ah ; offset of ident string mov si,offset vid7id2 ; Video 7 VGA board mov cx,vid7len2 repe cmpsb je cnv7fn2 ; e = found cnv7fx: stc ; strings are different ret ; cnv7fn1:test byte ptr es:[03ffeh],1 ; is this a 'Deluxe' Vega? jz cnv7fx ; z = nope, can't do it mov ah,35h ; DOS Get Vector mov al,10h ; Bios video interrupt int dos ; get it into es:bx mov di,bx ; es:bx is returned int 10h entry pnt sub di,5ah ; back offset to msg in 132X25.COM lea si,vid7id ; offset of validation message mov cx,vid7len ; length of validation string cld repe cmpsb ; Look for repeat of msg by 132X25.COM jne cnv7fn2 ; if different mov al,crt_mode ; prepare to reset video mode xor ah,ah cmp byte ptr temp,0 ; are we setting or resetting? je cnv7fn2a ; e is reset mov ax,0000h ; set to 132 cols (old 40x25) cnv7fn1a:int screen clc ret cnv7fn2:mov ax,6f00h ; check for VegaBios driver int screen cmp bx,'V7' ; Video 7 Bios presence response jne cnv7fx ; ne = not there mov ax,6f01h ; al gets monitor type (mono,color,ega) int screen mov bx,51h ; presume mono 132x25, page 0 cmp crt_lins,42 ; 43 lines active? jb cnv7fn2a ; b = no inc bx ; use bx = 52h for 132x43 cnv7fn2a: cmp al,10h ; analogue fixed freq (IBM 85xx)? je cnv7fx ; e = yes, no 132 columns cmp al,2 ; 1 = mono, 2 = color, above = ega jb cnv7fn3 ; b = mono or unknown mov bx,4fh ; presume med res color 132x25 je cnv7fn3 ; e = med res color, al = 2 mov bx,41h ; ega high res 132x25, enhanced mons cmp crt_lins,42 ; 43 lines active? jb cnv7fn3 ; b = no inc bx ; use bx = 42h for 132x43 cnv7fn3:mov ax,6f05h ; set special mode found in bl cmp byte ptr temp,0 ; resetting to 80 column mode? jne cnv7fn4 ; ne = no, setting 132x25 mov al,crt_norm ; get normal mode xor ah,ah ; set mode cmp crt_lins,42 ; 43 lines active? jb cnv7fn4 ; b = no mov bl,40h ; use Video 7 mode 40h 80x43 for color mov ax,6f05h ; and do special mode set cnv7fn4:int screen ; special mode is in bl mov ax,0f00h ; a nop screen bios command int screen clc ret ckevrx: mov ax,0c000h ; seg addr for Everex EV-659 mov es,ax ; set into es register mov di,0047h ; offset of message in ROM lea si,evrxid ; offset of message here mov cx,evrxlen ; length of validation string cld repe cmpsb ; compare strings jne ckfnr2 ; ne = strings differ mov ah,crt_lins ; we recognize either 44 or 25 rows cmp ah,43 ; equal to 44-1 rows? jne ckfnr1 ; ne = no mov ax,0070h ; Everex extended mode ident mov bl,09h ; prepare to reset video mode to 80x44 cmp byte ptr temp,0 ; are we setting or resetting? je ckfnr4 ; e is reset, exit mov bl,0bh ; 132x44 int screen clc ret ckfnr1: cmp ah,24 ; equal to 25-1 rows? je ckfnr3 ; e = yes ckfnr2: stc ; return failure ret ckfnr3: mov ax,0003h ; prepare to reset video mode cmp byte ptr temp,0 ; are we setting or resetting? je ckfnr4 ; e is reset, exit mov ax,0070h ; Everex extended mode ident mov bl,0ah ; 132x25 ckfnr4: int screen clc ret ckevga: mov ax,0c000h ; Everex FVGA-673, rom segment mov es,ax mov di,76h ; offset in rom for board's id string lea si,evgid ; id string mov cx,evglen ; length of id string cld repe cmpsb ; do they match? jne ckevg2 ; ne = no mov ax,3 ; prepare to reset video mode cmp byte ptr temp,0 ; setting or resetting mode? je ckevg1 ; e = resetting, exit mov ax,0070h ; mode for 132x25 mov bl,0ah ; Everex mode 0ah ckevg1: int screen clc ret ckevg2: stc ; say board not found ret ; AT&T EGA/VGA boards ckatt: mov ax,0c000h ; seg of first signature mov es,ax mov si,offset attvdc6 ; first pattern mov di,35h ; test area cld mov cx,attvdlen ; length repe cmpsb je ckatt2 ; e = found mov cx,attvdlen ; try second signature, same length mov si,offset attvdc7 mov ax,0e000h ; seg of second signature mov es,ax mov di,10h ; test area repe cmpsb je ckatt2 ; e = found stc ; not found ret ckatt2: mov al,crt_norm ; old mode xor ah,ah cmp byte ptr temp,0 ; resetting to 80 col? je ckatt3 ; e = yes mov ax,0055h ; 132 cols, set mode 55h ckatt3: int screen clc ret chgdsp endp ; Character write/read and cursor manipulation routines for terminal emulator ; All registers other than returned values are preserved. ; Read char and attributes under cursor. ; Returns AL = character, AH = video attributes getatch proc near push bx mov ah,8 ; read char and attributes xor bh,bh ; page 0 int screen ; Bios video call pop bx ret getatch endp ; Read cursor position ; DH = column, DL = row, both counted from 0,0 at upper left corner getpos proc near push ax push bx mov ah,3 ; get cursor position xor bh,bh ; page 0 int screen pop bx pop ax ret getpos endp ; Set cursor postion ; DH = column, DL = row, both counted from 0,0 at upper left corner setpos proc near push ax push bx mov ah,2 ; set cursor xor bh,bh ; page 0 int screen pop bx pop ax ret setpos endp ; Write char and attribute to screen at cursor position, do not move cursor. ; AL = char, AH = video attribute setatch proc near push ax push bx push cx mov cx,1 ; one char mov bl,ah ; attribute xor bh,bh ; page 0 mov ah,9 ; write char, do not move cursor int screen pop cx pop bx pop ax ret setatch endp ; Write char to screen at cursor position, move cursor, use current attributes ; AL = char. putchar proc near push ax push bx mov ah,0eh ; write char, increment cursor xor bh,bh ; page 0 int screen pop bx pop ax ret putchar endp ; Get bold video attribute bit ; Enter with AH = video attribute byte, returns AH = bold attribute bit getbold proc near and ah,att_intensity ; select bold bit xor ah,userbold ; invert with user bold ret getbold endp ; Set bold video attribute bit ; Enter with AH = video attribute byte setbold proc near or ah,att_intensity ; set bold bit xor ah,userbold ; invert with user bold ret setbold endp ; Clear bold video attribute bit ; Enter with AH = video attribute byte, returns new attribute byte in AH clrbold proc near and ah,not att_intensity ; clear bold bit or ah,userbold ; invert with user bold ret clrbold endp ; Get blink video attribute bit ; Enter with AH = video attribute byte, returns AH = blink attribute bit getblink proc near and ah,att_blink ; get blink bit ret getblink endp ; Set blink video attribute bit ; Enter with AH = video attribute byte setblink proc near or ah,att_blink ; set blink bit ret setblink endp ; Clear blink video attribute bit ; Enter with AH = video attribute byte, returns new attribute byte in AH clrblink proc near and ah,not att_blink ; clear blink bit ret clrblink endp ; Get underline video attribute bit ; Enter with AH = video attribute byte, returns AH = underline attribute bit getunder proc near ret getunder endp ; Set underline video attribute bit ; Enter with AH = video attribute byte, video_state (0=normal) ; Return AH holding new attribute byte, new video_state. setunder proc near cmp crt_mode,7 ; monochrome display adapter mode? je setund2 ; e = yes, otherwise reverse video jmp setrev setund2:call brkatt ; break apart attributes or al,att_underline ; set underline bit call addatt ; reassemble attributes ret setunder endp ; Clear underline video attribute bit ; Enter with AH = video attribute byte, returns new attribute byte in AH and ; new video_state. clrunder proc near cmp crt_mode,7 ; monochrome display adapter mode? je clrund2 ; e = yes, otherwise reverse video jmp clrrev clrund2:call brkatt ; break apart attributes and al,not att_underline ; turn off underline bit call addatt ; reassemble attributes ret clrunder endp setrev proc near cmp video_state,0 ; normal video jne setrev1 ; ne = no, reversed already call revideo ; do reversal mov video_state,1 ; say reversed setrev1:ret setrev endp clrrev proc near cmp video_state,0 ; normal video? je clrrev1 ; e = yes call revideo ; do reversal mov video_state,0 ; say normal clrrev1:ret clrrev endp ; Compute reversed video attribute byte. Normally preserves blink/bold. ; Enter with AH = video attribute byte, returns new attribute byte in AH revideo proc near 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 ret revideo endp ; 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. ; enter with 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: xor al,al ; Clear returned "extra" attributes test ah,att_intensity ; intensity attribute on? jz brkat3 ; z = no, check blink or al,att_intensity ; set intensity brkat3: test ah,att_blink ; blink on? jz brkat4 ; z = no or al,att_blink ; set blink brkat4: and ah,not(att_intensity+att_blink) ;strip blink/bold, leave color cmp crt_mode,7 ; monochrome display adapter mode? jne brkat2 ; ne = no, cut this short for color test ah,att_low_mask ; are any of these on? jnz brkat1 ; nz = yes, can't be underline test ah,att_underline ; underline? jz brkat2 ; z = no, some kind of reverse video or al,att_underline ; say underline test ah,70h ;;att_reverse ; reverse video + underline? jz brkat1 ; z = no, fix up low nibble and ah,not att_underline ; clear the underline bit in ah ret brkat1: or ah,att_normal ; normal, turn on all normal bits brkat2: ret ; This routine builds a cursor attribute given the base attribute for the ; screen background and the "extra" attributes we want (blink, etc.). ; enter with 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 ; z = no, no need for hack and ah,not att_low_mask ; clear background colors 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. revscn proc near push ax push bx push cx push dx 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 ; get screen offset into ax mov cx,ax ; Save it in cx for a minute 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 mov ax,tv_segs ; Get address of screen in ax, es:di mov es,ax xor di,di call scroff ; Turn screen off if color card cld revsc1: mov ax,es:[di] ; Fetch a word mov bl,al ; Save the character call revideo ; get reversed video attributes (AH) call addatt ; Put attributes back together mov al,bl ; Restore character stosw ; Stuff into screen memory 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 pop dx pop cx pop bx pop ax ret revscn endp ; IBM PC worker for insert/delete cx characters at and including cursor. ; dh= logical cursor row, dl= logical cursor column, ; cx has character repeat count, bl = logical screen width-1, ; bh = +1 for insert, -1 for delete chars. ; Double width lines have cx and dl doubled by our caller. Writing right to ; left is managed here. insdecom proc near push es push ax push cx push dx push si push di mov temp,0 ; worker temp mov skip,cx ; number of chars to insert/delete call scrseg ; pick up screen segment in es:di,ax test vtemu.vtflgop,vswdir ; writing left to right? jz insdec1 ; z = yes, no changes needed sub dl,bl ; logical to physical cursor position neg dl ; make dl positive again xor bl,bl ; right-to-left, edge is left margin ; bl is now logical eol insdec1:mov cl,dl ; physical cursor dl saved here cmp bh,0 ; insert? jl insdec2 ; l = no, leave dl at cursor column mov dl,bl ; insert uses logical end of line insdec2:call scrloc ; ax = offset in regen buffer add di,ax ; es:di = destination so far mov si,di ; align source to be same place cmp bh,0 ; inserting? jge insdec4 ; ge = yes test vtemu.vtflgop,vswdir ; writing right to left? jnz insdec4a ; nz = yes insdec3:add si,skip ; delete add si,skip mov byte ptr temp+1,0 ; remember direction here as 0=cld cld jmp short insdec5 insdec4:test vtemu.vtflgop,vswdir ; insert, writing right to left? jnz insdec3 ; nz = yes insdec4a:sub si,skip sub si,skip mov byte ptr temp+1,0 ; remember direction here as 1=std std insdec5:call scroff ; video off xor ch,ch sub cl,bl ; cursor - margin jnc insdec6 ; nc = non-negative neg cl ; make positive insdec6:inc cx ; include cursor location too sub cx,skip ; cx = number chars to be moved jle insdec7 ; le = none, just write spaces mov byte ptr temp,cl ; number of chars modified push ds push es pop ds rep movsw ; mov cx chars from es:[si] to es:[di] pop ds insdec7:mov cx,skip ; number chars skipped jcxz insdec8 ; z = none add byte ptr temp,cl ; number chars modified mov al,' ' ; get fill pattern mov ah,scbattr ; attribute rep stosw ; fill at the end insdec8:cld ; restore direction flag call scron ; video back on for CGA screens mov cl,byte ptr temp ; number of char cells touched xor ch,ch cmp byte ptr temp+1,0 ; was Direction bit set? je insdec9 ; e = no add di,cx ; make di be its highest value insdec9:call scrsync ; synch Topview pop di pop si pop dx pop cx pop ax pop es ret insdecom endp ; Set coloring attributes. ; Enter with AH holding current video attribute byte, ; BL holding ANSI color code (30-37 or 40-47) where 30's are foreground, ; 40's are background. ANSI colors are 1 = red, 2 = green, 4 = blue. ; Return new attribute byte in AH. setcolor proc near cmp video_state,0 ; normal video currently? je setcol0 ; e = yes mov al,ah ; make a copy and ax,7788h ; strip bold,blink, keep both in al rol ah,1 ; get colors in right parts rol ah,1 ; of ah = back, al = foreground rol ah,1 rol ah,1 call setcol0 ; set fore or background color rol ah,1 ; reverse coloring again rol ah,1 rol ah,1 rol ah,1 or ah,al ; put back blink and bold ret setcol0: cmp bl,30 ; ANSI color series? jb setcol7 ; b = no cmp bl,37 ; foreground set (30-37)? ja setcol4 ; 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 setcol1 ; z = no or ah,4 ; IBM red foreground bit setcol1:test bl,2 ; ANSI & IBM green? jz setcol2 ; z = no or ah,2 ; IBM green foreground bit setcol2:test bl,4 ; ANSI blue? jz setcol3 ; z = no or ah,1 ; IBM blue foreground bit setcol3:ret setcol4:cmp bl,40 ; background color set? jb setcol7 ; b = no cmp bl,47 ; background set is 40-47 ja setcol7 ; 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 setcol5 ; z = no or ah,40h ; IBM red background bit setcol5:test bl,2 ; ANSI & IBM green? jz setcol6 ; z = no or ah,20h ; IBM green background bit setcol6:test bl,4 ; ANSI blue? jz setcol7 ; z = no or ah,10h ; IBM blue background bit setcol7:ret setcolor endp ; Routine to do keyclick if flag is set, no arguments vclick proc near test vtemu.vtflgop,vskeyclick ; is keyclick flag on? jz vclick1 ; z = no, just return push bx 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, no arguments vtbell proc near cmp belltype,1 ; visual bell? je vtbell1 ; e = yes push di push bx mov di,880 ; 880 Hertz mov bx,40 ; For 40 ms call vtsound ; Do it pop bx pop di ret vtbell1:call revscn ; reverse screen push ax mov ax,40 ; for 40 milliseconds call pcwait pop ax call revscn ; put back 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 code ends end