; Add a TYPE command (starting at) PAGE,STRING - use DCCOC to display ; warn user if NEWer file is not newer than OLDer file ; give warning if byte size is not the same for both files ; have UPDATE check to see if updates have already been added TITLE FILCMP - File compare program SUBTTL EDIT HISTORY SEARCH MONSYM,MACSYM,MLIB INTERN DIE,SETTAB .REQUES LIB:MLIB .DIRECT FLBLST ;only list first line of multiline text SALL ;make neat listings VWHO==^o2 ;2 indicates an edit at customer site VMAJOR==^o1 ;MAJOR version number VMINOR==^o0 ;MINOR ver.- reset to zero when major changes VEDIT==^o3 ;EDIT number - never reset to zero VERSION==B2+B11+B17+VEDIT ;WHO DATE Edit MODIFICATIONS ;=== ========= ==== ================================================ ;DLW 15-Oct-84 00 -genesis ;ALF 27-MAY-85 01 -allow user to ignore spaces, tabs and new lines ; when performing the comparision. ;DLW 28-Jun-85 02 -have /IGNORE ignore nulls as well ;ALF 24-Oct-85 03 -fix problem with /VERIFY in UPDATE SUBTTL DEFINITIONS OP=P1 ;byte pointer to pmap area for OLDer file OB=P2 ;number of bytes left in pmap area after OP NP=P3 ;byte pointer to pmap area for NEWer file NB=P4 ;number of bytes left in pmap area after NP ;flags used in register "F" ; Bits "1B30 to 1B35" are reserved for flags used in MLIB F%VT==1B29 ;1=controlling terminal is a VT100 F%SES==1B28 ;1=output is to a VT100 like device F%QUIK==1B27 ;1=quick switch selected F%UPDF==1B26 ;1=write output file in UPDATE format F%ABRT==1B25 ;1=a routine had to be aborted due to errors F%VRFY==1B24 ;1=verify the change to be made is unique F%TTY==1B23 ;1=output is going to the terminal F%BOFM==1B22 ;1=BOFM marker was found in text region F%EOFM==1B21 ;1=EOFM marker was found in text region F%IGNO==1B20 ;1=ingore spaces, tabs, nulls, ^L, multiple blank lines F%LSTK==1B19 ;1=FINDL will use LSTK to get pointer to start of lines ;; F%____==1B18 ;1= F%WILD==1B17 ;1=wild file specs given for files to process F%APND==1B16 ;1=append data to the OUTput file F%OPEN==1B15 ;1=output file is open F%EXE==1B14 ;1=input files are in binary format DEFINE SENDES (AA) < SPTR T2, CALL SNDES > DEFINE RVIDON < CALL .RVIDO> DEFINE CATOFF < CALL .CATOF> DEFINE OSOUT% < SOUT% JERR (?,,PC,DIE)> SUBTTL CORRUPTIBLE DATA AREA CMD.DA (,>,60) ;set up command data area ENDCMD==:GETCMD## ;no special exit routine after each command VARBEG==. ;start of variable area zeroed for warm restart CMD.ZV ;assemble COMND variables to be zeroed VAREND==.-1 ;end of variable area zeroed for warm restart FDA:! PHASE 0 ;define structure of File Data Area. JFN:! 0 ;JFN of file FFP:! 0 ;fork handle,,first page of pmap area FLP:! 0 ;flags,,# pages to map in (normally length of pmap area) FPG:! 0 ;page of file to start pamping at PGL:! 0 ;length of file in pages BPP:! 0 ;# number of bytes/page BSZ:! 0 ;right half of byte pointer,,byte size of file BLN:! 0 ;byte length of file BLF:! 0 ;# unused bytes on last page of file PFP:! 0 ;pointer file page (used to hold FPG when PTR is used. It will ; allows one to return to a previous point in a file) PTR:! 0 ;byte pointer to pmap area BAP:! 0 ;# bytes after PTR left in the pmap area TOB:! 0 ;total number of bytes in pmap area EOF:! 0 ;end of file flag (If > 0 then last page of file is NOT mapped ; into the pmap area (EOF= the # pages of file left after ; last page in pmap area). If <= 0 then last page of file is ; currently mapped into the pmap area (EOF= the offset ; that when added to RH of FLP will give the page in memory ; that last file page is on) LPFP:! 0 ;pointer file page for lines in LPTR (see PFP) LBYG:! 0 ;number of bytes in the line group being searched for 0 ;stack pointer - points to top of LSTK stack DEPHASE FDALN==.-FDA ;length of File data area .ORG FDA ;reclaim space used for FDA definitons IFN , IFN , ;initialize part of FDA for the OLDer file OLD: 0 ;JFN .FHSLF,,OLDFPG ;FFP PM%CNT!PM%RD!PM%PLD+OLDPLN ;FLP BLOCK FDALN-<.-OLD> ;initialize part of FDA for the NEWer file NEW: 0 ;JFN .FHSLF,,NEWFPG ;FFP PM%CNT!PM%RD!PM%PLD+NEWPLN ;FLP BLOCK FDALN-<.-NEW> ;initialize part of FDA for the OUTput file (only need JFN) OUT: 0 ;JFN MAXL4M==^D64 ;max possible number of lines required for a match ; (the only requirement is that it must be < LSTKLN) ; (I chose 64 because I like that number) DEFL4M==^D3 ;default number of lines required for a match L4M: DEFL4M ;number of lines required for a match DL4M: DEFL4M ;default number of lines required for a match FMAFDA: 0 ;holds FDA's for FMATCH FMAPTR: 0 ;holds ptr 0 ;holds bytes after ptr FMALCT: 0 ;holds count of number of lines processed or searched DEFL2S==^D1000 L2S: DEFL2S ;# lines to search for a match before giving up DL2S: DEFL2S ;default # lines to search for a match before giving up DSWI.S: 0 ;default switches to set DSWIF==F%QUIK!F%UPDF!F%APND!F%IGNO!F%EXE ;default switches to clear CHGCNT: 0 ;for COMPARE - the # of differences found between the files ;for UPDATE - the actual number of changes processed or made CHGNUM: 0 ;the current change being processed MCCOC: BLOCK 2 ;holds modified CCOC words for terminal... ; ...will cause monitor to send actual code for OCCOC: BLOCK 2 ;holds original CCOC words for terminal DCCOC: 252525,,553125 ;will cause all control characters to be displayed... 252525,,652400 ; ...as a 2 character code execpt ^I,^J,^M and $ FILCNT: 0 ;holds the number of files processed FSPEC: BLOCK ^d<80/5> ;holds file specs temorarly for various things OLDFS: BLOCK ^d<80/5> ;holds non-wild file specs for OLDer file OLDFSW: BLOCK ^d<80/5> ;holds wild file specs for OLDer file NEWFSW: BLOCK ^d<80/5> ;holds wild file specs for NEWer file SUBTTL Software Interrupt Data PI.CNT: 0 ;holds # times ^A routine has been called CAOLOC: BLOCK 2 ;holds file location of OLDer file (ptr + page) CANLOC: BLOCK 2 ;holds file location of NEWer file (ptr + page) PI.ABT: 0 ;holds address of return routine for ^E,^X abort PI.P: 0 ;holds stack for interrupt routines PI.ACS: BLOCK CX+1 ;holds AC's (F to CX) for ^A interrupts LALL P.LVT ;assemble LEVTAB data for software interrupt processing SALL CHNTAB::DCW (3,CTRLA,.CACH,.CALV) ;0 ^A interrupts DCW (3,CTRLE,.CECH,.CELV) ;1 ^E interrupts DCW (3,CTRLX,.CXCH,.CXLV) ;2 ^X interrupts 0 ;3 free 0 ;4 free 0 ;5 free 0 ;6 arithmetic overflow 0 ;7 arithmetic floating pt overflow 0 ;8 reserved for DEC 0 ;9 PANIC - pushdown list overflow 0 ;10 end of file condition 0 ;11 PANIC - data error file condition 0 ;12 PANIC - disk full or quota exceeded 0 ;13 reserved for DEC 0 ;14 reserved for DEC 0 ;15 PANIC - illegal instruction 0 ;16 PANIC - illegal memory read 0 ;17 PANIC - illegal memory write 0 ;18 reserved for DEC 0 ;19 inferior process termination 0 ;20 PANIC - system resources exhausted 0 ;21 reserved for DEC 0 ;22 nonexistent page reference REPEAT ^D13,<0> ;23-35 free ONCHNL:: $ONCHN PURGE $ONCHN SUBTTL PMAPing Area ;----------------------------------------------------------------------------- .ORG 100K ;start area for PMAPing at this address PMBLN==100 ;length of PMAP buffers for NEWer and OLDer files ;----- OLDFPG==._^D-9 ;first page of OLDer file pmap area OLDPLN==PMBLN ;normal length of pmap area (must be at least 2) BLOCK IFN <^D36-<^L<._^D27>>>, ;----- NEWFPG==._^D-9 ;first page of NEWer file pmap area NEWPLN==PMBLN ;normal length of pmap area (must be at least 2) BLOCK IFN <^D36-<^L<._^D27>>>, ;----- LSTKLN==100*1K LSTK: BLOCK LSTKLN ; the LSTK holds the number of bytes in a line for a line in the NEWer ; and OLDer files: ; #-bytes-in-line-for-NEW-file,,#-bytes-in-line-for-OLD-file ; This stack is used by the FMATCH and FINDL routines to speed up the ; searching for where the two files start to match up again. The first ; word of LSTK is not used and may be trashed under certain conditions ; by the FMAINI routine. IFL <377777-LSTKLN>, IFL , ;----- .ORG ;reset relocation counter back to previous value ;----------------------------------------------------------------------------- SUBTTL NON-CORRUPTIBLE DATA AREA CSTRBP: POINT 7,CSTR CSTR: ASCIZ\>>>>>>>>>>>Change \ CSTRBC==^D19 ;number of bytes in CSTR FSTRBP: POINT 7,FSTR FSTR: ASCIZ\>>>>>File \ FSTRBC==^D11 ;number of bytes in FSTR TSTR: ASCIZ\total \ TSTRBC==^D6 ;number of bytes in TSTR TSTRFB=="t" ;first byte of TSTR BOFMBP: POINT 7,BOFM BOFMBC==^D9 ;number of bytes in BOFM BOFM: ASCIZ\<> \ EOFMBP: POINT 7,EOFM EOFMBC==^D9 ;number of bytes in EOFM EOFM: ASCIZ\<> \ ;============================================================================= ;These tables lists all the commands this program can process. When adding ;new entries make sure they are added in alphabetical order CMDTAB: CMDTLN,,CMDTLN ;actual,,maximum number of entries TBL (COMPARE) TBL (EXIT) TBL (HELP,,.HELP##) TBL (INFORMATION) TBL (QUIT,CM%INV,.QUIT##) ;same as EXIT at the top command level ; TBL (REMOVE) TBL (SET,,.SET##) TBL (TAKE,,.TAKE##) TBL (UPDATE) CMDTLN==<.-CMDTAB>-1 ;============================================================================= ;Table for the SET command SETTAB: SETTLN,,SETTLN ;actual,,max length of table TBL (ECHO,,.SECHO##) TBL (EXE,,.SEXE) TBL (IGNORE,,.SIGNO) TBL (LINES,,.SL4M) TBL (MAX-LINES,,.SL2S) TBL (NO,,.SNO##) TBL (QUICK,,.SQUIC) TBL (UPDATE-FORMAT,,.SUPDF) SETTLN==<.-SETTAB>-1 CMPSWI: FLDBK. .CMSWI,,CMPSTB,,,,CONFRM## ;FDB for COMPARE switches CMPSTB: CMPSTL,,CMPSTL ;actual,,maximum number of entries TBL (EXE) TBL (IGNORE,,.IGNO) TBL (LINES:,,.L4M) TBL (MAX-LINES:,,.L2S) TBL (NO:,,.SWNO) TBL (QUICK) TBL (UPDATE-FORMAT,,.UPDF) CMPSTL==<.-CMPSTB>-1 UPDSWI: FLDBK. .CMSWI,,UPDSTB,,,,CONFRM## ;FDB for UPDATE switches UPDSTB: UPDSTL,,UPDSTL ;actual,,maximum number of entries TBL (VERIFY,,0) UPDSTL==<.-UPDSTB>-1 NOTAB: NOTLN,,NOTLN ;actual,,max length of table TBL (EXE,,.NOEXE) TBL (IGNORE,,.NOIGN) TBL (MAX-LINES,,.NOMAX) TBL (QUICK,,.NOQU) TBL (UPDATE-FORMAT,,.NOUP) NOTLN==<.-NOTAB>-1 YNTAB: YNTLN,,YNTLN ;actual,,maximum number of entries TBL (NO,,0) TBL (YES,,1) YNTLN==<.-YNTAB>-1 SUBTTL MAIN PROGRAM ;start of entry vector ENTVEC: JRST START ;"@START" address JRST START ;"@REENTER" address VERSION ;version number (must be 3rd word) EVLEN==.-ENTVEC ;get length of entry vector START: RESET% ;initialize the world SETZ F, ;initialize flag register MOVE P,[IOWD PDLEN,PDL] ;initialize stack register CALL ERESET## ;say program has encountered no errors SKIPN STWARM ;is this a warm start? IFSKP. ;no, go to ENDIF. ;this code is only executed for warm restarts ZERO (VARBEG,VAREND) ;reinitialize memory SETZM NEW+JFN SETZM OLD+JFN SETZM OUT+JFN CMD.WM ;assemble warm restart code for COMND ENDIF. MOVEI T1,.CTTRM ;get the current CCOC words for... RFCOC% ; ... the terminal DMOVEM T2,OCCOC ;save the original CCOC words TRZ T3,3B19 ;clear the bits for and make the TRO T3,2B19 ;monitor send the actual caracter code DMOVEM T2,MCCOC ;save the modified CCOC words GTTYP% ;get terminal type JERR (?,,PC) ;; CAIN T2,.TT100 ;is it a VT100 ? ;; TXO F,F%VT ;yes CKTTY (F%VT) ;check whether it is VT100 type CALL ENAPSI## ;enable the interrupt system CALL RCNINP## ;set up to read commands from RESCAN ; SKIPN STWARM ;is this a warm start ; CALL TAKINI## ;no, setup to get commands from INI file SETOM STWARM ;next time though its a warm start MOVEI T1,DIE ;exit routine for this command level HRROI T2,TOPCLP ;prompt string for this command level CALL BEGCML## ;set up this command level RELJFN ;release any left over JFN's SKIPE T1,OUT+JFN ;any JFN's around from last command? CAIN T1,.PRIOU ;ignore .PRIOU TRNA ;nothing to release RLJFN% ;release it (JFN already in T1) JERR (%,,PC) SETZM OUT+JFN ;zero so I don't do it again PARSE (CMDBLK,<.CMKEY,,CMDTAB,>) HRRZ T2,(T2) ;get address of command server JRST (T2) ;dispatch to it SUBTTL Server for COMPARE command ;============================================================================= .COMPA: TXZ F,F%WILD!F%APND ;initialize flags MOVX T4,GJ%OLD!GJ%IFG ;parse an existing file... MOVEM T4,GTJBLK+.GJGEN ; ...allow wildcards NOISE (older file) PARSE (,<.CMFIL,CM%SDH,,>) MOVEM T2,OLD+JFN ;save JFN TXNE T2,GJ%DEV!GJ%DIR!GJ%NAM!GJ%EXT!GJ%VER ;wildcards found? TXO F,F%WILD ;yes, set flag NOISE (against newer file) CALL SETDNE ;set up the default name + extension PARSE (,<.CMFIL,CM%SDH,,>) MOVEM T2,NEW+JFN ;save JFN TXNE T2,GJ%DEV!GJ%DIR!GJ%NAM!GJ%EXT!GJ%VER ;wildcards found? TXO F,F%WILD ;yes, set flag NOISE (outputing differences to) MOVX T4,GJ%FOU ;parse a new file generation ; program can't handle a wild output file yet ; TXNE F,F%WILD ;wildcards used for other files? ; TXO T4,GJ%IFG ;yes, allow user to use wildcards here MOVEM T4,GTJBLK+.GJGEN SETZM GTJBLK+.GJNAM ;no defalut name HRROI T4,[ASCIZ/CMP/] ;use this default file extension MOVEM T4,GTJBLK+.GJEXT MOVEI T4,.PRIOU ;default output device MOVEM T4,OUT+JFN CALL SWINI ;init switches to their default values PARSE (,<.CMFIL,,,,,,CMPSWI>) TLZ T3,-1 ;get function discriptor block parsed CAIN T3,CONFRM## ;user confirmed command? JRST COMPA7 ;yes CAIN T3,CMPSWI ;a switch? JRST COMPA4 ;yes, go process it MOVEM T2,OUT+JFN ;no, must have parsed the output file COMPA3: PARSE (,,CMPSWI) ;parse a switch TLZ T3,-1 ;get function discriptor block parsed CAIN T3,CONFRM## ;confirm command? JRST COMPA7 ;yes COMPA4: HRRZ T2,(T2) ;get address of command server CALL (T2) ;call server for switch JRST COMPA3 ;parse next field COMPA7: CALL DOECHO## ;echo the command if necessary MOVEI T1,CMPFIL ;assume non-wild file specs given? TXNE F,F%WILD ;were wild file specs given? MOVEI T1,WLDCMP ;yes CALL @T1 ;call routine to compare the files JRST ENDCMD ;go get another command ;============================================================================= ;Routine to compare one ascii file with another ; CALL CMPFIL ;ACCEPTS: no registers need to be initialized ;RETURNS: +1 always ;Trashes - most registers CMPFIL: HRRZ T1,OUT+JFN ;get JFN of output device CALL CKDEV ;check output device CATOFF ;make sure graphic attributes off CALL FOPEN ;open the required files MOVEI T1,CMPXIT ;exit routine for ^E,^X abort CALL ATIAEX ;activate for interrupts MOVEI T1,.WLJFN ;compare JFN's HRRZ T2,OLD+JFN HRRZ T3,NEW+JFN WILD% JUMPE T1,[TMSGL < *** Files are identical *** > JRST CMPXIT] ;done SETZM CHGCNT ;initialize difference count TXZ F,F%NO!F%ABRT!F%LSTK ;initialize flags CMPLUP: JUMPG OB,CMPLU1 ;jump if still bytes in OLD pmap buffer MOVEI CX,OLD SKIPG EOF(CX) ;end of file? JRST CMPEOF ;yes CALL NXTPMP ;map in some more pages DMOVEM T2,OP ;save byte ptr + byte count CMPLU1: JUMPG NB,CMPLU2 ;jump if still bytes in NEW pmap buffer MOVEI CX,NEW SKIPG EOF(CX) ;end of file? JRST CMPEOF ;yes CALL NXTPMP ;map in some more pages DMOVEM T2,NP ;save byte ptr + byte count CMPLU2: MOVE T1,OP ;get byte ptr of OLDer file DMOVE T2,NP ;get byte ptr + byte count of NEWer file CAMLE T3,OB ;are length of strings equal? MOVE T3,OB ;no, get the lower one MOVEM T3,T4 ;save byte count I used TXNE F,F%IGNO ;ignore spaces, tabs, nulls & newlines? IFSKP. ;yes, CALL CMPSTR## ;compare the strings TXO F,F%NO ;strings weren't identical SUB T4,T3 ;calc # bytes compared SUB OB,T4 ;calc # bytes left in buffer for OLD SUB NB,T4 ;calc # bytes left in buffer for NEW ELSE. MOVE P5,OB MOVE P6,NB CALL SUPCMP ;routine to handle /IGNORE TXO F,F%NO ;strings weren't identical MOVE OB,P5 ;calc # bytes left in buffer for OLD MOVE NB,P6 ;calc # bytes left in buffer for NEW ENDIF. MOVEM T1,OP ;save updated ptr for OLD file MOVEM T2,NP ;save updated ptr for NEW file TXZN F,F%NO ;were strings identical? JRST CMPLUP ;yes, continue the comparison ; found a difference has been found between the two files. Search back to find ; the beginning of the lines for each file TXNE F,F%QUIK ;quick mode? JRST CMPQIK ;yes MOVEI CX,OLD DMOVE T1,OP ;get ptr + bytes left in pmap area CALL FBACKJ ;search backward for a ^J DMOVEM T1,OP ;save ptr + bytes left in pmap area MOVEI CX,NEW DMOVE T1,NP ;get ptr + bytes left in pmap area CALL FBACKJ ;search backward for a ^J DMOVEM T1,NP ;save ptr + bytes left in pmap area ; now see if I can find where the files start to match up again CALL FMATCH ;find where files start matching again IFSKP. ;no luck CALL OUTDIF ;output the differences JRST CMPLUP ;loop back to find the next difference ENDIF. JUMPL T4,CMPEND ;quit if L2S limit was exceeded SKIPG CHGCNT ;is this the first difference? JRST [MOVEI T1,OLD CALL CKBOF ;am I at beginning of file? JRST .+1 ;no MOVEI T1,NEW CALL CKBOF ;am I at beginning of file? JRST .+1 ;no TMSGL <% ***** Files are TOTALLY different from beginning to end ***** > TXO F,F%ABRT ;don't bother writing the output file JRST CMPXIT] JRST CMPEO5 ;output differences to the EOF ; program gets here when I've reached the end-of-file of the NEW and/or OLD ; file when executing code in CMPLUP. If not EOF for both files then all data ; of the longer file is different CMPEOF: TXNE F,F%IGNO CALL EATEOF SKIPG OLD+EOF SKIPLE OB JRST CMPEO3 ;not at the end of the OLDer file SKIPG NEW+EOF SKIPLE NB JRST CMPEO3 ;not at the end of the NEWer file JRST CMPEND ;I'm at the EOF for both files... ; ...so nothing to output CMPEO3: TXNE F,F%QUIK ;quick mode? JRST CMPQIK ;yes DMOVEM OP,OLD+PTR ;save ptr + bytes left for 1st file MOVE T1,OLD+FPG ;get current file page starting buffer MOVEM T1,OLD+PFP ;save current ptr's file page DMOVEM NP,NEW+PTR ;save ptr + bytes left for 2nd file MOVE T1,NEW+FPG ;get current file page starting buffer MOVEM T1,NEW+PFP ;save current ptr's file page ; program jumps here when I've reached the EOF of one of the files but there ; is still data left in the other file - so report the differences CMPEO5: SETOB Q2,Q1 ;initialize line group length CALL OUTDIF ;output the differences JRST CMPEND ;done ; gets here when /QUICK mode was set and files are different CMPQIK: TMSGL <% files are different > JRST CMPXIT CMPEND: SKIPE T2,CHGCNT ;any differences found? IFSKP. ;yes TMSGL < *** No differences found *** > ELSE. HRRZ T1,OUT+JFN RVIDON ;turn reverse video on MOVE T2,CSTRBP ;get byte pointer to CHANGE string TXNN F,F%UPDF ;use update format? IBP T2 ;no, skip first byte of string SETZ T3, OSOUT% HRROI T2,TSTR OSOUT% NUMOUT (CHGCNT,,-) SPTR T2,< > SETZ T3, OSOUT% CATOFF ;turn reverse video off TMSGL <% > NUMOUT (CHGCNT) TMSG < difference> MOVEI T1,"s" CAIE T2,1 ;more that 1 difference? PBOUT% ;yes, get tense right TMSG < found > ENDIF. CMPXIT: CALL DTIAEX ;deactivate for ^A,^E interrupts CALLRET FCLOSE ;close all files and return to caller ;=============================================================================== ;this routine will compare two strings and ignore all the tabs, spaces, nulls ;and multiple blank lines ; ; CALL SUPCMP ; ;Accept:T1-Byte ptr for the 1st string. ; T2-Byte ptr for the 2nd string. ; P5-Number of bytes availiable in the 1st string. ; P6-Number of bytes availiable in the 2nd string. ; ;Return:T1-Updated byte ptr for 1st string. ; T2-Updated byte ptr for 2nd string. ; P5-Updated byte count for 1st string. ; P6-Updated byte count for 2nd string. ; ;Trash: T3 ; SUPCMP: DMOVEM Q1,1(P) ;save ACs MOVEM T4,3(P) ADJSP P,3 ;adjust P for later subroutine calls ;use the shortest length in comparision SUPLEN: MOVE T3,P5 ;assume P5 < P6 CAMLE P5,P6 ;is P5 < P6? MOVE T3,P6 ;no, use P6 instead MOVE T4,T3 ;get # of bytes to compare from T3 SUPLOP: JUMPLE T3,SUPEQ ;quit when no more bytes to compare CALL CMPSTR## ;compare further JRST SUPNE ;find a mismatch SUB P5,T4 ;subtract # of byte compared SUB P6,T4 ;subtract # of byte compared ;this is the exit when two strings are found to be the same. SUPEQ: AOS -3(P) ;set up return+1 when two strings are matched SUPEXT: ADJSP P,-3 ;adjust P for ACs' restoration DMOVE Q1,1(P) ;restore ACs MOVE T4,3(P) RET ;retrun to caller ;To check whether the mismatch is caused by a tab, a space or new line (CR,LF), ;I must set both byte ptr back 1 position and set the byte counts. SUPNE: SUB T4,T3 ;get # of bytes which has compared from ;previous comparision SUB P5,T4 ;subtract # of byte compared SUB P6,T4 ;subtract # of byte compared ADDI P5,1 ;adjust byte cnt of string 1 ADDI P6,1 ;adjust byte cnt of string 2 SETOB Q1,Q2 ;set Q1 & Q2 to -1 ADJBP Q1,T1 ;adjust byte ptr back 1 byte for string1 MOVE T1,Q1 ;save the adjusted byte ptr ADJBP Q2,T2 ;adjust byte ptr back 1 byte for string2 MOVE T2,Q2 ;save the adjusted byte ptr ; get rid of all the leading spaces, tabs, nulls, and multiple blank lines ; which are causing the mismatch EXCH P5,T2 ;set up AC to call EATST CALL EATST EXCH P5,T2 ;restore ACs EXCH T2,P6 ;set up ACs to work on string2 EXCH T1,P6 CALL EATST EXCH T1,P6 ;restore ACs EXCH T2,P6 LDB Q1,T1 ;get byte pointed by ptr1 in string1 LDB Q2,T2 ;get byte pointed by ptr2 in string2 CAME Q1,Q2 ;are they equal? JRST SUPEXT ;no, found a mismatch and exit routine JUMPLE P5,SUPEQ ;quit when end of string1 JUMPLE P6,SUPEQ ;quit when end of string2 JRST SUPLEN ;go compare further ;=============================================================================== ;This routine adjusts the byte ptr up to the point where the first ;valid character is encountered (valid characters are characterers other than ;space, tab, null, ^L, ^J, ^M) ; ; CALL EATST ; ;Accept:T1-Byte ptr which points to the string for process. ; T2-Number of bytes availiable in the string after the byte ptr. ; ;Return:T1-Updated byte ptr ; T2-Updated byte count ; T3-# of bytes ignored. ; T4-Byte ptr to last ^J encountered, zero => no ^J encountered ; Q1-Bytes left after ptr in T4 ; ;Trash: Q2 ; EATST: SETZB T4,Q1 ;initialize counts MOVEM T2,T3 ;save byte count EATST3: JUMPLE T2,EATST9 ;quit when count reaches zero SUBI T2,1 ;adjust # bytes left in string ILDB Q2,T1 ;get the next byte CAIE Q2," " ;is it a SPACE? CAIN Q2," " ;is it a TAB? JRST EATST3 ;yes, loop back to process next byte CAIE Q2,.CTRLM ;is it a carriage return? CAIN Q2,.CTRLL ;is it a ^L (new page) JRST EATST3 ;yes, loop back to process next byte JUMPE Q2,EATST3 ;[02] ignore nulls CAIE Q2,.CTRLJ ;is it a line feed? JRST EATST8 ;no, found a non-separator DMOVEM T1,T4 ;save ptr to ^J + bytes after it JRST EATST3 ;loop back to process next byte EATST8: SUBI T3,1 ;correct count of bytes ignored EATST9: SUB T3,T2 ;calc # bytes ignored RET ;return to caller ;============================================================================= ;This routine will ignore all the leading tabs, spaces, nulls, ^L, and ;multiple blank lines before report the difference which exist at the end of ;the file. ; ; CALL EATEOF ; ;Accept:No register ; ;Return:OP-Updated byte ptr for older file. ; OB-Updated byte count for older file. ; NP-Updated byte ptr for newer file. ; NB-Updated byte count for newer file. ; ;TRASH: NO register ; EATEOF: DMOVEM T1,1(P) ;save the ACs DMOVEM T3,3(P) DMOVEM Q1,5(P) ADJSP P,6 ;adjust stack ptr before to do any call JUMPL OB,EATNEW ;is there any byte left in older file? MOVE T1,OP ;load information into ACs MOVE T2,OB CALL EATST SUB OB,T3 MOVE OP,T1 SETO T1, ;yes, set up AC to adjust byte ptr back ADJBP T1,OP ;up one byte MOVE OP,T1 EATNEW: JUMPL NB,EATFIN ;is there any byte left in newer file? MOVE T1,NP ;set up ACs to work on string2 MOVE T2,NB CALL EATST ;call routine to eleminate leading tabs ;spaces and new lines in string2. SUB NB,T3 MOVE NP,T1 ;restore ACs SETO T1, ;yes, set up AC to adjust byte ptr back ADJBP T1,NP ;up one byte MOVE NP,T1 EATFIN: ADJSP P,-6 ;adjust stack ptr DMOVE T1,1(P) ;restore ACs DMOVE T3,3(P) DMOVE Q1,5(P) RET ;return to caller ;=============================================================================== ;This routine will position the byte ptr to next non blank line to print. ;If the string is composed of multiple blank lines, this routine will return ;the ptr at the beginning of the last blank line. ; ; CALL EALIN ; ;Accept:T2-byte ptr to file which is going to be searched. ; T3-# of bytes after the byte ptr. ; ;Return:T2-Updated byte ptr ; T3-Updated byte count ; ;Trashes: No register. EATLIN: DMOVEM T1,1(P) ;save ACs DMOVEM T3,3(P) DMOVEM Q1,5(P) ADJSP P,6 ;adjust stack ptr MOVE T1,T2 ;set up ACs for EATST MOVE T2,T3 CALL EATST ;ignore leading multiple new lines ADJSP P,-6 ;adjust stack ptr, before restore ACs JUMPN T4,EATUP ;if T4 points at a ^J, go to EATUP. DMOVE T1,1(P) ;restore original values for ACs DMOVE T3,3(P) DMOVE Q1,5(P) RET ;returns to caller EATUP: IFE. T2 ;is EATST eats up the whole line group? MOVNI T2,2 ;set up ACs to perform adjustment MOVE T3,T2 ; ADJBP T2,T4 ;adjust T2 to point to last blank line SUB T3,Q1 ;calculate number of byte after T2 ELSE. ; we have eliminate the leading blank line(s) MOVE T2,T4 ;point to the rest of the line. MOVE T3,Q1 ;get number of byte after last ^J ENDIF. MOVE T1,1(P) ;restore the rest of the ACs MOVE T4,4(P) DMOVE Q1,5(P) RET ;return to caller ;============================================================================= ;Routine to pmap a file into memory. ; CALL PMP ;map starting at file page FPG into pmap area ; CALL NXTPMP ;map in next group of file pages into pmap area ;ACCEPTS: ; CX - address of the FDA (File Data Area) ;RETURNS: ; +1 always with: ; T1 - trashed ; T2 - byte pointer to start of pmap area ; T3 - # of bytes of file in the pmap area ; EOF(CX) -updated ; TOB(CX) -updated ;Trashes T1 NXTPMP: HRRZ T1,FLP(CX) ;get length of pmap buffer ADDM T1,FPG(CX) ;add current page at start of buffer... ; ...so next pmap will start here PMP: DMOVE T2,FFP(CX) ;initialize words for pmap HRRZ T1,T3 ;# pages to map in ADD T1,FPG(CX) ;add file page to start at SUB T1,PGL(CX) ;sub length of file in pages MOVNM T1,EOF(CX) ;save end of file flag SKIPLE T1 ;enough left to fill pmap area? SUB T3,T1 ;no, map in only what we need to HRL T1,JFN(CX) ;get JFN,,0 HRR T1,FPG(CX) ;JFN,,page of file to start mapping at PMAP% JERR (?,,PC,DIE) TLZ T3,-1 ;get # pages I mapped in IMUL T3,BPP(CX) ;calc # of bytes of file in pmap area SKIPG EOF(CX) ;am I at the end of file? SUB T3,BLF(CX) ;yes, sub # of free bytes on last page MOVEM T3,TOB(CX) ;save total bytes in pmap area LSH T2,9 ;convert page number to address HLL T2,BSZ(CX) ;make pointer to start of pmap area RET ;return to caller ;============================================================================= ;Routine to search backward for a ^J. If the search takes me to the beginning ;of the pmap buffer area then I'll bring in the previous page of the file and ;continue searching. If this routine reaches the beginning of the file then ;it will stop ; CALL FBACKJ ;ACCEPTS: ; T1 - byte pointer ; T2 - number of bytes left after pointer in pmap buffer ; CX - address of the FDA (File Data Area) ; TOB - total # bytes in pmap buffer ;RETURNS: ; +1 - always with T1,T2 updated ;Trashes none FBACKJ: MOVN T2,T2 ;negate # bytes in pmap area after ptr ADD T2,TOB(CX) ;calc # bytes in pmap area before ptr CALL BACKJ ;search backward for a ^J JRST FBACK5 ;didn't find one - check it out FBACK3: MOVN T2,T2 ;negate # bytes in pmap area before ptr ADD T2,TOB(CX) ;calc # bytes in pmap area after ptr RET ; gets here when BACKJ failed to find ^J in pmap area. At this point T2 must ; be zero and I must be a beginning of pmap buffer for the file. If it's not ; the first page of the file then map in a previous page of the file and then ; loop back to keep on looking for a ^J FBACK5: SKIPG FPG(CX) ;am I on the first page of the file JRST FBACK3 ;yes, don't back up any more PUSH P,T3 ;save a register SOS FPG(CX) ;back up one page of the file CALL PMP ;do it ADDI T2,1K ;increment ptr returned by PMP by 1 page SUB T3,BPP(CX) ; ... and decrement bytes left by 1 page DMOVE T1,T2 POP P,T3 ;restore register JRST FBACKJ ;loop back and continue looking ;============================================================================= ;Routine to search backward for a ^J. If the byte pointer supplied is already ;pointing to a ^J it is ignored and a search will be for a previous one. ;(NOTE: be careful when modifying this routine because you should keep the ; loop as short as possible and must not try to load the byte pointed to by ; the "base byte pointer" because it may not exist) ; CALL BACKJ ;ACCEPTS: ; T1 - byte pointer ; T2 - number of bytes I can back up (include byte T1 points to in count) ;RETURNS: ; +1 - reached backup limit before I found a ^J. T1 will be pointing to ; the byte before the last byte processed, T2 will be zero. ; +2 - with T1 pointing to the ^J and T2 updated ;Trashes none BACKJ: JUMPLE T2,BACKJ9 ;quit if T2 already zero DMOVEM T3,1(P) ;save T3,T4 MOVN T3,T2 ADJBP T3,T1 ;make base byte pointer SOJE T2,BACKJ7 ;ignore byte T1 is now pointing to BACKJ2: MOVE T1,T2 ;set up for ADJBP to gets last byte ADJBP T1,T3 ;back pointer up another byte LDB T4,T1 ;get byte CAIE T4,.CTRLJ ;is it a SOJG T2,BACKJ2 ;no, back up one more byte and try again JUMPE T2,BACKJ7 ;jump if I ran out of bytes AOSA (P) ;found a ^J - set +2 return and skip... ; ...because T1 is pointing to the ^J BACKJ7: MOVE T1,T3 ;use base byte pointer DMOVE T3,1(P) ;restore T3,T4 BACKJ9: RET ;============================================================================= ;Routine to do a pmap (if necessary) so that the place in the file pointed ;to by PTR, BAP and PFP will be in the pmap buffer ; CALL PTRPMP ;ACCEPTS: ; CX - address of the FDA (File Data Area) ;RETURNS: ; +1 - with PTR, BAP, PFP and pmap area for file updated ;Trashes T1-T3 PTRPMP: MOVE T1,PFP(CX) ;get pointer file page CAMN T1,FPG(CX) ;is this page still starting buffer? RET ;yes, I'm done DMOVE T2,PTR(CX) ;get ptr + byte count CALL CKPTR ;is this area of file in pmap buffer? IFSKP. ;no, I'll have to map it in MOVEM T1,PFP(CX) ;yes, save update pointer file page DMOVEM T2,PTR(CX) ;save updated ptr + bytes after ptr RET ;done ENDIF. ; if I have to remap the file buffer area I might as well remap it so that the ; page the PTR points to is the 1st page of the pmap buffer area because if ; the PTR points to a page near the end of the buffer area then another ; remap would have to be done again shortly - this logic would save me from ; having to do that 2nd remap so soon. HRRZ T3,FLP(CX) ;get length of pmap area ADD T3,PFP(CX) ;add ptr's file page SUB T3,PGL(CX) ;calc # file pages to be after buffer MOVEM T1,FPG(CX) ;have PMP start with this page JUMPGE T3,PMP ;if next pmap will bring last page... ; ...of file into buffer then don't bother adjusting ; do page adjusments so PTR will point to first page in pmap buffer PUSH P,T4 ;save register MOVE T2,PTR(CX) ;get byte ptr IBP T2 ;adjust to point to actual byte... ; ...incase ptr on page boundry TLZ T2,-1 ;isolate address of ptr LSH T2,-9 ;get page ptr is on HRRZ T3,FFP(CX) ;get page # of start of pmap buffer SUB T2,T3 ;calc page offset MOVEM T2,T4 ;save offset ADD T2,PFP(CX) ;calc page to start pmaping at JUMPL T2,[ CALL CKBOF ;check for beginning of file JRST [TMSGL JRST DIE] SETZB T2,T4 ;PTR(CX) must refer to nonexistant... JRST .+1] ; ...right before beginning of file MOVEM T2,PFP(CX) ;save this new pointer file page MOVEM T2,FPG(CX) ;have next PMP start with this page MOVN T1,T4 ;get offset LSH T1,9 ;put page # at proper place ADDM T1,PTR(CX) ;adjust ptr HRRZ T1,FLP(CX) ;get length of pmap area SUB T4,T1 ;calc # pages from PTR to end of buffer IMUL T4,BPP(CX) ;convert pages to bytes ADD T4,BAP(CX) ;calc # bytes from PTR to start of page CALL PMP ;get some more data ADD T4,T3 ;calc # bytes from ptr to end of buffer MOVEM T4,BAP(CX) ;save it POP P,T4 ;restore register RET ;============================================================================= ;Routine to check to see if a file relative byte pointer is in the pmap buffer ;for the file. If it is the file page number, the byte ptr, and the bytes ;of file after ptr will be adjusted accordingly ; CALL CKPTR ;ACCEPTS: ; T1 - pointer file page (see PFP) ; T2 - byte pointer (see PTR) ; T3 - bytes in pmap buffer after ptr (see BAP) ; CX - address of the FDA (File Data Area) ;RETURNS: ; +1 - data being pointed to is NOT in pmap buffer area ; +2 - data is in pmap buffer area. T1,T2,T3 will be updated ;Trashes none CKPTR: AOS (P) ;assume +2 return CAMN T1,FPG(CX) ;am I on the same page? RET ;yes, return+2 DMOVEM T4,1(P) ;save some registers MOVE Q1,T2 ;get byte pointer IBP Q1 ;adjust to point to actual byte... ; ...incase ptr on page boundry TLZ Q1,-1 ;isolate address of ptr LSH Q1,-9 ;isolate page # from the address HRRZ T4,FFP(CX) ;get first page of pmap buffer SUB Q1,T4 ;calc page offset of ptr ADD Q1,T1 ;calc actual file page ptr is on HRRZ T4,FLP(CX) ;get # pages in pmap buffer ADD T4,FPG(CX) ;calc last file page in buffer CAML Q1,FPG(CX) ;if file page the ptr is on... CAML Q1,T4 ; ...is not in buffer then... JRST CKPTR9 ; ...return +1 ; file data being pointed to by T1-T3 is in pmap buffer so readjust ptr in T2 MOVEM T1,T4 SUB T4,FPG(CX) ;calc offset for pointer LSH T4,9 ;make it a page offset ADD T2,T4 ;adjust the supplied byte pointer ; and also readjust # bytes after ptr which is in T3 HRRZ T4,FLP(CX) ;get # pages in pmap buffer ADD T1,T4 ;calc file page after buffer CAML T1,PGL(CX) ;was EOF in buffer? ADD T3,BLF(CX) ;yes, adjust # bytes IDIV T3,BPP(CX) ;calc # bytes from ptr to end of page SUB T4,BPP(CX) ;calc -(#bytes from page start to ptr) SUB Q1,FPG(CX) ;calc # pages into buffer new ptr is on IMUL Q1,BPP(CX) ;calc # bytes this represents MOVN T3,Q1 ADD T3,TOB(CX) ;calc # bytes after page ptr is on ADD T3,T4 ;calc # bytes after ptr ; and also readjust pointer file page in T1 MOVE T1,FPG(CX) ;set T1 to be consistent with T2,T3 TRNA ;take +2 return CKPTR9: SOS (P) ;set +1 return DMOVE T4,1(P) ;restore registers RET ;============================================================================= ;Routine to try to find where the OLDer and NEWer files match up again. ;The logic is as follows: Get the next L4M lines from the OLDer file and ;see if this line group matches the first FMALCT lines from the NEWer file ;If no match then get the next L4M lines from the NEWer file and see if ;it matches the first FMALCT lines of the OLDer file. If no match then increase ;the value of FMALCT and do the whole process again. ; CALL FMATCH ;ACCEPTS: ; OP - pointer to beginning of line for OLDer file ; OB - bytes left in pmap area after pointer for OLDer file ; NP - pointer to beginning of line for NEWer file ; NB - bytes left in pmap area after pointer for NEWer file ; L4M - # lines required for a match ; L2S - maximum # lines to search for a match before giving up ;RETURNS: ; +1 - files did not match up again because L2S limit reached (T4 will ; be < zero) --OR-- because EOF of both files were reached ; +2 - a match was found ; ; PTR, BAP, PFP - will be updated for both files and will contain ; the ptr data supplied when FMATCH was callled ; Q1 contains the byte length of matching line for NEW area ; Q2 contains the byte length of matching line for OLD area ; ; OP,OB,NP,NB -updated ptr and # bytes after pointer. They ; will point to the end of the matching line group ; for each file ; ;Trashes T1-P6 FMATCH: DMOVEM OP,PTR+OLD ;save ptr + bytes left for OLDer file MOVE Q2,FPG+OLD ;get current file page starting buffer MOVEM Q2,PFP+OLD ;save current ptr's file page SETZM LBYG+OLD ;initialize # bytes in line group DMOVEM NP,PTR+NEW ;save ptr + bytes left for NEWer file MOVE Q2,FPG+NEW ;get current file page starting buffer MOVEM Q2,PFP+NEW ;save current ptr's file page SETZM LBYG+NEW ;initialize # bytes in line group MOVEI Q2,1 MOVEM Q2,FMALCT ;initialize # of lines to search MOVEI CX,NEW MOVEM CX,FMAFDA ;save FDA for file MOVEI CX,OLD TXO F,F%LSTK ;initialize flags FMATC3: CALL FMAFIL ;try to find next line from OLD in NEW JRST FMATC8 ;found where file match up again JUMPL T4,FMATC9 ;jump if L2S limit exceeded JUMPG Q2,FMATC6 ;jump if not EOF of OLDer file SKIPG LBYG+NEW ;EOF of NEWer file as well? JRST FMATC9 ;yes, quit FMATC6: AOS FMALCT ;increase lines to search EXCH CX,FMAFDA ;switch FDA from OLDer to NEWer file EXCH OP,NP ;exchange byte ptrs and... EXCH OB,NB ; ...byte counts for call to FMAFIL CALL FMAFIL ;try to find next line from NEW in OLD TXO F,F%NO ;found it EXCH CX,FMAFDA ;switch FDA from NEWer to OLDer file EXCH OP,NP ;exchange byte ptrs and... EXCH OB,NB ; ...byte counts so I'm back to normal TXZE F,F%NO ;did I find where files match up again? JRST FMATC8 ;yes JUMPL T4,FMATC9 ;jump if L2S limit exceeded JUMPG Q2,FMATC3 ;jump if not EOF of NEWer file SKIPG LBYG+OLD ;EOF of OLDer file as well? JRST FMATC9 ;yes, quit JRST FMATC3 ;loop back to try some more FMATC8: AOS (P) ;set +2 return FMATC9: TXZ F,F%LSTK ;initialize flags RET ;============================================================================= ;Routine to get a line from one file (pointed to by CX) and search for it ;in another file (pointed to by FMAFDA). The search region is given by the ;line count in FMALCT ; CALL FMAFIL ;ACCEPTS: -see FMATCH. This routine was designed to be called only by FMATCH ;RETURNS: ; +1 - found where files match up again ; +2 - couldn't find where files match up again. If Q2 = -1 then ; reason is because EOF(CX) was reached. If T4 = -1 then reason ; is L2S count was exceeded FMAFIL: DMOVE Q2,LBYG(CX) ;get # bytes in line group... ; ...and stack pointer in Q3 JUMPE Q2,FMAINI ;do initialization if necessary... FMAFI0: ; ...and return to here ; this loop will get a line group from the 1st file. Each time it is executed ; it will move the line group down by one line. This line group will then be ; looked for in the 2nd file FMAFI1: AOBJP Q3,LSTKOF ;increment LSTK pointer MOVN Q1,L4M ;get # of lines required for a match ADD Q1,Q3 ;adjust to beginning of last line group CAIN CX,OLD HRRZ Q1,LSTK(Q1) ;get # bytes in this line of OLDer file CAIN CX,NEW HLRZ Q1,LSTK(Q1) ;get # bytes in this line of NEWer file SUB Q2,Q1 ;remove count from total bytes MOVN Q1,Q2 ADJBP Q1,OP ;make ptr to start of next line group MOVE T1,FPG(CX) ;get current file page starting buffer CAME T1,LPFP(CX) ;has it changed? CALL FMAPMP ;yes, need to readjust some ptrs CALL MSCANJ ;look for next ^J EXCH CX,FMAFDA ;switch around FDA's DMOVEM NP,FMAPTR ;save old ptr + bytes incase FINDL fails CALL PTRPMP ;go back to beginning of difference DMOVE NP,PTR(CX) ;start searching from here MOVE T4,FMALCT ;initialize # lines to search CAML T4,L2S ;have I exceeded the limit CALL L2SEXC ;yes, see if user wants to continue CALL FINDL ;search for line group in other file TXO F,F%NO ;couldn't find it EXCH CX,FMAFDA ;switch around FDA's TXZN F,F%NO ;did I find where files match up again? RET ;found it, return +1 DMOVE NP,FMAPTR ;restore previous ptr + bytes ; checking T4 will tell me whether or not FINDL quit because FMALCT was ; exhausted or EOF was reached. If EOF was reached then there is no need to ; return to the calling routine to switch files around since there are no ; more lines in the other file that need to be processed. JUMPLE T4,FMAFI8 ;jump if EOF of file NOT reached AOS FMALCT ;increase lines to search JRST FMAFI1 ;loop back to process more lines FMAFI8: DMOVEM Q2,LBYG(CX) ;save # bytes in line group + stack ptr FMAFI9: AOS (P) ;set +2 return RET ;============================================================================= ;Routine to search for the next ^J in the update file ; CALL MSCANJ ;ACCEPTS: ; Q1 - byte pointer to beginning of line group ; Q3 - pointer to next free location in LSTK ; OP,OB - ptr + bytes left after ptr to end of line group ;RETURNS: +1 unless EOF reached ; ;Trashes:T1-T4 MSCANJ: DMOVE T1,OP ;get ptr + bytes left after ptr MOVE T3,T2 ;save initial length of string MSCAN0: TXNN F,F%IGNO ;is user wants /IGNORE JRST MSCAN1 ;no, go scan for next ^J CALL EATJ ;set the ptr at 1st non-blank line JRST MSCAN1 ;ptr is already at the proper position ; gets here when the line I was on was blank (only spaces,tabs,nulls,^L's). So ; I will add the number of bytes skiped over to the previous line in LSTK. If ; this is the first time MSCANJ was called (from FMAINI) then the first word ; of LSTK will be trashed - thats ok because it's not used anyway SUB T3,T2 ;get # of bytes moved forward CAIE CX,OLD ;are we looking at the OLD file? HRLZ T3,T3 ;no, set data at the correct position ADDM T3,LSTK-1(Q3) ;add the data to the previous LSTK MOVE T3,T2 ;move the new byte cnt to T3 MSCAN1: CALL SCANJ ;look for next ^J JRST MSCAN4 ;search failed - check out why MSCAN2: DMOVEM T1,OP ;save ptr + bytes left after ptr SUB T3,T2 ;calc number of bytes in line ADD Q2,T3 ;calc # bytes in line group CAIN CX,OLD HRRM T3,LSTK(Q3) ;save # bytes in this line of OLDer file CAIN CX,NEW HRLM T3,LSTK(Q3) ;save # bytes in this line of NEWer file RET ; gets here when SCANJ couldn't find a ^J in the file. It failed because ; either it reached the EOF or end of data in pmap area for file. MSCAN4: SKIPLE EOF(CX) ;end of file? IFSKP. ;no CALL MSCAN2 ;yes, save the data collected ADJSP P,-1 ;remove call to MSCANJ from stack SETO Q2, ;set flag to indicate EOF reached JRST FMAFI8 ;quit ENDIF. PUSH P,T3 ;save # bytes searched so far MOVE T1,Q1 ;get ptr to start of current line group CALL SU4PMP ;setup for next call to PMP ADDM T1,Q1 ;adjust byte pointer MOVE T1,FPG(CX) ;get current file page starting buffer MOVEM T1,LPFP(CX) ;save current ptr's file page EXCH OP,NP ;exchange byte ptrs and... EXCH OB,NB ; ...byte counts for call to SUPMP5 CALL SUPMP5 ;setup for PMP and get some more data EXCH OP,NP ;exchange byte ptrs and... EXCH OB,NB ; ...byte counts so I'm back to normal POP P,T3 ;get # bytes searched so far ADD T3,T2 ;calc new value JRST MSCAN0 ;continue search for ^J ;=============================================================================== ;This routine will position the byte ptr to next ^J and skips all leading ;tabs, spaces, ^Ls, LFs and multiple blank lines (CR-LF). ; ; CALL EATJ ; ;Accept:T1-byte ptr to file which is going to be searched. ; T2-# of bytes after the byte ptr. ; ;Return:T1-Updated byte ptr. ; T2-Updated byte count ; ; +1-the line is a non-blank line, or cannot find next ^J. ; +2-a new ^J is found. ; ;Trashes: No register. EATJ: DMOVEM T1,1(P) ;save ACs DMOVEM T3,3(P) DMOVEM Q1,5(P) ADJSP P,6 ;adjust stack ptr CALL EATST ;ignore spaces, tabs, etc. ADJSP P,-6 ;adjust stack ptr, before restore ACs JUMPE T4,EATJNO ;does T4 point to a ^J? MOVE T1,T4 ;yes save new values in ACs MOVE T2,Q1 AOSA (P) ;set retun +2 EATJNO: DMOVE T1,1(P) ;no, restore original values for ACs DMOVE T3,3(P) DMOVE Q1,5(P) RET ;returns to caller ;============================================================================= ;Routine to adjust pointers and remap the file buffer (if necessary so as to ;return to a previous location in the file ; CALL FMAPMP ;ACCEPTS: ; Q1 - byte pointer to start of line group ; LPFP - pointer file page for pointer in Q1 ;RETURNS: +1 always FMAPMP: PUSH P,PFP(CX) ;save current ptr's file page PUSH P,PTR(CX) ;save current ptr PUSH P,BAP(CX) ;save current bytes after ptr MOVE T1,LPFP(CX) ;get line stack ptr file page MOVEM T1,PFP(CX) MOVEM Q1,PTR(CX) ;use pointer to start of line group CALL PTRPMP ;go to this location in the file POP P,BAP(CX) ;restore current bytes after ptr POP P,PTR(CX) ;restore current ptr POP P,PFP(CX) ;restore current ptr's file page MOVE T1,LPFP(CX) ;get line stack ptr file page DMOVE T2,OP ;get ptr to end of line region CALL CKPTR ;is end of line region in pmap buffer? JRST FMADJ9 ;no DMOVEM T2,OP ;save ptr + byte count (incase changed) MOVEM T1,LPFP(CX) ;save current ptr's file page RET ; since end of line group is not presently in pmap buffer but start of line ; group is I must remap so that all of line region is in the pmap buffer FMADJ9: MOVE T1,LPFP(CX) ;get line stack ptr file page MOVEM T1,FPG(CX) ;make next pmap start with this page CALLRET PMP ;get some more data ;============================================================================= ;Routine to do the initialization necessary for FMAFIL routine ; JRST FMAINI ;ACCEPTS: no registers ;RETURNS: to FMAFI0 always FMAINI: CALL PTRPMP ;make sure I'm at beginning of change DMOVE OP,PTR(CX) ;get ptr + bytes in case they changed MOVE T1,FPG(CX) ;get current file page starting buffer MOVEM T1,LPFP(CX) ;save current ptr's file page ; now initialize LSTK stack MOVN Q3,L4M ;set up for AOBJN instruction LSH Q3,^D18 ADDI Q3,1 ;set Q3 to 1 MOVE Q1,OP ;initialize for MSCANJ SETZ Q2, ;initialize line byte counts FMAIN1: CALL MSCANJ ;look for next ^J AOBJN Q3,FMAIN1 ;loop until stack initialized MOVE T1,L4M ;reinitialize ptr for LSTK SUBI T1,LSTKLN SUBI Q3,1 HRL Q3,T1 JRST FMAFI0 ;return to main FMAFIL routine ;============================================================================= ;Routine searches for a line (or lines) in a file. ; CALL FINDL ; CALL FINDLI ;same as FINDL but initializes PFP,PTR,BAP ; CALL FINDCK ;same as FINDLI but checks for BOFM and EOFM markers ;ACCEPTS: ; T4 - maximum number of lines to search before giving up ; Q1 - byte pointer to start of line ; Q2 - # bytes in line ; NP - pointer to where in pmap buffer to start searching ; NB - bytes left in pmap area after pointer ; CX - address of the FDA (File Data Area) ;RETURNS: ; +1 - line could not be found. Either EOF reached (T4 will be > 0) or ; maximum lines to search was reached (T4 will be zero). ; +2 - found the line ; Q1 - # bytes in line group of NEWer file ; Q2 - # bytes in line group of OLDer file ; ;Trashes T1-T3 & Q1 FINDCK: CALL FIBEOF ;check for BOFM and EOFM markers JRST FINDL ;PTR, BAP, PFP already intialized FINDLI: DMOVEM NP,PTR(CX) ;save ptr + bytes left MOVE T1,FPG(CX) ;get current file page starting buffer MOVEM T1,PFP(CX) ;save current ptr's file page FINDL: CAMG Q2,NB ;enough bytes left in file? IFSKP. ;yes CALL SUPMPE ;setup for PMP and get some more data RET ;end of file, so match is impossible ENDIF. MOVE T1,NP ;get ptr to start of line in file DMOVE T2,Q1 ;get ptr to start of line + length TXNE F,F%IGNO IFSKP. CALL CMPSTR## ;see if line(s) match TRNA ;no match yet - try next line JRST FINDL9 ;found where file match up again ELSE. MOVE P5,NB MOVE P6,Q2 CALL SUPCMP TRNA ;no match yet - try next line JRST FINDL9 ;found where file match up again ; no match found so get another line from the file and try that one ENDIF. SOJE T4,FINDL8 ;quit when max # lines to search reached CALL FSCANJ ;get next line from file JRST FINDL ;keep on searching ; program gets here when I've found the line in the file FINDL9: MOVEM T1,NP ;save ptr to end of match TXNE F,F%IGNO IFSKP. ;yes SUB NB,Q2 ;adjust # bytes left after pointer MOVE Q1,Q2 ;move # bytes left after pointer ELSE. SUB NB,P5 ;calculate # of byte in region of common MOVE Q1,NB ;save it MOVE NB,P5 ;store the updated byte count in NB CAIE CX,NEW ;does CX points to the NEWer file? EXCH Q1,Q2 ;no, switch around byte counts ENDIF. AOS (P) ;set +2 return FINDL8: RET ;============================================================================= ;Routine to get another line from the CX file. ; CALL FSCANJ ;ACCEPTS: ; NP,NB - containing ptr + bytes left after ptr ;RETURNS: +1 always unless EOF with T1-T2 as left by SCANJ FSCANJ: TXNN F,F%LSTK ;is LSTK initialized? JRST FSCAN5 ;no, use SCANJ to find next line MOVE T1,FMALCT ;calc index for LSTK SUB T1,T4 ;; SUBI T1,1 ;;; due to other changes in the program I no longer need to test of this ;;; HRRZ T2,LBYG+1(CX) ;get location of top of LSTK stack ;;; CAMLE T1,T2 ;if past the top of LSTK stack... ;;; JRST FSCAN5 ; ...then can't use stack CAIN CX,OLD HRRZ T1,LSTK(T1) ;get # bytes in this line of OLDer file CAIN CX,NEW HLRZ T1,LSTK(T1) ;get # bytes in this line of NEWer file CAMG T1,NB ;enough bytes left in pmap buffer? JRST FSCAN3 ;yes PUSH P,T1 ;save adjustment CALL SUPMPE ;setup for PMP and get some more data JRST FSCAN7 ;end of file encountered - so quit POP P,T1 ;restore adjustment FSCAN3: MOVN T2,T1 ADD T2,NB ;adjust # bytes after ptr ADJBP T1,NP ;adjust ptr to start of next line DMOVEM T1,NP ;save ptr + bytes left RET ; program jumps here to look for next line using SCANJ routine FSCAN5: DMOVE T1,NP ;get ptr + bytes left after ptr FSCAN6: CALL SCANJ ;look for next ^J IFSKP. ;search failed - check out why DMOVEM T1,NP ;save ptr + bytes left RET ENDIF. CALL SUPMPE ;setup for PMP and get some more data JRST FSCAN8 ;end of file encountered JRST FSCAN6 ;continue search for ^J FSCAN7: ADJSP P,-1 ;remove T1 saved on stack FSCAN8: ADJSP P,-1 ;remove call to FSCANJ from stack RET ;have FINDL routine return +1 ;=========================================================================== ;Routine to look for the next ^J character ; CALL SCANJ ;ACCEPTS: ; T1 - byte pointer to string ; T2 - length of string ;RETURNS: ; +1 - no ^J found (T2 will be zero) ; +2 - ^J found (T2 will be decremented) ;Trashes no registers SCANJ: DMOVEM T1+2,1(P) ;save T1+2,T1+3 DMOVEM T1+4,3(P) ;save T1+4,T1+5 EXCH T1,T2 ;put byte ptr and length in proper place MOVEI T1+3,1 ;write one byte if source runs out first MOVEI T1+4,T1+4 ;write nothing here if source runs out SETZB T1+2,T1+5 ;initialize for local byte pointers EXTEND T1,[MOVST JTBL] ;look for the next ^J AOS (P) ;^J found so set +2 return EXCH T1,T2 ;put byte ptr and length in proper place DMOVE T1+2,1(P) ;restore T1+2,T1+3 DMOVE T1+4,3(P) ;restore T1+4,T1+5 RET ;----------------------------------------------------------------------------- MVSTLN==^o200/2 ;length of table for MOVST instruction DEFINE MAKTBL,< ;; macro to generate the translation table for the MOVST instruction ;; it will generate a table to cause the MOVST instruction to halt on ;; line-feed (^J) XLIST $CHAR==0 REPEAT MVSTLN,< $WORD==0 ;;initialize the word IFE <$CHAR-.CTRLJ>,<$WORD==<1B2>> ;;break on ^J EXP $WORD ;;assemble the word $CHAR==$CHAR+2 ;;go on to next 2 bytes > LIST PURGE $WORD,$CHAR ;;purge temporary symbols >;end of MAKTBL JTBL: MAKTBL ;^J break table ;============================================================================= ;Routine to set up to for and do a call to PMP. The location of the file ;pointed to by NP will not be mapped out when the next PMP is done. Normally ;this routine is called when you've reached the end of the pmap area and ;want to get some more data but don't want to lose the current line you are ;working on (pointed to by NP). ; CALL SUPMP ; CALL SUPMPE -same as SUPMP but will return +2 if NOT end-of-file ; CALL SUPMP5 -alternate entry point ;ACCEPTS: ; NP,NB - pointer and bytes after pointer in pmap area ; CX - address of the FDA (File Data Area) ;RETURNS: ; +1 with NP,NB adjusted so they will point to the data they did before ; T1,T2 will be the ptr and bytes after pointer that use to ; refer to the byte at the end of the the pmap buffer. SUPMPE: SKIPG EOF(CX) ;end of file? RET ;yes, return +1 AOS (P) ;no, set +2 return SUPMP: MOVE T1,NP ;no, get ptr to start of line CALL SU4PMP ;setup for next call to PMP ADDM T1,NP ;adjust ptr SUPMP5: PUSH P,T2 ;save page adjusment CALL PMP ;get some more data POP P,T1 ;restore page adjustment LSH T1,9 ;make offset adjustment for byte ptrs ADD T1,T2 ;adjust ptr returned by PMP MOVE T2,1(P) ;get page adjustment IMUL T2,BPP(CX) ;calc byte adjustment SUBM T3,T2 ;adjust # bytes returned by PMP ADDM T2,NB ;calc # bytes left after ptr RET ;----------------------------------------------------------------------------- ;Routine to set up to for another call to PMP. It will adjust FPG(CX) so that ;next call to PMP will map in the file page pointed to by T1 but this page ;will be the first page in the pmap area and T1 will be adjusted so that ;it will refer to the location in the file it pointed to previously ; CALL SU4PMP ;ACCEPTS: ; T1 - byte ptr (refers to byte before actual byte you want) ; CX - address of the FDA (File Data Area) ;RETURNS: ; +1 - FPG(CX) ajusted so ptr supplied in T1 will be on 1st page of ; pmap buffer. T1 will contain the ptr adjusment necessary to ; readjust byte pts and T2 will contain a page adjustment ; which you may need to use after PMP is called ;Trashes none SU4PMP: IBP T1 ;adjust to point to actual byte... ; ...incase ptr on page boundry HRRZ T2,T1 ;get ptr to use LSH T2,-9 ;get page ptr is on SUB T2,FFP(CX) ;calc page offset HRRES T2 ;remove triva from LH JUMPLE T2,[TMSGL JRST DIE] ADDM T2,FPG(CX) ;add offset to current file page... ; ...and save it for next call to PMP MOVNS T1,T2 ;save page offset LSH T1,9 ;make offset adjustment for byte ptrs ADD T2,FLP(CX) ;calc page adjustment HRRES T2 ;remove triva from LH RET ;============================================================================= ;Routine to check for the BOFM or EOFM markers in the text region pointed ;to by Q1,Q2 ; CALL FIBEOF ;ACCEPTS: ; (same as FINDLI) ;RETURNS: ; +1 - only difference between this and +2 return is that PTR, BAP and PFP ; have been already initialized ; +2 - the BOFM or EOFM was found - F%BOFM, or F%EOFM will be set ; and T4,Q1,Q2,NP,NB maybe adjusted ;Trashes T1-T3 FIBEOF: AOS (P) ;set +2 return SKIPG CHGCNT ;is this the 1st change to be made? JRST FIBEO5 ;yes, check for BOFM FIBEO1: CALL CKEOFM ;check for EOFM marker in text region RET ;it's not there TXO F,F%EOFM ;set flag, EOFM marker found HRRZ T2,FLP(CX) ;get length of pmap area CAMLE T2,PGL(CX) ;is file smaller than pmap area MOVE T2,PGL(CX) ;yes, use smaller value MOVN T1,T2 ;negate it ADD T1,PGL(CX) ;calc page to start pmaping at IMUL T2,BPP(CX) ;calc # bytes in pmap area SUB T2,BLF(CX) ;sub # free bytes on the last page SUB T2,Q2 ;sub length of text region HRRZ T4,FFP(CX) ;get first page of pmap area LSH T4,9 ;convert page number to address HLL T4,BSZ(CX) ;make pointer to start of pmap area ADJBP T2,T4 ;adjust pointer to last byte of file MOVE T3,Q2 ;get # bytes left in file after ptr MOVEM T1,PFP(CX) ;save pointer file page DMOVEM T2,PTR(CX) ;save ptr + bytes after pointer PUSH P,FPG(CX) ;save current file page I'm on CALL PTRPMP ;map last page of file into pmap area POP P,PFP(CX) ;initialize ptr's file page EXCH NP,PTR(CX) ;get ptr EXCH NB,BAP(CX) ;get bytes after ptr SOS (P) ;set +1 return FIBEO9: MOVEI T4,1 ;perform FINDL loop once RET ;----------------------------------------------------------------------------- ;Routine to check for BOFM marker in the text region FIBEO5: CALL CKBOFM ;check for BOFM marker in text region JRST FIBEO1 ;it's not there - so check for EOFM... ; ...in case only one change in file ; don't neet to check for beginning of file because this code is only executed ; if CHGCNT is zero. When CHGCNT is zero then I must be at beginning of file ; CALL CKBOF ;at beginning of file? ; JRST [TMSGL > but I'm not at beginning of file!!> ; JRST DIE] TXO F,F%BOFM ;set flag, BOFM marker found JRST FIBEO9 ;found it ;============================================================================= ;Routines to check for BOFM or EOFM marker in a text region ; CALL CKBOFM ; CALL CKEOFM ;ACCEPTS: ; Q1 - byte pointer to text region ; Q2 - byte length of text region ;RETURN: ; +1 - marker not found in text region ; +2 - marker found. Q1 and Q2 will be adjusted so as to exclude the ; marker ;Trashes T1-T3 CKEOFM: MOVE T1,Q2 ;get length of text region SUBI T1,EOFMBC ;sub length of EOFM JUMPL T1,CKEOF1 ;jump if EOFM not there ADJBP T1,Q1 ;point to start of EOFM (if it exists) MOVE T2,EOFMBP ;get byte pointer to EOFM MOVEI T3,EOFMBC ;get # bytes in EOFM CALL CMPSTR## ;no, look for EOFM CKEOF1: RET ;EOFM is NOT in text region SUBI Q2,EOFMBC ;ignore EOFM in text region AOS (P) ;set +2 return RET ;----------------------------------------------------------------------------- CKBOFM: MOVE T1,Q1 ;get ptr to start of text region MOVE T2,BOFMBP ;get byte pointer to BOFM MOVEI T3,BOFMBC ;get # bytes in BOFM CAMG T3,Q2 ;is text region shorter than BOFM ? CALL CMPSTR## ;no, look for BOFM RET ;BOFM is not in text region MOVEM T1,Q1 ;save ptr to byte after BOFM SUBI Q2,BOFMBC ;calc # bytes in text region after BOFM AOS (P) ;set +2 return RET ;=========================================================================== ;Routine to output the difference between the two files. ; CALL OUTDIF ;ACCEPTS: ; PFP,PTR,BAP - refer the beginning of the first line of the files that ; don't match ; FPG,OP,OB - refer to the OLDer file and point to the end of the line ; group where the files started matching up again ; FPG,NP,NB - refer to the NEWer file and point to the end of the line ; group where the files started matching up again ; Q2 - length of matching line group in bytes. If < zero then ; all data from PTR to the end-of-file will be output ;RETURNS: ; +1 - always (NOTE: the FPG,OP,OB for the OLDer file and FPG,NP,NB ; for the NEWer file may have been adjusted by CKPTR but they ; will still point to the same actual position in the file) ;Trashes: T1-Q1 OUTDIF: SKIPG CHGCNT ;is this the first difference? CALL OUTHDR ;yes, output header stuff HRRZ T1,OUT+JFN RVIDON ;turn reverse video on MOVE T2,CSTRBP ;get byte pointer to CHANGE string TXNN F,F%UPDF ;use update format? IBP T2 ;no, skip first byte of string SETZ T3, OSOUT% AOS T2,CHGCNT ;get and increment difference count NUMOUT (,,-) SPTR T2,< > SETZ T3, OSOUT% MOVE T2,FSTRBP ;get byte pointer to FILE string TXNN F,F%UPDF ;use update format? IBP T2 ;no, skip first byte of string OSOUT% SPTR T2,<1 > OSOUT% CATOFF ;turn reverse video off PUSH P,Q1 MOVEI CX,OLD DMOVE T1,OP ;get ptr + bytes after ptr CALL ODIF ;output the region of difference DMOVEM T1,OP ;save ptr + bytes incase it was changed HRRZ T1,OUT+JFN RVIDON ;turn reverse video on MOVE T2,FSTRBP ;get byte pointer to FILE string TXNN F,F%UPDF ;use update format? IBP T2 ;no, skip first byte of string SETZ T3, OSOUT% SPTR T2,<2 > OSOUT% CATOFF ;turn reverse video off POP P,Q2 ;get Q1 into Q2 MOVEI CX,NEW DMOVE T1,NP ;get ptr + bytes after ptr CALL ODIF ;output the region of difference DMOVEM T1,NP ;save ptr + bytes incase it was changed RET ;============================================================================= ;Routine to output the differences between two files plus one line in common. ;If the F%UPDF flag is set then a few more lines of text will be output either ;before and after the region of difference. ; CALL ODIF ;ACCEPTS: (see OTXT) ;RETURNS: +1 - always ;Trashes T3-Q1 ODIF: TXNN F,F%UPDF ;writing output file in /UPDATE-FORMAT? JRST ODIF7 ;no JUMPG Q2,ODIF7 ;jump if NOT outputing to EOF ; if the output file is to be written in /UPDATE-FORMAT and I'm outputing ; to EOF then I must place a few lines before the difference in the output file ; so the UPDATE procedure will know where to put the update PUSH P,T1 ;save registers PUSH P,T2 CALL PTRPMP ;set pmap buffer to start of text DMOVE T1,PTR(CX) ;get ptr + bytes MOVE T3,L4M ;get # lines required for a match CALL FBACKJ ;back up a line... SOJG T3,.-1 ; ...loop for required # of lines DMOVEM T1,PTR(CX) ;save updated ptr + bytes MOVE T1,FPG(CX) ;get file page starting buffer MOVEM T1,PFP(CX) ;save ptr's file page POP P,T2 ;restore registers POP P,T1 ODIF7: SKIPN PFP(CX) ;am I at beginning of file? CALL OBOFM ;could be, check it out CALL OTXT ;output the region of difference JUMPL Q2,OEOFM ;if EOF then output EOF marker DMOVEM T1,1(P) ;save registers ADJSP P,2 ;adjust stack ptr for later calls MOVN T2,Q2 ADJBP T2,T1 ;back up ptr to start of text HRRZ T1,OUT+JFN MOVE T3,Q2 ;# bytes in line group SKIPN T3 ;skip if no bytes to output IFSKP. TXNN F,F%UPDF ;is user in update mode? CALL EATLIN ;no, print the first non-blank line TXNE F,F%UPDF ;writing output file in /UPDATE-FORMAT? MOVN T3,T3 ;yes, write all of matching line group MOVEI T4,.CTRLJ ;output up to next ^J OSOUT% ENDIF. ADJSP P,-2 ;adjust stack ptr to restore ACs DMOVE T1,1(P) ;restore registers RET ;============================================================================= ;Routine to output the beginning-of-file marker to the output file ; CALL OBOFM ;ACCEPTS: no registers need to be initialized ;RETURNS: +1 - always ;Trashes T3,T4 OBOFM: CALL CKBOF ;at beginning of file? RET ;no, don't write marker HRROI T4,BOFM ;get beginning-of-file marker CALLRET OMRKER ;output marker ;----------------------------------------------------------------------------- ;Routine to check to see if PTR is pointing to beginning of the file or ;beginning of pmap buffer ; CALL CKBOF -checks to see if ptr at beginning of file ; CALL CKBOB -checks to see if ptr at beginning of pmap buffer ;ACCEPTS: ; CX - address of the FDA (File Data Area) ;RETURNS: ; +1 - PTR is NOT pointing to beginning of file/buffer ; +2 - PTR is pointing to beginning of the file/buffer ;Trashes T3 CKBOF: SKIPE PFP(CX) ;at beginning of file? RET ;no, return +1 CKBOB: MOVE T3,FFP(CX) ;get first page of pmap area LSH T3,9 ;convert page number to address HLL T3,BSZ(CX) ;make pointer to start of pmap area CAMN T3,PTR(CX) ;am I at the beginning of the file? IFSKP. ;yes MOVEM T3,1(P) ;save ptr SETZ T3, ADJBP T3,1(P) ;make it a real ptr CAME T3,PTR(CX) ;am I at the beginning of the file? RET ;no ENDIF. AOS (P) ;set +2 return RET ;============================================================================= ;Routine to output the end-of-file marker to the output file ; CALL OEOFM ;ACCEPTS: no registers need to be initialized ;RETURNS: +1 - always ;Trashes T3,T4 OEOFM: HRROI T4,EOFM ;get end-of-file marker OMRKER: PUSH P,T1 ;save registers PUSH P,T2 HRRZ T1,OUT+JFN SENDES <> ;turn blinking on MOVE T2,T4 ;get marker to output SETZ T3, OSOUT% CATOFF ;turn blinking off POP P,T2 ;restore registers POP P,T1 RET ;============================================================================= ;Routine to output the header information for file differences ; CALL OUTHDR ;ACCEPTS: no registers need to be initialized ;RETURNS: +1 -always ;Trashes none OUTHDR: DMOVEM T1,1(P) ;save needed AC's DMOVEM T3,3(P) ADJSP P,4 ;adjust stack for later CALLs HRRZ T1,OUT+JFN SETZ T3, TXNN F,F%TTY ;skip if output to the terminal TXNN F,F%APND ;appending to the output file? JRST OUTHD1 ;no SPTR T2,< > OSOUT% OUTHD1: SPTR T2,< File 1: > OSOUT% FILSTR (OLD+JFN,,-) SETZ T3, SPTR T2,< File 2: > OSOUT% FILSTR (NEW+JFN,,-) SETZ T3, SPTR T2,< > OSOUT% ADJSP P,-4 ;adjust stack pointer DMOVE T1,1(P) ;restore registers DMOVE T3,3(P) RET ;============================================================================= ;Routine to output the region of text to the output file. ; CALL OTXT ;ACCEPTS: ; FPG - pointer file page for T1,T2 ; T1 - byte pointer to end of region of text to output ; T2 - bytes left in pmap buffer after pointer in T1 ; Q2 - number of bytes at end of region to ignore - this data will not ; be output. If less than 0 then all the data from PFP,PTR,BAP ; to the end-of-file will be output. ; CX - address of the FDA (File Data Area) ; PFP,PTR,BAP - refer the beginning of the region of text to output ;RETURNS: ; +1 - always (NOTE: T1,T2 may be adjusted by CKPTR but they ; will still point to the same actual position in the file) ;Trashes T3-Q1 OTXT: JUMPL Q2,OTXEOF ;jump to output from PTR to EOF TXNE F,F%TTY ;output going to TTY? CALL SETDCC ;yes, set CCOC words for display DMOVEM OP,1(P) ;save registers DMOVEM NP,3(P) ADJSP P,4 ;adjust because I will do a CALL later MOVN OP,Q2 ADJBP OP,T1 ;back up ptr to start of text to ignore ADD T2,Q2 ;calc # bytes left MOVEM T2,OB ;save it MOVE Q1,FPG(CX) ;get pointer file page for ptr in OP CALL PTRPMP ;set pmap buffer to start of text DMOVE NP,PTR(CX) ;get ptr + bytes to output SETZ T4, ;initialize flag OTXT3: MOVE T1,Q1 ;get ptr's file page DMOVE T2,OP ;get ptr + byte count CALL CKPTR ;is this area of file in pmap buffer? IFSKP. ;no, not yet SETO T4, ;set flag DMOVEM T2,OP ;save ptr + bytes after ptr SUB NB,OB ;calc bytes to output ENDIF. HRRZ T1,OUT+JFN ;get output device DMOVE T2,NP ;get ptr + bytes to output SKIPN T3 ;skip if no bytes to output IFSKP. CALL EATLIN MOVN T3,T3 ;write a string this long OSOUT% ENDIF. JUMPL T4,OTXT5 ;quit when flag set CALL NXTPMP ;not done yet - get some more data DMOVEM T2,NP ;save ptr + bytes after ptr JRST OTXT3 ;loop back to output difference OTXT5: MOVE T1,Q2 ADJBP T1,OP ;advance ptr to end of text MOVE T2,OB SUB T2,Q2 ;calc # bytes left ADJSP P,-4 ;adjust stack pointer DMOVE OP,1(P) ;restore registers DMOVE NP,3(P) TXNE F,F%TTY ;output going to TTY? CALL SETOCC ;yes, reset original CCOC words RET ;============================================================================= ;routine to output from PTR to the end-of-file ; CALL OTXEOF ;ACCEPTS: (see OTXT) ;RETURNS: (see OTXT) ;Trashes: T3 OTXEOF: TXNE F,F%TTY ;output going to TTY? CALL SETDCC ;yes, set CCOC words for display PUSH P,T1 ;save registers PUSH P,T2 CALL PTRPMP ;set pmap buffer to start of difference DMOVE T2,PTR(CX) ;get ptr + bytes to output OTXEO1: HRRZ T1,OUT+JFN ;get output device MOVN T3,T3 ;write a string this long SKIPE T3 ;skip if no bytes to output OSOUT% SKIPG EOF(CX) ;at end of file? IFSKP. ;yes CALL NXTPMP ;no, get some more data JRST OTXEO1 ;loop back and write some more ENDIF. POP P,T2 ;restore registers POP P,T1 TXNE F,F%TTY ;output going to TTY? CALL SETOCC ;yes, reset original CCOC words RET ;=========================================================================== ;Routine to write the output file and replace one region of text with another ; CALL OUTRPL ;ACCEPTS: ; PFP,PTR,BAP - refer the beginning of text that needs to be written ; to the output file ; FPG,OP,OB - refer to the OLDer file and point to the end of the text ; region that is to be replaced by the one in the NEWer file ; Q2 - length of text region in the OLDer file that will be replaced ; by the text region of the NEWer file ; FPG,NP,NB - refer to the NEWer file and point to the end of the text ; region that is to replace the one in the OLDer file ; Q3 - length of text region in the NEWer file that will replace the ; text region of the OLDer file ;RETURNS: ; +1 - always (NOTE: the FPG,OP,OB for the OLDer file and FPG,NP,NB ; for the NEWer file may have been adjusted by CKPTR but they ; will still point to the same actual position in the file) ;Trashes: T1-Q2 OUTRPL: MOVEI CX,OLD DMOVE T1,OP ;get ptr + bytes after ptr CALL OTXT ;output upto the replacement text DMOVEM T1,OP ;save ptr + bytes incase it was changed HRRZ T1,OUT+JFN ;if output is to the terminal then... RVIDON ; ...turn reverse video on MOVEI CX,NEW SETZ Q2, ;output all of replacement text TXNE F,F%BOFM!F%EOFM ;was BOFM or EOFM found in the change? CALL IBEOFM ;yes, ignore BOFM or EOFM for output DMOVE T1,NP ;get ptr + bytes after ptr CALL OTXT ;output the replacement text DMOVEM T1,NP ;save ptr + bytes incase it was changed HRRZ T1,OUT+JFN ;if output is to the terminal then... CATOFF ; ...turn reverse video off AOS CHGCNT ;increment # changes made to file RET ;----------------------------------------------------------------------------- ;Routine to adjust the pointers so BOFM or EOFM markers are not written out ;to the output file. IBEOFM: DMOVE Q1,PTR(CX) ;get ptr + bytes to start of text SUB Q2,NB ;calc length of replacement text TXZN F,F%BOFM ;was BOFM found earlier? IFSKP. ;no, must have been EOFM CALL CKBOFM ;check for BOFM in replacement text CALLRET [HRROI T1,BOFM CALLRET IBEOFE] ; TXZ F,F%BOFM ;clear BOFM flag ADD Q2,NB ;calc # bytes after ptr DMOVEM Q1,PTR(CX) ;save new ptr + bytes SETZ Q2, ;output all of replacement text RET ENDIF. CALL CKEOFM ;check for EOFM in replacement text CALLRET [HRROI T1,EOFM CALLRET IBEOFE] ADD Q2,NB ;calc # bytes after ptr MOVN Q2,Q2 ;negate it ADD Q2,BAP(CX) ;ignore EOFM at end of text RET ;----------------------------------------------------------------------------- ;Routine to output error message if both change and replacement text don't ;contain the BOFM or EOFM IBEOFE: PUSH P,T1 ;save marker TMSGL <%The text for "> HRROI T1,FSTR PSOUT% TMSG <2" in change #> NUMOUT (CHGNUM) TMSG < should also contain > POP P,T1 ;get marker PSOUT% SETZ Q2, ;output all of replacement text RET ;============================================================================= ;Routine to send an escape sequence. The position ;of the terminals pointer is adjusted so that the monitor won't count ;the esc-sequence being set and try to put in a where is shouldn't ;(I assume the esc-sequence will not be displayed by the terminal). ; CALL SNDES ;ACCEPTS: ; T1 - output JFN ; T2 - esc-sequence string to send ;RETURNS: +1 always ;Trashes T2,T3 .RVIDO: SPTR T2,<> ;turn reverse video on TRNA .CATOF: SPTR T2,<> ;turn all character attributes off SNDES: TXNN F,F%SES ;send escape sequence? RET ;no DMOVEM T4,1(P) ;save registers MOVEM T2,T4 ;save escape sequence to send DMOVE T2,MCCOC ;set the modified CCOC words SFCOC% ;modify CCOC RFPOS% ;get current line#,,column# MOVEM T2,Q1 ;save it TRZ T2,-1 ;reset column# incase near end of line SFPOS% ;set current line#,,column# MOVE T2,T4 ;get escape sequence to send SETZ T3, SOUT% JERR (?,,PC,DIE) MOVE T2,Q1 SFPOS% ;set current line#,,column# DMOVE T2,OCCOC ;set the original CCOC words SFCOC% DMOVE T4,1(P) ;restore registers RET ;============================================================================= ;Routine to set the CCOC words. ; CALL SETDCC ;set CCOC in DCCOC ; CALL SETOCC ;set CCOC in OCCOC ;ACCEPTS: no registers need to be initialized ;RETURNS: +1 always ;Trashes none SETOCC: DMOVEM T2,2(P) ;save registers DMOVE T2,OCCOC ;get original CCOC words CALLRET SETDC1 SETDCC: DMOVEM T2,2(P) ;save registers DMOVE T2,DCCOC ;get "display" CCOC words SETDC1: MOVEM T1,1(P) ;save register HRRZ T1,OUT+JFN ;get output device SFCOC% MOVE T1,1(P) ;restore registers DMOVE T2,2(P) RET SUBTTL Server for UPDATE command ;============================================================================= .UPDAT: HRLZI T4,(GJ%OLD) ;parse existing file MOVEM T4,GTJBLK+.GJGEN NOISE (source file) PARSE (,<.CMFIL,CM%SDH,,>) MOVEM T2,OLD+JFN ;save JFN NOISE (using changes in) PUSH P,T1 ;save register HRROI T1,FSPEC ;default file name is here MOVEM T1,GTJBLK+.GJNAM FILSTR (OLD+JFN,,-) POP P,T1 ;restore register HRROI T4,[ASCIZ/CMP/] ;use this default file extension MOVEM T4,GTJBLK+.GJEXT PARSE (,<.CMFIL,CM%SDH,,>) MOVEM T2,NEW+JFN ;save JFN NOISE (giving) HRLZI T4,(GJ%FOU) ;parse a new file generation MOVEM T4,GTJBLK+.GJGEN CALL SETDNE ;set up the default name + extension TXZ F,F%VRFY!F%WILD!F%LSTK!F%IGNO ;initialize flags PARSE (,<.CMFIL,,,,,,UPDSWI>) UPDAT5: TLZ T3,-1 ;get function discriptor block parsed CAIN T3,CONFRM## ;user confirmed command? JRST UPDAT7 ;yes CAIE T3,UPDSWI ;a switch? IFSKP. ;no TXO F,F%VRFY ;yes, set it CONFIRM JRST UPDAT8 ENDIF. HRRZM T2,OUT+JFN ;no, must have parsed the output file PARSE (,,UPDSWI) ;parse a switch JRST UPDAT5 UPDAT7: CALL DOECHO## ;echo the command if necessary UPDAT8: CALL UPDFIL ;update the file JRST ENDCMD ;go get another command ;============================================================================= ;Routine to update a ascii file using the changes in a update file ; CALL UPDFIL ;ACCEPTS: no registers need to be initialized ;RETURNS: +1 always ;Trashes - most registers UPDFIL: HRRZ T1,OUT+JFN ;get JFN of output device CALL CKDEV ;check output device CATOFF ;make sure graphic attributes off CALL FOPEN ;open the required files MOVEI T1,UPDXIT ;exit routine for ^E,^X abort CALL ATIAEX ;activate for interrupts TXZ F,F%ABRT!F%BOFM!F%EOFM ;initialize flags SETZM CHGCNT ;initialize change count SETZM CHGNUM ;initialize change number UPDBEG: MOVEI CX,NEW ;initialize FDA to file with changes MOVE Q1,CSTRBP ;byte pointer to CHANGE string MOVEI Q2,CSTRBC ;# bytes in CHANGE string SETZ T4, ;search until EOF CALL FINDLI ;search for next change JRST UPDNOD ;couldn't find change delimiter UPDLUP: DMOVE T1,NP ;get updated ptr + bytes left in buffer CALL USCANJ ;look for next ^J MOVE T3,NP ;get ptr ILDB T3,T3 ;get byte after CHANGE string CAIN T3,TSTRFB ;is this the end of all changes? JRST UPDEOF ;yes, quit TXNE F,F%EOFM ;was EOFM marker found in last change? JRST [TMSGL HRROI T1,EOFM PSOUT% TMSG <" was found in change #> NUMOUT (CHGNUM) TMSG < but this is NOT the last change in the file. Will assume that is should be > JRST UPDEOF] EXCH T1,NP ;save updated ptr... MOVEM T2,NB ; ...and bytes left CALL D2B## ;get change number AOS CHGNUM ;increment change number CAME T2,CHGNUM ;is it right? JRST [PUSH P,T2 ;save number TMSGL <%Was expecting change #> NUMOUT (CHGNUM) TMSG < but found change #> POP P,T2 ;restore number NUMOUT TMSG < instead > CAMG T2,CHGNUM ;is new change number bigger that last JRST [ TXO F,F%ABRT ;no TMSG JRST UPDXIT] MOVEM T2,CHGNUM ;attempt to recover TMSG < will contiune processing updates from here.... > JRST .+1] MOVE Q1,FSTRBP ;byte pointer to FILE string MOVEI Q2,FSTRBC ;# bytes in FILE string SETZ T4, ;search until EOF CALL FINDLI ;search for start of "File 1" change JRST UPDNOD ;couldn't find change delimiter DMOVE T1,NP ;get updated ptr + bytes left in buffer CALL USCANJ ;look for next ^J ILDB T3,NP ;get file number CAIE T3,"1" ;is this it? JRST UPDNOF ;no DMOVEM T1,NP ;save ptr+bytes for start of change MOVE Q1,FSTRBP ;byte pointer to FILE string MOVEI Q2,FSTRBC ;# bytes in FILE string SETZ T4, ;search until EOF CALL FINDLI ;search for end of "File 1" change JRST UPDNOD ;couldn't find change delimiter DMOVE T1,NP ;get updated ptr + bytes left in buffer CALL USCANJ ;look for next ^J ILDB T3,NP ;get file number CAIE T3,"2" ;is this it? JRST UPDNOF ;no DMOVEM T1,NP ;save ptr+bytes for start of replacement CALL FBACKJ ;search backward for a ^J DMOVE Q1,PTR(CX) ;get ptr+bytes for start of change SUB Q2,T2 ;calc # bytes in change JUMPLE Q2,UPDNOB ;no bytes - should not happen MOVEI CX,OLD EXCH OP,NP ;exchange byte ptrs and... EXCH OB,NB ; ...byte counts to search OLDer file SETZ T4, ;search until EOF CALL FINDCK ;search for where to put change JRST [TMSGL NUMOUT (CHGNUM) ; TMSG < in > ; FILSTR (JFN(CX)) TMSG < (this update will NOT be made) > CALL PTRPMP ;go back to where I was DMOVE OP,NP ;restore ptr + bytes back to normal DMOVE NP,PTR(CX) ;get ptr + bytes left in buffer JRST UPDBEG] ;ignore this update TXNN F,F%BOFM!F%EOFM ;verify NOT needed if BOFM or EOFM found TXNN F,F%VRFY ;verify the change is unique? IFSKP. ;no PUSH P,PFP(CX) ;save file location data PUSH P,PTR(CX) PUSH P,BAP(CX) CALL FINDLI ;see if string occurs more than once TRNA ;didn't find another occurance JRST [TMSGL NUMOUT (CHGNUM) TMSG < is not unique. Will make change to 1st occurance ONLY!! > JRST .+1] CALL PTRPMP ;go back to where I was before FINDLI DMOVE NP,PTR(CX) ;restore ptr + bytes after ptr POP P,BAP(CX) ;restore file location data POP P,PTR(CX) POP P,PFP(CX) ENDIF. MOVEI CX,NEW EXCH OP,NP ;exchange byte ptrs and... EXCH OB,NB ; ...byte counts so I'm back to normal PUSH P,Q2 ;save length of change text MOVE Q1,CSTRBP ;byte pointer to CHANGE string MOVEI Q2,CSTRBC ;# bytes in CHANGE string SETZ T4, ;search until EOF CALL FINDLI ;search for next change JRST UPDNOD ;couldn't find change delimiter POP P,Q2 ;restore length of change text PUSH P,NP ;save ptr to end of CHANGE string... PUSH P,NB ; ...and bytes after ptr DMOVE T1,NP ;get ptr + bytes left in buffer CALL FBACKJ ;search backward for a ^J DMOVEM T1,NP ;save ptr + bytes left in buffer MOVE Q3,BAP(CX) ;get bytes after start of replacement SUB Q3,NB ;calc # bytes in replacement text JUMPLE Q3,UPDNOB ;no bytes - should not happen CALL OUTRPL ;write output file using replacement POP P,NB ;restore ptr to end of CHANGE string... POP P,NP ; ...and bytes after ptr JRST UPDLUP ;loop back to make next update ;============================================================================= ;Routine to search for the next ^J in the update file ; CALL USCANJ ;ACCEPTS: ; NP,NB - containing ptr + bytes left after ptr ;RETURNS: +1 always unless EOF with T1-T2 as left by SCANJ USCANJ: DMOVE T1,NP ;get ptr + bytes left after ptr USCAN1: CALL SCANJ ;look for next ^J TRNA ;search failed - check out why RET CALL SUPMPE ;setup for PMP and get some more data JRST [ TMSGL FILSTR (NEW+JFN) ADJSP P,-1 ;remove CALL to USCANJ from stack TXO F,F%ABRT JRST UPDXIT] ;abort update JRST USCAN1 ;continue SCANJ ;============================================================================= ;Program jumps here when the end of the update file is reached UPDEOF: MOVEI CX,OLD MOVE Q2,FPG(CX) ;get file page starting buffer MOVEM Q2,PFP(CX) ;init ptr's file page DMOVEM OP,PTR(CX) ;init ptr + bytes after ptr SETO Q2, ;write anything left in the source... CALL OTXT ; ... file to the output file SPTR T1,< > PSOUTL NUMOUT (CHGCNT) TMSG < change> MOVEI T1,"s" CAIE T2,1 ;more that 1 change? PBOUT% ;yes, get tense right TMSG < made using > FILSTR (NEW+JFN) TMSG < > MOVEI T1,TSTRBC ;get length of TSTR ADJBP T1,NP ;skip over it CALL D2B## ;get total number of changes CAME T2,CHGCNT ;is it same as # of changes I made? JRST [TMSG <% ...but update file said there should have been > NUMOUT TMSG < changes!! > JRST .+1] ;----------------------------------------------------------------------------- UPDXIT: CALL DTIAEX ;deactivate for ^A,^E interrupts CALLRET FCLOSE ;close all files and return to caller ; SUBTTL Error handlers for UPDATE ;----------------------------------------------------------------------------- UPDNOB: TMSGL NUMOUT (CHGNUM) TXO F,F%ABRT JRST UPDXIT ;----------------------------------------------------------------------------- ;program jumps here when either CSTR or FSTR couldn't be found. This strings ;are used to delimit the changes and replacements to be made to the file so it ;is important that they be in the file ; JRST UPDNOD ;ACCEPTS: ; Q1 - either CSTR or FSTR ;RETURNS: never UPDNOD: TMSGL MOVE T1,Q1 ;get CPTR or FPTR PSOUT% TMSG <" to delimit changes Problem with file or file was not written in /UPDATE-FORMAT> TXO F,F%ABRT ;abort any updates done so far JRST UPDXIT ;----------------------------------------------------------------------------- ;program jumps here when byte after FSTR was not "1" or "2" or was not what I ; was expecting ; JRST UPDNOF ;ACCEPTS: ; T3 - byte found after FSTR ;RETURNS: never UPDNOF: TMSGL MOVE T1,T3 PBOUT% TMSG <" after "> HRROI T1,FSTR PSOUT% TMSG <" for change #> NUMOUT (CHGNUM) TMSG < This is not what I was expecting > TXO F,F%ABRT ;abort any updates done so far JRST UPDXIT SUBTTL Miscellaneous Subroutines ;============================================================================= ;This routine will set the default file name and file extension in the ;GTJBLK to the same as those of the OLDer file ; CALL SETDNE ;ACCEPTS: ; OLD+JFN - JFN of OLDer file ;RETURNS: +1 always ;Trashes T2-T3 SETDNE: PUSH P,T1 ;save register HRROI T1,FSPEC ;default file name is here MOVEM T1,GTJBLK+.GJNAM MOVE T2,OLD+JFN ;get flags,,JFN FILSTR (-,,-) IBP T1 ;preserve null at end of string MOVEM T1,GTJBLK+.GJEXT ;defalut file extension will be here FILSTR (-,,-) POP P,T1 ;restore register RET ;============================================================================= ;This routine will initialize command switches to their default values. ; CALL SWINI ;ACCEPTS: nothing ;RETURNS: +1 always ;Trashes T4 SWINI: TXZ F,DSWIF ;clear these default flags IOR F,DSWI.S ;set the ones that should be set MOVE T4,DL4M ;get default lines for a match MOVEM T4,L4M ;initialize it MOVE T4,DL2S ;get default lines to search MOVEM T4,L2S ;initialize it RET ;============================================================================= ;Routine to compare files when the files have wildcards in their file specs ; CALL WLDCMP ;ACCEPTS: no registers need to be initialized ;RETURNS: +1 always WLDCMP: TXO F,F%APND ;insure output file is appended to HRROI T1,OLDFSW MOVE T2,OLD+JFN CALL BLDFS ;put wild file specs here HRROI T1,NEWFSW MOVE T2,NEW+JFN CALL BLDFS ;put wild file specs here RELJFN NEW+JFN ;don't need JFN anymore SETZM FILCNT ;initialize the file count WLDCM1: HRROI T1,OLDFS HRRZ T2,OLD+JFN CALL BLDFS ;put non-wild file specs here MOVE P1,[POINT 7,OLDFSW] MOVE P2,[POINT 7,OLDFS] MOVE P3,[POINT 7,NEWFSW] MOVE P4,[POINT 7,FSPEC] CALL BWILD ;build the NEW DEV: fields CALL BWILD ;build the NEW file-name field CALL BWILD ;build the NEW file-type field CALL BWILD8 ;build the NEW file-generation field MOVX T1,GJ%SHT!GJ%IFG!GJ%OLD ;get JFN for NEWer file HRROI T2,FSPEC GTJFN% JRST [TMSGL ;couldn't get JFN for some reason HRROI T1,FSPEC PSOUT% CALL ERSTRI## ;output last error message JRST WLDCM8] MOVEM T1,NEW+JFN ;save indexable file handle WLDCM3: TMSGL < Comparing > FILSTR (OLD+JFN) TMSG < with > FILSTR (NEW+JFN) ; TXNE F,F%TTY ;output going to the terminal? ; JRST WLDCM6 ;yes ; MOVE T2,OUT+JFN ; TXNN T2,GJ%DEV!GJ%DIR!GJ%NAM!GJ%EXT!GJ%VER ;wildcards found? ; JRST WLDCM6 ;no ; TMSG < outputing to > ; **** must add code to built output file here *** ;WLDCM6: TMSG < > CALL CMPFIL ;compare the files AOS FILCNT ;increment file count WLDCM8: MOVEI CX,NEW CALL NEXTF ;get next file in group TRNA ;no more file in wildcard group JRST WLDCM3 ;go process next file MOVEI CX,OLD CALL NEXTF ;get next file in group TRNA ;no more file in wildcard group JRST WLDCM1 ;go process next file TMSGL < A total of > NUMOUT (FILCNT) TMSG < comparisons were done > TXZ F,F%WILD ;let OCLOSE close the file CALLRET OCLOSE ;close the output file ;============================================================================= ;Routine to execute the GNJFN% to get the next file in the wildcard group ; CALL NEXTF ;ACCEPTS: ; CX - address of the FDA (File Data Area) ;RETURNS: ; +1 - no more files in wildcard group. JFN will be released and JFN(CX) ; will be set to zero ; +2 - JFN will now refer to next file in wildcard group ;Trashes T1 NEXTF: SKIPN T1,JFN(CX) ;get indexable file handle RET ;JFN released so no more files GNJFN% ;get next JFN in wildcard group IFSKP. ;GNJFN jsys failed AOS (P) ;set +2 return RET ENDIF. CAIE T1,GNJFX1 ;GNJFN failed because no more JFN's? ERR (?,,PC,DIE) ;no, some other error SETZM JFN(CX) ;JFN is released (last GNJFN% did it) CALLRET ERESET ;reset last error ;============================================================================= ;Routine to build a the file string required by BWILD, each field will be ;separated by a null ; CALL BLDFS ;ACCEPTS: ; T1 - byte pointer to where file string is to go ; T2 - JFN or indexable file handle (flags,,JFN) ;RETURNS: +1 always ;Trashes T1-T3 BLDFS: FILSTR (-,,-) IBP T1 ;keep null at end FILSTR (-,,-) IBP T1 ;keep null at end FILSTR (-,,-) IBP T1 ;keep null at end FILSTR (-,,-) RET ;============================================================================= ;Routine to build a new non-wild string from a wild and non-wild string and ;a 2nd wild string. The 1st non-wild string must be a valid element in the ;wildcard set of the 1st wild string - no checking will be done to insure this. ; CALL BWILD ; CALL BWILD8 -write bytes directly from 2nd wild string to non-wild ;ACCEPTS: ; P1 - byte pointer to 1st wild string ; P2 - byte pointer to 1st non-wild string ; P3 - byte pointer to 2nd wild string ; P4 - byte pointer to where to place 2nd non-wild string ;RETURNS: ; +1 with P1-P4 updated to end of strings. P4 is adjusted so that ; next IDPB will overwrite termining null ;Trashes T1-T4 BWILD: BWILD1: ILDB T1,P1 ;get a byte from 1st wild string ILDB T2,P2 ;get a byte from 1st non-wild string JUMPE T1,BWILD8 ;end of 1st wild string found CAMN T1,T2 JRST BWILD1 ;loop until difference found SETO T2, ADJBP T2,P2 ;back up ptr to 1st non-wild string MOVEM T2,P2 ;save it ;don't need to check because I left that up to the user who called me ; CAIE T1,"*" ; CAIN T1,"%" ; TRNA ; JRST [TMSGL ; JRST ENDCMD] BWILD2: ILDB T3,P3 ;get a byte from 2nd wild string JUMPE T3,BWILD6 ;end of 2nd wild string found CAIE T3,"*" CAIN T3,"%" IFSKP. ;wildcard found IDPB T3,P4 ;build new string JRST BWILD2 ;loop back for more ENDIF. CAME T1,T3 ;wildcards should be same for both JRST [TMSGL JRST ENDCMD] CAIE T1,"%" IFSKP. ILDB T2,P2 ;get byte from 1st non-wild string IDPB T2,P4 ;build 2nd non-wild string JRST BWILD1 ;loop back to process more wildcards ENDIF. ; find the text region that corresponds to the wildcard to the 2nd non-wild ; string MOVE T3,P1 ;save ptr to 1st wildcard string SETZ T4, BWILD4: ILDB T1,P1 ;get byte from 1st wild string JUMPE T1,BWILD7 ;quit when end of 1st wild string CAIE T1,"*" CAIN T1,"%" TRNA ;found another wildcard AOJA T4,BWILD4 ;keep on searching JUMPE T4,BWILD2 ;2 wildcards are next to each other MOVEM T3,P1 ;restore ptr to 1st wildcard string BWILD5: DMOVE T1,P1 ;get ptr to wild + non-wildstring MOVE T3,T4 ;get length of common string CALL CMPSTR## ;look for common string TRNA ;not found yet IFSKP. ;found it ILDB T2,P2 ;get byte from 1st non-wild string IDPB T2,P4 ;build 2nd non-wild string JRST BWILD5 ;keep on looking for a match ENDIF. DMOVEM T1,P1 ;save updated pointers JRST BWILD1 ;loop back to process more wildcards ; execution gets here when end of 2nd wild string found. So make sure pointers ; to 1st wild and non-wild string are updated (point to the end of string) BWILD6: ILDB T1,P1 ;advance to end of 1st wild string JUMPN T1,.-1 ;loop until null is reached ILDB T2,P2 ;advance to end of 1st non-wild string JUMPN T2,.-1 ;loop until null is reached JRST BWILD9 ;quit ; execution gets here when end of 1st wild string found when looking for ; the string that the wildcard matches. When this happens (usually about 90% ; of the time) I don't have to do the "expensive" CMPSTR loop because I have ;the information to shortcut the process. BWILD7: SETZ T3, ;initialize count MOVE T2,P2 ;get ptr to 1st non-wild string ILDB T1,P2 ;get byte from 1st non-wild string SKIPE T1 AOJA T3,.-2 ;loop until end of string SUB T3,T4 ;calc # bytes corresponding to "*" JUMPE T3,BWILD8 ;no bytes correspond to "*" ILDB T1,T2 ;get byte from 1st non-wild string IDPB T1,P4 ;add it to 2nd non-wild string SOJG T3,.-2 ;loop until done ; execution gets here when end of 1st wild string found. So write any left ; over bytes in 2nd wild string to the 2nd non-wild string I'm building BWILD8: ILDB T3,P3 ;get byte from 1st non-wild string BWILD9: IDPB T3,P4 ;build 2nd non-wild string JUMPN T3,BWILD8 ;loop for all bytes in 2nd non-wild SETO T2, ADJBP T2,P4 ;back up ptr past terminating null MOVEM T2,P4 ;save it RET ;============================================================================= ;This routine will check the output device to determine whether it's a ;terminal and set the appropiate flags ; CALL CKDEV ;ACCEPTS: ; T1 - JFN of output device ;RETURNS ; +1 - always with F%SES set appropriately and T1 will contain the ; output designator ;Trashes T2-T3 CKDEV: TXZ F,F%SES!F%TTY ;initialize flags DVCHR% ;get characteristics of the device JERR (?,,PC) TLZ T2,777000 ;remove unwanted info HLRZ T2,T2 ;get device type CAIN T2,.DVTTY ;is it a terminal TXO F,F%TTY ;yes, set flag TXNE F,F%VT ;is program running from a VT100? TXNN F,F%TTY ; ...and output going to the terminal? TRNA ;no TXO F,F%SES ;yes, set flag to send escape sequences RET ;============================================================================= ;Routine to open all required files ; CALL FOPEN ;ACCEPTS: no registers need to be initialized ;RETURNS: +1 always ;Trashes T1-T3 FOPEN: MOVEI CX,OLD CALL FOPEN7 ;open file and map some pages in DMOVEM T2,OP ;save byte ptr + byte count MOVEI CX,NEW CALL FOPEN7 ;open file and map some pages in DMOVEM T2,NP ;save byte ptr + byte count HRRZ T1,OUT+JFN CAIE T1,.PRIOU ;output going here? TXOE F,F%OPEN ; or is it already open? RET ;yes, I'm done MOVX T2,+OF%WR ;open the file, ascii write ; TXNE F,F%APND ;append to the output file? ; TXO T2,OF%APP!OF%RD ;yes, open for append OPENF% JERR (?,,PC,DIE) RET ;----------------------------------------------------------------------------- ;Routine to open a ascii file for input and map the pages of the file into ;memory ; CALL FOPEN7 ;ACCEPTS: ; CX - address of the FDA (File Data Area) ;RETURNS: +1 always with T2,T3 as returned by PMP FOPEN7: MOVEI T1,7 ;assume it is a 7bit (ascii) file TXNE F,F%EXE ;is user want to compare EXE file? MOVEI T1,36 ;yes, force it to use 36bit CALL FDAINI ;init file data area for OLD file HRRZ T1,JFN(CX) MOVX T2,+OF%RD ;Open the file, ascii read OPENF% JERR (?,,PC,DIE) CALL CKHOLE ;check file for holes JRST DIE ;can't handle files with holes CALLRET PMP ;map the file into memory ;============================================================================= ;Routine to initialize the FDA (File Data Area) for a file. ; CALL FDAINI ;ACCEPTS: ; T1 - byte size to force file to if necessary ; CX - address of the FDA (File Data Area) ; JFN(CX) - JFN of file ;RETURNS: ; +1 -always. with FDA updated ;Trashes T1-T2 FDAINI: DMOVEM T3,1(P) ;save needed AC's DMOVEM Q1,3(P) ADJSP P,4 ;adjust because I may do a CALL later HRRZM T1,BSZ(CX) ;save byte size MOVEI T2,^D36 ;# bits/word IDIV T2,T1 ;calc # bytes/word IMULI T2,1K ;calc # bytes/page MOVEM T2,BPP(CX) ;save it HRRZ T1,JFN(CX) ;get JFN MOVE T2,[2,,.FBBYV] ;get number of pages and bytes in file MOVEI T3,Q1 ;start saving info here GTFDB% JERR (?,,PC,DIE) LDB T1,[POINT 6,Q1,11] ;get byte size JUMPE T1,[TMSGL JRST DIE] MOVEI T2,^D36 ;# bits/word IDIV T2,T1 ;calc # bytes/word MOVE T1,Q2 ;get # bytes in file IDIV T1,T2 ;calc # words in file DMOVEM T1,T3 ;save # words + remainder SKIPE T2 ;any partial words? ADDI T1,1 ;yes, bump up # words in file IDIVI T1,1K ;calc # pages for this many words SKIPE T2 ;any partial pages? ADDI T1,1 ;yes, bump up # pages in file MOVEM T1,PGL(CX) ;save length of file in pages MOVEM T1,EOF(CX) ;initialize EOF flag HRRZ T1,Q1 ;get actual # pages in file CAME T1,PGL(CX) ;does it match actual pages? JRST [ CAMG T1,PGL(CX) ;is actual bigger? JRST [ TMSGL JRST DIE] TMSGL <%Actual page count is greater than that calculated by using byte count Data after logical end of file will be ignored... > JRST .+1] LDB T1,[POINT 6,Q1,11] ;get byte size CAMN T1,BSZ(CX) ;is byte size same as one to force? IFSKP. ;yes, don't need to force byte size ;T3= # words in file, T4=remainder bytes MOVEI T2,^D36 ;# bits/word MOVEM T3,Q2 ;save # words in file IDIV T2,BSZ(CX) ;calc # bytes/word for new byte size IMUL Q2,T2 ;calc # bytes for new byte size IMUL T1,T4 ;calc # bits remaining in last word IDIV T1,BSZ(CX) ;calc # bytes this is SKIPE T2 ;any remainder bits? ADDI T1,1 ;yes, bump up # bytes in file ADD Q2,T1 ;calc new byte count ENDIF. MOVEM Q2,BLN(CX) ;save length of file in bytes MOVE T1,BPP(CX) ;get number of bytes/page IMUL T1,PGL(CX) ;calc # bytes if all page full SUB T1,Q2 ;calc # bytes free on last page MOVEM T1,BLF(CX) ;save it SETZM FPG(CX) ;init first page to start pmaping at HRLZ T1,BSZ(CX) ;get byte size LSH T1,6 ;put byte size in "S" field for byte ptr TLO T1,440000 ;initialize "P" field for byte ptr HLLM T1,BSZ(CX) ;save it SETZM PTR(CX) ;init pointer for ^A interrupts ADJSP P,-4 ;adjust stack pointer DMOVE T3,1(P) ;restore needed AC's DMOVE Q1,3(P) RET ;return to caller ;============================================================================= ;Routine to check file for holes ; CALL CKHOLE ;ACCEPTS: ; CX - address of the FDA (File Data Area) ;RETURNS: ; +1 - file has holes ; +2 - file does NOT have holes ;Trashes T1-T2 CKHOLE: AOS (P) ;set +2 return HRRZ T1,JFN(CX) ;make 0,,JFN (start at page 0) FFFFP% ;find first free page JERR (?,,PC,DIE) ;T1 = JFN,,page-number-first-free-page TLZ T1,-1 ;get page # of first free page CAML T1,PGL(CX) ;does file have holes? RET ;no TMSGL FILSTR JFN(CX) TMSG < has holes > SOS (P) ;set +1 return RET ;============================================================================= ;Routine to close all required files ; CALL FCLOSE ; CALL OCLOSE -close the output file ;ACCEPTS: no registers need to be initialized ;RETURNS: +1 always ;Trashes T1-T3 FCLOSE: MOVEI CX,NEW CALL UNMAPC ;unmap and close it MOVEI CX,OLD CALL UNMAPC ;unmap and close it OCLOSE: SKIPE T1,OUT+JFN ;if JFN already released CAIN T1,.PRIOU ; ...or output to here? RET ;then, I'm done TXNN F,F%TTY ;output to a terminal? TXNN F,F%ABRT ; ...or NOT aborting? JRST FCLOS5 ;then don't display abort message TMSGL FILSTR (OUT+JFN) FCLOS5: TXNE F,F%WILD ;processing wildcard group? RET ;yes, don't close output file MOVEI CX,OUT CALLRET FCLOS7 ;close the output file ;============================================================================= ;routine to unmap the pmap buffer area for a file and close it ; CALL UNMAPC ; CALL FCLOS7 -just close file ;ACCEPTS: ; CX - address of the FDA (File Data Area) ;RETURNS: +1 always ;Trashes T1-T2 UNMAPC: SKIPN JFN(CX) ;is there a JFN RET ;no, nothing to do SETO T1, ;unmap pmap buffer from memory DMOVE T2,FFP(CX) ;fork,,first page of pmap area ;T3 = number of pages to unmap PMAP% JERR (?,,PC,DIE) FCLOS7: HRRZ T1,JFN(CX) TXNE F,F%WILD ;am I processing a wildcard group? TXO T1,CO%NRJ ;yes, don't release JFN CAIN CX,OUT ;closing output file? TXNN F,F%ABRT ;aborting output? TRNA ;no, don't set CZ%ABT flag TXO T1,CZ%ABT ;yes, abort any changes made CLOSF% ;close the file JERR (?,,PC) TXNN T1,CO%NRJ ;was JFN released? SETZM JFN(CX) ;yes, say JFN is released CAIN CX,OUT ;closing output file? TXZ F,F%OPEN ;yes, say it's closed RET SUBTTL Software Interrupt Routines ;============================================================================= ;Routine to activate ^A, ^E and ^X interrupts ; CALL ATIAEX ;ACCEPTS: ; T1 - address of command routine ;RETURNS: +1 always ;Trashes T1 ATIAEX: SETOM PI.CNT ;set flag SETZM CAOLOC ;initialize file location for OLDer file SETZM CANLOC ;initialize file location for NEWer file MOVEM T1,PI.ABT ;save exit routine for abort MOVEM P,PI.P ;save stack for interrupt MOVE T1,[.TICCA,,.CACH] ;activate to intercept ^A ATI% JERR (?,,PC) MOVE T1,[.TICCE,,.CECH] ;activate to intercept ^E ATI% JERR (?,,PC) MOVE T1,[.TICCX,,.CXCH] ;activate to intercept ^X ATI% JERR (?,,PC) RET ;============================================================================= ;Routine to deactivate ^A, ^E and ^X interrupts ; CALL DTIAEX ;ACCEPTS: none ;RETURNS: +1 always ;Trashes T1 DTIAEX: MOVEI T1,.TICCA ;deassign ^A DTI% JERR (?,,PC) MOVEI T1,.TICCE ;deassign ^E DTI% JERR (?,,PC) MOVEI T1,.TICCX ;deassign ^X DTI% JERR (?,,PC) RET ;============================================================================= ;Routine to hande ^A interrupts. I must set up a new stack so the CALLs I ;make won't destroy data that may be temporarly saved past the top of stack - ;eg. by the DMOVEM _,_(P). Since this program spends most of it time executing ;the MOVST instruction (in SCANJ) or CMPSN (in CMPSTR), I can test for this and ;use this information to report where in the file the program is currently ;working. CTRLA: IP.SAVE ;save F to P ; save the AC's in PI.ACS because I may need them later if I interrupted ; an EXTEND instruction MOVEM CX,PI.ACS+CX ;save BLT register MOVEI CX,PI.ACS BLT CX,PI.ACS+CX-1 ;save registers F to CX-1 MOVE CX,PI.ACS+CX ;restore BLT register MOVE CX,PI.ABT ;get command being processed AOSE PI.CNT ;this the first time I've been called? JRST CTRLA3 ;no, don't need to display file names SKIPE TAKJFN ;is TAKE in progress? TXNE F,F%ECHO ;yes, am I echoing the commands? JRST CTRLA3 ;yes, don't need to display file names SPTR T1,< Comparing > CAIE CX,CMPXIT ;COMPARE command? SPTR T1,< Updating > ;no PSOUTL FILSTR OLD+JFN TMSG < with > FILSTR NEW+JFN CTRLA3: SPTR T1,< > PSOUTL NUMOUT CHGCNT TMSG < change> PSOUT% MOVEI T1,"s" CAIE T2,1 ;more that 1 ? PBOUT% ;yes, get tense right SPTR T1,< found> CAIE CX,CMPXIT ;COMPARE command? SPTR T1,< made> ;no PSOUT% DMOVE P1,CAOLOC ;get previous ptr + page for OLDer file DMOVE P3,CANLOC ;get previous ptr + page for NEWer file DMOVE Q1,@LEVTAB-1+.CALV ;get flags + PC of next instruction HLRZ T1,(Q2) ;get LH of interrupted instruction TRZ T1,000777 ;isolate op code CAIE T1,(EXTEND) ;extended instruction? JRST CTRLA4 ;no, HLRZ T1,@(Q2) ;get left half of what EXTEND refers to TRZ T1,000777 ;isolate op code CAIE T1,(MOVST) ;is it the move string instruction? CAIN T1,(CMPSN) ;is it the compare string instruction? TRNA ;yes JRST CTRLA4 ;no, LDB Q2,[POINT 3,(Q2),12] ;get accumulator used MOVE T1,PI.ACS+1(Q2) ;get 1st byte ptr from EXTEND CALL CKLOC ;check which file it refers to MOVE T1,PI.ACS+4(Q2) ;get 2nd byte ptr from EXTEND CALL CKLOC ;check which file it refers to JRST CTRLA7 ;output file location data ; see if program is in FMATCH routine. If it is then the data in NP and ; OP can be trusted and used for outputing the file location data CTRLA4: TXNN F,F%LSTK ;is program in FMATCH routine? JRST CTRLA7 ;no, MOVE T1,PI.ACS+OP ;get 1st byte ptr CALL CKLOC ;check which file it refers to MOVE T1,PI.ACS+NP ;get 2nd byte ptr CALL CKLOC ;check which file it refers to CTRLA7: MOVEI CX,OLD DMOVE T1,P1 ;get file location CALL OUTLOC ;output file location DMOVEM T1,CAOLOC ;save previous ptr + page for OLDer file MOVEI CX,NEW DMOVE T1,P3 ;get file location CALL OUTLOC ;output file location DMOVEM T1,CANLOC ;save previous ptr + page for NEWer file TMSG < > RET ;dismiss interrupt ;----------------------------------------------------------------------------- ;Routine to determine if a byte pointer points to the pmap area for ;the OLDer or NEWer file. ; CALL CKLOC ;ACCEPTS: ; T1 - byte pointer ;RETURNS: +1 always with P1,P2 updated if pointer points to OLDer file and P3,P4 ; updated if pointer points to NEWer file ;Trashes T1-T4 CKLOC: MOVEI CX,OLD CALL CKLOC5 ;see if pointer belongs to this file JRST CKLOC3 ;yes MOVEI CX,NEW CALL CKLOC5 ;see if pointer belongs to this file DMOVEM T1,P3 ;yes, save info here TRNA CKLOC3: DMOVEM T1,P1 ;yes, save info here RET CKLOC5: MOVE T2,T1 ;get byte pointer IBP T2 ;adjust to point to actual byte... ; ...incase ptr on page boundry TLZ T2,-1 ;isolate address of ptr LSH T2,-9 ;get page ptr is on HRRZ T3,FFP(CX) ;get start of pmap buffer SUB T2,T3 ;calc page offset JUMPL T2,CKLOC9 ;jump if ptr not in pmap area HRRZ T3,FLP(CX) ;get length of pmap buffer CAML T2,T3 ;is ptr in pmap buffer? CKLOC9: AOSA (P) ;no, set +2 return ADD T2,FPG(CX) ;yes, add offset to page starting buffer RET ;----------------------------------------------------------------------------- ;Routine to output the approximate location of the file the program is currently ;working on ; CALL OUTLOC ;ACCEPTS: ; T1 - byte pointer to pmap area of the file ; T2 - actual page of file the pointer refer to ; CX - address of the FDA (File Data Area) ;RETURNS: +1 always ;Trashes T3-Q2 OUTLOC: JUMPN T1,OUTLO1 ;jump if ptr is initialized SKIPN T1,PTR(CX) ;get ptr RET ;ptr not initialized yet IBP T1 ;adjust to point to actual byte... ; ...incase ptr on page boundry HRRZ T2,T1 ;isolate address of ptr LSH T2,-9 ;get page ptr is on SUB T2,FFP(CX) ;calc page offset HRRES T2 ;remove triva from LH ADD T2,PFP(CX) ;add offset to ptr's file page OUTLO1: DMOVEM T1,Q1 ;save registers TMSG < File> SPTR T1,<1: > CAIE CX,OLD ;working on the OLDer file? SPTR T1,<2: > ;no PSOUT% TMSG NUMOUT (-) ;output it IMULI T2,^D100 ;calc % of file I'm on... IDIV T2,PGL(CX) ; ... MOVEM T2,T4 ;save % of file for later TMSG <.> HRRZ T2,Q1 ;get byte pointer TRZ T2,777000 ;isolate word on page IDIVI T2,^D51 ;calc approx. fraction of page I'm on NUMOUT (-) TMSG <, > NUMOUT (T4) ;output % of file I'm on TMSG <%> DMOVE T1,Q1 ;restore T1,T2 RET ;============================================================================= ;Routines to handle ^E or ^X interrupts CTRLX: TMSGL <^X > JRST CTRLEX ;rejoin common code CTRLE: TMSGL <^E > TXZ F,F%WILD ;if I'm processing wild file specs... ; ...then don't process anymore files CTRLEX: HRRZ T1,OUT+JFN ;if output is to the terminal then... CATOFF ; ...make sure graphic attributes off ; ...and also make sure OCCOC are set CAIN CX,CMPXIT ;aborting UPDATE command? TXO F,F%ABRT ;yes, set abort flag IFN <.CXLV-.CELV>, MOVE T2,@LEVTAB-1+.CXLV ;get PC flags TXO T2,PC%USR ;abort JSYS if I was executing one MOVE T3,PI.ABT ;get address of exit routine DMOVEM T2,@LEVTAB-1+.CXLV ;save new PC and flags MOVE P,PI.P ;restore P ADJSP P,-1 ;remove call to ATIAEX DEBRK% ;dismiss interrupt SUBTTL Switch Servers ;----------------------------------------------------------------------------- ;Server for the switch /NO: .SWNO: PARSE (,<.CMKEY,,NOTAB>) HRRZ T2,(T2) ;get address of service routine JRST (T2) ; ....dispatch to the handler ;------------------------------------------------------------------------------ ;Server for SET LINES: number .SL4M: TXNE F,F%NO ;user want NO lines? IFSKP. NOISE CALL .L4M CONFIRM MOVE T2,L4M MOVEM T2,DL4M ELSE. TMSGL ENDIF. JRST ENDCMD ;------------------------------------------------------------------------------- ;Server for /LINES: switch .L4M: PARSE (,<.CMNUM,CM%SDH,^D10,,\DEFL4M>) CAIG T2,MAXL4M CAIGE T2,1 JRST [TMSGL JRST ENDCMD] MOVEM T2,L4M ;save number parsed ; routine to check the lines for match with lines to search to see if ok CKL4M: CAMLE T2,L2S JRST [TMSGL JRST ENDCMD] RET ;----------------------------------------------------------------------------- ;Server for SET MAX-LINES .SL2S: TXNE F,F%NO ;user want NO ? IFSKP. NOISE CALL .L2S CONFIRM ELSE. CONFIRM CALL .NOMAX ENDIF. MOVE T2,L2S MOVEM T2,DL2S JRST ENDCMD ;------------------------------------------------------------------------------- ;Server for /MAX-LINES: switch .L2S: PARSE (,<.CMNUM,CM%SDH,^D10,,1000>) JUMPL T2,[TMSGL JRST ENDCMD] SKIPG T2 ;if number is zero or less then... .NOMAX: MOVE T2,[377777,,777777] ; ...use maximum positive number MOVEM T2,L2S ;save number parsed MOVE T2,L4M CALLRET CKL4M ;check L2S against L4M ;----------------------------------------------------------------------------- ;Server for SET QUICK .SQUIC: CONFIRM MOVE T2,DSWI.S ;load default switches in T2 IOR F,T2 ;set these switchs TXNN F,F%NO ;did user enter "NO"? IFSKP. ;no TXZ F,F%QUIK ;yes, set QUICK off TXZ T2,F%QUIK ELSE. CALL .QUICK ;check out if OK to set it TXO T2,F%QUIK ENDIF. MOVEM T2,DSWI.S ;save default switches JRST ENDCMD ;return ;------------------------------------------------------------------------------- ;Server for /QUICK switch .QUICK: TXNE F,F%UPDF ;is /UPDATE-FORMAT also set? JRST QU.ERR ;yes TXO F,F%QUIK ;set the switch RET ;no QU.ERR: TMSGL JRST ENDCMD ;------------------------------------------------------------------------------- ;Server for /NO:QUICK switch .NOQU: TXZ F,F%QUIK ;yes, set QUICK off RET ;----------------------------------------------------------------------------- ;Server for SET UPDATE .SUPDF: CONFIRM MOVE T2,DSWI.S ;load default switches in T2 IOR F,T2 ;set these switchs TXNN F,F%NO ;did user enter "NO"? IFSKP. ;no TXZ F,F%UPDF ;yes, set UPDATE-FORMAT off TXZ T2,F%UPDF ELSE. CALL .UPDF ;no, call .UPDF to set switch TXO T2,F%UPDF ENDIF. MOVEM T2,DSWI.S ;save the default switches JRST ENDCMD ;return ;------------------------------------------------------------------------------- ;Server for /UPDATE-FORMAT switch .UPDF: TXNE F,F%QUIK ;is /UPDATE-FORMAT also set? JRST QU.ERR ;yes TXNE F,F%EXE ;is /EXE also set? JRST UP.ERR ;yes TXO F,F%UPDF ;set the switch RET ;return UP.ERR: TMSGL JRST ENDCMD ;------------------------------------------------------------------------------- ;Server for /NO:UPDATE switch .NOUP: TXZ F,F%UPDF ;turn off the /UPDATE-FORMAT RET ;------------------------------------------------------------------------------- ;Server for SET IGNORE ; .SIGNO: NOISE () CONFIRM MOVE T2,DSWI.S ;load default switches in T2 IOR F,T2 ;set these switchs TXNN F,F%NO ;did user enter "NO"? IFSKP. ;no TXZ F,F%IGNO ;yes, do not ignore! TXZ T2,F%IGNO ;set swith in T2 ELSE. CALL .IGNO ;no, go set ignore! TXO T2,F%IGNO ENDIF. MOVEM T2,DSWI.S ;both default and F are the same JRST ENDCMD ;go get another command ;------------------------------------------------------------------------------- ;Server for /IGNORE switch .IGNO: TXNE F,F%EXE ;is /EXE also set? JRST IG.ERR ;yes TXO F,F%IGNO ;set the switch RET ;return IG.ERR: TMSGL JRST ENDCMD ;------------------------------------------------------------------------------- ;Server for /NO:IGNORE switch .NOIGN: TXZ F,F%IGNO ;set F%IGNO to off RET ;return to caller ;------------------------------------------------------------------------------- ;Server for SET EXE .SEXE: NOISE () CONFIRM MOVE T2,DSWI.S ;load default switches in T2 IOR F,T2 ;set these switchs TXNN F,F%NO ;did user enter "NO"? IFSKP. ;no CALL .NOEXE ;yes, turn it off! TXZ T2,F%EXE ELSE. CALL .EXE ;no, user want EXE to be on TXO T2,F%EXE ENDIF. MOVEM T2,DSWI.S ;save the default switches JRST ENDCMD ;go get another command ;------------------------------------------------------------------------------- ;Server for /EXE switch ;input files are in binary format .EXE: TXO F,F%EXE ;turn on the EXE switch TXZ F,F%IGNO ;turn off ignore spaces, tab function TXZ F,F%UPDF ;turn off update mode TXO F,F%QUIK ;turn on quick mode RET ;return to caller ;------------------------------------------------------------------------------- ;Server for /NO:EXE switch .NOEXE: TXZ F,F%EXE ;turn off the EXE switch TXZ F,F%QUIK ;turn off the QUICK switch RET ;return to caller SUBTTL Server for EXIT command ;============================================================================= C.EXIT SUBTTL Server for INFORMATION command ;============================================================================= C.INFO < TMSG < Default switch settings: /LINES:> NUMOUT (DL4M) TMSG < /MAX-LINES:> MOVE T2,DL2S CAME T2,[377777,,777777] IFSKP. TMSG <+INF> ELSE. NUMOUT (-) ENDIF. MOVE T2,DSWI.S ;get default switches set SPTR T1,< /QUICK> TXNE T2,F%QUIK PSOUT% SPTR T1,< /UPDATE-FORMAT> TXNE T2,F%UPDF PSOUT% SPTR T1,< /EXE> TXNE T2,F%EXE PSOUT% SPTR T1,< /IGNORE> TXNE T2,F%IGNO PSOUT% TMSG < > >;end of C.INFO ;============================================================================= ;Routine to handle when L2S in exceeded in FMAFIL routine. ; CALL L2SEXC ;ACCEPTS: ; T4 - FMALCT ;RETURNS: ; +1 - user wants to continue search (a new, higher, /MAX-LINES: is set) ; +2 - user does NOT want to continue. T4 will be set to -1. ;Trashes T1-T3 WHILWO: TMSGL MOVE T2,CHGCNT ADDI T2,1 NUMOUT (-) TMSG < couldn't find where the files match up again even after searching ahead for > RET L2SEXC: CALL WHILWO ;output "While working on..." message NUMOUT (L2S) ;output max lines to search TMSG < lines... > ; MOVEI T1,DIE ;there is no exit routine SPTR T2, ;prompt string for command level CALL BEGCML## ;set up this command level PARSE (,<.CMKEY,CM%SDH,YNTAB,>) HRRZ T4,(T2) ;get answer parsed CONFIRM CALL RMVCML## ;remove last command level JUMPE T4,L2SEX8 ;jump if answer was NO ; MOVEI T1,DIE ;there is no exit routine SPTR T2, CALL BEGCML## ;set up this command level CALL .L2S ;get number of lines to search CONFIRM MOVE T4,FMALCT ;reset T4 CAML T4,L2S ;is it bigger than last value? IFSKP. ;no, display error message CALL RMVCML## ;yes, remove last command level RET ;done ENDIF. TMSGL NUMOUT (FMALCT) TMSG <. New value must be bigger > JRST ENDCMD ;ask user again L2SEX8: SETO T4, ;set flag - don't continue search AOS (P) ;set +2 return RET ;============================================================================= ;Routine to handle LSTK overflow. AOBJP will jump here when LSTK is full LSTKOF: CALL WHILWO ;output "While working on..." message MOVEI T2,LSTKLN ;get length of LSTK NUMOUT (-) ;output # lines searched TMSG < lines... Files can't be compared because of LSTK overflow (The internal value of LSTKLN may have to be increased and the the program reassembled)> JRST DIE LITPOL: XLIST ;so user can identify literal pool when running DDT LIT ;put literals here LIST END ;set length and start of entry vector