home *** CD-ROM | disk | FTP | other *** search
- ; -=[ PATCH&GO - Load Program, Patch It, and Execute ]=-
- ;
- ; USAGE: PATCH&GO c:comfile d:patfile
- ;
- ; where: c:comfile = name of program to be loaded, patched, and
- ; executed (c: specifies the drive where the
- ; program will be found when it is loaded and
- ; defaults to the drive currently selected at
- ;
- ; d:patfile = name of program that will load, patch, and
- ; execute "comfile" (d: specifies the drive
- ; where the "patfile" is saved and defaults
- ; to the currently selected drive)
- ;
- ; Both filenames are required and can not contain wildcards. The
- ; COM file type is implied on both files.
- ;
- ; IMPLEMENTATION NOTES:
- ;
- ; Equate DEFDRV controls whether or not the "comfile" will be loaded
- ; from drive A: if it is not found on the currently selected drive
- ; and the drive was not specified explicitly.
- ;
- ; REVISION HISTORY:
- ;
- ; v1.0 Original version coded entirely in 8080 mnemonics for CP/M
- ; 2.2 systems. (J.D. Osnes, 7/17/86)
- ;
- ; COPYRIGHT:
- ;
- ; PATCH&GO may be copied and distributed freely at no cost for
- ; the benefit and enjoyment of all registered CP/M users. It
- ; may not be sold or included in a package for sale without
- ; prior written permission of the copyright owner:
- ;
- ; Copyright (c) 1986 by John D. Osnes
- ; 1084 6th Street #41
- ; Albany, CA 94710
- ;
- ; The author specifically disclaims any warranties, implied or
- ; otherwise, as to the performance and suitability of PATCH&GO.
-
- FALSE EQU 0
- TRUE EQU NOT FALSE
-
- DEFDRV EQU TRUE ; If true, load program to be patched
- ; from drive A: if it is not found on
- ; the currently selected drive and its
- ; drive was not specified explicitly
- ; when the patching program was created
-
- BDOS EQU 0005H ; Addr of jump to BDOS
- FCB1 EQU 005CH ; Addr of FCB for 1st file
- FCB2 EQU 006CH ; Addr of FCB for 2nd file
- TPA EQU 0100H ; Addr of Transient Program Area
-
- CONOUT EQU 02H ; BDOS "Console Output" function
- DCONIO EQU 06H ; BDOS "Direct Console I/O" function
- PRINTS EQU 09H ; BDOS "Print String" function
- OPENF EQU 0FH ; BDOS "Open File" function
- CLOSEF EQU 10H ; BDOS "Close File" function
- DLETEF EQU 13H ; BDOS "Delete File" function
- READS EQU 14H ; BDOS "Read Sequential" function
- WRITES EQU 15H ; BDOS "Write Sequential" function
- MAKEF EQU 16H ; BDOS "Make File" function
- SETDMA EQU 1AH ; BDOS "Set DMA Address" function
-
- CNTLC EQU 03H ; Control-C (abort)
- BELL EQU 07H ; Bell
- BS EQU 08H ; Backspace
- LF EQU 0AH ; Linefeed
- CR EQU 0DH ; Carriage return
- CNTLX EQU 18H ; Control-X (delete entry)
-
- ORG TPA
- JMP GETPAT
-
- VERS: DB CR,LF
- DB 'PATCH&GO v1.0 (07/17/86)'
- DB CR,LF,'$'
-
- DB 'Copyright (c) 1986 by John D. Osnes'
-
- GETPAT: MVI C,PRINTS ; Display signon msg
- LXI D,VERS
- CALL BDOS
-
- LXI H,FCB1+1 ; Name of program specified?
- MOV A,M
- CPI ' '
- JNZ GETP02 ; YES
-
- GETP01: MVI C,PRINTS ; NO, display help
- LXI D,HELP
- JMP BDOS ; Return to CCP via BDOS
-
- GETP02: LXI B,9 ; Store name of program
- LXI D,COMFCB
- DCX H
- CALL MOVE
- CALL AMBIG ; Check for ambiguous filename
-
- LXI H,FCB2+1 ; Name of patching program
- MOV A,M ; specified?
- CPI ' '
- JZ GETP01 ; NO, display help and exit
-
- LXI B,9 ; Move name of patching program
- LXI D,FCB1 ; to default FCB
- DCX H
- CALL MOVE
- LXI B,3 ; Append COM extension
- LXI H,COMEXT
- CALL MOVE
- CALL AMBIG ; Check for ambiguous filename
-
- MVI C,PRINTS ; Display command msg
- LXI D,COMMSG
- CALL BDOS
-
- ; Loop for entry of patches
-
- GETP04: LXI D,ADRMSG ; Prompt for addr
- GETP05: MVI C,PRINTS
- CALL BDOS
- MVI C,4 ; Get addr (4 digits max)
- LXI D,ADDR
- CALL HEXIN
- JNZ GETP05 ; If zero set, restart entry
- JC SAVPAT ; If carry set, end of patches
- DCR B ; Empty entry?
- JNZ GETP06 ; NO, convert addr to binary
-
- LHLD PATADR ; YES, get last addr and increment it
- DCX H
- DCX H
- MOV D,M
- DCX H
- MOV E,M
- INX D
- MOV A,D ; Display addr
- CALL BINHEX
- MOV A,E
- CALL BINHEX
- LXI H,VALMSG
- JMP GETP07
-
- GETP06: LXI D,ADDR ; Convert addr to binary
- CALL HEXBIN
- XCHG
- GETP07: PUSH H
- LHLD PATADR ; Store addr at location for
- MOV M,E ; next patch
- INX H
- MOV M,D
- POP D
-
- MVI C,PRINTS ; Prompt for value
- CALL BDOS
- XRA A ; Disable period terminator
- STA PTERM
- MVI C,2 ; Get value (2 digits max)
- LXI D,VALUE
- CALL HEXIN
- MVI A,RZ ; Enable period terminator
- STA PTERM
- JNZ GETP05 ; If zero set, restart entry
-
- DCR B ; Empty entry?
- JNZ GETP08 ; NO, convert value to binary
-
- LHLD PATADR ; YES, get last value and repeat it
- DCX H
- MOV E,M
- MOV A,E ; Display value
- CALL BINHEX
- JMP GETP09
-
- GETP08: LXI D,VALUE ; Convert addr to binary
- CALL HEXBIN
- XCHG
- GETP09: LHLD PATADR ; Store value at location for
- INX H ; next patch
- INX H
- MOV M,E
- INX H ; Store location for next patch
- SHLD PATADR
- LHLD PATCNT ; Increment number of patches
- INX H
- SHLD PATCNT
- JMP GETP04 ; Get next patch
-
- ; Save patching program
-
- SAVPAT: MVI C,PRINTS ; Display informative msg
- LXI D,ENDPAT
- CALL BDOS
-
- LHLD PATCNT ; Any patches entered?
- MOV A,H
- ORA L
- JNZ SAVP02 ; YES
-
- MVI C,PRINTS ; NO, don't save patching program
- LXI D,NOPATS
- JMP BDOS ; Return to CCP via BDOS
- NOPATS: DB LF
- DB '++ No Patches - Patching Program Not Saved ++'
- DB BELL,CR,LF,'$'
-
- SAVP02: LXI H,PATMOV ; Patch addr in MOVE routine of
- SHLD JMPMOV ; patching program
- LHLD PATADR
- LXI B,RELOC
- CALL SBCHL ; Patch length of relocatable
- SHLD RELEN ; module in patching program
-
- MVI C,DLETEF ; Delete patching file if it
- LXI D,FCB1 ; already exists
- CALL BDOS
-
- MVI C,MAKEF ; Create patching file
- LXI D,FCB1
- CALL BDOS
- INR A
- JNZ SAVP04 ; Successfully created
-
- MVI C,PRINTS ; Directory full
- LXI D,DIRFUL
- JMP BDOS ; Return to CCP via BDOS
- DIRFUL: DB LF,'++ Directory Full ++',BELL,CR,LF,'$'
-
- SAVP04: LXI D,PATPRO ; Save patching program, beginning
- SAVP05: MVI C,SETDMA ; at addr PATPRO
- PUSH D
- CALL BDOS
- MVI C,WRITES
- LXI D,FCB1
- CALL BDOS
- POP D
- ORA A
- JNZ DSKFUL ; Disk full
- LXI H,128
- DAD D
- XCHG ; DE = next record of patching program
- LHLD PATADR ; HL = end of patching program
- MOV A,D
- CMP H
- JC SAVP05 ; Save next record if H > D
- JNZ SAVP06 ; Done if H < D
- MOV A,E ; H = D, compare L and E
- CMP L
- JC SAVP05 ; Save next record if L > E
-
- SAVP06: MVI C,CLOSEF ; Close patching file
- LXI D,FCB1
- CALL BDOS
-
- MVI C,PRINTS ; Done
- LXI D,DUNMSG
- JMP BDOS ; Return to CCP via BDOS
- DUNMSG: DB LF,'Done ...',CR,LF,'$'
-
- DSKFUL: MVI C,DLETEF ; Disk full, so delete partial file
- LXI D,FCB1
- CALL BDOS
-
- MVI C,PRINTS ; Display error msg
- LXI D,DSKMSG
- JMP BDOS ; Return to CCP via BDOS
- DSKMSG: DB LF,'++ Disk Full ++',BELL,CR,LF,'$'
-
- ; Check for ambiguous filename in default FCB (abort if name is
- ; ambiguous)
-
- AMBIG: MVI A,'?'
- MVI C,8
- LXI H,FCB1+1
- AMBIG2: CMP M
- JZ AMBIG4
- INX H
- DCR C
- JNZ AMBIG2
- RET
-
- AMBIG4: POP H ; Restore stack
- MVI C,PRINTS ; Display error msg
- LXI D,AMBMSG
- JMP BDOS ; Return to CCP via BDOS
- AMBMSG: DB '++ Wildcards Not Allowed in Filenames ++'
- DB BELL,CR,LF,'$'
-
- ; Get hexadecimal input (C digits max, store in buffer at DE; on
- ; return, B = number of digits entered + 1; zero set and carry
- ; clear if terminated by carriage return; zero and carry set if
- ; terminated by period; zero clear if terminated by ^X)
-
- HEXIN: MVI B,0 ; Erase last entry from buffer
- PUSH B
- PUSH D
- LXI H,ERASEN
- CALL MOVE
- POP D
- POP B
- INR B ; B = char counter
- INR C ; C = buffer counter
-
- HEXIN2: PUSH B ; Loop for each digit
- PUSH D
- HEXIN4: MVI C,DCONIO ; Get char using Direct Console I/O
- MVI E,0FFH
- CALL BDOS
- ORA A
- JZ HEXIN4 ; Loop til a char is entered
- ANI 7FH ; Strip parity bit
- CPI 'a' ; Convert lowercase to uppercase
- JC HEXIN6
- CPI 'z'+1
- JNC HEXIN6
- ANI 5FH
- HEXIN6: POP D
- POP B
- CPI '0' ; Is char a hex digit?
- JC CNTLIN ; NO, but may be control char
- CPI 'F'+1
- JNC BADCH2 ; NO, error
- CPI '9'+1
- JC HEXIN8 ; YES, store it
- CPI 'A'
- JC BADCH2 ; NO, error
- HEXIN8: DCR C ; Max digits already entered?
- JZ MAXDIG ; YES, error
- INR B ; NO, increment digit counter
- STAX D ; Store digit in buffer
- INX D ; Increment buffer pointer
-
- HEXCHO: CALL PCHAR ; Echo digit
- JMP HEXIN2 ; Get next digit
-
- MAXDIG: INR C ; Max digits entered, so restore
- JMP BADCH2 ; buffer counter and ring bell
-
- CNTLIN: CPI CR ; Check control chars
- RZ ; Carriage return terminates entry
- CPI CNTLX
- JZ RENTER ; ^X restarts entry
- CPI CNTLC
- JZ ABORT ; ^C aborts
- DCR B
- JNZ BACKSP ; Not 1st char, so may be backspace
- CPI '.' ; 1st char, so may be period
- STC
- PTERM: RZ ; Lone period terminates patches
-
- BADCHR: INR B ; Restore char counter
- BADCH2: MVI A,BELL ; Ring bell on error
- JMP HEXCHO
-
- BACKSP: CPI BS ; Backspace routine
- JNZ BADCHR ; Not backspace, so bad char
- CALL PCHAR
- INR C
- DCX D
- MVI A,' '
- STAX D
- CALL PCHAR
- MVI A,BS
- JMP HEXCHO
-
- RENTER: MVI C,PRINTS ; ^X entered, so restart entry
- LXI D,ERASE ; Erase line
- CALL BDOS
- LXI D,ADRMS2
- XRA A
- INR A ; Clear zero flag
- RET
-
- ABORT: POP H ; ^C entered, so restore stack
- MVI C,PRINTS ; Display appropriate msg
- LXI D,ABMSG
- JMP BDOS ; Return to CCP via BDOS
- ABMSG: DB '^C .. Abort ..',BELL,CR,LF,'$'
-
- ; Convert ASCII hexadecimal digits beginning at DE to binary and
- ; return value in HL (digits terminated by space and DE = addr of
- ; space on return)
-
- HEXBIN: LXI H,0 ; Zero accummulator
- HEXB02: LDAX D ; Get next hex digit (or terminator)
- SUI '0'
- RC ; Terminator (space)
- CPI 10
- JC HEXB04
- SUI 'A'-'9'-1
- HEXB04: DAD H
- DAD H
- DAD H
- DAD H
- ORA L
- MOV L,A
- INX D
- JMP HEXB02
-
- ; Display byte in A in hexadecimal notation (2 ASCII chars)
-
- BINHEX: PUSH PSW
- RLC
- RLC
- RLC
- RLC
- CALL BINH02
- POP PSW
- BINH02: ANI 0FH
- ADI '0'
- CPI '9'+1
- JC PCHAR
- ADI 'A'-('9'+1) ; Fall thru PCHAR
-
- ; Display char in A (BC and DE preserved)
-
- PCHAR: PUSH B
- PUSH D
- MVI C,CONOUT
- MOV E,A
- CALL BDOS
- POP D
- POP B
- RET
-
- ; Data area for PATCH&GO
-
- PATADR: DW PATCHS ; Addr to store next patch
-
- ADRMSG: DB CR,LF ; Address prompt
- ADRMS2: DB 'Addr: $'
- ADDR: DB ' ' ; Storage for address (in ASCII)
- VALMSG: DB ' Value: $' ; Value prompt
- VALUE: DB ' ' ; Storage for value (in ASCII)
-
- ERASE: DB CR ; Erases line of current entry
- ERASEN: DB ' ',CR,'$'
-
- ENDPAT: DB '.. End of Patches ..',CR,LF,'$'
-
- ; Patching program and its data area begins here
-
- PATPRO: LXI D,PATFCB
- OFFSET EQU PATPRO-TPA ; (offset between addr in PATCH&GO
- PATOPN EQU $-OFFSET ; and addr in patching program)
- MVI C,OPENF ; Attempt to open file to load and
- CALL BDOS ; patch
- INR A ; Program found?
- JNZ PATP02 ; YES
-
- IF DEFDRV
- LXI D,PATFCB ; NO
- LDAX D ; Was drive specified explicitly?
- ORA A
- JNZ NOFILE ; YES, abort
- INR A ; NO, try drive A:
- STAX D
- JMP PATOPN
- NOFILE EQU $-OFFSET
- ENDIF
-
- MVI C,PRINTS ; Program not found, so display
- LXI D,NOFMSG ; error msg
- JMP BDOS ; Return to CCP via BDOS
- NOFMSG EQU $-OFFSET
- DB '++ COM File Not Found ++',BELL,CR,LF,'$'
-
- PATP02 EQU $-OFFSET
- LDA BDOS+2
- SUI 8
- MOV H,A
- MVI L,0 ; HL = top-of-TPA
- RELEN EQU $+1
- LXI B,0 ; BC = length of relocatable module
- CALL PATSBC
- SHLD RELADR ; Store relocation addr
- PUSH B
- LXI B,PATREL
- CALL PATSBC
- XCHG ; DE = offset between addr in patching
- ; program and addr in relocated module
- LHLD CH1 ; Add offset to addresses in relocatable
- DAD D ; module
- SHLD CH1
- LHLD CH2
- DAD D
- SHLD CH2
- LHLD CH3
- DAD D
- SHLD CH3
- LHLD CH4
- DAD D
- SHLD CH4
- LHLD CH5
- DAD D
- SHLD CH5
- LHLD CH6
- DAD D
- SHLD CH6
- LHLD CH7
- DAD D
- SHLD CH7
- LHLD CH8
- DAD D
- SHLD CH8
-
- POP B ; BC = length of relocatable module
- LHLD RELADR
- XCHG ; DE = relocation addr
- PUSH D ; Push relocation addr on stack
- LXI H,PATREL ; Relocate module (fall thru MOVE
- ; and "return" to relocated module)
-
- PATMOV EQU $-OFFSET
- MOVE: MOV A,B ; Move BC bytes from HL to DE
- ORA C
- RZ
- MOV A,M
- STAX D
- INX H
- INX D
- DCX B
- JMPMOV EQU $+1
- JMP MOVE
-
- PATSBC EQU $-OFFSET
- SBCHL: MOV A,L ; HL = HL - BC
- SUB C
- MOV L,A
- MOV A,H
- SBB B
- MOV H,A
- RET
-
- PATREL EQU $-OFFSET
- RELOC EQU $ ; Addr of rel mod in PATCH&GO
-
- LXI D,TPA ; Read program to be patched into TPA
- PATLOD EQU $-OFFSET
- LXI H,128
- DAD D
- RELADR EQU $+1-OFFSET
- LXI B,0
- MOV A,B
- CMP H
- CH1 EQU $+1-OFFSET
- JC MEMERR ; Will overwrite rel mod if H > B
- CH2 EQU $+1-OFFSET
- JNZ PATRDR ; Load next record if H < B
- MOV A,C ; H = L, compare L and C
- CMP L
- CH3 EQU $+1-OFFSET
- JC MEMERR ; Will overwrite rel mod if L > C
- PATRDR EQU $-OFFSET
- MVI C,SETDMA ; Read a record into TPA
- PUSH H
- CALL BDOS
- MVI C,READS
- CH4 EQU $+1-OFFSET
- LXI D,PATFCB
- CALL BDOS
- POP D
- ORA A ; End-of-file?
- CH5 EQU $+1-OFFSET
- JZ PATLOD ; NO, read next record
-
- PATCNT EQU $+1
- LXI B,0 ; BC = number of bytes to patch
- CH6 EQU $+1-OFFSET
- LXI H,PATPAT ; HL = addr of patches
- PATLOP EQU $-OFFSET ; Loop for installing patches
- MOV A,B ; When BC = 0, jump to base of TPA
- ORA C ; to execute patched program
- JZ TPA
- DCX B
- MOV E,M
- INX H
- MOV D,M
- INX H
- MOV A,M
- INX H
- STAX D
- CH7 EQU $+1-OFFSET
- JMP PATLOP
-
- MEMERR EQU $-OFFSET ; Attempt to overwrite relocation
- MVI C,PRINTS ; module, so can't load program
- CH8 EQU $+1-OFFSET
- LXI D,MEMSG ; Display error msg
- JMP BDOS ; Return to CCP via BDOS
- MEMSG EQU $-OFFSET
- DB '++ Out of Memory ++',BELL,CR,LF,'$'
-
- PATFCB EQU $-OFFSET
- COMFCB: DB 0,' ' ; FCB for program
- COMEXT: DB 'COM',0,0,0,0,0,0
- DB 0,0,0,0,0,0,0,0,0
- DB 0,0,0,0,0,0
- DW 0-1
- DB 0
-
- PATPAT EQU $-OFFSET
- PATCHS EQU $ ; Patches (overwrites msgs)
-
- COMMSG: DB LF ; Command msg
- DB 'All Entries in Hexadecimal, Terminated '
- DB 'by RETURN',CR,LF
- DB ' (Empty Entry = Next Address or Repeat '
- DB 'Value)',CR,LF,LF
- DB ' ^H = Backspace, ^X = Restart Current '
- DB 'Entry',CR,LF
- DB ' PERIOD = End of Patches, ^C = '
- DB 'Abort',CR,LF
- DB '$'
-
- HELP: DB LF ; Help msg
- DB 'Creates a program which loads, patches, and '
- DB 'executes another program.',CR,LF,LF
- DB 'USAGE: PATCH&GO c:comfile d:patfile',CR,LF,LF
- DB 'where: c:comfile = name of the program to '
- DB 'be loaded, patched, and',CR,LF
- DB ' executed (c: specifies '
- DB 'the drive where the pro-',CR,LF
- DB ' gram will be found when '
- DB 'it is loaded and defaults',CR,LF
- DB ' to the drive currently '
- DB 'selected at the time',CR,LF
- DB ' "comfile" is loaded'
- IF DEFDRV
- DB ' or to drive A: if "comfile"',CR,LF
- DB ' is not found on the '
- DB 'currently selected drive'
- ENDIF
- DB ')',CR,LF,LF
- DB ' d:patfile = name of the program '
- DB 'that will load, patch, and',CR,LF
- DB ' execute "comfile" '
- DB '(d: specifies the drive where',CR,LF
- DB ' the "patfile" is '
- DB 'saved and defaults to the',CR,LF
- DB ' currently selected '
- DB 'drive)',CR,LF,LF
- DB 'Both filenames are required and can not '
- DB 'contain wildcards. The COM',CR,LF
- DB 'file type is implied on both files.',CR,LF
- DB '$'
-
- END