; PROGRAM: Z3INSTP SYS.ENV --> TURBO pascal .COM file video installer ; AUTHOR: Steven M. Cohen ; VERSION: 2.0 ; DATE: 23 November 85 ; PREVIOUS VERSION: 1.0 written in Turbo-Pascal 6/85 ; VERS equ 20 Z3ENV set 0f300h ; ; Thió filå anä alì fileó iî thå LIBRARÙ calleä ZTP-INS2.LBÒ ; arå copyrighô 198µ bù Steveî M® Cohen¬ anä thereforå remaiî ; hió property® Yoõ maù freelù distributå it¬ buô yoõ maù noô ; selì iô oò bundlå iô aó parô oæ anù packagå foò salå ; withouô thå expresó writteî consenô oæ thå author. ; ; Z3INStp is installed by Z3INS. ; ; Z3INStp works with all Z80 CP/M systems with ZCPR3. ; ; M80 is required for assembly of this file. ; ; Usage: Z3INStp $1 [$2] where $1 is a mandatory file to install ; and $2 is optional, allowing the options of ; 'A' - installing one-character arrow keys at the four ; bytes beginning at 130H in Turbo Programs. ; FATCAT.COM is one program that can make use of this ; 'N' - turn off high/intensity - low intensity switching ; On a bad terminal no highlighting may be better ; than bad highlighting. Some programs (again like ; FATCAT.COM) may allow workarounds in the event ; that no highlighting is available. ; 'R' - Reverse the high and low intensities. Often ; a program written for "reverse video" might look ; better the other way around if only "reduced intensity" ; is available. ; ; Routines here need VLIB, Z3LIB and SYSLIB ; ext z3vini,vidptr,cls ; VLIB ext z3init,envptr ; Z3LIB ext eprint,hmovb ; SYSLIB ext bdos,capstr,pafdc,cout ; SYSLIB ext fillb,codend,pfn2,capine ; SYSLIB ext f$rename,fxi$open,fxo$open ; SYSLIB ext fx$get,fx$put,fxi$close ; SYSLIB ext fxo$close,fname,retud,f$delete ; SYSLIB ext getud,putud,logud,F$exist ; SYSLIB ext compb ; SYSLIB ; ; ; Customization Equates ; FALSE equ 0 TRUE equ not FALSE ; ; Basic Definitions ; CR equ 'M'-'@' LF equ 'J'-'@' BELL equ 'G'-'@' CTAIL equ 81h ; command tail fcb1 equ 5ch ; default CPM FCB's fcb2 equ 6ch ; BLKSZ equ 80h NOBLX equ 80h ;No of blocks in copy buffer --> 16K buffers ; ASEG .z80 org 100h ; ; Environment Definition ; if Z3ENV ne 0 ; ; External ZCPR3 Environment Descriptor ; jp START db 'Z3ENV' ;This is a ZCPR3 Utility db 1 ;External Environment Descriptor Z3EADR: dw Z3ENV START: ld hl,(Z3EADR) ;pt to ZCPR3 environment ; else ; ; Internal ZCPR3 Environment Descriptor ; MACLIB Z3BASE.LIB MACLIB SYSENV.LIB Z3EADR: jp START SYSENV START: ld hl,Z3EADR ;pt to ZCPR3 environment endif ; call z3init call z3vini ; ; Establish Locations for File Buffers ; call codend ld (bufad1),hl ld de,noblx*blksz add hl,de ld (bufad2),hl ; ; GET Command Line Options ; ld hl,ctail gclo: ld a,(hl) or a jp z,ztphlp ;Help screen if no command line inc hl cp ' ' jr z,gclo cp '/' ;If char 1 of cmd tail is '/' then ;help jp z,ztphlp dec hl ;hl points to first line of filename ld de,renfcb call fname or a ;invalid disk or user? jp z,baddu ;yes, abort ld (optptr),hl ;hl now points to the 2nd ; (option) token ; ; Process DU: bc still contains du: value from fname ; du: push bc pop de ;move cmdline selected du: into de call retud ;currently logged du: into bc call putud ;save same in memory drive: ld a,d ;drive code cp 0ffh ;use default? jr z,user ;yes, dflt already in b dec d ;no, so subtract 1 ld b,d ;and put in b user: ld a,e ;user code cp 0ffh ;use default? jr z,log ;yes, dflt already in c ld c,e ;no, transfer from e log: call logud ;from bc ; ; Load the command line parameter into the appropriate FCBS ; Only the filename is moved, program controls the type ; gfcb: ld hl,ftp2 ;fname obliterated renfcb's filetype ld de,renft ;so we restore it from fcb2, which is ld bc,3 ;preset to .COM ldir ; ld hl,renfn ;move filename (not type) from push hl ld de,fnm1 ;renfcb to iofcb1 ld bc,8 ldir ; pop hl ;renfn ld de,fnm2 ;move it to iofcb2 ld bc,8 ldir ; ; Print Banner ; call cls call eprint db 'Z3INStp Version ' db VERS/10+'0','.',(VERS mod 10)+'0',CR,LF db 'ZCPR3 ---> Turbo Pascal program Installer' db CR,LF,CR,LF,0 ; ld hl,(optptr) jp option ;process options on command line ; ; RENAME fn.COM TO fn.OLD ; comold: ld de,iofcb1 call f$EXIST jp nz,extest ; ren: ld HL,IOFCB1 ld DE,renfcb call F$RENAME jp z,fnf ; ; ; Open the called for Turbo File now renamed to fn.OLD ; for Input and create a new file called fn.COM open for output ; ld de,ioctl1 ;IO control block call FXI$OPEN ;open for input jp z,fnf ; ; Transfer first 2 128-byte blocks from bufad1 to ; Turbf1. This is the code that the program will modify ; ld hl,(bufad1) ;we just read it into here ld de,turbf1 ;temporary home ld bc,100h ldir ; ; Modify the code ; ld de,renfcb ;to print the correct filename call testp ;on msg if not Turbo file call ztpins call opo ;process H or R options ; ; Now transfer the modified code from turbf1 back to ; Bufad1, for writing back to the file ; ld hl,turbf1 ld de,(bufad1) ld bc,100h ldir ; ; Create a new file called fn.COM ; ld de,ioctl2 ;IO control block call FXO$OPEN ;open for output jp z,nodir ; ; This simple routine provides a byte-by-byte transfer ; between the modified memory buffer of the old file ; and the new one ; io: ld de,ioctl1 call fx$get jp z,clos ld de,ioctl2 call fx$put jp z,werr jr io clos: ld de,ioctl2 call FXO$CLOSE jp z,fcerr ld de,ioctl1 call FXI$CLOSE ; ; Say goodbye ; call gmsg ;report success and exit call getud ;restore du: to original ret ; The main body of code is contained in this subroutine ; here the TCAP and ENV information is put into the ; format used by Turbo-Pascal and the programs it compiles. ; ztpins: ld hl,tgxy ;zero out the tgxy section of the ld (hl),0 ;turbo buffer by zeroing its "length" byte ; ld ix,(envptr) ld a,(ix+2Bh) ld (speed),a ;transfer speed ld a,(ix+31h) ld (tcols),a ;transfer # columns ld a,(ix+32h) ld (trows),a ;transfer # rows vids: ld hl,tname ld (hl),10h ;a 16 byte string ld hl,(vidptr) ;pt to environment ld de,tname+1 ld bc,10h ldir ;move terminal name ;hl now points to arrow keys ; ld a,(narrfl) ;no arrows? or a jr z,arrows push hl ;save sys.env pointer ld hl,tup ;fill arrow area with zeroes ld b,4 ld a,0 call fillb pop hl ; inc hl inc hl inc hl inc hl ;hl now points to cls delay in env area jr mcls arrows: ld bc,4 ld de,tup ldir ;move arrow keys ;hl now points to cls delay in env area ; mcls: ld a,(hl) ;move it to the Turbo Interface page ld d,0 ld e,a ld (tclsd),de inc hl ;hl now points to the cursor motion delay ; ld a,(hl) ;move it to the Turbo Interface page ld d,0 ld e,a ld (tgxyd),de inc hl ;hl now points to the hi/low video delay ; ld a,(hl) ;move it to the Turbo Interface page ld d,0 ld e,a ld (thilod),de inc hl ;hl now points to cls in env area ; ld de,workbf ; call trak ;move cls string to temporary buffer ;hl now points to gxy in env area ld de,gxybuf call trak ;move GXY string to temp buffer ;hl now points to cleol in env area ld de,tcleol call trak ;move Clreol String to turbo page ;hl now points to hi vid in env area ld de,thivid ; call trak ;move hi vid string to turbo page ;hl now points to lovid ld de,tlovid call trak ;move lo vid string to turbo page ;hl now points to init String ld de,tini call trak ;move init string to turbo page ;hl now points to exit string ld de,texi call trak ;move exit string to turbo page ; ; handle the clear screen/home cursor sequence ; clrhom: ld hl,workbf ;temporary buffer for clr-home ld a,(hl) cp 6 jr nc,tolong ;if more than 5 chars have to split it ld b,0 ;not too long, simply transfer to tcls ld c,a inc bc ;don't forget the length byte ld de,tcls ldir xor a ;zero out any unneeded home string ld (thome),a jr pgxy tolong: ;String too long for turbo Cls space ;so try to break down into two esc sequences ld b,0 ld c,2 ;start at 3rd character after first ESC+char beglp: inc bc ld hl,workbf ld a,(hl) ;if C > length-byte at workbuf, split cp c ;randomly (no 2nd ESC found) jr c,split add hl,bc ld a,(hl) ;examine pointed-to byte cp 1Bh ; is it ESC? jr nz,beglp ;no so get next byte dec bc ;Escape found, now transfer 2nd half of seq to ;thome ld de,workbf push de pop hl add hl,bc ld a,(de) sub c push bc ld (thome),a ld c,a ld de,thome+1 ldir pop bc ;transfer 1st half to tcls ld a,c ld (tcls),a ld hl,workbf+1 ld de,tcls+1 ldir jr pgxy split: ld a,5 ;randomly split the too long sequence ld (tcls),a ;into "clear" and "home" strings in ;unlikely event that 2nd ESC seq. ld b,0 ;is not found ld c,a ld hl,workbf+1 ld de,tcls+1 ldir ld a,(Workbf) sub 5 ld (thome),a ld c,a ld hl,workbf+6 ld de,thome+1 ldir ; ; parse the GXYBUF to Turbo format ; pgxy: ld hl,gxybuf ;capitalize the GXYSTR to make subsequent call capstr ;work easier ; ld b,0 ld c,1 ; ; find the first "command character" ; beglp1: ld e,1 ;flag for a "less than" test call while jp c,endlp1 ld hl,gxybuf add hl,bc ld a,(hl) cp '%' ;command char? jr nz,endcas ;if not then skip dec hl ld a,(hl) cp '\' ;if so, is the previous char jr z,endcas ;the "literal" flag? Skip if so. inc hl inc hl ;now we look at the following byte ld a,(hl) cp 'R' ;Reverse column and row? jr nz,testi ld a,true ld (revflg),a jr endcas testi: cp 'I' ;cursor home = (1,1)? jr nz,other ld a,true ld (start1),A jr endcas other: cp '.' jr z,exit cp '+' jr z,exit cp '2' jr z,exit cp '3' jr z,exit cp 'D' jr nz,endcas exit: inc bc jr endlp1 endcas: inc bc jr beglp1 endlp1: ld (ptr1),bc ; ld c,1 beglp2: ld e,0 ;<= call while jr c,endlp2 call while2 jr z,endlp2 call addchr jr beglp2 endlp2: ;here we determine if terminal uses ld bc,(ptr1) ld hl,gxybuf ;binary addressing or not. add hl,bc ld a,(hl) cp '+' ;binaries branch to btrue, others jr z,btrue ;to bfalse cp '.' jr z,btrue cp '2' jp z,bfalse cp '3' jp z,bfalse cp 'D' ;Turbo cannot handle this type of jp z,nocan ;cursor ld A,(tisbin) or a jp z,bfalse btrue: ld a,1 ld (tisbin),a ld de,ofs1 call ofsfig ; beglp3: ld e,0 ;<= call while jr c,endlp3 call while2 jr z,endlp3 call addchr jr beglp3 endlp3: inc bc ld de,ofs2 call ofsfig beglp4: ld e,0 ;<= call while jr c,endlp4 call addchr jr beglp4 endlp4: jp endlp6 bfalse: ;decimal cursor addressing ld a,0 ld (tisbin),a call nbinfl ld de,ofs1 call ofsfd beglp5: ld e,0 ;<= call while jr c,endlp5 call while2 jr z,endlp5 call addchr jr beglp5 endlp5: inc bc call nbinfl ld de,ofs2 call ofsfd inc bc beglp6: ld e,0 ;<= call while jr c,endlp6 call addchr jr beglp6 endlp6: ;load column and row biases ;and the markers that direct turbo to them ld a,(revflg) ;Is column First? or a jr z,nrvrs ;if not, do in normal fashion rvrs: ;but we aren't normal ld a,(ofs1) ;take offset #1 ld (tcofs),a ;put it in the column "column" ld a,(ofs2) ;take offset #2 ld (trofs),a ;put it in the row "column" ld a,(plc1) ;take place marker #1 ld (tcpla),a ;put it in the column place ld a,(plc2) ;take place marker #2 ld (trpla),a ;put it in the rows' place jr bot ; nrvrs: ;we are normal ld a,(ofs1) ;take offset #1 ld (trofs),a ;put it in the row "column" ld a,(ofs2) ;take offset #2 ld (tcofs),a ;put it in the column "column" ld a,(plc1) ;take place marker #1 ld (trpla),a ;put it in the row place ld a,(plc2) ;take place marker #2 ld (tcpla),a ;put it in the column place ; bot: ret ; ; Subroutines called by the ztpins subroutine ; while: ;stops the loop when hl points ;past the end of the gxy buffer ld a,(gxybuf) ld d,a ld a,e ;e reg must be set to 0 for a <= test or a ;or nz for an = test jr z,lesseq dec d lesseq: ld a,d cp c ret ;carry flag set means time to end loop ; while2: ld hl,gxybuf ;stops the loop when hl points to add hl,bc ;a '%' and preceding char was not '\' ld a,(hl) cp '%' ret nz dec hl ld a,(hl) cp '\' jr z,nonz ;here we are simply reversing the zero xor a ;flag for sake of consistency jr retp nonz: xor a cpl or a retp: ret ;zero flag set means time to end loop ; addchr: ld hl,gxybuf ;this routine adds the char pointed to add hl,bc ;at gxybuf + c to the turbo tgxy string ld a,(hl) cp '\' jr z,nadd push bc push af ld hl,tgxy ld b,0 ld a,(tgxy) inc a ld (hl),a ld c,a add hl,bc pop af ld (hl),a pop bc nadd: inc bc ret ; ofsfig: ld hl,gxybuf ;routine in which the binary offsets are add hl,bc ;calculated and stored in the Turbo Interface ex de,hl ;page ld (hl),0 ld a,(de) cp '+' jr nz,noadd inc de ld a,(hl) push hl ld l,a ld a,(start1) add a,l ld l,a ld a,(de) add a,l pop hl ld (hl),a noadd: ex de,hl ld hl,tgxy ld a,(hl) push bc ld b,0 inc a inc de inc de ld (de),a ld (hl),a ld c,a add hl,bc ld (hl),0 pop bc inc bc ;advance to the offset inc bc ;advance past the offset ret ; nbinfl: ld hl,gxybuf ; put the proper # of zeroes into the decimal add hl,bc ; addressing sequence push bc ld a,(hl) ;hl has # of decimal digits sub 30h ;ascii --> binary ld b,a ;b has # of digits for fillb call ld a,(tgxy) ;a has curr. lgth of string ld e,a ;e has it too add a,b ;a has sum of both ld (tgxy),a ;put it in the turbo gxy string ld d,0 inc e ld hl,tgxy add hl,de ;hl has where to begin ld a,'0' ;a has fill character - '0' call fillb pop bc ret ; ofsfd: ;figure offset and place for non-binaries ;de contains the addr of the offset ;place marker is two bytes past push bc ld hl,start1 ldi ;loads 1 if home is (1,1), 0 if (0,0) inc de ;de now points to place marker ld hl,tgxy ldi ;loads current length of the tgxy String pop bc inc bc ret ; ; Transfer bytes until a zero is encountered and preced new string ; with byte indicating its length ; trak: push de ;save the ptr to first byte of dest inc de ;for length ld bc,0 mov0: ld a,(hl) or a jr z,fin ldi ;advance source & dest one byte & copy jr mov0 ;stop if byte = 0 fin: inc hl dec bc ld a,c cpl pop de ;restore the ptr to the first (length) byte ld (de),a ;save the length ret ; ; PROCESS Command Line Options ; opo: ld a,(novids) ;the 'O' option or a jr z,opr xor a ;zero accumulator ld (thivid),a ;now zero the first bytes of hi and ld (tlovid),a ;low intensity strings (length = 0) ret ; opr: ld a,(swvids) ;the 'R' option or a ret z ; ; swap the high and low video control strings ; ld hl,thivid ld de,workbf push de push hl ld bc,6 ldir ; ld hl,tlovid pop de ;thivid to de push hl ld bc,6 ldir ; pop de ;tlovid to de pop hl ;workbf to hl ld bc,6 ldir ret ; ; OPTION processor ; option: ld a,(hl) ;on entry,hl points to beg. of options list ; in cmd line or a ;eol? jp z,comold ;end of option line,"ret" to program inc hl ;point to next char push hl ;save it ld hl,opttab ;point to option table call cmdpro pop hl ;return next char jr option ; cmdpro: ld b,a ;put option char into b cmdp1: ld a,(hl) ;command letter from table or a ;done? jr z,cmdp2 ; cp b ;command line option = table entry? jr nz,cmdp3 cmdp2: inc hl ld e,(hl) inc hl ld d,(hl) ex de,hl jp (hl) cmdp3: inc hl inc hl inc hl jr cmdp1 ; ; option command table ; opttab: defb ' ' ;done defw opts defb 'A' ;no arrows defw opta defb 'H' ;no highlight defw opth defb 'R' ;hi/low reverse defw optr defb 0 ;end of table defw ztphlp ;bad option - call help exit ; ; SKIP OPTION ; opts: ret ; ; Arrows option opta: ld a,(narrfl) cpl ld (narrfl),a ret ; ; No highlight option opth: ld a,(novids) cpl ld (novids),a ret ; ; Reverse high/low video option optr: ld a,(swvids) cpl ld (swvids),a ret ; ; Message routines for file operations ; rerenm: ;rename file back to .COM ld hl,renfcb ld de,iofcb1 call f$rename ret pdu: ;print du: ld a,b add a,'A' call cout ld a,c call pafdc ld a,':' call cout ret ; pdufn: call retud inc de call pdu call pfn2 ret ; pdufn1: call eprint db CR,LF,'File ',0 call pdufn ret ; gmsg: ld de,iofcb2 call pdufn1 call eprint db ' installed',CR,LF,0 ret ; ; Test that file is a Turbo-Pascal generated .COM file ; vers 2.0 or higher before proceeding ; testp: push de ld hl,turbf1+18h ld de,borl ld b,0Bh call compb pop de jr nz,nturb ld a,(turbf1+16h) cp '4' jr c,nturb ret nturb: call pdufn1 call eprint db ' is not a Turbo-Pascal generated .COM file',CR,LF,0 call rerenm jp 0 borl: db 'BORLAND Inc',0 baddu: call eprint db CR,LF,'Improper Drive or User - ',0 ld a,b dec a call pdu call eprint db cr,lf,0 jp 0 fnf: call pdufn1 call eprint db ' not Found',CR,LF db 0 jp 0 ; nocan: call eprint DB CR,LF db CR,LF,'ZTPINS cannot install, nor can the' db CR,LF,'Turbo-Pascal video system accept terminals' db CR,LF,'that use variable length decimal addressing' db CR,LF,0 call rerenm jp 0 nodir: call eprint db CR,LF,'No Room in directory',CR,LF db 0 call rerenm jp 0 ; werr: call eprint db CR,LF,'Disk Write Error',CR,LF db 0 call rerenm jp 0 ; fcerr: call eprint db CR,LF,"Can't Close File ",0 call pdufn call eprint db CR,LF,0 db 0 call rerenm jp 0 ; ; File fn.old exists. Ask user if deletion wanted ; If yes, delete. If no, abort ; extest: call pdufn1 call eprint db ' already exists. Delete it? (Y/N) ',0 call capine cp 'Y' jp nz,0 ;abort if no delete dec de call f$delete ;delete and continue jp ren ; ;ZTPHLP Help Screen ; ztphlp: call eprint db cr,lf,'Syntax:' db cr,lf,' Z3INSTP du:filename o.' db cr,lf,' [where filename refers to a Turbo-Pascal-created' db cr,lf,' COM file (vers. 2.0 or higher) --' db cr,lf,' filetype of .COM assumed]' db cr,lf db cr,lf,'Options:' db cr,lf,' A -- Install Arrow Keys' db cr,lf,' H -- No Highlighting' db cr,lf,' R -- Reverse Highlight/Normal Video' db 0 jp 0 ; ; Data Buffers ; REVFLG: defb false ;column /row reversal flag START1: defb false ;true = home = (1,1). false = (0,0) NOVIDS: defb false ;no high/low intensity flag SWVIDS: defb false ;reverse high/low intensity flag NARRFL: defb true ;no arrows flag (default - yes, arrows) OFS1: defb 0 ;temp storage for row & col offsets OFS2: DEFB 0 ; PLC1: defb 0 ;temp storage for vector to place offset PLC2: defb 0 ; PTR1: defw gxybuf ;internal pointer into gxybuf OPTPTR: defs 2 ;pointer to options on command line GXYBUF: defs 10h ;temp buffer for GXYStr; WORKBF: defs 10h ;temp buffer for swapping hi/low intensity ; ; TURBO Interface Page ; ; the following 256 bytes of data is the buffer into which the ; Standard Interface (First Page) of all Turbo - Created .COM ; files is read, and from which it is read back to the newly installed ; file. ; TURBF1: defs 24h ;first 24 bytes of Turbo Page 1 SPEED: defs 01h ;clock speed in mHz defs 2Eh ;free space TNAME: defs 11h ;terminal name string ; ; The next four items are not part of the Standard Turbo-Pascal Interface. ; Since the Turbo System allows for a twenty character name and the Z3 TCAP ; allows for only sixteen (+1 for length byte = 11h) we have exactly the ; four bytes we need to place the arrow keys where we know we will not be ; disturbing anything, since Turbo expects, if anything, characters in a ; terminal name. Since the length byte will always be <=10h these ; characters will never be touched ; TUP: defs 01h ;up arrow TDOWN: defs 01h ;down arrow TRIGHT: defs 01h ;right arrow TLEFT: defs 01h ;left arrow ; TCOLS: defs 01h ;# of cols byte TROWS: defs 01h ;# of rows byte defs 01h ;free byte TINI: defs 10h ;CRT Initialization String TEXI: defs 10h ;CRT Exit String TGXY: defs 10h ;GOTOXY String TISBIN: defb 1 ;binary flag 0=decimal,1=binary TCOFS: defs 01h ;Column offset byte TROFS: defs 01h ;ROw offset byte TCPLA: defs 01h ;Position within TGXY where the column offset ;is to be inserted into the TGXY template TRPLA: defs 01h ;Position within TGXY where the row offset ;to be inserted into the TGXY template TGXYD: defs 02h ;16 bit value for Delay on TGXY calls TCLS: defs 06h ;Clear screen string THOME: defs 06h ;Home cursor string TINSLN: defs 06h ;Insert Line String TDELLN: defs 06h ;Delete Line String TCLSD: defs 02h ;16 bit value for Delay on CLS calls TCLEOL: defs 06h ;Clear To End of Line String ;Below two items reversible with ;the 'R' flag THIVID: defs 06h ;Bright Video String TLOVID: defs 06h ;Dim Video String THILOD: defs 02h ;16 bit value for Delay on Hi/Lo Vid Calls defs 30h ;Free space ; ; FXIO Control Blocks ; ; Original File - Rename to fn.OLD ; IOCTL1: defb noblx ;numberr of 128-byte blocks defs 1 defs 2 defs 2 bufad1: defs 2 ;address of io buffer, det'd by codend IOFCB1: defs 1 FNM1: defs 8 FTP1: defb 'OLD' defs 24 ; ; New File - fn.COM ; IOCTL2: defb noblx ;numberr of 128-byte blocks defs 1 defs 2 defs 2 bufad2: defs 2 ;address of io buffer, det'd by codend IOFCB2: defs 1 FNM2: defs 8 FTP2: defb 'COM' defs 24 ; ; Buffer FCB for Renaming ; RENFCB: defs 1 RENFN: defs 8 RENFT: defb 'COM' DEFS 24 end