;      Patching CP/M-80's PIP for Multiple Disk File Transfers
; 
;                          By: Kelly Smith
;  
; 
; "We  shall  not cease from exploration,  and the end of  all  our 
; exploring  will be to arrive where we started and know the  place 
; for the first time."         - T.S. Eliot, Little Gidding
; 
; Digital  Researchs's PIP (Peripheral Interchange Program) is  the 
; CP/M  transient  command used to move a single file  or  multiple 
; files  from one disk to another,  or to other peripheral devices.  
; Unfortunately  PIP  will  not  allow the  transfer  of  files  to 
; multiple  disks...you  must  always exit PIP and re-log  any  new 
; disks or warm boot (by entering your keyboard Control-C) the CP/M 
; system, then invoke PIP again to proceed...agonizing, if you want 
; to do multiple disk copies of specific files.
; 
; How  would  you  like to be able to transfer  files  to  multiple 
; disks  without exiting PIP,  as well as have it repeat  the  last 
; operation  that  you  entered  at PIP's command  level  with  ONE 
; keystroke?   Its EASY   Edit and assemble the following 'patch', 
; then merge it into your existing CP/M-80 (Version 2.2)  'PIP.COM' 
; utility as follows:
; 
; A>ddt pip.com<cr> <-- invoke DDT to load memory with 'PIP.COM'
; DDT VERS 2.2      <-- DDT telling us that...
; NEXT  PC
; 1E00 0100         <-- 'PIP.COM' uses 29 pages of memory
; -ipatch.hex<cr>   <-- Input the 'patch' file
; -r<cr>        <-- Read it in to memory (overlaying parts of PIP)
; NEXT  PC
; 1E00 0000
; -^C               <-- Control-C to exit DDT
; 
; A>save 29 rpip.com<cr> <-- save 29 pages of memory as 'RPIP.COM'
; 
; So, for a little "demo" of what you can do and expect from adding 
; this 'patch', lets give it a whirl:
; 
; A>rpip<cr>        <-- invoke our new 'Repeating PIP'...
; 
; PIP 1.5 with (R)eset Disks and (Q)uick Repeat
; *r<cr> <-- lets try 'R' for R)eset of the disk system
; Resetting all disks to R/W <-- keeping user informed...
; *b:=a:*.lib<cr> <-- change any (or all) disks here if you like,
;                     and start PIP'n to your hearts content...
; COPYING -
; MACRO.LIB
; COPYRGHT.LIB
; *q<cr>          <-- change disks, and then a little "quickie"
;                     with Q)uick Repeat...
; 
; Repeating:  b:=a:*.lib <-- PIP remembers us...amazing
; 
; COPYING -
; MACRO.LIB
; COPYRGHT.LIB
; *q<cr>          <-- change disks again for two "quickies"
;                     in a row (and no Vitamin-E required)
; Repeating:  b:=a:*.lib
; 
; COPYING -
; MACRO.LIB
; COPYRGHT.LIB
; *         <-- PIP waiting patiently for something else to do...
; 
; Alright,  now  that I have whetted your appetite  to  incorporate 
; this into your PIP,...here's the code to do it
;
;
;
; PIP Patch to add '(R)eset Disks' and '(Q)uick Repeat' function
;
bdos		equ	05h	; bdos entry address
fcb		equ	5ch	; default file control block address
;
pmessg		equ	9	; print message function
rdcbuf		equ	10	; read console buffer function
rsetdsk		equ	13	; reset disk system function
;
start$pip	equ	04ceh	; normal start of pip
con$buff	equ	1ecbh	; pip's internal console buffer	
pip$cr$lf	equ	082eh	; pip's internal cr/lf output routine
pip$prompt	equ	053ch	; pip's command parser entry address
pip$patch	equ	096fh	; pip gets patched at this address
;
lf		equ	0ah	; line feed character
cr		equ	0dh	; carriage return character
;

	org	100h
;
	jmp	begin		; jump over INP:/OUT: vectors and EOF
;
	org	10ah
;
begin:	lda	fcb+1		; filename specified?
	cpi	' '		; if space character, no file
	jnz	start$pip	; let pip do it's thing if file specified
	lxi	d,msg1		; and sign in please...
	call	prnt$messg	; print message
	jmp	start$pip	; and off to pip
;
added:	lxi	h,con$buff	; point to pip's console buffer
	mvi	m,128		; set-up for 128 character command string
	xchg			; pointer swapped to [DE] for CP/M
	mvi	c,rdcbuf	; read console buffer function
	call	bdos		; let CP/M do the work
	lda	con$buff+1	; check how many characters typed
	cpi	1		; just one?
	jnz	save$char$cnt	; if not, save character count and return
	lda	con$buff+2	; get single character command
	ani	05fh		; force to uppercase character
	cpi	'Q'		; repeat pip function last specified?
	jnz	reset$dsk$sys	; if not, check for reset disk system
	lhld	char$cnt	; get character count
	shld	con$buff+1	; stuff back to console buffer
	lxi	d,msg3		; tell'em repeating last process
	call	prnt$messg	; print message
	lxi	h,con$buff+1	; point to last command entry in console buffer
	mov	c,m		; get command length to calculate offset
	mvi	b,0		; clean high byte bias
	inx	h		; bump to start of command string address
	dad	b		; add bias to locate end of string
	mvi	m,'$'		; tag end of command string for message
	lxi	d,con$buff+2	; point to command string for message output
	call	prnt$messg	; print message
	mvi	c,rsetdsk	; reset disk system function
	call	bdos		; let CP/M do the work
	ret			; "Vulcan Princes...How I love You..."
				; - Stanley Clark, 'Return to Forever'
;
reset$dsk$sys:
;
	cpi	'R'		; reset disk system?
	jnz	save$char$cnt	; if not, restore character count and return
	lxi	d,msg2		; tell'em all disk set R/W
	call	prnt$messg	; print message
	mvi	c,rsetdsk	; reset disk system function
	call	bdos		; let CP/M do the work
	call	pip$cr$lf	; do carriage return/line feed
	pop	h		; clean the stack for pip restart
	jmp	pip$prompt	; do pip '*' prompt and wait for command
;
save$char$cnt:
;
	lhld	con$buff+1	; get character count + character
	shld	char$cnt	; save character count
	ret			; "Welcome Back My Friends,
				;      To The Show That NEVER Ends..."
				; - Emerson, Lake & Palmer, Brain Salad Surgery
;
prnt$messg:
;
	mvi	c,pmessg	; print message function
	call	bdos		; let CP/M do the work
	ret			; "We May Never Pass This Way Again..."
				; - Seals and Crofts, Diamond Girl -
;
msg1:		db	cr,lf,'PIP 1.5 with (R)eset Disks and (Q)uick Repeat',cr,lf,'$'
;
msg2:		db	cr,lf,'Resetting all disks to R/W$'
;
msg3:		db	cr,lf,'Repeating:  $'
;
char$cnt	dw	0	; console buffer character count
;
	org	pip$patch	; patch to get to added code goes here
;
	jmp	added		; check for reset or repeat command
;
;
;
	end
