; Program:      WordStar Shell Modification Patches
; Author:       Jay Sage
; Date:         August 7, 1988

; Patches to make the WordStar Release 4 'R' command operate as a ZCPR2-type
; shell.  Several routines in WS.COM and WS.OVR must be changed.
;
; 1. WordStar must be prevented from pushing its name onto the Z-System shell
;    stack.  However, a flag that is used by the 'R' command to determine how
;    to operate must be set as if WS4 had set itself up as a shell.
;
; 2. The popping of the shell stack when WS4 terminates must be disabled.
;
; 3. The user input to the prompt from the 'R' command must be handled
;    differently.  A command to reinvoke WS4 must be appended to the user's
;    input, and then any commands pending in the multiple command line buffer
;    must be added as well.  The result is then placed into the command line
;    buffer.  If overflow occurs, the user command is ignored, and an error
;    message is displayed until a key is pressed.  The chaining command is of
;    the form ";DUU:WSNAME ,".  The comma at the end of the command tail is
;    used as a signal that WS4 was invoked as a ZCPR2 shell.
;
; 4. An optional patch can be included to defeat the use of the path for
;    searching for the overlay files.  An internal path can be specified.

;------------------------------------------------------------

no      equ     0
yes     equ     not no

intpath equ     yes             ; Use internal path to find OVR files?

morpat  equ     045bh           ; Patch area
namebuf equ     morpat+128-16   ; Keep program ";DUU:PROGNAME ,<0>"
                               ; ..at end of patch area
envoff  equ     0aa4h           ; WordStar ENV offset routine
zflag   equ     2200h           ; Z-System running flag
rcmdbuf equ     1f38h           ; Buffer for 'R' command input
rcmd    equ     rcmdbuf+1       ; Beginning of user's command line
clrscr  equ     0386h           ; Clear screen character sequence
scrnfn  equ     17c7h           ; Routine to perform screen functions
conout  equ     0280h           ; Routine to output character in A to console

bell    equ     07              ; Bell character

;----------------------------------------------------------------------
;
;                       PATCHES TO WS.OVR
;
;----------------------------------------------------------------------

; Modifications to the code that pushes WordStar onto the shell stack.

; This patch prevents the WordStar shell entry from being set up, but it
; sets the flag in 2200h that makes WordStar think that it has set it up.
; In this way, the 'R' command will work as it would with shells engaged.
; The space is used to determine the command line needed to reinvoke
; WordStar.  The ZCPR33 facility for returning the directory in which the
; program was located is used to provide an explicit DU: prefix.  The
; resulting command line is kept at the end of the user patch area.

offset  defl    2380h           ; Real address = address in overlay + offset

       org     3cbfh           ; Place to install patch

       ld      e,24h           ; Get pointer to XFCB
       call    envoff          ; HL -> XFCB

       push    hl
       ld      de,0dh          ; Offset to user number where WS.COM found
       add     hl,de
       ld      b,(hl)          ; User number to B
       inc     hl
       ld      a,(hl)          ; Drive to A

       add     a,'A'-1         ; Convert drive to letter
       ld      hl,namebuf      ; Point to buffer at end of patch area
       ld      (hl),';'        ; Command separator
       inc     hl
       ld      (hl),a          ; Store drive letter
       inc     hl

       ld      a,b             ; Now work on user number
       ld      c,'0'-1         ; Tens value
tens:
       inc     c
       sub     10
       jr      nc,tens
       add     10+'0'          ; Convert units to ASCII
       ld      (hl),c          ; Stash tens digit
       inc     hl
       ld      (hl),a          ; Stash units digit
       inc     hl

       ld      (hl),':'        ; Insert colon
       inc     hl

       pop     de              ; Get pointer to XFCB again
       ld      b,8             ; Maximum of 8 letters
copyname:
       inc     de              ; Advance to next letter
       ld      a,(de)
       cp      ' '
       jr      z,copydone      ; Quit at first space
       ld      (hl),a
       inc     hl
       dec     b
       jr      nz,copyname     ; Quit after eight characters
copydone:
       ld      (hl),' '        ; Put shell signal tail (a comma)
       inc     hl
       ld      (hl),','
       inc     hl
       ld      (hl),0          ; Put in terminating null

       ld      a,0ffh          ; Fool WS into thinking shell installed
       ld      (zflag),a
       jp      60aah

end1pat:
endaddr defl    60aah - offset
free    defl    endaddr - end1pat
        if     $ gt endaddr
       ERROR: Patch to shell installation at 3CBFh is too long
        endif

;------------------------------------------------------------

; This patch takes the user's response to the 'R' command, adds the command
; to reinvoke WordStar, and appends any pending commands in the command line
; buffer.  The result is written out to the command line buffer.  This
; implements a ZCPR2-style shell for the 'R' command.

; If the resulting command line is too long for the MCL, an error message is
; displayed until a key is pressed, and then WS resumes as if no command line
; had been entered.

; The first part of this patch replaces code in WS.OVR.  There is not enough
; space there for all the code, so it continues in the user patch area.

offset  defl    -1e00h          ; Real address = address in overlay - offset

scratch equ     0a000h          ; Area to use as scratch buffer

       org     67b2h           ; Address in WS.OVR

       ld      hl,rcmdbuf      ; Point to 'R' command buffer
       ld      c,(hl)          ; Get length into BC
       ld      b,0
       inc     hl              ; Point to user's command
       ld      de,scratch      ; Scratch buffer in RAM
       ldir                    ; Copy user's command to buffer

       ld      hl,namebuf      ; Point to WS4 reinvocation command line
       call    cpy2nul         ; Copy through ending null
       jp      morpat          ; Continue in patch area

end2pat:
free    defl    67cbh - end2pat
        if     $ gt 67cbh
       ERROR: Patch to command-line code at 67B2h is too long
        endif

;----------------------------------------------------------------------
;
;                       PATCHES TO WS.COM
;
;----------------------------------------------------------------------


; This is the continuation of the patch in WS.OVR that inserts the user's
; command line, together with the WS reinvocation command, into the multiple
; command buffer.

       org     morpat

       push    de              ; Save pointer to buffer
       ld      e,18h           ; Get pending commands from MCL
       call    envoff
       ld      e,(hl)          ; Get pointer to next command into DE
       inc     hl
       ld      d,(hl)
       ex      de,hl           ; Switch into HL as source for copy
       pop     de              ; Destination pointer into buffer
       call    cpy2nul         ; Copy through ending null

       ld      hl,clrscr       ; Clear the screen
       call    scrnfn

       ld      e,18h           ; Get MCL pointer
       call    envoff          ; HL -> MCL buffer, A = max characters

       ; Check length of new command

       ld      de,scratch      ; Point to new command line
       ld      b,a             ; Max length in B
lenloop:
       ld      a,(de)
       or      a
       jr      z,oklength
       inc     de
       djnz    lenloop

       ld      de,errmsg       ; Display error message
       ld      c,9
       call    0005h
       call    sak             ; Wait for key to be pressed
       jp      7f4eh           ; Pretend no user input

oklength:
       ld      de,4            ; Offset to command line in buffer
       ex      de,hl           ; Reverse pointers
       add     hl,de
       ex      de,hl           ; HL = MCL, DE = MCL+4
       ld      (hl),e          ; Set up pointer in MCL
       inc     hl
       ld      (hl),d
       ld      hl,scratch      ; Source for command line
       call    cpy2nul         ; Copy it in

       jp      13f6h           ; Chain to command line from WS

errmsg:
       db      bell,'MCL Ovfl - press any key...$'

end3pat:
free    defl    namebuf - end3pat
        if     $ gt namebuf
       ERROR: Patch in MORPAT is too long
        endif

;------------------------------------------------------------

; This optional patch causes WS4 to use an internal path to locate
; its overlay files.

        if     intpath

       org     0f5fh           ; This is where z3 path location is determined

       call    setpath         ; Call alternative routine
       nop                     ; Must fill 5 bytes
       nop

        endif  ;intpath

;------------------------------------------------------------


; Modification to the termination routine that pops the shell stack.

; This patch eliminates the popping of the shell stack on exit from
; WordStar.  The space from the end of this patch to 13f6h is available
; for other uses (40 bytes).

       org     13ceh

       jp      13f6h           ; Exit routine


; This routine copies the string pointed to by HL to the address pointed to by
; DE until a null byte is encountered.  The null byte is copied as well.

cpy2nul:
       ld      a,(hl)          ; Get source character
       ld      (de),a          ; Put into destination
       or      a               ; Check for null
       ret     z               ; If so, quit
       inc     hl              ; Bump up pointers
       inc     de
       jr      cpy2nul


; Alternative internal path routine

        if     intpath

setpath:
       ld      hl,path0        ; Point to internal path size
       ld      a,(hl)
       inc     hl              ; Point to actual path
       or      a               ; Set flags
       ret

path0:  db      2               ; Allow up to two elements
       db      2               ; Drive (A=1)
       db      4               ; User
       db      0,0             ; Space for another entry
       db      0               ; Terminating null

        endif  ;intpath

end4pat:
free    defl    13f6h - end4pat
        if     $ gt 13f6h
       ERROR: Patch in shell popping code at 13CEh is too long
        endif

;------------------------------------------------------------

; Modification to initialization code where WS4 determines if it was
; invoked as a shell.  We have defined a convention where a comma on
; the end of the command line signals WS4 to display its shell-wait
; message and wait for the user to press a key.

       org     1a2fh

       ld      hl,80h          ; Point to command tail
       ld      l,(hl)          ; Get length into L
       set     7,l             ; In effect, add 80h
       ld      a,(hl)          ; Get last character
       cp      ','             ; See if it is a comma
       jr      nz,1a5fh        ; Not a 'shell', so go on ahead

       ld      (hl),' '        ; Get rid of the comma

       ld      de,1b10h        ; Display 'shell wait' message
       ld      c,9             ; (note: message is trashed by other code and
       call    0005            ; ..cannot be called from elsewhere)
       call    sak             ; Wait for key to be pressed

       jr      1a5fh           ; Proceed normally

sak:
       ld      e,0ffh          ; Poll console input status
       ld      c,6
       call    0005
       or      a
       jr      z,sak           ; ..until a key is pressed

       ld      e,0dh           ; Echo carriage return
       ld      c,6
       jp      0005

end5pat:
free    defl    1a5fh - end5pat
        if     $ gt 1a5fh
       ERROR: Patch to initialization code at 1A2Fh is too long
        endif


       end