; 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
                                                         