;PATCHA/ASM - Continuation of Patch Program ; ; Routine to position to file's end ; POSFIL PUSH HL ;Save fm display call PUSH DE LD HL,POSLD$ ;"positioning ... CALL $DSPLY POP DE POP HL ; POSFIL1 CALL $GET ;Get a type byte CP 20H ;X'20' & up are illegal JP NC,FILERR CP 2 ;Transfer address? RET Z CP 3 ;Not really used in RET Z ; a file, yet... CP 4 ;End of ISAM member? RET Z CP 0AH ;End of ISAM directory? RET Z LD C,A ;Save type byte CALL $GET ;Get block length LD B,A ;Save it for countdown DEC C ;Was type = 1 ? JR NZ,POSFIL2 ;Jump if not CALL $GET ;Read off the load addr DEC B ;Adjust length for each CALL $GET DEC B POSFIL2 CALL $GET ;Read the block DJNZ POSFIL2 JR POSFIL1 ;Loop to next type code ; ; Routine to put the patch name header block into the ; prg data buffer and then position to the next X'' line ; STUFNM PUSH HL ;Save posn in fix data LD HL,GENPCH$ ;"generating patch... CALL $DSPLY LD DE,PGMDATA LD HL,NAMLEN$ ;Pt to fix name field LD A,(HL) OR A JR Z,STUFNM2 ;Go if no name len LD A,7 ;Set fix patch type LD (DE),A INC DE LD B,(HL) ;Set header length INC B ;Bump to write length STUFNM1 LD A,(HL) ;P/u name byte INC HL LD (DE),A ;Put in output buffer INC DE DJNZ STUFNM1 ;Loop for namelen ; STUFNM2 POP HL ;Recover posn in fix data STUFNM3 LD (SETMSG+1),HL ;Start of this line LD A,(HL) CP ETX ;End of fix data? JP Z,RIPPLE INC HL CP '.' ;Comment? JR Z,STUFNM4 RES 5,A ;In case lower case CP 'X' ;Start of code line? JR Z,DOXVB ;Go if so JP PCHERR ;"patch input format err ; STUFNM4 LD A,(HL) ;In a comment, loop until INC HL ; end of line CP ETX ;End of patch code? JP Z,PCHERR ;Abort if so CP CR ;EOL? JR NZ,STUFNM4 ;Loop if not JR STUFNM3 ; ; Do the 'X' verb patch ; HL => Fix data buffer ; DE => Program data buffer ; DOXVB CALL CNTLIN ;Count installed lines LD A,1 ;Show type 1 (code block) LD (DE),A ;Put in output buffer INC DE PUSH DE ;Save ptr to length INC DE LD A,(HL) ;Should be "'" INC HL ; around address (X'nnnn') CP 27H JP NZ,PCHERR ;Error if not CALL PRSFIX ;P/u hex digit pair LD B,A ;Save hi-order address CALL PRSFIX ;P/u hex digit pair LD (DE),A ;Stuff lo-order address INC DE LD A,B LD (DE),A ;Stuff hi-order address INC DE LD A,(HL) ;Syntax requires "=" or CP '=' ; "'" next JR Z,DOXVB1 CP 27H ;Bypass optional clsng ' JP NZ,PCHERR ;Error if not ',= INC HL DOXVB1 INC HL ;Bypass the '=' LD B,2 ;Len of bytes already stuffed DOXVB2 LD A,(HL) ;Get char of fix data CP '"' ;ASCII string? JR Z,DOXVB5 ;Go process if so DOXVB3 LD A,(HL) ;P/u line byte INC HL CP ';' ;Logical end? JR Z,DOXVB4 ;Ignore trailing CP CR ;End of line? JR Z,DOXVB6 CP 20H JR Z,DOXVB2 ;Ignore spaces DEC HL ;Back up, its a byte CALL PRSFX1 ;Get the hex digit pair LD (DE),A ;Stuff into code buffer INC DE INC B ;Bump block length JR DOXVB3 ; ; Bypass until end of line ; DOXVB4 LD A,(HL) ;P/u the character INC HL CP CR ;End of line? JR NZ,DOXVB4 JR DOXVB6 ; ; Fix has double quote string ; DOXVB5 INC HL LD A,(HL) ;Get next char CP ETX ;End of fix data? JP Z,PCHERR ;Can't end w/o some EOL INC HL CP CR ;End of line? JP Z,DOXVB6 ;Valid end CP '"' ;Closing quote? JR Z,DOXVB3 ;Go for more DEC HL LD (DE),A ;Stuff the char INC DE INC B ;Bump counter JR DOXVB5 ;Loop until end or " ; ; Found valid end - update length ; DOXVB6 EX (SP),HL ;Grab length pointer LD (HL),B ;Stuff the length POP HL JP STUFNM3 ;Go for more lines ; ; Got to the end of the fix input ; RIPPLE PUSH HL EX DE,HL ;Last patch byte to HL LD DE,PGMDATA ;Pt to patch code buffer XOR A SBC HL,DE ;Calc length of fixup LD (RPRMAP9+1),HL ;Stuff for later LD HL,INSPCH$ ;"installing patch CALL $DSPLY LD HL,PGMDCB ;Move prog into fix LD DE,FIXDCB ; file control block LD BC,32 ; for output use LDIR LD HL,LIBBUF ;Set the i/o buffer LD (FIXDCB+3),HL LD DE,FIXDCB ;Reread the last program @@RREAD ; sector JP NZ,IOERR ;Quit on read error ; ; Now ripple the file down while stuffing bytes ; LD HL,PGMDATA ;Beginning of "fixed" code RIPPL1 LD DE,FIXDCB ;Get prog byte CALL $GET1 JP NZ,RIPPL2 PUSH HL ;Save buffer ptr & byte PUSH AF LD DE,PGMDCB ;Use the output fcb LD A,(HL) ;P/u byte from fixbuf CALL $PUT ;Put to disk LD BC,(RPRMAP9+1) ;Pt to patch length ADD HL,BC ;Pt past patch code POP AF ;Recover prog byte LD (HL),A ; & stuff after fix code POP HL ;Rcvr buf ptr INC HL ;Bump & loop JR RIPPL1 ; RIPPL2 CP 1CH ;Got to end of file? JP NZ,FILERR ;Quit on any other error LD DE,PGMDCB LD BC,(RPRMAP9+1) ;Get length of patch RIPPL3 LD A,(HL) ;Put rest of program INC HL ; (ie the bytes = to CALL $PUT ; length of patch code) DEC BC ;Do until len left = 0 LD A,B OR C JR NZ,RIPPL3 POP HL RET ; ; Routine to read & convert fix code values ; PRSFIX XOR A ;Entry to clear LD (STRFLG+1),A ; STRING check PRSFX1 LD A,(HL) ;P/u patch char CP ETX ;End of text? JP Z,PCHERR ;Error if so CP '"' ;String? JR NZ,STRFLG LD (STRFLG+1),A ;Stuff string indicator INC HL LD A,(HL) ;P/u char CP ETX ;End again? JP Z,PCHERR STRFLG LD A,0 ;Test string flag OR A LD A,(HL) ;P/u char again INC HL ;Bump pointer RET NZ ;Ret if '"' was prev char CALL CVTBIN ;Convert hex digit to bin LD C,A ;Save value LD A,(HL) ;P/u next digit INC HL CP ETX ;Backup pointer and ret JP Z,PCHERR ; if next char is not hex CP '0' ; else pack it into regC JR C,PRSFX3 ; & place in reg A CP '9'+1 JR C,PRSFX2 CP 'A' JR C,PRSFX3 PRSFX2 RLC C ;Assume digit, move RLC C ; over a nybble RLC C RLC C CALL CVTBIN ;Get hex digit OR C ;Merge hi-order nybble RET PRSFX3 LD A,C ;Non-hex char, DEC HL ; rcvr & exit RET ; ; Routine to convert hex digit to binary ; CVTBIN SUB 30H ;1st adjustment to binary JP C,NONHEX ;Quit if too low CP 10 ;0-9 range? RET C ;Back if so RES 5,A ;In case lower case SUB 7 CP 16 ;Less than F+1? RET C ;Ok if so JP NONHEX ; else abort ; ; Routine to find ISAM member pointer in map table ; FISAM LD DE,PGMDCB FISAM1 CALL $GET1 ;Get a type byte JR Z,FISAM1A ;Go on no error CP 1CH ;EOF? JP Z,LIBERR ;Invalid library format JP IOERR ; else I/O error FISAM1A CP 8 ;Start of map table? JR Z,FISAM3 CP 0AH ;End of map table? JP Z,NOVRLY ;Should not be end PUSH BC LD C,A ;Save TYPE CALL $GET ;Get block length LD B,A ;Set counter & read DEC C JR NZ,FISAM1B ;Go if not load record CALL $GET ; else read 1st two DEC B ; bytes & then fall thru CALL $GET ; in case len=01 or 02 DEC B FISAM1B LD A,B POP BC LD B,A FISAM2 CALL $GET ;Through the block DJNZ FISAM2 JR FISAM1 ;Go back for more ; ; Found a map field ; FISAM3 CALL $GET ;Get field length LD B,A ;Set counter CALL $GET ;Get overlay # DEC B ;Reduce count CP C ;Is this the one? JR NZ,FISAM2 ;Loop to next field CALL $GET ;Get lo-order traadr CALL $GET ;Get hi-order transfer CALL $GET ;Get lo-order NRN LD C,A ;Save in C CALL $GET ;Get hi-order NRN LD B,A ;Save in B CALL $GET ;Get byte offset RET ; ; Routine to repair the library map ; RPRMAP LD DE,PGMDCB ;Rewind the file LD BC,0 CALL $POSN LD HL,PGMDATA ;Pt to buffer area RPRMAP1 CALL $GET ;Read the map into buf CP 0AH ;End of table? JR Z,RPRMAP3 LD (HL),A ;Save type code CALL $GET ;Get length LD B,A ;Set counter LD A,(HL) ;Reget the TYPE INC HL ;Bump where to stuf len DEC A ;Is this a load record? LD (HL),B ;Put length in too INC HL JR NZ,RPRMAP2 ;Go if other type CALL $GET ; else get two extra DEC B ; & adjust length in LD (HL),A ; case len = 01 or 02 INC HL CALL $GET DEC B INC HL LD (HL),A RPRMAP2 CALL $GET ;Save member # & rest of LD (HL),A ; data entries INC HL DJNZ RPRMAP2 JR RPRMAP1 ; ; Found end of table ; RPRMAP3 LD (HL),A ;Show map end LD HL,PGMDATA ;Pt to beginning RPRMAP4 LD A,(HL) ;P/u type code INC HL LD B,(HL) ;P/u length INC HL CP 8 ;Map is type 8 JR Z,RPRMAP6 CP 0AH ;End of map? JP Z,NOVRLY ;Should not have gotten DEC A JR NZ,RPRMAP5 INC HL ;You should know what DEC B ; this is for by now INC HL DEC B RPRMAP5 INC HL ;Bypass this field DJNZ RPRMAP5 JR RPRMAP4 ; ; Found a type 8, check if ISAM # matches ; RPRMAP6 LD A,(HL) ;P/u member # INC HL DEC B ;Count down OVRLY CP 0 ;Compare to patched one JR NZ,RPRMAP5 ;Keep reading until found INC HL ;Bypass transfer address INC HL LD E,(HL) ;P/u the position lo INC HL LD D,(HL) ; & the pos hi INC HL LD C,(HL) ; & the byte offset LD A,B ;Calc ptr to next field SUB 4 LD B,A INC HL DJNZ $-1 ;Loop to next field RPRMAP7 LD A,(HL) ;End of table? CP 0AH ;If end, write the JR Z,RWRMAP ; map back to disk INC HL ;Pt to field length LD B,(HL) INC HL ;Pt to member # INC HL ;Transfer Low INC HL ;Transfer High INC HL ;NRN Low LD A,B ;Adjust count for SUB 4 ; 4 INC HLs LD B,A LD A,(HL) ;If position is the same INC HL ; as that of patched CP E ; one, its posn has not JR NZ,RPRMAP8 ; changed, so don't LD A,(HL) ; change it INC HL DEC B CP D ;Cp the hi order JR NZ,RPRMAP9 LD A,(HL) CP C ; and the offset JR NZ,RPRMAP9 LPFLD INC HL DJNZ $-1 ;Loop to end of field JR RPRMAP7 ; ; Add the patch length to each position vector ; RPRMAP8 INC HL ;Bump to offset byte DEC B RPRMAP9 LD DE,0 ;P/u patch length LD A,(HL) ;P/u offset & add ADD A,E ;Lo-order patch length LD (HL),A DEC HL ;Pt to NRN DEC HL LD A,(HL) ;P/u NRN lo-order ADC A,D ;Add to it LD (HL),A INC HL ;Pt to pos hi order LD A,(HL) ;P/u the hi ADC A,0 ;Add in any carry LD (HL),A INC HL ;Pt to next map field LD DE,0 JR LPFLD ;Loop ; ; Routine to re-write the library map table ; RWRMAP LD DE,PGMDCB ;Rewind the program file LD BC,0 CALL $POSN LD HL,PGMDATA ;Pt to mapbuf start RWRMAP1 LD A,(HL) ;Ret when we get to CP 0AH ; the map end type RET Z LD C,A ;Save the type INC HL CALL $PUT ;Put the type LD A,(HL) ;P/u length INC HL LD B,A ;Save as counter CALL $PUT ;Put out the length DEC C ;Again, by now... JR NZ,RWRMAP2 LD A,(HL) INC HL CALL $PUT DEC B LD A,(HL) INC HL CALL $PUT DEC B RWRMAP2 LD A,(HL) ;Put block of code INC HL CALL $PUT DJNZ RWRMAP2 JR RWRMAP1 ;Loop for more ; ; This routine enters at PASS1. It does the first pass ; thru the fix data, and checks for parms as well ; as checking the Drr,bb and Frr,bb matches. ; SPASS2 LD (PASS2),A ;Flag pass 2 JP DOFIX ;Start over ; PASS1 CP '.' ;Comment line? JR Z,OK CP ETX ;End of fix data? JR Z,SPASS2 ;End of pass1 RES 5,A ;Make Upper case CP 'D' ;D line patch? JR Z,FCHK CP 'R' ;Remove parm? JP Z,REMOVE CP 'O' ;Special O parm? JP Z,OVERB CP 'F' ;Find line data? JR Z,OK CP 'Y' ;Yank parm? JR Z,OK CP 'L' ;Library ISAM number? JR Z,OK CP 'X' ;X line patch? JP NZ,PCHERR ;If not one of these, abort OK JP COMMENT ; ; Check the Drr,bb (if Remove) or Frr,bb line ; FCHK LD A,0FFH ;If O parm = OFF, then OPARM EQU $-1 ; don't do the check OR A JP Z,COMMENT ;Skip check if O=OFF LD A,$-$ ;Remove parm used? RPARM EQU $-1 OR A JP NZ,YANKD ;Reverse D & F lines if so LD (DL),HL ;Save D pointer CALL SKPLN ;Move to F line CALL DOCHK ;Cp F line bytes w/file JP DOFIX1 ; ; ; Checks Drr,bb and Frr,bb addresses for a match ; Checks Frr,bb against program file if patching, or ; Drr,bb if removing ; DOCHK LD (SETMSG+1),HL ;Set line error msg PUSH HL ;Save posn LD DE,(DL) ;Get D or F line LD B,3 ;Init check count CP3 INC HL INC DE LD A,(DE) CP (HL) JP NZ,FERROR ;'FIND' error DJNZ CP3 ;Check first 3 bytes ; LD B,3 ;Assume was 2 digit rec # LD A,',' ;Comma? CP (HL) JR Z,CP5 ;Yes, continue LD B,5 ;Adjust, assume 4 dig rec # CP5 INC HL ;Check rest of 'rr,bb' string INC DE LD A,(DE) CP (HL) JP NZ,FERROR ;'FIND' error DJNZ CP5 ; EX (SP),HL ;Pointer to '=' in fix line CALL DPOSN ;Posn file POP HL CALL DLINE ;Check line for match RET ; ; Remove used. Check Drr,bb lines instead of Frr,bb lines ; YANKD PUSH HL ;Save D line pointer CALL SKPLN ;Move to F line LD (DL),HL ;Save pointer POP HL ;=>D line PUSH HL ;Save D line again CALL DOCHK ;Test D line POP HL ;=>'D' LD (HL),'.' ;Make comment for pass2 LD HL,(DL) LD (HL),'D' ;Make 'F' line into D line CALL SKPLN ;=>next line JP DOFIX1 ; ; Skip past the current line, posn to start of next ; SKPLN CALL SKPLN1 ;Move past current line LD A,(HL) ;Check 1st char next line CP '.' ;Is it comment? JR Z,SKPLN ;Then skip it too RET ; SKPLN1 LD A,(HL) ;P/u line char INC HL CP CR ;Physical EOL? RET Z CP ';' ;Logical EOL? RET Z JR SKPLN1 ;Loop until EOL ; ; Get the next char, convert to UC ; GETNXT LD A,(HL) ;P/u the char INC HL ;Bump the buffer ptr RES 5,A ;Convert to upper RET ; ; Either write a char or check for a match ; PUTORCHK LD C,A ;Char in question LD A,(PASS2) ;Write pass? OR A LD A,C ;Char back in A JP NZ,$PUT ;Writing patch.. CALL $GET ;Get next char fm file CP C ;Match w/patch? RET Z ;OK if match FERROR LD HL,LOCERR$ ;Init "Find mismatch JP ERRDSP ;Dsply and quit ; ; Count patch lines ; CNTLIN PUSH HL LD HL,(LINCNT) ;Get current count, INC HL ; += 1 LD (LINCNT),HL ; and put it back POP HL RET ; ; After an error, show file not closed if needed ; FLOPN LD A,(WRFLAG) ;Did we modify file? OR A JR NZ,MESS ;Yes, don't close it @@CLOSE ;No changes JP NZ,IOERR RET MESS LD HL,WARN1$ ;File is modified but CALL $DSPLY ;PATCH did not complete LD HL,WARN2$ ; "oops... JP $DSPLY ;Then return to caller ; $OPEN @@OPEN JR NZ,IOERR RET $POSN @@POSN JR NZ,IOERR RET $BKSP @@BKSP JR NZ,IOERR RET $RWRIT @@RWRIT JR NZ,IOERR RET $GET1 @@GET ;Use this one if prog might get EOF RET $GET @@GET ;This one if EOF is also error JR NZ,IOERR RET $PUT PUSH BC LD C,A LD A,0FFH ;Flag.. LD (WRFLAG),A ;That file is modified @@PUT POP BC JR NZ,IOERR RET $DSPLY @@DSPLY JR NZ,IOERR RET $READ @@READ JR NZ,IOERR RET $DSP PUSH BC LD C,A @@DSP POP BC RET Z ;If OK else fall error ; ; Error handling ; IOERR LD L,A ;HL also gets error # LD H,0 OR 0C0H ;Abbrev, return LD C,A @@ERROR ;Display the error JR QUIT1 ; ; Internal error routine ; NOVRLY LD HL,NOVRLY$ ;"Library not found DB 0DDH LIBERR LD HL,LIBERR$ ;"Invalid library DB 0DDH FILERR LD HL,FILERR$ ;"Not load file format DB 0DDH PRMERR LD HL,PRMERR$ ;"Parm error DB 0DDH TOOBIG LD HL,TOOBIG$ ;"Fix file too big DB 0DDH PGMREQ LD HL,PGMREQ$ ;"Patch what file? ERREXIT @@LOGOT ;Display the error LD HL,-1 ;Set abort code QUIT1 JP $QUIT ; NONHEX LD HL,NONHEX$ ;"Non hex digit DB 0DDH PCHERR LD HL,PCHERR$ ;"Patch format error ERRDSP PUSH HL LD A,CR ;Move the cursor down CALL $DSP SETMSG LD HL,0 @@LOGOT POP HL JR ERREXIT ; YNKFLG DB 0 ;Was function YANK? LINCNT DW 0 ;Count lines installed WRFLAG DB 0 ;Did pgm write to file? DL DW 0 ;Save pointer to line CMDEXT DB 'CMD' FIXEXT DB 'FIX' PGMDCB DB 0 DS 32 FIXDCB DS 32 HELLO$ DB 'PATCH' *GET CLIENT:3 PGMREQ$ DB 'PROGRAM file name required',CR PRMERR$ DB 'Parameter error',CR POSLD$ DB 29,'Positioning load file',30,32,3 RDGINP$ DB 29,'Reading input',30,32,3 GENPCH$ DB 29,'Generating patch',30,32,3 INSPCH$ DB 29,'Installing patch',30,32,3 BLDMAP$ DB 29,'Re-building library map',30,32,3 YNKPCH$ DB 29,'Yanking patch from file',30,32,3 NOYANK$ DB LF,'Can''t yank, ' DB 'patch not in load file',CR NOVRLY$ DB 'Library overlay not found',CR LIBERR$ DB 'Invalid library format',CR PCHERR$ DB 'Patch input format error',CR FILERR$ DB 'Load file format error',CR NONHEX$ DB 'Non-hex digit encountered',CR SUCCES$ DB LF,'Patch function completed.',CR LINMSG$ DB ' No patch line' PLURAL DB 's installed.',CR TOOBIG$ DB 'Fix file too big - partition it',CR YANKMSG DB 'Patch successfully yanked',CR NAMLEN$ DB 3 ;Length of fix file name NAMFIX$ DB 'CLP ' ;Fix file name LOCERR$ DB 'FIND line mismatch',CR WARN1$ DB 'WARNING - File ' FNM$ DB ' ' WARN2$ DB ' Not Closed',CR ; PTBL$ DB 80H DB FLAG!ABB!6 DB 'REMOVE',0 DW RPARM1 DB FLAG!1 DB 'O',0 DW OPARM1 NOP ; ORG $<-8+1<+8 FIXBUF DS 256 ;I/O buffer for /FIX LIBBUF DS 256 ;I/O buffer for ISAM PGMBUF DS 256 ;I/O buffer for PGM FIXDATA DS 1400H ;5k alloted for fix data PGMDATA EQU $ ;Takes the rest of core