; ; WSPAT-DM.ASM ; ; Combines WSPATCH.ASM and WS-ZCPR.ASM into one handy patch file ; ; WSPATCH.ASM allows WordStar to use the ZCPR3 TCAP segment to achieve ; "terminal independence" (In other words, no need to patch it every time ; you use change terminals). ; ; WS-ZCPR.ASM allows WordStar to look for the *.OVR files on another user ; area than the current one. Currently this is set for A15:. ; ; I have minimized any changes or deletions to these files, but some small ; changes were required to WS-ZCPR.ASM in order to relocate it. The ; length of the SAVE command used after the .HEX patch file is read is ; currently 7Ah records (remember, ZCPR3 understands hex parameters for the ; SAVE command). ; ; Thanks for writing these patches, guys. They sure take a lot of the ; headaches out of using WordStar! ; ; -David McCord 1-27-85 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; WSPATCH.ASM ; ; ; ; Patch for Wordstar 3.0 running under ; ; The Echelon 'Z' System. Modifies ; ; Wordstar to use the current terminal ; ; characteristics defined in Z3TCAP. ; ; ; ; Copyright (c) 1985 by Dennis Wright ; ; and Echelon, Inc. ; ; ; ; Contains selected routines from ; ; Echelon's VLIB. ; ; ; ; VLIB is Copyrighted by Richard Conn ; ; and Echelon Inc. ; ; ; ; Note: It may be possable to install ; ; this patch on other versions of Word- ; ; Star if the equates below are changed ; ; to agree with versions' addresses. ; ; ; ; WordStar is a trademark of ; ; MicroPro International Corporation ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; MACLIB Z3BASE ; ; WordStar 3.0 USER1 Patch Addresses from Installation manual. ; TNAME EQU 0190H ; Terminal name (not documented in manual). HITE EQU 0248H ; Number of lines. WID EQU 0249H ; Number of columns. ERAEOL EQU 026DH ; Erase to end of line. LINDEL EQU 0274H ; Delete line. LININS EQU 027BH ; Insert line. IVON EQU 0284H ; Highlighting on. IVOFF EQU 028BH ; Highlighting off. DELMIS EQU 02AFH ; Delay for non-cursor set functions. TRMINI EQU 0292H ; Terminal init string. TRMUNI EQU 029BH ; Terminal de-init string. UCRPOS EQU 0264H ; User cursor positioning routine. INISUB EQU 02A4H ; User init routine. MORPAT EQU 02E0H ; WordStar user patch area. PBGMEM EQU 035CH ; Contains beginning of text buffer address. OCHAR EQU 0267H ; Contains address of WordStar outchr routine. ; ; The following equate is the base address of the patch routines. ; PATCH EQU 7849H ; Get this address from original PBGMEM. ; ORG UCRPOS ; User-patchable cursor positioning routine. JMP XYPOS ; Use VLIB cursor positioning routine. ; ORG INISUB ; User-patchable init subroutine. JMP INIT ; Use patch init routine. ; ORG MORPAT ; WordStar user patch area. INIT: LXI H,Z3ENV ; Point to 'Z' System environment descriptors. LXI D,80H SHLD ENVPTR ; Save pointer. PUSH H ; Save for later. DAD D ; Displace to Z3TCAP. SHLD VIDPTR ; Save pointer. LHLD OCHAR ; Address of WS outchr routine is kept here. SHLD COUT1+1 ; Inline modify patch cout to use WS outchr. POP H ; Restore env pointer. LXI D,47 ; Offset to Z3TCAP crt select byte. DAD D MOV A,M ; Get it. LXI D,2 ; Set offset to crt 0 data area. ORA A ; Crt 0? JZ GETCRT ; Yes move crt 0 data to WS patch area. LXI D,5 ; No, move crt 1 data. GETCRT: DAD D ; Offset to selected Z3TCAP crt data area. MOV A,M ; Get Z3TCAPs terminal width. STA WID ; Patch WS width. INX H ; Bump to Z3TCAPs number of lines. MOV A,M ; Get number of lines. STA HITE ; Patch WS hite. XRA A ; Clear following WS patchs. STA LINDEL ; Line delete STA LININS ; ..and line insert (we don't support these). LHLD VIDPTR ; Get Z3TCAP pointer. LXI D,22 ; Offset to CE delay. DAD D MOV A,M ; Get CE delay. STA DELMIS ; Patch WS misc delay. INX H CALL VIDSKP ; Skip past CL string. CALL VIDSKP ; Skip past CM string. LXI D,ERAEOL ; Point to WS eol string. CALL FILL ; Replace with Z3TCAPs eol string. LXI D,IVON ; Point to WS turn on highlighting. CALL FILL ; Replace with Z3TCAPs string. LXI D,IVOFF ; Point to WS turn off highlighting. CALL FILL ; Replace with Z3TCAPs string. LXI D,TRMINI ; Point to WS terminal init string. CALL FILL ; Replace with Z3TCAPs string. LXI D,TRMUNI ; Point to WS terminal de-init string. CALL FILL ; Replace with Z3TCAPs string. CALL NAMIT ; Replace WS terminal name with Z3TCAPs. RET ; We're done. ; ORG PBGMEM ; The beginning of the text memory is DW BEGMEM ; ..moved up to accommidate our patch. ; ORG PATCH ; Extended patch area. NAMIT: LHLD VIDPTR ; Point to Z3TCAPs terminal name LXI D,TNAME ; ..and WS terminal name. MVI C,16 ; Move our 16 bytes. NFILL: MOV A,M STAX D INX H INX D DCR C JNZ NFILL XCHG NFILL2: MOV A,M ; Pad out the remainder with spaces. CPI 0FH ; Till this. RZ ORA A ; Or zero. RZ MVI A,20H MOV M,A INX H JMP NFILL2 ; ; This routine moves Z3TCAP data into the WordStar patch area. ; Because WordStar requires the number of bytes for each entry ; we must count the bytes we patch and place the number at the ; beginning of the patch. ; FILL: PUSH D MVI C,-1 ; Set byte counter. FIL1: INX D MOV A,M ; Replace WS data with Z3TCAPs. STAX D INX H INR C ORA A ; Reached end? JNZ FIL1 POP D ; Yes, restore pointer to first byte. MOV A,C ; Insert number of bytes in string. STAX D RET ; COUT: PUSH H PUSH D COUT1: CALL 0000H ; This is inline modified by the INIT. POP D ; Routine to call WordStars outchr POP H ; ..routine. RET ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; The following routines are from VLIB by Richard Conn. ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; GOTO XY (From VLIB) ; HL = Row/Col, with Home=0/0 ; Return with A=0 and Zero Flag Set if not done ; XYPOS: MOV D,L ; Swap row & column MOV E,H ; ..for vlib XCHG GOTOXY: PUSH B ; Save regs PUSH D PUSH H LHLD VIDPTR ; Pt to environment MOV A,M ; No terminal? CPI ' '+1 JC ERR LXI D,15H ; Pt to CM delay DAD D MOV A,M ; Get it STA CMDELAY ; Save it INX H ; Pt to CL string INX H CALL VIDSKP ; Skip CL string MOV A,M ; Get first char of CM string ORA A ; If no string, error JZ ERR XCHG ; DE=address of CM string POP H ; Get coordinates in HL PUSH H CALL GXY ; Output xy string with delay LDA CMDELAY ; Pause CALL VIDELAY POP H ; Done POP D POP B XRA A ; Return NZ DCR A RET ERR: POP H ; Done POP D POP B XRA A ; Return Z RET ; ; GOTOXY (From VLIB) ; On input, H=Row and L=Column to Position To (0,0 is Home) ; On input, DE=address of CM string ; GXY: XRA A ; Set row/column STA RCORDER ; Row before column STA RCBASE ; Add 0 to base ; ; Cycle thru string ; GXYLOOP:LDAX D ; Get next char INX D ; Pt to next ORA A ; Done? RZ CPI '%' ; Command? JZ GXYCMD CPI '\' ; Escape? JZ GXYESC CALL COUT ; Send char JMP GXYLOOP ; ; Escape - output following byte literally ; GXYESC: LDAX D ; Get next char CALL COUT ; Output literally INX D ; Pt to next JMP GXYLOOP ; ; Interpret next character as a command character ; GXYCMD: LDAX D ; Get command char INX D ; Pt to next CPI 'd' ; %d JZ GXYOUT1 CPI '2' ; %2 JZ GXYOUT2 CPI '3' ; %3 JZ GXYOUT3 CPI '.' ; %. JZ GXYOUT4 CPI '+' ; %+v JZ GXYOUT5 CPI '>' ; %>xy JZ GXYGT CPI 'r' ; %r JZ GXYREV CPI 'i' ; %i JZ GXYINC CALL COUT ; Output char if nothing else JMP GXYLOOP ; ; Set row/col home to 0,0 ; GXYINC: MVI A,1 ; Set rcbase to 1 STA RCBASE JMP GXYLOOP ; ; Reverse order of output to column then row (default is row then column) ; GXYREV: MVI A,1 ; Set column and row order STA RCORDER JMP GXYLOOP ; ; Command: >xy ; If value of row/col is greater than x, add y to it ; GXYGT: CALL GETVAL ; Get value MOV C,A ; Save value LDAX D ; Get value to test INX D ; Pt to next CMP C ; If carry, value>x JNC GXYGT1 LDAX D ; Get value to add ADD C CALL PUTVAL ; Put value back GXYGT1: INX D ; Pt to next JMP GXYLOOP ; Resume ; ; Command: +n ; Add n to next value and output ; GXYOUT5:LDAX D ; Get value to add INX D ; Pt to next MOV B,A ; Save in B CALL GETVAL ; Get value ADD B ; Add in B CALL COUT ; Output value RCMARK: LDA RCORDER ; Mark output ORI 80H STA RCORDER JMP GXYLOOP ; ; Command: . ; Output next value ; GXYOUT4:CALL GETVAL ; Get value CALL COUT ; Output value JMP RCMARK ; ; Command: 3 ; Output next value as 3 decimal digits ; GXYOUT3:CALL GETVAL ; Get value MVI B,100 ; Output 100's MVI C,1 ; Leading zeroes CALL DIGOUT GXYOT3: MVI B,10 ; Output 10's MVI C,1 ; Leading zeroes GXYOT2: CALL DIGOUT ADI '0' ; Output 1's CALL COUT JMP RCMARK ; ; Command: 2 ; Output next value as 2 decimal digits ; GXYOUT2:CALL GETVAL ; Get value JMP GXYOT3 ; ; Command: d ; Output next value as n decimal digits with no leading zeroes ; GXYOUT1:CALL GETVAL ; Get value MVI B,100 ; Output 100's MVI C,0 ; No leading zeroes CALL DIGOUT MVI B,10 ; Output 10's MVI C,0 ; No leading zeroes JMP GXYOT2 ; ; Return next value in A ; GETVAL: LDA RCORDER ; Get order flag ORA A ; Already output the first value? JM GETVAL2 ANI 1 ; Look at lsb JZ GETVALR ; If 0, row first GETVALC:LDA RCBASE ; Get base offset ADD L ; Get column RET ; GETVALR:LDA RCBASE ; Get base offset ADD H ; Get row RET ; GETVAL2:ANI 1 ; Look at lsb JZ GETVALC JMP GETVALR ; ; Store A as next value ; PUTVAL: MOV C,A ; Save value LDA RCORDER ; Get order flag ORA A ; Already output the first value? JM PUTVAL2 ANI 1 ; Look at lsb JZ PUTVALR ; If 0, row first PUTVALC:MOV L,C ; Set column RET ; PUTVALR:MOV H,C ; Set row RET ; PUTVAL2:ANI 1 ; Look at lsb JZ PUTVALC JMP PUTVALR ; ; Output A as decimal digit char ; B=Quantity to Subtract from A, C=0 if no leading zero ; DIGOUT: PUSH D ; Save DE MVI D,'0' ; Char DECOT1: SUB B ; Subtract JC DECOT2 INR D ; Increment char JMP DECOT1 ; DECOT2: ADD B ; Add back in PUSH PSW ; Save result MOV A,D ; Get digit CPI '0' ; Zero? JNZ DECOT3 MOV A,C ; Get zero flag ORA A ; 0=no zero JZ DECOT4 DECOT3: MOV A,D ; Get digit CALL COUT ; Print it DECOT4: POP PSW ; Get A POP D ; Restore DE RET ; ; GXY Buffers ; RCORDER:DS 1 ; 0=row/col, else col/row RCBASE: DS 1 ; 0=org is 0,0, else org is 1,1 CMDELAY:DS 1 ; Number of milliseconds to delay for CM ; ; VIDELAY pauses for the number of milliseconds indicated by the A ; register. VIDELAY assumes a ZCPR3 environment and uses it to determine ; processor speed. ; VIDELAY:PUSH PSW ; Save regs PUSH B PUSH D PUSH H MOV C,A ; Save count in C ORA A ; No delay? JZ DONE LHLD ENVPTR ; Pt to environment LXI D,2BH ; Offset to processor speed DAD D MOV A,M ; Get processor speed ORA A ; Zero? JNZ VID1 MVI A,4 ; Assume 4 MHz VID1: MOV B,A ; Processor speed in B VID2: PUSH B ; Delay 1 ms CALL DELAY POP B DCR C ; Count down JNZ VID2 DONE: POP H ; Restore regs POP D POP B POP PSW RET ; ; Delay 1 ms at Clock speed ; DELAY: CALL DEL1 ; Delay 1 ms at 1MHz DCR B ; Count down clock speed JNZ DELAY RET ; ; Delay 1 ms at 1MHz ; DEL1: MVI C,20 ; 20 loops of 51 cycles each ~ 1000 cycles DEL1A: XTHL ; 18 cycles XTHL ; +18 = 36 cycles DCR C ; + 5 = 41 cycles JNZ DEL1A ; +10 = 51 cycles RET ; ; VIDSKP - Skip over video string pted to by HL; pt to byte after string ; VIDSKP: MOV A,M ; Get next char INX H ; Pt to next ORA A ; Done if zero RZ CPI '\' ; Literal value? JNZ VIDSKP ; Continue if not INX H ; Pt to after literal value JMP VIDSKP ; ; ZCPR3 Pointer save area ; VIDPTR: DS 2 ; First byte of termcap entry ENVPTR: DS 2 ; 'Z' System environment package. ; ;****************************************************************************** ; title 'ZCPR II patches for Wordstar Overlay Files' ; ;****************************************************************************** ; ; WS.COM can be made to work with ZCPR II 04/17/84 ; ; You know how irritating the @@@@'s get when you try to open a file in a ; user area that does not have the *.OVR files present ????? I had been ; pipping everything to a given user area to edit and then back again. ARRGH. ; To make a long story short, a few hours with DDT revealed several key areas ; within WS.COM that should interest a true hacker. Seems as how the FCB for ; WSOVLY1.OVR is at 364Dh, WSMSGS.OVR is at 3784h, the only BDOS entry vector ; is at 1823h and finally, the area between 02E0h and 035Bh inclusive is a ; safe patch area. Well, well well....... A real simple kludge of mushware will ; set a default drive and user area every time WS.COM looks for an *.OVR file ; and then set it back again after the DOS operation. The infernal thing can ; find the *.OVR files from any drive and user area A dream come true and ; it is really painless...... ; ; ;////////////////////////////////////////////////////////////////////////////// ;\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ ; ; ; Copyright (c) 1984 .... Oak Brook Design ; ; All rights reserved. ; ; Permission is hereby granted to copy and distribute this ; program for any non-commercial purpose. Any use of this ; material for commercial advantage without prior written ; consent of John P Sojak acting on behalf of Oak Brook Design ; is prohibited. ; ;\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ ;////////////////////////////////////////////////////////////////////////////// ; ; You MUST examine your Wordstar under SID or DCON to verify several ; locations within the memory image.... > denotes a console input ; ; ;> A0>DCON ; ; --- dcon banner and some other gook --- ; ;> #F100 5000 00 ; clear the ram out ;> #IWS.COM ; set up for read ;> #R ; ;> #P0000 ; set a break at warmboot ;> #G100 ; ; --- you will get the usual WS menu.... Just eXit with 'X' ; ; 01 PASS 0000 ; -Z-E- A=00 B=1800 D=0006 H=3441 S=3443 P=0000 ; ----- A'=00 B'=00 D'0000 H'0000 X=0000 Y=0000 JMP XXXX ; *XXXX ; ;> #D3780 3790 ; 3780: 00 00 00 00 03 57 53 47 53 20 20 4F 56 52 .....WSMSGS OVR ; 3790: 00 \ ; there it is... ; ; here it is... ;> #D3640 3660 / ; 3640: 00 00 00 00 00 00 00 00 00 00 00 00 57 53 ..............WS ; 3650: 4F 56 4C 59 31 20 4F 56 52 00 00 00 00 00 OVLY1 OVR....... ; 3660: 00 . ; ; ;> #L1820 ; 1820 INX H ; 1821 PUSH D ; 1822 PUSH H ; 1823 CALL 0005 --- here is the DOS entry @ 1823h ; 1826 POP H ; 1827 POP D ; 1829 XTHL ; 182A RET ; ;> #-P ; clear the pass point at warmboot ;> #G0 ; and exit to CCP ; ; A0> ; ; Now you can assemble the file, I used Mac. M80 / L80 has a problem with ; extranious 00 between the two ORGs. Dont use it. ; ; Use the same procedure to load WS.COM into memory again but this time, ; dont set any pass point at 0000. Set up for the read with IWSUSER.HEX ; and then do a R to overlay the hex file. Exit to the CCP and then ; ; A0>SAVE 64 WS-TEST.COM ; ; Thats it..... WS will, or should now, work with all user areas and ; drives. ; ; ;****************************************************************************** ; bdos equ 0005 ; DOS entry ; ;============================================================================== ; The WSMSGS.OVR fcb... msgfcb equ 3784h ;============================================================================== ; The WSOVR1.OVR fcb... ovrfcb equ 364Dh ;============================================================================== ; ; set these to your desired default drive and user for the *.OVR files ovruser equ 15 ; User area... 0-31 ovrdrv equ 01 ; Drive Spec... A:-> 01, B:-> 02 etc ; ;****************************************************************************** ; ; the patcher starts here ; ;****************************************************************************** ; bdosvec equ $ ; intercept the call to DOS before actual entry ... mov a,c sta nowfun cpi 15 ; open file jz chkit cpi 16 ; close jz chkit cpi 17 ; search first jz chkit cpi 18 ; search next jz chkit cpi 20 ; read next jz chkit cpi 33 ; read random jz chkit ; pass the call on without further hassle, its not for us passit: jmp bdos ;****************************************************************************** ; ; check for the two OVR fcb addresses, set if not found ; chkit: mvi a,(LOW msgfcb) ; fcb for WSMSGS.OVR cmp e jnz nogood mvi a,(HIGH msgfcb) cmp d jz good nogood: mvi a,(LOW ovrfcb) ; fcb for WSOVLY1.OVR cmp e jnz bdos mvi a,(HIGH ovrfcb) cmp d jnz bdos ; found one of the FCB's... set the user and drive good: push d ; save the FCB mvi c,32 ; get the current user number mvi e,0FFh call bdos ani 00111111b sta user mvi c,32 mvi e,ovruser ; find the overlays in this user call bdos pop d ; now fix the drive specification ldax d sta nowdrive mvi a,ovrdrv ; find the overlays on this drive stax d lda nowfun ; original function call mov c,a push d call bdos pop d push psw ; save the result flags for later lda nowdrive stax d mvi c,32 ; set the old user... maybe funnies lda user mov e,a push d ; save original FCB ... call bdos pop d ; ... restore lda nowfun mov c,a ; restore c pop psw ; get error flags ret ; back to Wordstar user: db 15 nowdrive: db 00 nowfun: db 00 BEGMEM EQU $ ; org 1823h ; remove the existing DOS hook call bdosvec END