; -*-MIDAS-*- TITLE SRCCOM ;;SRCCOM COMMAND ;; SRCCOM_/@/A/L/C/S ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; ;;; NOTE: THE CANONICAL SOURCE FOR THIS PROGRAM LIVES IN ;;; [MIT-AI] SYSENG;SRCCOM > ;;; ALL CHANGES, BUG FIXES, ETC SHOULD BE REFLECTED THERE. ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;WAS ONCE DEC SRCCOM VERSION 16, MINIMALLY ADAPTED TO ITS. ;ALMOST TOTALLY REWRITTEN BY RMS, DEC '75. ;MUNGED FOR 10X/20X ASSEMBLY BY KLH, MAR '79. IF1 { ITS==1 TNX==1 DEC==1 .INSRT SYSTEM } IFN TNX,[ DEFINE HLPFIL ; SPECIFIES LOC OF HELP FILE ASCIZ "SRCCOM.DOC"!TERMIN ; shouldn't this be SRCCOM.INFO? ] ;I/O CHANNELS. FOR TNX THESE ARE INDICES INTO JFNCHS. CHTTI==0 ;TTY INPUT. CHIN1==1 ;FIRST INPUT FILE CHIN2==2 ;SECOND INPUT FILE. CHIN3==3 ;THIRD INPUT FILE, FOR 3-WAY MERGES. CHMRG==4 ;/M OUTPUT DEVICE FOR MERGE FILE CHTTO==5 ;ITS NEEDS TYO CHANNEL CHERR==6 ;FOR ERR DEVICE. CHOUT==7 ;OUTPUT CHNL FOR DIFFERENCES. CHCMD==10 ;COMMAND FILE READING CHANNEL. ;MAIN AC DEFINITIONS W1=1 W2=2 W3=3 F1=4 ;LINE POINTER FILE 1 (CONTAINS ADDRESS OF LINE BLOCK) F2=5 ;DITTO FILE 2 F3=6 ;DITTO FILE 3 FR=7 ;FLAG REGISTER (LH) AND FILE #(0 OR 1 OR 2)(RH) CS=10 C=11 ;CONTAINS 1 CHAR FOR PROCESSING T=12 ;TEMPORARY AC (MUNGED BY XJSYS CALLS) TT=13 ;TEMP AC BP=14 ; (RDLIN AC LOOP) BYTE POINTER IN FILENAME READER. FP=15 ; BP+1 (RDLIN AC LOOP) ADDR OF FILE BLK ;=16 ; BP+2 (RDLIN AC LOOP) P=17 ;PUSH DOWN POINTER ; ACC DEFS FOR TNX JSYS CODE IFN TNX, R1=1 ? R2=2 ? R3=3 ? R4=4 ? R5=5 ; ACC DEFS FOR STUFF BORROWED FROM MIDAS IFN TNX, AA=6 ? A=1 ? B=2 ? D=4 ? E=5 ? F=FP ; NOTE A NOT AA+1 ;ASCII CHARACTERS TAB==11 ALTM==33 ;/M ALT-MODE TO END TTY INPUT FOR MERGE(/M) ;FLAGS - LH OF AC FR: FL==1,,525252 ;BIT TYPEOUT MODE MASK. FLINDR==1 ;/@ - FILE NAME FOLLOWS THE STRING ";COMPARISON OF " IN SPEC'D FILE. ;APPLIES TO 1ST INPUT FILE ONLY. FLXCTF==2 ;/X - OPEN A COMMAND FILE AND START EXECUTING FROM IT. FLISWT==4 ;/I - MERGE, BUT AUTOMATICALLY ANSWER "I" TO EVERY QUESTION ;AND DON'T TYPE ON THE TTY. FLARCH==10 ;/A SWITCH - "ARCHIVE". APPEND OUTPUT TO FRONT OF EXISTING FILE. FLLABL==20 ;/L SWITCH - REMEMBER FOR EACH FILE AND LINE THE PREVIOUS LABEL, ;AND PRINT IT IN THE HEADER LINE. FLENDL==40 ;/E SWITCH - PRINT OUT THE FIRST MATCHING LINE FROM EACH FILE ;AFTER EACH RUN OF DIFFERENCES. FLSPAC==100 ;/S SWITCH - IGNORE SPACING FLCMNT==200 ;/C SWITCH - IGNORE COMMENTS FLALL==400 ;/B OR /M SWITCH (ALLOWS COMPARING BLANK LINES) ; CR,LF,FF STORED LIKE DATA AND COMPARED FLEOF1==1000 ;EOF SEEN ON FILE 1 FLEOF2==2000 ;EOF SEEN ON FILE 2 FLEOF3==4000 ;EOF SEEN ON FILE 3 FLFNUM==10000 ;/W SAYS PRINT FILE # ON EACH LINE OF DIFFERENCES. FLFLAG==20000 ;/F SAYS MAKE COPY OF FILE 2, FLAGGING CHANGED LINES WITH VERT. BARS. FLCASE==40000 ;/K SAYS IGNORE DIFFERENCES IN ALPHABETIC CASE FLOVRD==100000 ;/! SAYS DO THE COMPARISON EVEN IF FILE1 AND FILE2 ARE SAME FILE. FLXLBL==200000 ;/Y SAYS ANY UNINDENTED LINE NOT STARTING WITH A ";" IS A LABEL. FLMERG==400000 ;/M SWITCH-MERGE 2 FILES INTO ONE CONVERSATIONALLY ;RH OF FR TELLS CERTAIN FUNCTIONS WHICH INPUT FILE TO OPERATE ON: 0 => FILE 1, 1 => FILE 2. ;NAMES OF THE HEADER WORDS OF A FILE LINE LNNEXT==0 ;MUST BE 0! ADDR OF HEADER OF NEXT LINE, OR 0 FOR LAST LINE. LNSIZE==1 ;# OF CHARACTERS IN THE LINE, NOT COUNTING TERMINATING ZERO. LNLLBL==2 ;1ST WORD OF ASCIZ OF MOST RECENT LABEL, OR 0. LNLLB1==3 ;2ND WORD OF ASCIZ. COLON IS INCLUDED. LNLLB2==4 ;4 WORDS IN ALL FOR HOLDING A LABEL. LNLLB3==5 LNLBLN==4 LNPGNM==6 ;PAGE # THIS LINE STARTED ON LNLNNM==7 ;LINE NUMBER THIS LINE STARTED ON LNCHNM==10 ;CHARACTER NUMBER IN FILE OF 1ST CHARACTER IN LINE LNDATA==11 ;INDEX OF THE FIRST DATA WORD. THE DATA ARE AN ASCIZ STRING ;THERE ARE ASSUMED TO BE JUST ENOUGH DATA WORDS ;TO HOLD THE NUMBER OF CHARACTERS THAT LNSIZE SAYS THERE ARE. ;PARAMETERS IFNDEF MATCH,MATCH==3 ;# LINES TO BE MATCHED BEFORE RUN OF DIFFERENCES ENDS. IFNDEF WPL,WPL==<40.*4>/5+1 ;# WORDS FOR FILENAMES FOR HEADER LINES. IFNDEF LPDL,LPDL==30 ;LENGTH OF PUSH DOWN LIST IFNDEF FILBFL,FILBFL==100 ;LENGTH OF INPUT FILE BUFFERS. MRGBSZ==FILBFL*5 ;MERGE OUTPUT BUFFER LENGTH IN CHARS. ;/M THIS SRCCOM ALSO PERFORMS A MERGE FUNCTION IF /M IS TYPED ;/M DESTINATION FILE BECOMES MERGE OF 2 SOURCE FILES. ;/M DIFFERENCES ARE TYPED ON TTY, USER SELECTS WHICH HE WANTS ;/M AND IN WHAT ORDER BY TYPING IN 1 LINE COMMAND AFTER EACH PAIR ;/M OF DIFFERENCES IS TYPED OUT. ;/M HE MAY TYPE 1, 2, AND/OR T IN ANY ORDER FOLLOWED BY CR ;/M OR HE MAY CHANGE THE LAST COLUMN TYPED OUT TO ### BY TYPING ;/M C### FOLLOWED BY CR AS A SEPARATE COMMAND AFTER ANY PAIR OF DIFFERENCES ;/M TYPED OUT. SRCCOM WILL RESPOND WITH ANOTHER *, SO THE USER CAN TYPE ;/M ANOTHER COMMAND TO SELECT WHICH DIFFERENCES HE WANTS. INITIALLY THE ;/M MAX. COLUMN IS SET TO 72 WHENEVER SRCCOM IS RESTARTED WITH START COMMAND ;/M IT IS NOT RESET AFTER EACH FILE COMPARED. ;/M SIMILARLY THE USER MAY SET THE MAXIMUM ;/M NUMBER OF LINES TYPED FROM EACH FILE WITH L###. ;OPDEFS CALL=PUSHJ P, RET=POPJ P, SAVE=PUSH P, REST=POP P, PJRST==JRST IFN ITS,ERRHLT==.LOSE IFN TNX,ERRHLT==HALT ;MACROS IFN ITS,[ DEFINE SYSCAL A,B .CALL [ SETZ ? SIXBIT/A/ ? B ((SETZ))] TERMIN ] IFN TNX, .INSRT XJSYS DEFINE DBP7J AC,TAG=.+2 ADD AC,[070000,,] JUMPGE AC,TAG SUB AC,[430000,,1] IFSN [TAG].+2,JRST TAG TERMIN DEFINE INSIRP INSN,ADDRS IRPS ADDR,,[ADDRS] INSN,ADDR TERMIN TERMIN ;ADVANCE TO THE NEXT LINE IN FILE FILN, READING IT FROM THE FILE IF NECESSARY. ;GO TO EOFA IF THERE IS NO LINE DUE TO EOF. DEFINE NEXTLN FILN,(EOFA) SKIPE LNNEXT(F1+FILN-1) JRST .+4 HRRI FR,FILN-1 CALL RDLIN IFNB EOFA, JRST EOFA .ELSE CAIA MOVE F1+FILN-1,LNNEXT(F1+FILN-1) TERMIN ; SOME MACROS TO MAKE I/O A LITTLE LESS SYSTEM DEPENDENT. ; OPTIMIZED IN FAVOR OF ITS. IFN ITS,[ DEFINE M.CLS CH ; CLOSE CHAN .CLOSE CH, TERMIN DEFINE M.MVCH CH1,CH2 ; MOVE CHANNEL FROM CH1 TO CH2 .IOPUS CH1, .IOPOP CH2, TERMIN DEFINE MOUTC CH,?LOC ; SINGLE CHAR OUTPUT .IOT CH,LOC TERMIN DEFINE M.BIN CH,LOC .IOT CH,LOC TERMIN DEFINE M.SOUT CH,BPA,CNTA SYSCAL SIOT,[MOVEI CH ? BPA ? CNTA] .LOSE %LSFIL TERMIN DEFINE M.SIN CH,BPA,CNTA SYSCAL SIOT,[MOVEI CH ? BPA ? CNTA] .LOSE %LSFIL TERMIN ] ;IFN ITS IFN TNX,[ DEFINE M.CLS CH ; CLOSE CHAN SAVE R1 SKIPLE R1,JFNCHS+CH CLOSF ERJMP .+1 SETZM JFNCHS+CH REST R1 TERMIN DEFINE M.MVCH CH1,CH2 ; MOVE CHANNEL FROM CH1 TO CH2 SAVE R1 SETZ R1, EXCH R1,JFNCHS+CH1 EXCH R1,JFNCHS+CH2 CAILE R1, CLOSF ERJMP .+1 REST R1 TERMIN DEFINE MOUTC CH,?LOC ; OUTPUT BYTE AT LOC CALL [ PUSH P,JFNCHS+CH PUSH P,LOC PJRST TOUTC] TERMIN DEFINE M.BIN CH,LOC ; INPUT BYTE TO LOC CALL [ PUSH P,JFNCHS+CH PUSH P,[LOC] JRST TINC] TERMIN DEFINE M.SOUT CH,BPA,CNTA ; OUTPUT STRING MOVNS CNTA SYSCAL SOUT,[JFNCHS+CH ? BPA ? CNTA][JUNK ? BPA ? CNTA] MOVNS CNTA TERMIN DEFINE M.SIN CH,BPA,CNTA ; INPUT STRING MOVEI T,[JFNCHS+CH ? BPA ? CNTA] CALL TINS TERMIN ] ;IFN TNX DEFINE MOUTI CH,VAL ; OUTPUT IMMEDIATE VALUE MOUTC CH,[VAL] TERMIN ; SO MIDAS-BORROWED CODE WILL INTEGRATE BETTER. DEFINE ETF ?ASCZ JRST [ JSP T,ERRMSG ASCZ ] TERMIN DEFINE TYPE &STR CALL [ PUSH P,[[ASCIZ STR]] PJRST TYPM] TERMIN SUBTTL File Description Storage (FILBLK's) ; Definitions for indices into a FILBLK. ; Scratch block FB is formed while defining indices... OFFSET -. ; Lots of crocks depend on the exact order of these 4 items. IFN ITS\DEC,[ $F6DEV:: 0 ; SIXBIT Device name $F6FN1:: 0 ; SIXBIT Filename (on ITS, FN1) $F6FN2:: 0 ; SIXBIT Extension (on ITS, FN2) $F6DIR:: 0 ; SIXBIT Directory (may be numerical PPN) $FDEV==:$F6DEV ; These definitions made so some common code can do $FDIR==:$F6DIR ; the right things. $FNAME==:$F6FN1 $FEXT==:$F6FN2 $FVERS==:$F6FN2 ] IFN TNX,[ ; Almost all entries here are BP's to ASCIZ strings. $FDEV:: 0 ; Device name $FDIR:: 0 ; Directory name $FNAME:: 0 ; File name (i.e. main name) $FEXT:: 0 ; File type (or extension) $FVERS:: 0 ; File version (or generation). NUMBER, not string. $FTEMP:: 0 ; -1 => File is a temporary file. $FACCT:: 0 ; Account string $FPROT:: 0 ; Protection string $FJFN:: 0 ; JFN for file (may be ,,) ] L$FBLK==. ; Length of a FILBLK. OFFSET 0 ; End of index definitions. INFB: BLOCK L$FBLK LSTFB: BLOCK L$FBLK IFN TNX,[ JFNCHS: BLOCK 20 ; INDEXED BY CHAN #, HOLDS JFNS ] ;SRCCOM STARTS HERE BEG: MOVE P,[-LPDL,,PPSET-1] ;SET UP PDL. IFN ITS,[ .OPEN CHTTI,[.UAI,,'TTY] ERRHLT .OPEN CHTTO,[.UAO,,'TTY] ERRHLT .SUSET [.RSNAM,,DEFDIR] ;GET DEFAULT DIR. .SUSET [.ROPTIO,,W1] TLO W1,OPTOPC .SUSET [.SOPTIO,,W1] .SUSET [.SMASK,,[%PIMPV]] .SUSET [.SMSK2,,[1_CHTTO+1_CHOUT]] ;ENABLE --MORE-- INTERRUPTS ] ;IFN ITS IFN TNX,[ RESET CALL SEE20X ; SEE IF 10X OR 20X. MOVEI W1,.PRIIN MOVEM W1,JFNCHS+CHTTI MOVEI W1,.PRIOU MOVEM W1,JFNCHS+CHTTO ] CALL GETJCL ; LOOK FOR JCL, SKIP IF FOUND CAIA ; NONE JRST RESTR1 ; HAVE SOME, GO EXECUTE. MOVE 0,[SIXBIT/SRCCOM/] ;NO COMMAND STRING FROM SUPERIOR: CALL TTOSIX ;IDENTIFY SELF TO USER. MOUTI CHTTO,40 ;SPACE IFDEF .FVERS,[ MOVE 0,[.FVERS] CALL TTODEC ] .ELSE [ MOVE 0,[.FNAM2] ;PRINT VERSION NUMBER. CALL TTOSIX ] JRST RESTRT ;COME HERE FOR A NEW COMMAND, AFTER FINISHED OR ERROR. RESTRT: SETZM TTIBUF RESTR1: MOVE P,[-LPDL,,PPSET-1] ;SET UP PUSH DOWN LIST IFN ITS,.SUSET [.SWHO1,,[0]] ;CLEAR USER-SPEC'D WHOLINE FIELDS. IFN ITS,.SUSET [.SMEMT,,[ENDCOR]] SETZB FR,BEGP ;THIS IS THE ZERO WHICH WILL ;BE "BLT"ED TO CLEAR CORE MOVE 0,[BEGP,,BEGP+1] BLT ENDP-1 MOVE W1,[440700,,MRGBF] MOVEM W1,MRGBP MOVEI W1,MRGBSZ MOVEM W1,MRGCT MOVE W1,SEG1 MOVEM W1,LBUFP1 MOVE W1,SEG2 MOVEM W1,LBUFP2 MOVE W1,SEG3 MOVEM W1,LBUFP3 AOS PAGNUM+0 ;ZEROED BY BLT ABOVE-1ST PAGE IS 1 AOS PAGNUM+1 ;DITTO FOR SECOND FILE AOS PAGNUM+2 AOS LINNUM+0 ;SAME TRUE FOR 1ST LINE AOS LINNUM+1 AOS LINNUM+2 SKIPE TTIBUF ;IF HAVE A JCL COMMAND, SETOM CTLCF ;SAY RETURN AFTER JUST THIS CMD. SKIPN TTIBUF CALL CMDLIN ;NO DDT CMD, READ TTY LINE. CALL TRYHLP ;IF COMMAND IS JUST "?" OR "HELP", PRINT HELP. MOVE C,FSTTY ;OUTPUT DEFAULTS TO TTY IF NOT SPEC'D, SKIPN CMDFIL ;UNLESS WE'RE IN A COMMAND FILE. MOVEM C,LSTFB+$FDEV MOVEI FP,INFB CALL RFILE ;READ FILE NAME IFN TNX,CAIE C,"= CAIN C,"_ ;IF FOLLOWED BY "_", IS OUTPUT SPEC, CAIA JRST CMD3 MOVE C,[INFB,,LSTFB] BLT C,LSTFB+L$FBLK-1 ;SO USE AS LST FILE NAMES. SETOM LSTEXP ;SAY LST FILE WAS EXPLICITLY SPECIFIED. SETZM INFB+$FDEV SKIPE CMDFIL ;IF NOT IN A COMMAND FILE, 1ST INPUT FILE SNAME SETZM INFB+$FDIR ;DEFAULTS TO OUTPUT FILE SNAME. CALL RFILE ;AND READ ANOTHER SPEC FOR 1ST INPUT FILE. JRST CMD3 ;NOW HAVE READ WHAT IS CERTAINLY THE 1ST INPUT SPEC. CMD3: MOVE W2,DEFDIR ;DEFAULT THE OUTPUT FILE DEV AND SNAME NOW. SKIPE CMDFIL ;CAN DO IT SINCE IT DOESN'T DEPEND ON SWITCH SETTINGS MOVE W2,CMDOS ;AND MUST DO IT SINCE MIGHT GO TO CMDXCT AND WANT SKIPN LSTFB+$FDIR ;TO KNOW THEIR FINAL VALUES. MOVEM W2,LSTFB+$FDIR MOVE W2,FSDSK SKIPE CMDFIL MOVE W2,CMDOD SKIPN LSTFB+$FDEV MOVEM W2,LSTFB+$FDEV TLNN FR,FLINDR ;IF THE FIRST INPUT FILE IS INDIRECT, DEFAULT THE FN2 JRST CMD6 ;OF THE FILE TO GO INDIRECT THROUGH TO MOVE W1,FSCMP ;TO THE FN2 OF THE LISTING FILE, AS WELL AS WE CAN. TLNE FR,FLARCH ;CAN LOSE IN OBSCURE SITUATIONS THAT THE DOCUMENTATION MOVE W1,FSCMPA ;WARNS USERS TO AVOID. SKIPE LSTFB+$FEXT MOVE W1,LSTFB+$FEXT SKIPN INFB+$FEXT MOVEM W1,INFB+$FEXT MOVE W1,LSTFB+$FDIR ;ALSO DEFAULT SNAME AND DEV THAT WAY, BUT NEVER USE TTY: SKIPN INFB+$FDIR ;NOTE THAT THE FN1 WILL DEFAULT TO THE LIST FILE'S MOVEM W1,INFB+$FDIR ;ANYWAY. MOVE W1,LSTFB+$FDEV CAMN W1,FSTTY MOVE W1,FSDSK SKIPN INFB+$FDEV MOVEM W1,INFB+$FDEV CMD6: MOVE W1,CMDIS SKIPN CMDFIL MOVE W1,DEFDIR SKIPN INFB+$FDIR MOVEM W1,INFB+$FDIR MOVE W1,CMDID ;DEFAULT DEVICE FOR 1ST INPUT FILE DEPENDS ON SKIPN CMDFIL ;WHETHER WE'RE IN A COMMAND FILE. MOVE W1,FSDSK SKIPN INFB+$FDEV MOVEM W1,INFB+$FDEV SKIPN W1,INFB+$FVERS MOVE W1,FVLOW ;IF ONLY ONE INPUT FILE SPECIFIED, DEFAULT ITS FN2 TO "<", SKIPG TTICNT ;SINCE 2ND INPUT FILE WILL BE THE ">" OF THE SAME FILE. MOVEM W1,INFB+$FVERS RFIND1: MOVEI W1,CHIN1 CALL INOPEN ;NOW OPEN CHANNEL CHIN1. TLNE FR,FLXCTF ;IS THIS AN EXECUTE FILE? JRST CMDXCT TLNE FR,FLINDR ;MAYBE THE FILE WE OPENED JUST HAS THE NAMES OF THE JRST RFINDR ;REAL 1ST INPUT FILE. IF SO, READ THEM. CALL RFILE ;READ NAMES OF & OPEN 2ND INPUT. MOVEI W1,CHIN2 CALL INOPEN TLNE FR,FLINDR\FLXCTF JRST ERRIN2 ;FILE 2 INDIRECT? THAT ISN'T ALLOWED. SKIPG TTICNT ;MORE FILES? MUST BE A 3-WAY MERGE. JRST CMD4 CALL RFILE ;READ THE THIRD FILE'S NAME. TLNN FR,FLMERG JRST ERR3NM ;ERROR IF /M NOT SPECIFIED. SETOM 3WAY MOVEI W1,CHIN3 CALL INOPEN TLNE FR,FLINDR\FLXCTF ;ERROR IF THIRD FILE IS INDIRECT. JRST ERRIN3 SKIPG TTICNT ;ERROR IF ANYTHING LEFT AFTER THIRD FILE NAME. JRST ERRXTRA JRST CMD4 ;NOW OPEN THE OUTPUT FILE. CMD4: MOVEI FP,LSTFB MOVE W2,FSCMP ;NORMAL DEFAULT OUTPUT FN2. TLNE FR,FLARCH MOVE W2,FSCMPA MOVEI W1,CHOUT ;NORMALLY, SPEC'D FILE IS OUTPUT FILE, TLNN FR,FLMERG JRST CMD5 TLNE FR,FLARCH JRST ERRARC MOVEI W1,CHMRG ;BUT IF /M, IT IS MERE FILE NAME, IFN ITS,[ .OPEN CHOUT,[.UAO,,'TTY] ;AND OUTPUT IS TO TTY: ERRHLT ] IFN TNX,[ PUSH P,JFNCHS+CHTTO POP P,JFNCHS+CHOUT ] MOVE W2,FSDMF2 TLNE FR,FLFLAG ;ALSO, WE HAVE DIFFERENT DEFAULT FN2'S MOVE W2,FSFLGD MOVE T,FSTTY SKIPL LSTEXP ;AND DON'T DEFAULT TO TTY:; USE DSK: INSTEAD. CAME T,LSTFB+$FDEV JRST CMD5 MOVE T,FSDSK MOVEM T,LSTFB+$FDEV CMD5: SKIPN LSTFB+$FEXT ;DEFAULT THE FN2 IF NEC. MOVEM W2,LSTFB+$FEXT IFN ITS,[ SYSCAL TRANS,[ $FDEV(FP) ? $FNAME(FP) ? $FEXT(FP) ? $FDIR(FP) MOVEI .UAO MOVEM $FDEV(FP) ? MOVEM $FNAME(FP) MOVEM $FEXT(FP) ? MOVEM $FDIR(FP)] CALL OPENL SYSCAL OPEN,[5000,,.UAO ? W1 $FDEV(FP) ? ['_SRCCO] ? ['OUTPUT] ? $FDIR(FP)] CALL OPENL ;ERROR RTN, IN CASE FAILED. SYSCAL TTYGET,[MOVEI CHOUT ? MOVEM TTYST1 ? MOVEM TTYST2 ? MOVEM W1] JRST CMD2 ;JUMP IF OUTPUT FILE ISN'T A TTY. SETOM OUTTTY MOVEM W1,TTYSTS ;IT IS A TTY; SAVE THE TTYSTS TO RESTORE LATER TLZE W1,%TSMOR ;AND TURN ON **MORE**'ING NOW. SYSCAL TTYSET,[MOVEI CHOUT ? TTYST1 ? TTYST2 ? W1] JFCL ] ;IFN ITS IFN TNX,[ MOVE T,FSTTY CAMN T,LSTFB+$FDEV ; ABOUT TO OPEN TTY FOR OUTPUT? JRST [ PUSH P,JFNCHS+CHTTO ; IF SO JUST DUPLICATE TTY JFN POP P,JFNCHS+CHOUT SETOM OUTTTY JRST CMD20] MOVEI FP,LSTFB HRLI FP,(W1) ; GET ,, CALL OPNWR CALL OPENL CMD20: ] ;FINAL INITIALISATION, AND PRINTING OF THE FILE HEADER. CMD2: SETZB F1,F2 ;RIGHT NOW WE HAVE NO LINES OF EITHER FILE IN CORE. TLNE FR,FLMERG ;IF MERGING, LINES FLUSHED FROM FILE 1 SETOM MRGOUT+0 ;GO OUT TO THE MERGE FILE. SETZ 0, IFN ITS,[ .SUSET [.SWHO1,,[.BYTE 8 ? 166 ? 0 ? 55 ? ",]] .SUSET [.SWHO3,,[1,,1]] ;INITIALIZE THE USER WHO-LINE FIELDS. .SUSET [.SWHO2,,['HEADER]] ] SKIPE 3WAY ;3-WAY MERGES HAVE A SPECIAL MAIN LOOP. JRST 3LOOP TLNE FR,FLMERG JRST ENTER MOVSI W1,-WPL MOVE T,HBUF1(W1) ;LOOK FOR DIFFERENCES BETWEEN REAL FILE NAMES CAMN T,HBUF2(W1) ;OF OUR TWO INPUT FILES. AOBJN W1,.-2 TLNN FR,FLOVRD ;UNLESS FORCED BY /!, JUMPGE W1,FIN5 ;IF THE NAMES ARE THE SAME, DON'T WASTE TIME COMPARING. MOVEI W1,[ASCIZ / ;COMPARISON OF /] CALL PRINT MOVE W1,RCHSTP CALL PRINT MOVEI W1,[ASCIZ / AND /];RFINDR DEPENDS ON EXACT STRINGS USED HERE. CALL PRINT MOVE W1,RCHSTP+1 CALL PRINT MOVEI W1,[ASCIZ / ;OPTIONS ARE /] ;NOTE RFINDR DEPENDS ON PRECISE STRING USED HERE. CALL PRINT IRPS X,,FLARCH FLALL FLCMNT FLENDL FLCASE FLLABL FLSPAC FLFNUM FLXLBL,Y,,A B C E K L S W Y MOVEI W1,[ASCIZ * /Y*] TLNE FR,X CALL PRINT TERMIN MOVEI W1,[ASCIZ * /*] CALL PRINT MOVE T,NUMLIN AOS T CALL PNTDEC CALL PCRLF CALL PCRLF JRST ENTER ENTER: IFN ITS,.SUSET [.SWHO2,,[SIXBIT/SAME/]] ;THIS IS THE MAIN LOOP OF SRCCOM. ;COME HERE WHEN THE LAST TWO LINES MATCHED, TO TRY THE NEXT TWO. SAME: SKIPE F1,LNNEXT(F1) ;ADVANCE PAST THE LINE THAT MATCHED JRST SAME1 TRZ FR,-1 ;IF NO MORE LINES IN CORE, FLUSH ALL SKIPE MRGOUT+0 ;THE LINES WE PASSED BY, CALL MOVEUP SETZM NLINE1 ;(IN THE SIMPLE COMMON CASE, FLUSH THEM FAST) CALL RDLIN ;AND READ ANOTHER. JRST END0 ;EOF => CHECK FILE 2 FOR EOF. ERRHLT SAME1: SKIPE F2,LNNEXT(F2) ;SIMILAR FOR F2, JRST SAME2 SETZM NLINE2 ;BUT SINCE MRGOUT+1 SHOULD BE ZERO, IT'S SIMPLE. HRRI FR,1 CALL RDLIN JRST DIFF ;EOF IN FILE 2 BUT NOT IN FILE 1 => IT'S A DIFFERENCE. ERRHLT SAME2: CALL COMPL JRST SAME ;THE TWO LINES ARE IDENTICAL; KEEP SCANNING. JRST DIFF ;ELSE SEE HOW BIG THIS RUN OF DIFFERENCES IS. ;COME HERE WHEN A DIFFERENCE IS SEEN. F1 AND F2 POINT TO THE 1ST PAIR OF NON-MATCHING ;LINES, OR ARE ZERO TO SAY THAT AN ENTIRE FILE HAS BEEN MATCHED OFF. DIFF: CALL MOVEUP ;FLUSH ANY MATCHING LINES STILL IN CORE BEFORE THOSE TWO. TRC FR,1 CALL MOVEUP SKIPE 0 ;0 SHOULD ALWAYS HOLD 0 FOR NEXTLN'S SAKE. ERRHLT IFN ITS,.SUSET [.SWHO2,,[SIXBIT/DIFF/]] SETZM NCOMP1 ;NCOMP1 GETS NUMBER OF LINES OF FILE 1 WE HAVE FOR SKIPE F1 ;CONSIDERATION. AOS NCOMP1 SETZM NCOMP2 ;NCOMP2 GETS THE SAME THING FOR FILE 2. SKIPE F2 AOS NCOMP2 DIFFRD: NEXTLN 1,END2 ;READ ANOTHER LINE FROM EACH FILE. AOS NCOMP1 NEXTLN 2,DIFF2 ;NO NEW LINE FROM FILE 2 => DON'T COMPARE FILE 1 WITH IT DIFF3: AOS NCOMP2 SKIPN CS,NCOMP1 ;HOW MANY FILE 1 LINES SHOULD WE CONSIDER? JRST DIFFRD ;NONE? SKIPA F1,LBUFP1 ;ELSE COMPARE ALL THE NON-MATCHING LINES OF FILE 1, 1 AT A TIME, DIFF0: MOVE F1,W1 ;WITH THE NEW LINE FROM FILE 2. CALL COMPL CALL MULTI ;MATCH => CHECK FOR MULTI-LINE MATCH, GO TO SAME IF FOUND. SKIPE W1,LNNEXT(F1) SOJG CS,DIFF0 ;AFTER COMPARING ALL THE FILE 1 LINES WITH THE NEW FILE 2 LINE, OR IF THERE IS NO NEW ;FILE 2 LINE, COME HERE TO COMPARE THE NEW FILE 1 LINE WITH ALL THE FILE 2 LINES. ;F1 IS ALREADY POINTING AT THE NEW FILE 1 LINE ("NEW" MEANS THAT DIFFRD GOT IT. ;IT MIGHT HAVE BEEN IN CORE ALREADY DUE TO NEXTLN'S DONE INSIDE MULTI). DIFF2: SKIPE EOFFL1 ;BUT DON'T DO IT IF NO NEW FILE 1 LINE. JRST DIFFRD SKIPN CS,NCOMP2 ;HOW MANY LINES ARE WE CONSIDERING YET FROM FILE 2? JRST DIFFRD ;NONE => NOTHING TO COMPARE WITH THE NEW LINE FROM 1. SKIPA F2,LBUFP2 ;(MAY NOT BE SAME AS NLINE2, IF MULTI READ SOME LINES.) DIFF1: MOVE F2,W1 ;ELSE LOOP HERE OVER THE FILE 2 LINES. CALL COMPL CALL MULTI SKIPE W1,LNNEXT(F2) SOJG CS,DIFF1 JRST DIFFRD ;NO MATCH => READ ANOTHER PAIR OF LINES AND TRY MATCHING THEM. END0: SKIPE F2,LNNEXT(F2) ;HERE WHEN EOF IN FILE 1 AT SAME. JRST DIFF ;MORE LINES IN FILE 2 => THEY'RE DIFFERENT. SETZM NLINE2 HRRI FR,1 CALL RDLIN JRST FIN2 ;EOF IN FILE 2 => ALL DONE. ERRHLT JRST DIFF END2: NEXTLN 2,FINDIF ;NO NEW FILE 1 LINE IN DIFFRD. NO NEW FILE 2 LINE EITHER => JRST DIFF3 ;ALL THE NON-MATCHING LINES WE HAVE ARE DIFFERENCES. ;NEW LINE FROM FILE 2 => TRY MATCHING IT AGAINST FILE 1 LINES. ;AT THIS POINT NEITHER FILE HAS ANY MORE LINES TO BE READ. ;PRINT AS DIFFERENCES ANY LINES REMAINING FOR EITHER FILE. FINDIF: SETZB F1,F2 ;MAKE SURE ALL LINES PRINTED IN CASE NO /E. CALL COMSPC ;SEE IF DIFFERENCES VANISH IF WE IGNORE SPACES AND COMMENTS. JRST FIN2 ;THEY DO; DON'T PRINT AS DIFFERENCES. CALL PNTBTH ;PRINT ANY LINES CALL TRYMRG JRST FIN2 MOVEI W1,[ASCIZ/*************** /] CALL PRINT ;COME HERE WHEN THE OUTPUT AND MERGE FILES ARE ALL GENERATED. FIN2: TRZ FR,-1 ;OUTPUT THE STUFF IN FILE 1, IN CASE IN /M MODE. CALL MOVEUP TLNN FR,FLARCH ;IF SUPOSED TO BE ARCHIVING, DO THE APPEND NOW. JRST FIN3 SKIPN ERRCNT ;BUT IF NO NEW STUFF TO APPEND, DO NOTHING, JRST FIN5 ;AND THROW AWAY OUR 0-BLOCK FILE. MOVE FP,[CHIN1,,LSTFB] CALL OPNRDA JRST FIN3 ;NO OLD FILE => JUST MAKE NEW ONE. MOUTI CHOUT,^L FIN4: MOVE W2,GCHARB ;IF SO, IF WE'RE ABOUT TO OVERWRITE A FILE, MOVEI C,FILBFL*5 ;APPEND ITS OLD CONTENTS TO OUR OUTPUT, WITH ^L BETWEEN. M.SIN CHIN1,W2,C ; INPUT MOVNS C ADDI C,FILBFL*5 JUMPE C,FIN3 MOVE W2,GCHARB CALL PNTCNT JRST FIN4 FIN5: M.CLS CHOUT IFN ITS,[ SYSCAL DELETE,[LSTFB+$FDEV ? ['_SRCCO] ? ['OUTPUT] ? LSTFB+$FDIR] JFCL ] FIN3: TLNE FR,FLMERG CALL MRGFRC ;IF MERGING, FORCE OUT OUR BUFFER. MOVEI W1,CHOUT ;WHICH CHANNEL IS OUR MOST IMPORTANT OUTPUT FILE ON? TLNE FR,FLMERG MOVEI W1,CHMRG CALL RENMLO MOVEI T,[ASCIZ /NO DIFFERENCES ENCOUNTERED/] SKIPN ERRCNT ;ANY DIFFERENCES? CALL TYPMS0 ;NO, PRINT MESSAGE SKIPE ERRCNT ;/M ANY DIFFERENCES? TLNN FR,FLMERG ;/M YES, MERGE IN PROGRESS? JRST RELDEV ;/M NO, END OF SOURCE COMPARE MOVEI T,[ASCIZ /END OF MERGE/] TLNN FR,FLISWT\FLFLAG CALL TYPMSG ;/M YES, PRINT END OF MERGE JRST RELDEV ;END OF SOURCE COMPARE ;CALL MULTI TO CHECK FOR A MULTI-LINE MATCH, IF NECESSARY. ;IF THERE IS ONE, OR IT ISNT NECESSARY (NUMLIN = 0), RETURNS TO SAME ;AFTER PRINTING THE DIFFERENCES. IF THE MATCH FAILS, IT RETURNS ;NON-SKIPPING TO ITS CALLER. ;IN A 3-WAY MERGE, WE ARE USED TO COMPARE FILES 1 AND 2. ;WHEN WE FIND A MULTI-LINE MATCH, WE PUSH AN ENTRY ON ;12MTAB, THE TABLE OF PLACES WHERE FILES 1 AND 2 MATCH. ;EACH SUCH PLACE GETS COMPARED AGAINST FILE 3 LATER. MULTI: SAVE CS MOVEM F1,TEMPF1 ;SAVE CURRENT POINTERS MOVEM F2,TEMPF2 SKIPG NUMLIN ;MULTIPLE LINE TEST? JRST MULT8 ;NO SETZM NUMTMP ;INIT MULTI-LINE COUNTER MULT2: NEXTLN 1,MULTE ;MUST GET A NEW LINE FROM BOTH FILES NEXTLN 2,MULT4 ;TO CONTINUE THE MULTI-LINE MATCH. CALL COMPL ;COMPARE THEM JRST MULT6 ;MATCH, TEST MULTI COUNTER MULT4: SKIPE F1,TEMPF1 ;NO MATCH, RESET REGS SETZM EOFFL1 ;IF NO LONGER AT LAST LINE, CAN'T BE AT EOF. SKIPE F2,TEMPF2 SETZM EOFFL2 REST CS RET MULTE: NEXTLN 2,MULT8 JRST MULT4 MULT6: AOS W1,NUMTMP ;INDEX MULTI-LINE COUNTER CAMGE W1,NUMLIN ;TEST FOR ENOUGH LINES MATCHED JRST MULT2 ;COMPARE NEXT TWO. MULT8: SKIPE 3WAY JRST [ MOVE W1,TEMPF2 ;IN A 3-WAY MERGE, RECORD THIS MATCH OF FILES 1 AND 2 HRL W1,TEMPF1 IDPB W1,12MTBP JRST MULT4] ;AND RETURN TO OUR CALLER (JUST AS IF WE HAD FAILED). EXCH F1,TEMPF1 ;REMEMBER WHERE THE MULTI-LINE MATCH STOPPED, EXCH F2,TEMPF2 ;GO BACK TO WHERE IT STARTED. SUB P,[2,,2] ;FLUSH MULTI'S RETURN ADDRESS. CALL COMSPC ;SEE IFF ALL DIFFERENCES VANISH WHEN IGNORE SPACES & COMMENTS. JRST MULT10 CALL PNTBTH ;PRINT DIFFERENCES ;THE TEXT OF DIFFERENCES HAS BEEN PRINTED--PUT IN ****** ;AND A CARRIAGE RETURN-LINE FEED AND GO BACK AND START COMPARING ;WHEN WE START COMPARING AGAIN THE LINE POINTERA WILL ;BE POINTING TO THE FIRST TWO LINES AFTER THE MATCHING LINES CALL TRYMRG ;/M CHECK IF /M IN EFFECT, ASK FOR COMMAND ;/M AND OUTPUT IF YES JRST MULT10 ;/M IN EFFECT MOVE W1,[440700,,[ASCIZ /*************** /]] CALL PRINT MULT10: SKIPE F1,TEMPF1 ;NOW MOVE FORWARD PAST THE LINES MATCHED SETZM EOFFL1 ;IN THE MULTI-LINE MATCH. SKIPE F2,TEMPF2 SETZM EOFFL2 JRST ENTER ;AFTER FINDING A RUN OF DIFFERENCES, SEE WHETHER THE FILES ARE IDENTICAL ;WHEN WE IGNORE SPACES AND COMMENTS ACCORDING TO THE /S AND /C SWITCHES. ;IF SO, RETURNS NON-SKIPPING. SKIPS IF THE DIFFERENCE SHOULD BE PRINTED. ;EVEN IF /S AND /C ARE NOT SET, THIS ROUTINE TAKES CARE OF IGNORING ;DIFFERENCES IN BLANK LINES. ALSO, IF /K, IGNORES DIFFERENCES IN CASE. COMSPC: TLNE FR,FLSPAC ;THIS ROUTINE CAN MAKE A DIFFERENCE IF TLNE FR,FLALL ;WE ARE IGNORING BOTH SPACING AND BLANK LINES TLNE FR,FLCMNT ;OR WE ARE IGNORING COMMENTS. CAIA JRST POPJ1 ;NOTHING IGNORED => DO PRINT. SAVE F1 SAVE F2 SKIPE F1,NLINES+0 ;MAKE F1 AND F2 POINT AT THE FIRST DIFFERING LINES. MOVE F1,LBUFP+0 SKIPE F2,NLINES+1 MOVE F2,LBUFP+1 COMSPL: CAMN F1,-1(P) ;HAVE WE CONSIDERED ALL THE LINES FROM FILE 1? JRST COMSP2 HRRI FR,0 ;NO. TLNN FR,FLALL ;DON'T SKIP LINES WITH JUST COMMENTS IF NOT IGNORING BLANK LINES! CALL BLANKP ;FIRST, TRY TO IGNORE ESSENTIALLY BLANK LINES JRST COMSP2 ;IN FILE 1. MOVE F1,LNNEXT(F1) ;FOUND ONE => SKIP PAST IT. JRST COMSPL COMSP2: CAMN F2,(P) ;THEN TRY FOR BLANK LINES IN FILE 2 JRST COMSPX ;NO LINES IN FILE 2 => CAN'T WIN. HRRI FR,1 TLNN FR,FLALL CALL BLANKP JRST COMSP3 MOVE F2,LNNEXT(F2) JRST COMSPL COMSP3: CAMN F1,-1(P) ;IF BOTH FILES HAVE LINES, JRST COMSPX CALL COMPCS ;SEE IF THEY ARE EQUAL WHEN SPACES & COMMENTS ARE IGNORED. JRST COMSPF ;HERE WHEN WE CAN'T ELIMINATE ANY MORE LINES BY IGNORING SPACES & COMMENTS COMSPX: CAMN F1,-1(P) ;IF NO LINES LEFT FROM EITHER FILE, WE WIN CAME F2,(P) AOS -2(P) ;OTHERWISE, THE DIFFERENCES ARE ESSENTIAL. REST F2 REST F1 RET ;COME HERE IF TWO LINES MATCH WHEN WE IGNORE APPROPRIATE STUFF. COMSPF: MOVE F1,LNNEXT(F1) ;SKIP BOTH LINES. MOVE F2,LNNEXT(F2) JRST COMSPL ;SKIP IF THE LINE F1(FR) POINTS AT IS BLANK WHEN ;SPACES AND COMMENTS ARE IGNORED ACCORDING TO SWITCH SETTINGS. BLANKP: HRRZ W1,F1(FR) MOVE C,LNSIZE(W1) ADD W1,[440700,,LNDATA] BLANK1: ILDB T,W1 SOJLE C,POPJ1 ;WE WIN IF EXHAUST THE LINE AFTER JUST SPACES AND CRLFS. CAIE T,^M CAIN T,^J JRST BLANK1 CAIE T,40 CAIN T,^I TLNN FR,FLSPAC CAIA JRST BLANK1 TLNE FR,FLCMNT ;IF /C, WE ALSO WIN IF WE FIND A SEMICOLON. CAIE T,"; RET JRST POPJ1 3LOOP: IFN ITS,.SUSET [.SWHO2,,[SIXBIT/SAME/]] ;THIS IS THE MAIN LOOP OF 3-WAY MERGING. ;COME HERE WHEN THE LAST LINES OF ALL 3 FILES MATCHED, TO TRY THE NEXT LINES OF ALL 3. 3SAME: SKIPE F1,LNNEXT(F1) ;ADVANCE PAST THE LINE THAT MATCHED JRST 3SAME1 TRZ FR,-1 ;IF NO MORE LINES IN CORE, FLUSH ALL SKIPE MRGOUT+0 ;THE LINES WE PASSED BY, CALL MOVEUP SETZM NLINE1 ;(IN THE SIMPLE COMMON CASE, FLUSH THEM FAST) CALL RDLIN ;AND READ ANOTHER. CAIA JFCL 3SAME1: SKIPE F2,LNNEXT(F2) ;SIMILAR FOR F2, JRST 3SAME2 SETZM NLINE2 ;BUT SINCE MRGOUT+1 SHOULD BE ZERO, IT'S SIMPLE. HRRI FR,1 CALL RDLIN CAIA JFCL 3SAME2: SKIPE F3,LNNEXT(F3) ;FOR F3, JUST LIKE F2. JRST 3SAME3 SETZM NLINE3 HRRI FR,3 CALL RDLIN CAIA JFCL 3SAME3: MOVE W1,EOFFL1 ;UNLESS EITHER ALL 3 FILES ARE ENDING OR NONE, CAMN W1,EOFFL2 ;IT'S A DIFFERENCE. CAME W1,EOFFL3 JRST 3DIFF CALL COMPL ;COMPARE LINE FROM FILE 1 WITH THAT FROM FILE 2. CAIA JRST 3DIFF EXCH F2,F3 CALL COMPL ;COMPARE FILE 1 WITH FILE 3. CAIA JRST [ EXCH F2,F3 JRST 3DIFF] EXCH F2,F3 ;1 MATCHES 2 AND MATCHES 3 => ALL 3 STILL THE SAME. SKIPE EOFFL1 JRST FIN2 JRST 3SAME ;COME HERE, DURING A 3-WAY MERGE, WHEN A DIFFERENCE IS SEEN. ;THAT IS, WHEN ALL 3 FILES CEASE TO BE IDENTICAL. ;F1, F2, F3 POINT AT THE FIRST NON-MATCHING LINES, ;OR ARE ZERO TO SAY THAT AN ENTIRE FILE HAS BEEN MATCHED OFF. ;COME HERE WHEN A DIFFERENCE IS SEEN. F1 AND F2 POINT TO THE 1ST PAIR OF NON-MATCHING ;LINES, OR ARE ZERO TO SAY THAT AN ENTIRE FILE HAS BEEN MATCHED OFF. 3DIFF: HRRI FR,0 CALL MOVEUP ;FLUSH ANY MATCHING LINES STILL IN CORE BEFORE THOSE TWO. HRRI FR,1 CALL MOVEUP HRRI FR,2 CALL MOVEUP SKIPE 0 ;0 SHOULD ALWAYS HOLD 0 FOR NEXTLN'S SAKE. ERRHLT IFN ITS,.SUSET [.SWHO2,,[SIXBIT/DIFF/]] SETZM NCOMP1 SKIPL EOFFL1 AOS NCOMP1 SETZM NCOMP2 SKIPL EOFFL2 AOS NCOMP2 SETZM NCOMP3 SKIPL EOFFL3 AOS NCOMP3 MOVE W1,12MTBB ;CLEAR THE TABLE OF MATCHES BETWEEN FILES 1 AND 2. MOVEM W1,12MTBP 3DIFFR: NEXTLN 1 ;READ ANOTHER LINE FROM EACH FILE. SKIPL EOFFL1 AOS NCOMP1 NEXTLN 2 SKIPL EOFFL2 AOS NCOMP2 NEXTLN 3 SKIPL EOFFL3 AOS NCOMP3 SKIPE EOFFL2 JRST 3DIFF2 SKIPN CS,NCOMP1 ;HOW MANY FILE 1 LINES SHOULD WE CONSIDER? JRST 3DIFF2 SKIPA F1,LBUFP1 ;COMPARE ALL THE NON-MATCHING LINES OF FILE 1, 1 AT A TIME, 3DIFF0: MOVE F1,W1 ;WITH THE NEW LINE FROM FILE 2. CALL COMPL CALL MULTI ;MATCH => CHECK FOR MULTI-LINE MATCH, PUT IN 12MTAB IF FOUND. SKIPE W1,LNNEXT(F1) SOJG CS,3DIFF0 ;AFTER COMPARING ALL THE FILE 1 LINES WITH THE NEW FILE 2 LINE, OR IF THERE IS NO NEW ;FILE 2 LINE, COME HERE TO COMPARE THE NEW FILE 1 LINE WITH ALL THE FILE 2 LINES. ;F1 IS ALREADY POINTING AT THE NEW FILE 1 LINE ("NEW" MEANS THAT DIFFRD GOT IT. ;IT MIGHT HAVE BEEN IN CORE ALREADY DUE TO NEXTLN'S DONE INSIDE MULTI). 3DIFF2: SKIPE EOFFL1 ;BUT DON'T DO IT IF NO NEW FILE 1 LINE. JRST 3DIFF3 SKIPN CS,NCOMP2 ;HOW MANY LINES ARE WE CONSIDERING YET FROM FILE 2? JRST 3DIFF3 SKIPA F2,LBUFP2 ;(MAY NOT BE SAME AS NLINE2, IF MULTI READ SOME LINES.) 3DIFF1: MOVE F2,W1 ;ELSE LOOP HERE OVER THE FILE 2 LINES. CALL COMPL CALL MULTI ;IF MULTI-LINE MATCH FOUND, PUT IT IN 12MTAB. SKIPE W1,LNNEXT(F2) SOJG CS,3DIFF1 ;NOW WE KNOW ABOUT THE PLACES WHERE FILES 1 AND 2 MATCH. ;EACH SUCH PLACE (WITHIN THE RANGE BEING CONSIDERED) IS LISTED IN 12MTAB. ;WE NOW COMPARE EACH OF THOSE PLACES AGAINST WHAT WE HAVE OF FILE 3. 3DIFF3: PUSH P,F1 PUSH P,F2 MOVE W1,12MTBB 3DIFF6: CAMN W1,12MTBP JRST 3DIFF4 ;NO MATCH => READ ANOTHER PAIR OF LINES AND TRY MATCHING THEM. ILDB F2,W1 PUSH P,W1 ANDI F2,-1 ;FIND THE FILE 2 LOCATION OF THE NEXT 1-2 MATCH. MOVE CS,NCOMP3 SKIPA F1,LBUFP3 3DIFF5: MOVE F1,W1 CALL COMPL ;COMPARE THAT AGAINST EACH POINT OF FILE 3. CALL 3MULTI ;NOTE THAT WE ARE USING F1 TO HOLD THE FILE 3 POINTER. SKIPE W1,LNNEXT(F1) SOJG CS,3DIFF5 POP P,W1 JRST 3DIFF6 3DIFF4: POP P,F2 POP P,F1 ;NO MATCH FOUND. SKIPE EOFFL1 ;NORMALLY, READ ANOTHER LINE FROM EACH FILE. SKIPL EOFFL2 JRST 3DIFFR SKIPL EOFFL3 JRST 3DIFFR JRST 3ALDIF ;BUT IF ALL ARE AT EOF, TAKE ALL REMAINING LINES OF ALL FILES AS DIFFS. ; THIS IS A COLLECTION OF STUFF THAT WAS UNDEFINED AT THE ; TIME CONVERSION TO TNX WAS DONE. VALUES ARE FURNISHED HERE ; JUST TO MINIMIZE ASSEMBLY BARFAGE, BUT SOMEDAY PRESUMABLY ; SOMEONE WILL REPLACE WITH THE PROPER THINGS. 3ALDIF: 3MULTI: RET ; NOP FOR NOW .SCALAR 3WAY ; -1 IF DOING 3-WAY COMPARE .SCALAR 12MTBP ; SOMETHING TO DO WITH 3WAY MERGE? .SCALAR 12MTBB ; DITTO ;/M ROUTINE TO TEST IF MERGE IN EFFECT AND IF YES ;/M ACCPT COMMAND AND PASS TO MERGE OUTPUT FILE ;/M COMMANDS ARE ANY COMBINATION OF 1,2,I AND/OR T (WITH NO COMMAS) ;/M ALL OTHER CHARACTERS ARE ILLEGAL ;/M CALL: CALL TRYMRG ; MERGER DONE RETURN ; /M NOT IN EFFECT RETURN TRYMRG: TLNN FR,FLMERG ;/M /M SWITCH IN EFFECT? JRST POPJ1 ;/M NO, SKIP RETURN IFN ITS,.SUSET [.SWHO2,,[SIXBIT/MERGE/]] TLNE FR,FLISWT ;/I => ASSUME "I" AS AN ANSWER. JRST MRGI1 TLNE FR,FLFLAG ;/F => PUT OUT THE FILE 2 STUFF WITH FLAGS. JRST MRGU1 CALL GETMRG ;/M TYPE *,GET ALL OF MERGE COMMAND(CHECK SYNTAX) LISTEN: CALL MRGIN ;/M GET NEXT MERGE COMMAND INPUT CHAR CAIE C,"1 ;/M DID HE TYPE 1? CAIN C,"2 ;/M DID HE TYPE 2? JRST MRG5 ;YES FOR ONE OF THEM! CAIN C,"I JRST MRGI ;"I"=> PUT IN BOTH FILES' TEXTS AND IDENTIFYING MARKS. CAIE C,"T ;/M "T" TYPED? JRST MRG4 ;/M NO, CHECK FOR END OF COMMAND MRG3B: CALL TTILIN MRG3A: CALL TTICHR ;GET TTY INPUT CHAR. CAIE C,^C ;/M EOF OR CAIN C,ALTM ;/M ALT-MODE? JRST LISTEN ;/M YES, END OF INSERT FROM TTY CALL MRGO ;/M NO, OUTPUT CHAR TO MERGE FILE CAIE C,^M ;CR -> SPECIAL. JRST MRG3A ;ELSE GET MORE MOVEI C,^J ;PUT IN ^J AFTER ^M. CALL MRGO JRST MRG3B ;GET NEXT TTY LINE. MRG4: CAIE C,0 ;/M MUST BE NULL(END OF COMMAND) ERRHLT ;/M NO SOME THING IS VERY WRONG HRRI FR,0 ;/M FLUSH DIFFERENCES IN FILE ONE IF NOT ALREADY SETZM MRGOUT(FR) ;/M BUT DO NOT OUTPUT ON MERGE FILE CALL MOVEUP ;/M NO, OUTPUT DIFFERENCES AND FLUSH HRRI FR,1 ;/M FLUSH DIFFERENCES IN FILE TWO IF NOT ALREADY SETZM MRGOUT(FR) ;BUT DO NOT OUTPUT ON MERGE FILE CALL MOVEUP ;/M NO, OUTPUT DIFFERENCES AND FLUSH SETOM MRGOUT+0 RET ;/M RETURN, LEAVING MATCH LINES STILL IN BUFFER MRG5: HRRI FR,-"1(C) SETOM MRGOUT(FR) ;/M YES, SET FLAG SO MOVEUP WILL OUTPUT CALL MOVEUP ;/M MOVE BUFFER UP OVER DIFFERENCES USER WANTS JRST LISTEN ;/M GO GET ANOTHER CHARACTER ;/F => WHEN DIFFERENCES ARE FOUND, OUTPUT THE LINES FROM FILE 2 ;WITH A "|" AT THE FRONT OF EACH ONE. MRGU1: SETOM MRGOUT+1 HRRI FR,1 SETOM MRGUFL ;TELL MOVEUP TO INSERT "|"'S PUSH P,F1(FR) CALL MOVEUP ;OUTPUT THE STUFF FROM FILE 2 REST W1 MOVEI W2,[ASCIZ /^^^^/] ;THEN OUTPUT "^^^^" IN FRONT OF NEXT LINE CAMN W1,F1(FR) ;IF THERE WERE NO LINES FROM FILE 2 (A DELETION). CALL MRGPNT SETZB C,MRGUFL JRST MRG4 ;THROW AWAY STUFF FROM FILE 1 AND RETURN. ;"I" MERGE COMMAND - PUT IN THE MERGE FILE THE FOLLOWING: ;*** MERGE LOSSAGE *** ;*** FILE FOOBAR 1001 HAS: ; ;*** FILE FOOBAR 1002 HAS: ; ;*** END OF MERGE LOSSAGE *** MRGI: SAVE [LISTEN] MRGI1: MOVEI W2,[ASCIZ /*** MERGE LOSSAGE *** *** FILE /] CALL MRGPNT MOVE W2,RCHSTP ;-> NAMES OF FILE 1. CALL MRGPNT MOVEI W2,[ASCIZ / HAS: /] CALL MRGPNT SETOM MRGOUT ;OUTPUT THE TEXT OF FILE 1 HRRI FR,0 CALL MOVEUP MOVEI W2,[ASCIZ /*** FILE /] CALL MRGPNT MOVE W2,RCHSTP+1 ;-> NAMES OF FILE 2. CALL MRGPNT MOVEI W2,[ASCIZ / HAS: /] CALL MRGPNT SETOM MRGOUT+1 ;OUTPUT TEXT FROM FILE 2. HRRI FR,1 CALL MOVEUP SETZM MRGOUT+1 ;CLEAR THIS OR WE'D GET 2 COPIES OF FURTHER UNCHANGED TEXT! MOVEI W2,[ASCIZ /*** END OF MERGE LOSSAGE *** /] JRST MRGPNT ;PRINT ASCIZ STRING <- W2 ON THE MERGE FILE. MRGPNT: HRLI W2,440700 MRGPN1: ILDB C,W2 JUMPE C,CPOPJ CALL MRGO JRST MRGPN1 ;OUTPUT STRING <- W2 WITH # CHARS IN C. MRGCNT: SAVE W1 SKIPN W1,C JRST POPW1J MRGCN1: ILDB C,W2 CALL MRGO SOJG W1,MRGCN1 JRST POPW1J ;HERE TO OUTPUT ONE CHARACTER TO CHMRG VIA BUFFER. MRGO: IDPB C,MRGBP SOSLE MRGCT RET ;EMPTY OUT OUR CHMRG BUFFER. MRGFRC: SAVE W1 SAVE W2 MOVE W1,[440700,,MRGBF] MOVEM W1,MRGBP MOVEI W2,MRGBSZ SUB W2,MRGCT ;# CHARS FILLED IN IT. ADDM W2,MRGCT ;MARK IT EMPTY (AFTER WE WRITE DATA). JUMPE W2,MRGFR1 M.SOUT CHMRG,W1,W2 ; OUTPUT STRING MRGFR1: REST W2 POPW1J: REST W1 RET ;/M ROUTINE TO GET INPUT FOR MERGE COMMAND ;/M STORES ENTIRE COMMAND IN SPECIAL BUFFER ;/M IN CASE USER TYPES T COMMAND AS ONE OF COMMANDS ;/M WHICH WILL SLAO REQUIRE TTY INPUT ;/M CHECK SYSTAX, DO NOT RTURN UNTIL GOOD COMMAND LINE TYPED IN GTMRG0: HLRZ C,(P) MOVEM W1,(C) GETMRG: CALL TTILNA ;READ TTY LINE, PROMPTING WITH A "*". MOVE W1,[440700,,MRGCOM] ;/M SET UP BYTE POINTER TO MERGE ;/M COMMAND BUFFER GTMRG1: MOVEI C,0 ;/M IN CASE TOO LONG COMMAND CAME W1,[350700,,MRGCOM+MRGLEN-1] CALL TTICHU CAIGE C,40 ;/M ALTM,LF? MOVEI C,0 ;/M YES, FLAG END OF MERGE COMAND WITH NULL IDPB C,W1 ;/M STORE CHAR CAIE C,"1 ;/M IS IT "1"? CAIN C,"2 ;/M OR "2"? JRST GTMRG1 ;/M YES, GET ANOTHER CAIE C,"I CAIN C,"T ;/M NO, IS IT "T"? JRST GTMRG1 ;/M YES, GET ANOTHER CAIN C,"L JRST GTMRGL CAIE C,"C ;/M C? JRST GTMRG3 ;/M NO SKIPA W1,[COLMAX] GTMRGL: MOVEI W1,LINMAX HRLM W1,(P) MOVEI W1,0 GTMRG2: CALL TTICHR ;/M GE CHAR CAIGE C,40 ;/M END OFLINE CHAR? JRST GTMRG0 ;/M YES STORE NEW MAX. CAIL C,"0 ;/M NO, A DECIMAL DIGIT? CAILE C,"9 ;/M JRST GTMRG4 ;/M NO, PRINT ERROR IMULI W1,12 ;/M YES CONVERT TO BINARY ADDI W1,-"0(C) ;/M ADD IN THIS DIGIT JRST GTMRG2 ;/M GO GET NEXT DIGIT GTMRG3: MOVE W1,[440700,,MRGCOM] ;/M ASSUME IT IS END OF LINE MOVEM W1,MRGBYT ;/M AND STORE BYTE POINTER TO SCANNED STRING JUMPE C,CPOPJ ;/M IS IT? GTMRG4: MOVE W1,[440700,,[ASCIZ "?ONLY 1, 2, I, AND/OR T ARE LEGAL IN MERGE COMMANDS OR C### TO SET MAX. COL. OR L### TO SET MAX. LINES TYPED. "]] CALL PRINT ;/M PRINT ERROR JRST GETMRG ;/M AND ASK FOR COMMAND OVER AGAIN ;/M ROUTINE TO GET NEXT CHAR FROM MERGE COMMAND BUFFER ;/M CALL: CALL MRGIN ;/M RETURN WITH CHAR IN C MRGIN: ILDB C,MRGBYT ;/M GET NEXT CHAR RET ;MOVEUP FLUSHES ALL THE LINES OF THE FILE SPECIFIED BY RH(FR) ;THAT ARE BEFORE THE LINE POINTED BY F1 OR F2 OR F3. ;IF THERE ARE ANY LINES AFTER F1 OR F2 OR F3, THEY HAVE TO BE BLT'ED DOWN ;TO THE BEGINNING OF THE FILE'S SEGMENT. IF THERE ARE NONE, ;ONLY POINTER RELOCATION TAKES PLACE. ;F1 OR F2 OR F3 CONTINUES TO POINT AT THE SAME LINE, OR REMAINS 0. ;IF MRGOUT(FR) IS NONZERO, THE FLUSHED LINES ARE OUTPUT TO THE ;MERGE FILE. MOVEUP: SKIPE MRGOUT(FR) ;SKIP IF SHOULD OUTPUT TO MERGE FILE, CALL MOVEU1 ;DO SO. SKIPE W1,F1(FR) ;GET ADDR OF 1ST LINE NOT TO FLUSH. JRST MOVEU5 SETZM NLINES(FR) ;FLUSHING ALL LINES => JUST SAY THERE ARE NONE. RET MOVEU5: MOVEI T,1 ;T COUNTS THE NUMBER OF LINES LEFT. MOVN C,W1 ;WE MUST BLT FROM C(W1) TO C(LBUFP(FR)) ADD C,LBUFP(FR) ;HOW FAR IS THAT? MOVEU3: MOVE W2,W1 ;W2 REMEMBERS THE LAST LINE'S ADDR CAMN W1,TEMPF1(FR) ;RELOCATE TEMPF1 IF IT POINTS AT THIS LINE. ADDM C,TEMPF1(FR) SKIPN W1,LNNEXT(W1) ;FIND THE NEXT LINE WHERE IT NOW IS JRST MOVEU4 ADDM C,LNNEXT(W2) ;RELOCATE POINTER -> WHERE IT WILL BE BLT'ED TO. AOJA T,MOVEU3 ;ANOTHER LINE => COUNT IT. MOVEU4: MOVEM T,NLINES(FR) HRLZ W1,F1(FR) ;LH(W1) GETS CURRENT ADDRESS OF 1ST LINE TO KEEP HRR W1,LBUFP(FR) ;RH GETS NEW ADDR MOVE T,LNSIZE(W2) ;FIND END OF LAST LINE ADDI T,5 IDIVI T,5 ;FIRST FIND LENGTH IN WORDS ADDI W2,LNDATA-1(T) ;ADD ADDR OF START OF LINE ADD W2,C ;FIND WHERE THAT END IS BEING RELOCATED TO. BLT W1,(W2) ;COPY THE LINES THAT ARE LEFT TO THEIR NEW HOMES. MOVE W1,LBUFP(FR) MOVEM W1,F1(FR) ;NOW RELOCATE F1(FR). RET ;OUTPUT THE LINES UP THE FILE IN FR THAT ARE BEFORE F1 OR F2 OR F3 TO THE MERGE FILE. MOVEU1: MOVE W1,LBUFP(FR) ;GET ADDR OF 1ST LINE TO BE FLUSHED. SKIPN NLINES(FR) SETZ W1, MOVEU2: CAMN W1,F1(FR) ;REACHED 1ST LINE NOT TO BE FLUSHED? RET ;NO, OUTPUT LINE W1 POINTS AT. TLNE FR,FLFLAG SKIPGE LPHONY ;IF THIS LINE IS PHONY (NOT FIRST AFTER A CRLF) JRST MOVEU6 ;OMIT ANY /F HACKERY. SKIPLE LPHONY ;IF FOLLOWS A STRAY CR, JUST PUT IN A TAB. JRST MOVEU7 MOVEI C,"| SKIPE MRGUFL ;IF OUTPUTTING DIFFERENCES IN /F MODE, PREFIX WITH "|". CALL MRGO TLNN FR,FLFLAG ;IN /F MODE, PUT A TAB BEFORE EVERY LINE JRST MOVEU6 MOVEU7: MOVEI C,^I ;SO "|"'S AND "^"'S CAN STAND OUT. CALL MRGO MOVEU6: MOVEI W2,LNDATA(W1) HRLI W2,440700 ;GET ADDR OF 1ST DATA WORD MOVE C,LNSIZE(W1) ;AND # OF CHARACTERS. SETZM LPHONY ;SET LPHONY FOR NEXT LINE UNLESS THIS ONE ENDS IN A CRLF. CAIGE C,2 SETOM LPHONY CALL MRGCNT ;TRANSFER THE CHARACTERS. SOS W2 REPEAT 3,IBP W2 ;DECREMENT W2 TWICE. ILDB C,W2 CAIE C,^M SETOM LPHONY ;CHECK FOR THE TERMINAL CRLF. ILDB C,W2 CAIE C,^J SETOM LPHONY CAIN C,^M MOVNS LPHONY ;LEAVE 1 IN LPHONY IF LINE ENDS IN JUST CR. MOVE W1,LNNEXT(W1) ;GO TRY THE NEXT LINE. JRST MOVEU2 ;SKIP UNLESS THE TWO CURRENT LINES ARE EQUAL. IGNORES CASE CHANGES AND ;SPACING CHANGES IF SPECIFIED, BUT NEVER IGNORES COMMENTS. ;MUSTN'T CLOBBER CS. COMPL: MOVE C,LNSIZE(F1) ;FIRST TEST FOR EXACT MATCH. CAME C,LNSIZE(F2) JRST COMPUL ;LINE LENGTHS DIFFER => NO EXACT MATCH, MOVEI W1,5(C) ;ELSE COMPARE THE LINES WORD-BY-WORD. IDIVI W1,5 MOVNS W1 ;-<# WDS OF DATA IN LINE> HRLZS W1 HRRI W1,LNDATA(F1) ;AOBJN POINTER TO DATAT IN FILE 1 LINE. MOVEI W2,LNDATA(F2) ;AND POINTER TO DATA OF FILE 2 LINE. SUB W2,W1 HRRM W2,COMPLX COMPL1: MOVE C,(W1) ;COMPARE WORD BY WORD, IGNORING LOW BITS. COMPLX: XOR C,(W1) ;ADDR FIELD MAKES E.A. POINT TO SECOND FILE'S LINE. TDNE C,[-2] JRST COMPUL ;JUMP IF NO EXACT MATCH. AOBJN W1,COMPL1 RET COMPUL: TLNN FR,FLCASE\FLSPAC ;NO EXACT MATCH. CAN WE TRY IGNORING STUFF? JRST POPJ1 ;NO, SO MUST RETURN "NO MATCH". ;IGNORING CASE OR SPACING => WE GET A SECOND CHANCE. MOVEI W1,LNDATA(F1) MOVEI W2,LNDATA(F2) HRLI W1,440700 HRLI W2,440700 COMPU1: ILDB T,W1 ;GET A CHARACTER FROM LINE FROM FIRST FILE ILDB TT,W2 ;AND ONE FROM SECOND FILE CAME T,TT ;THEY'RE EXACTLY EQUAL => KEEP LOOKING JRST COMPU2 JUMPN T,COMPU1 ;BUT DON'T LOOK PAST ENDS OF THE LINES. POPJ P, ;REACH ENDS OF LINES => LINES MATCH. COMPU2: TLNN FR,FLSPAC JRST COMPU4 CAIE T,40 ;IF SUPPOSED TO IGNORE CHANGES IN SPACING, DO SO CAIN T,^I ;BY SKIPPING ALL SPACES & TABS IN BOTH FILES. JRST [ILDB T,W1 JRST .-2] CAIE TT,40 CAIN TT,^I JRST [ILDB TT,W2 JRST .-2] COMPU4: TLNN FR,FLCASE JRST COMPU3 CAIL T,"A+40 ;IF SUPPOSED TO IGNORE CHANGES IN CASE, CONVERT TO U.C. CAILE T,"Z+40 CAIA SUBI T,40 CAIL TT,"A+40 CAILE TT,"Z+40 CAIA SUBI TT,40 COMPU3: CAMN T,TT ;DO THEY MATCH NOW? JRST COMPU1 JRST POPJ1 ;NO => LINES DON'T MATCH. ;SKIP UNLESS THE TWO CURRENT LINES ARE THE SAME WHEN APPROPRIATE ;STUFF IS IGNORED (SPACES AND COMMENTS, OR ALPHABETIC CASE, ; ACCORDING TO SWITCHES). COMPCS: MOVEI W1,LNDATA(F1) MOVEI W2,LNDATA(F2) HRLI W1,440700 HRLI W2,440700 COMPL3: ILDB T,W1 ;GET A CHARACTER FROM LINE FROM FIRST FILE COMPL6: ILDB TT,W2 ;AND ONE FROM SECOND FILE CAME TT,T ;THIS IS THE BIG TEST--ARE THEY EQUAL JRST COMPL4 ;NO COMPL7: CAIN T,"; ;YES, COMMENT? TLNN FR,FLCMNT ;YES, SUPPRESS COMMENTS? JUMPN T,COMPL3 ;NO,NO. TEST FOR END OF LINE RET ;LINES MATCH, RETURN COMPL4: TLNN FR,FLSPAC ;CHARS DIFFER: MAYBE TRY IGNORING SPACING JRST COMPL8 CAIE TT,40 ;SPACE IN FILE 2, OR TAB? CAIN TT,TAB JRST COMPL6 ;IF SO, SKIP IT. COMPL5: CAIE T,40 ;SPACE IN FILE 1? CAIN T,TAB ;OR TAB? JRST [ILDB T,W1 ;SKIP TO FIRST NON-SPACE NON-TAB. JRST COMPL5] CAMN T,TT ;ARE THE CHARACTERS NOW THE SAME? JRST COMPL7 ;YES, TEST FOR END OF LINES COMPL8: TLNN FR,FLCASE ;SPACES DIDN'T HELP - ARE WE IGNORING CASE? JRST COMPL2 CAIL T,"A+40 ;CHARS DON'T MATCH => WE STILL HAVE A CHANCE CAILE T,"Z+40 ;IF THEY'RE BOTH LETTERS; CONVERT BOTH TO UPPER CASE. CAIA SUBI T,40 CAIL TT,"A+40 CAILE TT,"Z+40 CAIA SUBI TT,40 CAMN T,TT ;IF THIS HELPED, KEEP GOING JRST COMPL3 ;NO USE CHECKING FOR EOL - THESE MUST BE BOTH LETTERS. ;LAST CHANCE - MAYBE ONE FILE HAS A COMMENT AND THE OTHER IS AT END OF LINE. COMPL2: CAIE T,"; ;COMMENT IN FILE 1? CAIN TT,"; ;OR IN FILE 2? TLNN FR,FLCMNT ;AND ARE COMMENTS BEING IGNORED? JRST POPJ1 ;NO, FILES DON'T MATCH, SKIP RETURN JUMPE T,CPOPJ ;YES, OTHER CHAR MUST BE NULL OR ELSE ONE JUMPE TT,CPOPJ ; LINE IS LONGER THAN OTHER AND FILES DIFFER POPJ1: AOS (P) APOPJ: CPOPJ: RET ;WHEN WE GET TO THIS POINT WE HAVE FOUND ;THE EXTENT OF THE DIFFERENCES AND WE ARE READY TO PRINT ;THESE DIFFERENCES OUT. F1 AND F2 POINT AT THE TWO MATCHING LINES ;THAT END THE RUN OF DIFFERENCES. PNTBTH: AOS ERRCNT ;INCREMENT # OF RUNS OF DIFFERENCES. TLNE FR,FLISWT+FLFLAG RET ;DON'T TYPE ON TTY IF /I OR /F. IFN ITS,.SUSET [.SWHO2,,[SIXBIT/PRINT/]] MOVEM P,FLUSHP ;SUPPLY P FOR --MORE--FLUSHED TO POPJ FROM. TRZ FR,-1 ;OUTPUT FILE 1 CALL PNTTXT ;PRINT FILE 1 DIFFERENCES HRRI FR,1 ;THEN PRINT FILE 2 DIFFERENCES CALL PNTTXT SETZM FLUSHP RET ;OUTPUT THE LINES OF FILE (FR) BEFORE F1(FR), WITH A HEADER LINE. ;IF FLENDL=1, ALSO PRINTS THE LINE F1(FR) POINTS AT, IF ANY. PNTTXT: CALL PNTHDL ;FIRST, THE HEADER LINE. SKIPN NLINES(FR) RET ;NO LINES => THAT'S ALL. MOVE W1,LBUFP(FR) SETZ W3, SKIPE CS,F1(FR) ;CS GETS LINE TO STOP AT. TLNN FR,FLENDL CAIA MOVE CS,LNNEXT(CS) PNTTX1: CAME W1,CS ;REACHED 1ST LINE NOT TO OUTPUT => DONE. CAML W3,LINMAX ;PRINTED MAX # OF LINES => STOP. RET TLNN FR,FLFNUM ;IF USER WANTS FILE # ON EVERY LINE, JRST PNTTX2 SAVE W1 MOVEI W1,FNUMBR(FR) ;PRINT IT FOR HIM. CALL PRINT REST W1 PNTTX2: MOVEI W2,LNDATA(W1) HRLI W2,440700 MOVE C,LNSIZE(W1) CAML C,COLMAX ;IN /M MODE, LIMIT CHARS PRINTED TO COLMAX. MOVE C,COLMAX TLNN FR,FLMERG MOVE C,LNSIZE(W1) CALL PNTCNT ;OUTPUT THE TEXT OF THE LINE. TLNN FR,FLALL ;IN /B MODE, THE CRLF IF ANY IS IN THE LINE. CALL PCRLF ;OTHERWISE, MUST SUPPLY IT. MOVE W1,LNNEXT(W1) ;MOVE TO NEXT LINE. AOJA W3,PNTTX1 ;COUNT # LINES OUTPUT SO FAR. FNUMBR: ASCIZ /1) / ;FILE NUMBER OF FILE, FOR PRINTING. ASCIZ /2) / IFN .-FNUMBR-2,.ERR STRING TOO LONG ;OUTPUT A CRLF TO THE DIFFERENCE FILE. PCRLF: MOVE W2,[440700,,[.BYTE 7 ? ^M ? ^J]] MOVEI C,2 PNTCNT: M.SOUT CHOUT,W2,C RET ;OUTPUT A HEADER LINE TO THE DIFFERENCE FILE, FOR INPUT FILE (FR). PNTHDL: MOVE W2,[440700,,[ASCIZ/**** FILE /]] MOVEI C,10. CALL PNTCNT MOVE W1,RCHSTP(FR) CALL PRINT ;PRINT THE ASCIZ STRING CONTAINING THE FILE'S NAMES. MOVE W2,[440700,,[ASCIZ /, /]] MOVEI C,2 CALL PNTCNT MOVE W1,LBUFP(FR) ;GET THE PAGE # OF THE FIRST LINE FROM THE FILE. SKIPN NLINES(FR) SKIPA T,PAGNUM(FR) ;OR THE .IOT'ING PAGE # IF THERE AR NONE. MOVE T,LNPGNM(W1) CALL PNTDEC MOUTI CHOUT,"- SKIPN NLINES(FR) ;THEN THE LINE NUMBER SKIPA T,LINNUM(FR) MOVE T,LNLNNM(W1) CALL PNTDEC MOVEI W1,[ASCIZ/ (/] ;AND, IN PARENS, THE CHARACTER NUMBER. CALL PRINT MOVE W1,LBUFP(FR) SKIPN NLINES(FR) SKIPA T,CHRNUM(FR) MOVE T,LNCHNM(W1) CALL PNTDEC MOUTI CHOUT,51 ; RIGHT PAREN (SCREWS MACRO) TLNN FR,FLLABL\FLXLBL JRST PCRLF MOVE W1,LBUFP(FR) ;IF THE LAST LABEL IS KNOWN, PRINT IT TOO. SKIPN NLINES(FR) JRST [ MOVEI T,(FR) IMULI T,LNLBLN ADDI T,LLABEL JRST PNTHD1] MOVEI T,LNLLBL(W1) PNTHD1: SKIPN (T) JRST PCRLF MOVEI W1,[ASCIZ / AFTER /] SAVE T CALL PRINT REST W1 TLNE FR,FLXLBL MOUTI CHOUT,"" SAVE LNLBLN(W1) SETZM LNLBLN(W1) ;SUPPLY A ZERO TO END THE ASCIZ. CALL PRINT REST LNLBLN(W1) TLNE FR,FLXLBL MOUTI CHOUT,"" JRST PCRLF ;PRINT NUMBER IN T IN DECIMAL TO DIFFERENCE FILE PNTDEC: MOVE W2,[440700,,PNTDBF] SETZ C, CALL PNTDE1 MOVE W2,[440700,,PNTDBF] JRST PNTCNT PNTDE1: IDIVI T,10. HRLM TT,(P) SKIPE T CALL PNTDE1 HLRZ TT,(P) ADDI TT,"0 IDPB TT,W2 AOJA C,CPOPJ ;RH(W1) IS ADDR OF ASCIZ STRING; PRINT IT ON DIFFERENCE FILE. PRINT: MOVEI W2,(W1) HRLI W2,440700 SETZ C, ;FIRST COUNT CHARS IN THE STRING, ILDB T,W2 SKIPE T AOJA C,.-2 MOVEI W2,(W1) ;THEN OUTPUT THE STRING. HRLI W2,440700 JRST PNTCNT ;ASSUMING THAT F1(FR) POINTS TO THE LAST LINE IN FILE (FR), ;READ ANOTHER LINE AND MAKE F1(FR) POINT AT IT. ;ALSO OK IS IF WE HAVE NO LINES FROM THAT FILE AND F1(FR) IS 0. ;SKIPS TWICE IF SUCCESSFUL. CAN FAIL AND NOT SKIP IF CAN'T GET A LINE ;BECAUSE OF EOF; WILL RETURN WITH F1(FR) UNCHANGED AND EOFFL1(FR) NONZERO. ;WE DON'T EXPLICITLY GET CORE - THE MPV INT HANDER DOES THAT. ;THE MPV INT HANDLER CHECKS THE PC - ANY INSN THAT CAN LEGITIMATELY GET AN MPV ;SHOULD HAVE A LABEL SUCH AS "MPVOK1" AND BE MADE KNOWN TO THE INT HANDLER. RDLIN: TDNE FR,EOFTBL(FR) ;GIVE UP IF AT EOF IN FILE. JRST [ SETOM EOFFL1(FR) RET] MOVE W1,LBUFP(FR) ;IF NO LINES IN CORE, NEXT LINE GOES AT START OF SEG. SKIPN NLINES(FR) JRST RDLIN0 SKIPN W1,F1(FR) ;ELSE, GET POINTER TO CURRENT LINE ERRHLT MOVE T,LNSIZE(W1) ;FIND WORD AFTER THE END OF IT ADDI T,5 IDIVI T,5 ADDI W1,LNDATA(T) ;THAT WILL BE THE ADDRESS OF THE NEW LINE. RDLIN0: SETZ W3, ;COUNT # OF CHARS WE SKIP IN T. MOVE CS,@GCHARP(FR) ;SWAP THE FILE B.P. INTO AN AC FOR SPEED. RDLIN1: ILDB C,CS CAIG C,^M XCT RDLT1(C) ;LOOP TILL 1ST CHAR OF NON-NULL LINE SEEN. RDLIN4: ADDB W3,CHRNUM(FR) ;INITIALIZE THE LINE'S DATA, MPVOK0: MOVEM W3,LNCHNM(W1) ;STORING THE LAST WORD FIRST TO MAKE SURE CORE EXISTS. IFN LNDATA-LNCHNM-1,.ERR TLNN FR,FLLABL\FLXLBL ;SAVE TIME IF LABEL FEATURE NOT IN USE. JRST RDLIN5 MOVEI W3,LNLLBL(W1) DPB FR,[240100,,W3] ;PUT 4*RH(FR) IN LH(W3) ADD W3,[LLABEL,,] .SEE LNLBLN ;4 WORDS OF LABEL STRING. BLT W3,LNLLB3(W1) RDLIN5: MOVE W2,PAGNUM(FR) MOVEM W2,LNPGNM(W1) MOVE W2,LINNUM(FR) MOVEM W2,LNLNNM(W1) SETZM LNNEXT(W1) MOVEI W2,LNDATA(W1) HRLI W2,440700 ;THEN MAKE W2 A B.P. TO IDPB THE DATA AREA, MOVE RDLIN7,[RDLIN6,,BP] BLT RDLIN7,RDLIN7 TDZ W3,W3 ;AND COUNT CHARS STORED IN LINE IN W3. JRST MPVOK1 RDLIN6: OFFSET BP-. RDLIN2:: ILDB C,CS MPVOK1:: XCT RDLT2(C) ;USUALLY IDPB C,W2, BUT MAY EXIT TO RDLIN3. RDLIN7:: AOJA W3,RDLIN2 OFFSET 0 RDLIN3: AOS NLINES(FR) ;WHEN WE GET HERE, THE LINE REALLY EXISTS, SKIPE F1(FR) ;SO PUT IT IN THE CHAIN MOVEM W1,@F1(FR) IFN LNNEXT,.ERR MOVEM W1,F1(FR) ;AND POINT AT IT. MOVEM W3,LNSIZE(W1) ;REMEMBER # CHARS IN THIS LINE. ADDM W3,CHRNUM(FR) ;UPDATE CHAR POSITION IN FILE MOVEM CS,@GCHARP(FR) ;STORE BACK THE FILE'S BUFFER B.P. SETZB T,TT MPVOK6: IDPB T,W2 ;STORE A TRAILING ZERO, THEN LDB T,[360600,,W2] ;ZERO OUT REST OF LAST WORD. DPB T,[301400,,W2] DPB TT,W2 TLNE FR,FLXLBL ;IF ANY UNINDENTED NON-COMMENT LINE IS A LABEL CALL LABEL ;GO SET UP LLABEL WITH THIS LINE'S LABEL IF IT HAS ONE. AOS (P) JRST POPJ1 ;DISPATCH TABLE FOR FINDING A NON-NULL LINE. RDLT1: JFCL JFCL JFCL JRST RDLINC ;^C REPEAT 6,JFCL JRST RDLINJ ;^J JFCL JRST RDLINL ;^L JRST RDLINM ;^M IFN .-RDLT1-^M-1,.ERR WRONG LENGTH TABLE ;DISPATCH TABLE FOR ADDING MORE CHARS TO A LINE. RDLT2: REPEAT 200,IDPB C,W2 LOC RDLT2+^C ? JRST RDLILC LOC RDLT2+^J ? JRST RDLILJ LOC RDLT2+^L ? JRST RDLILL LOC RDLT2+^M ? JRST RDLILM LOC RDLT2+": ? JRST RDLCLN LOC RDLT2+200 ;^J, ^L OR ^M WHEN LOOKING FOR START OF LINE: ;UPDATE PAGE OR LINE NUMBER, AND IGNORE CHAR UNLESS /B. RDLINL: TLNE FR,FLALL JRST RDLIN4 SETZM LINNUM(FR) AOS PAGNUM(FR) AOS LINNUM(FR) IFN ITS,[ HRLZ T,PAGNUM+0 HRR T,PAGNUM+1 .SUSET [.SWHO3,,T] ] AOJA W3,RDLIN1 RDLINJ: TLNE FR,FLALL JRST RDLIN4 AOS LINNUM(FR) AOJA W3,RDLIN1 RDLINM: TLNN FR,FLALL AOJA W3,RDLIN1 ;NO /B; SKIP THE CHAR, BUT COUNT IT IN # THAT WERE SKIPPED. JRST RDLIN4 ;/B, ANY CHAR STARTS A LINE. ;^J, ^L OR ^M WHEN ADDING TO A NON-NULL LINE: ;UPDATE PAGE OR LINE NUM, AND END THE LINE, STORING CHAR IFF /B. RDLILL: SETZM LINNUM(FR) AOS PAGNUM(FR) IFN ITS,[ HRLZ T,PAGNUM+0 HRR T,PAGNUM+1 .SUSET [.SWHO3,,T] ] RDLILJ: AOS LINNUM(FR) TLNN FR,FLALL JRST RDLIL1 MPVOK2: IDPB C,W2 AOJA W3,RDLIN3 RDLIL1: AOS CHRNUM(FR) ;NOT /B: MUST UPDATE # CHARS FROM FILE SINCE RDLIN3 WON'T. JRST RDLIN3 RDLILM: TLNN FR,FLALL ;^M INSIDE A LINE. JRST RDLIL1 MPVOK3: IDPB C,W2 ;IN /B MODE, STORE IT AND LOOK FOR FOLLOWING ^J. RDLIL2: ILDB C,CS CAIN C,^J AOJA W3,RDLILJ ;FOUND => STORE IT TOO. CAMN CS,GCHARE(FR) ;DON'T LOSE BECAUSE OF WRAPAROUND IN BUFFER. JRST [ CALL RELOAD JRST RDLIL2] AOJ W3, DBP7J CS,RDLIN3 ;HANDLE COLON IN A LINE. IF /L, MAYBE SET THE FILE'S LLABEL VARIABLE. RDLCLN: TLNN FR,FLLABL JRST MPVOK4 ;COLON JUST GOES INTO LINE IF LABEL FEATURE OFF. JUMPE W3,MPVOK4 ;COLON AT BEGINNING OF LINE ISN'T A LABEL. MOVEI T,LNDATA(W1) ;MAKE SURE THERE ARE NO SPACES, TABS, COLONS OR SEMIS HRLI T,440700 ;BEFORE THIS COLON. RDLCL0: ILDB TT,T CAIG TT,40 JRST MPVOK4 CAIE TT,": CAIN TT,"; JRST MPVOK4 ;IT LOSES - IT'S JUST A NORMAL COLON. CAME T,W2 ;SKIP IF IT WINS. MAKE IT THIS FILE'S LAST LABEL. JRST RDLCL0 MPVOK5: MOVES LNDATA+1(W1) ;MAKE SURE AT LEAST 2 WORDS OF CORE EXIST MPVOK7: MOVES 1(T) ;MAKE SURE THERE'S SPACE FOR THE COLON AND TRAILING 0. MOVEI TT,": IDPB TT,T ;STORE THE COLON IN THE LINE. SETZ TT, ;STORE A ^@ AFTER THE COLON. IT WILL GET OVERWRITTEN IDPB TT,T ;BY LINE'S NEXT CHAR, BUT WILL LIVE ON IN LLABEL. HRRZ T,FR LSH T,2 ADDI T,LLABEL-1 ;T GETS LLABEL-1, PLUS 4 TIMES FILE NUMBER. PUSH T,LNDATA(W1) ;STORE 1ST 2 WORDS OF THIS LINE'S DATA THERE. PUSH T,LNDATA+1(W1) REPEAT LNLBLN-2,PUSH T,[0] ;2 WORDS ARE ENOUGH FOR A MIDAS LABEL, SO ZERO OUT THE REST. JRST MPVOK4 ;HERE IF /Y, AFTER READING IN THE LINE, TO SEE IF IT HAS A LABEL. ;A LINE HAS A LABEL IN /Y MODE IF IT STARTS WITH ANYTHING BUT A SPACE, TAB OR ;. ;W1 POINTS AT THE LINE. LABEL: SKIPN W3,LNSIZE(W1) RET ;IGNORE EMPTY LINES. LDB T,[350700,,LNDATA(W1)] ;GET THE LINE'S FIRST CHARACTER. CAILE T,40 JRST LABEL1 ;STARTS WITH NON-CONTROL NOT SPACE => PROBABLY A LABEL. CAIN T,40 RET CAIE T,^I CAIN T,^L ;BUT LINES STARTING WITH FORMATTERS AREN'T. RET CAIE T,^M ;IN /B MODE A LINE CAN BE JUST ONE OF THESE. THEY AREN'T. CAIN T,^J RET LABEL1: CAIN T,"; ;CHECK ; HERE - SAVES TIME FOR INDENTED LINES. RET HRRZ T,FR IMULI T,LNLBLN ADDI T,LLABEL-1 ;GET -1 + ADDR OF PLACE TO PUT LABEL. MOVE TT,T ;SAVE THIS FOR LABEL2 WHICH ALSO NEEDS IT. REPEAT LNLBLN,[ CAIL W3,.RPCNT*5+1 ;COPY START OF LINE INTO IT, BUT DON'T GO PAST END OF LINE PUSH T,.RPCNT+LNDATA(W1) ;IF IT IS A SHORT ONE. ] ;NO NEED TO ZERO OUT REST OF WORDS CAUSE IF LINE IS SHORT TLNN FR,FLALL ;THEN THE REAL DATA MUST HAVE A ^@ AFTER IT ANYWAY. RET MOVEI T,1(TT) ;IN /B MODE, THE LINE MAY HAVE A REAL ^M^J IN IT, HRLI T,440700 ;AND IF IT IS SHORT THEN THE ^M^J WAS COPIED INTO THE LABEL. MOVEI W3,5*LNLBLN ;SO REPLACE IT WITH A NULL, IN THE LABEL. LABEL2: ILDB TT,T JUMPE TT,CPOPJ ;LABEL ENDS WITH NULL AND HAS NO ^M OR ^J? CAIE TT,^M CAIN TT,^J CAIA SOJG W3,LABEL2 ;MAYBE WE EXHAUST THE WORDS OF LABEL AND THERE IS NONE. JUMPE W3,CPOPJ SETZ TT, ;IF THERE IS A ^M OR ^J, TRUNCATE LABEL AT THAT POINT. DPB TT,T RET ;HANDLE ^C WHEN LOOKING FOR START OF LINE. RDLINC: CAMN CS,GCHARE(FR) ;IS THIS THE ^C AFTER THE BUFFER? JRST [ CALL RELOAD ;YES, RELOAD THE BUFFER AND TRY AGAIN. JRST RDLIN1] CAME CS,@GCHARZ(FR) ;IS THIS EOF, OR A ^C IN THE FILE? JRST RDLIN4 ;^C IN FILE STARTS A LINE. IOR FR,EOFTBL(FR) ;IT IS EOF. RDLIL5: SETOM EOFFL1(FR) MOVEM CS,@GCHARP(FR) RET ;HANDLE ^C WHEN ADDING TO A LINE. RDLILC: CAMN CS,GCHARE(FR) JRST [ CALL RELOAD JRST RDLIN2] CAME CS,@GCHARZ(FR) ;^C IN FILE GOES IN THE LINE. JRST MPVOK4 IOR FR,EOFTBL(FR) ;EOF IN MIDDLE OF LINE: SAY EOF WAS REACHED. MOVEI T,LNDATA-1(W1) RDLIL4: CAIN T,(W2) ;FLUSH ALL ^C'S AND ^@'S OFF THE END OF THE LINE. JRST RDLIL5 ;LINE WAS NOTHING BUT ^C'S AND ^@'S? SAY THERE WAS NO LINE. LDB C,W2 CAIE C,^C JUMPN C,RDLIN3 ;LINE HAS SOMETHING ELSE, SO RETURN IT. SOJ W3, DBP7J W2,RDLIL4 MPVOK4: IDPB C,W2 ;COME HERE TO INSERT A ^C OR : IN A LINE, AOJA W3,RDLIN2 ;WITHOUT THE SPECIAL HANDLING THEY SOMETIMES GET. ;REFILL THE BUFFER OF THE FILE (FR). WORKS WHETHER READING IN CHAR ;OR WORD MODE, ON BOTH ITS AND TNX (WHICH UPDATE BP'S DIFFERENTLY). RELOAD: MOVE C,GCHARI(FR) ;YES, JUST REFILL THE BUFFER. GET BP MOVEI CS,FILBFL ;AND COUNT CALL @GCHARX(FR) ;INPUT THE STUFF TLZ C,7700 TLO C,0700 ;MAKE BP A CHAR B.P. (IF NOT ALREADY) MOVEI CS,^C IDPB CS,C ;PUT A ^C AFTER WHAT WE INPUT. MOVEM C,@GCHARZ(FR) ;AND SAVE BP TO EOF CHAR. MOVE CS,GCHARB(FR) ;RE-INIT THE B.P. RET GCHARP: FILPT1 ;ADDRESS OF BUFFER BP OF FILE. FILPT2 FILPT3 GCHARZ: FILEP1 ;ADDR OF B.P. TO THE ^C AFTER WHAT WAS READ IN. FILEP2 FILEP3 GCHARI: 444400,,FILBF1 ; BP TO IDPB 1ST WD OF BUFFER. 444400,,FILBF2 444400,,FILBF3 GCHARB: 440700,,FILBF1 ;B.P. TO ILDB 1ST CHAR OF BUFFER. 440700,,FILBF2 440700,,FILBF3 GCHARE: 350700,,FILBE1+1 ;B.P. TO ^C AFTER END OF BUFFER. 350700,,FILBE2+1 350700,,FILBE3+1 GCHARX: [M.SIN CHIN1,C,CS ;INSTRS TO INPUT ON CHIN1 RET] [M.SIN CHIN2,C,CS ;DITTO FOR CHIN2 RET] [M.SIN CHIN3,C,CS RET] EOFTBL: FLEOF1,, ;EOF FLAG FOR FILE 1 FLEOF2,, ;EOF FLAG FOR FILE 2 FLEOF3,, RCHSTP: 440700,,HBUF1 ;BYTE POINTERS TO HEADER TABLES 440700,,HBUF2 440700,,HBUF3 ; INT HANDLER, ITS ONLY - HANDLES MPV AND --MORE-- INTERRUPTS. ; TNX DOESN'T NEED MPV HANDLER (ALTHO IT MAKES ERRORS HARDER TO FIND) ; AND DOESN'T HAVE --MORE-- INTERRUPTS... IFN ITS,[ TSINT: LOC 42 ? JSR TSINT ? LOC TSINT ; ENSURE INT VECTOR SET UP 0 0 EXCH W1,TSINT JUMPL W1,MORINT CAIE W1,%PIMPV ERRHLT HRRZ W1,TSINT+1 ;MPV INTERRUPTS TO GET MORE CORE ARE LEGAL CAIE W1,MPVOK7 ;ONLY FROM CERTAIN SPOTS. CAIN W1,MPVOK6 JRST TSINT2 CAIE W1,MPVOK5 CAIN W1,MPVOK4 JRST TSINT2 CAIE W1,MPVOK3 CAIN W1,MPVOK2 JRST TSINT2 CAIE W1,MPVOK1 CAIN W1,MPVOK0 CAIA ERRHLT TSINT2: .SUSET [.RMPVA,,W1] LSH W1,-10. SYSCAL CORBLK,[MOVEI 400000 ? MOVEI -1 ? W1 ? MOVEI 400001] JRST [ CALL TYLERR ? JRST ERRFIN] MOVE W1,TSINT .DISMI TSINT+1 MORINT: MOVE W1,TSINT INSIRP PUSH P,C T MOVEI T,[ASCIZ /--MORE--/] CALL TYPMS0 SYSCAL IOT,[MOVEI CHTTI ? MOVE C ? 5000,,%TIPEK] .LOSE 1000 CAIN C,^C JRST MORKIL CAIE C,40 CAIN C,177 .IOT CHTTI,C ;SPACE OR RUBOUT IS GOBBLED. SKIPE FLUSHP CAIN C,40 ;IF IT ISN'T SPACE, AND WE CAN FLUSH, DO SO. JRST MORPRC MOVEI T,[ASCIZ /FLUSHED /] CALL TYPMS0 MOVE P,FLUSHP SETZM FLUSHP .DISMI [CPOPJ] MORKIL: .IOT CHTTI,C ;^C => GOBBLE IT AND KILL THE SRCCOM. .LOGOUT .BREAK 16,160000 MORPRC: MOVEI T,[ASCIZ / /] CALL TYPMS0 INSIRP POP P,T C .DISMI TSINT+1 ] ;IFN ITS ;OPEN INPUT FILE ON CHNL IN W1. INOPEN: MOVEI FP,INFB HRLI FP,(W1) ;MAKE ,, IFN ITS,[ MOVSI W2,(SIXBIT/>/) SKIPN $F6FN2(FP) ;DEFAULT THE FN2 TO ">". MOVEM W2,$F6FN2(FP) ] MOVEI W2,OPNRDA ;USE UNIT MODE FOR /X FILES, TLNN FR,FLXCTF MOVEI W2,OPNRDW ;USE BLOCK MODE FOR OTHER INPUT FILES. CALL (W2) CALL OPENL ; LOST?? REPORT ERROR. MOVE W2,INOPT3-CHIN1(W1) ;GET ADDR OF LAST WORD OF BUFFER. MOVEI W1,(W2) HRLI W1,10700 ;MAKE B.P. TO END OF BUFFER, MOVEM W1,FILPT1-FILBE1(W2) MOVE W1,[ASCIC//] MOVEM W1,1(W2) HRRI FR,0 ;PUT NUMBER OF FILE INTO FR. CAIE W2,FILBE1 HRRI FR,1 PJRST RCHST ;SET UP FILE'S HEADER. INOPT3: FILBE1 FILBE2 FILBE3 ;COME HERE WHEN /@ IS SPECIFIED FOR THE 1ST INPUT FILE. ;THAT MEANS TO TREAT THE SPECIFIED 1ST INPUT FILE AS A COMPARISON ;FILE, EXTRACT THE NAME OF THE SECOND FILE USED IN THAT COMPARISON, ;AND USE THAT FILE AS OUR 1ST INPUT FILE THIS TIME. ;JUMPS BACK TO THE COMMAND PROCESSING LEVEL TO OPEN THE REAL 1ST INPUT FILE. RFINDR: MOVE W1,GCHARI MOVEI W2,FILBFL M.SIN CHIN1,W1,W2 ;READ IN SOME OF THE FILE. ADDI W1,1 ANDI W1,-1 ;MAKE SURE IT LOOKS LIKE A COMPARISON FILE. CAIGE W1,FILBF1+10. JRST ERRIND MOVE W1,FILBF1 MOVE W2,FILBF1+1 CAMN W1,[ASCII / ;CO/] CAME W2,[ASCII /MPARI/] JRST ERRIND MOVE W1,FILBF1+2 CAME W1,[ASCII /SON O/] JRST ERRIND MOVE W1,[350700,,FILBF1+3] ;POINT AT THE SPACE AFTER THE "OF". MOVEI W2,4 RFIND2: ILDB C,W1 ;THEN SKIP PAST 3 SPACES, TO BE AFTER THE "AND". CAIE C,40 JRST RFIND2 SOJG W2,RFIND2 SAVE TTIPNT ;WHICH IS JUST AT THE SECOND COMPARED FILE'S NAME. SAVE TTICNT HRLZM P,TTICNT MOVEM W1,TTIPNT ;READ IN THAT FILE NAME CALL RFILE ;RFILE RETURNS AFTER THE FN2 SINCE FLINDR=1. ILDB C,TTIPNT CAIE C,^J JRST .-2 ;PASS THE LINEFEED OF THAT LINE MOVEI C,3 ADDM C,TTIPNT ;SKIP THE ";OPTIONS ARE " CALL RFILSW ;READ THE SWITCHES FROM THE COMPARISON FILE REST TTICNT REST TTIPNT TLZ FR,FLINDR JRST RFIND1 IFN ITS,[ ;PUT FILE DESCRIPTION IN ASCII INTO HBUF FOR THIS FILE RCHST: SYSCAL RFNAME,[ MOVEI CHIN1(FR) 2000,,RCHSTB 2000,,RCHSTB+1 2000,,RCHSTB+2 2000,,RCHSTB+3] .LOSE 1000 MOVE W2,RCHSTP(FR) ;NOW SET UP BYTE POINTER TO HEADER AREA TO READ INTO MOVE T,RCHSTB ;GET THE CHOSEN DEVICE NAME JSP W1,RCHST6 ;DEVICE NAME ": ;END WITH COLON MOVE T,RCHSTB+3 JSP W1,RCHST6 ;SYSTEM NAME "; ;TERMINATED BY SEMICOLON SKIPN T,RCHSTB+1 MOVE T,INFB+$FNAME ;IF REALLY NONE, USE SPEC'D. SKIPN LSTFB+$FNAME ;DEFAULT OUTPUT FN1 TO INPUT. MOVEM T,LSTFB+$FNAME JSP W1,RCHST6 ;FNAM1 40 ;TERMINATED (ITS CONVENTION) BY SPACE SKIPN T,RCHSTB+2 MOVE T,INFB+$FEXT JSP W1,RCHST6 ;FNAM2 0 ;DON'T PRINT TERMINATING CHAR MOVEI C,0 IDPB C,W2 ;MARK END OF STRING RET ;JSP W1,RCHST6 ;PRINT (IDPB ASCII VIA W2) SIXBIT WORD IN T ; " ;FOLLOW WITH TERMINATING CHAR UNLESS SIXBIT IS NULL ; ^ DOESN'T PRINT TRAILING SPACES RCHST6: JUMPE T,1(W1) ;RETURN ON NULL ARG RCHS6A: MOVEI C,0 ;CLEAR OUT C TO RECEIVE CHAR LSHC C,6 ;SHIFT IN NEXT CHAR ADDI C,40 ;CONVERT TO ASCII IDPB C,W2 ;DEPOSIT WHEREVER IT'S GOING JUMPN T,RCHS6A ;LOOP UNTIL WORD EMPTY SKIPE C,(W1) ;NOW GET TERMINATOR IDPB C,W2 ;NOT NULL, USE IT JRST 1(W1) ] ;IFN ITS ;READ IN A COMMAND, PROCESSING RUBOUTS, PROMPTING WITH "#". CMDLIN: SKIPE CMDFIL JRST TTIFIL ;IF IN COMMAND FILE, READ FROM IT INSTEAD OF TTY. TTILIN: HRROS (P) ;PROMPT WITH "#". CAIA TTILNA: HRRZS (P) ;FOR /M INPUT, PROMPT WITH "*" JRST TTILI1 ;READ A CHAR OF TTY INPUT (OR ^M IF NONE LEFT). TTICHR: SOSGE TTICNT ;IF NO CHARS LEFT, SKIPA C,[^M] ;SAY EOL. ILDB C,TTIPNT ;ELSE GET NEXT CHAR FROM BUFFER. RET ;READ AND UPCASE A CHAR OF INPUT. TTICHU: CALL TTICHR ;GET CHAR CAIL C,"A+40 ;SKIP IF LESS THAN LOWER CASE A CAILE C,"Z+40 ;SKIP IF IN RANGE A-Z CAIA ;SKIP IF NOT A-Z (LC) SUBI C,40 ;LOWER CASE TO UPPER CASE RET IFN ITS,[ RUBOUT"A=1 RUBOUT"B=2 RUBOUT"C=3 RUBOUT"D=4 RUBOUT"$$PROMPT==1 .INSRT SYSENG;RUBOUT RUBOUT"INCHR: .IOT CHTTI,RUBOUT"A RET RUBOUT"OUTCHR: SYSCAL IOT,[%CLIMM,,CHTTO ? RUBOUT"A ? %CLBIT,,%TJMOR] .LOSE %LSFIL RET RUBOUT"DISPLAY: SYSCAL IOT,[%CLIMM,,CHTTO ? RUBOUT"A ? %CLBIT,,%TJMOR+%TJDIS] .LOSE %LSFIL RET RUBOUT"PROMPT: MOVEI RUBOUT"A,"# SKIPL PRMNUM MOVEI RUBOUT"A,"* JRST RUBOUT"OUTCHR RUBOUT"DISPATCH: CAIN RUBOUT"A,%TXCTL+"Q ;MAKE ^Q NOT SPECIAL FOR RUBOUT PROCESSING. JRST RUBOUT"INSECH ;THAT IS, IT WON'T QUOTE A RUBOUT. CAIN RUBOUT"A,%TXCTL+"M ;^M SHOULD JUST INSERT A ^M, NOT ^M^J JRST RUBOUT"BRKINS JRST RUBOUT"RB$DSP .SCALAR PRMNUM ;NEGATIVE => PROMPT WITH #. POS OR ZERO => PROMPT WITH *. .VECTOR RBBLK(RUBOUT"RB.LEN) ;RUBOUT PROCESSOR ARGUMENT BLOCK. ;READ A LINE BY CALLING THE RUBOUT PACKAGE. ASSUMES LH OF (P) NEGATIVE => PROMPT WITH #. TTILI1: CALL CRLF MOVE W1,(P) MOVEM W1,PRMNUM TTILI9: CALL RUBOUT"PROMPT MOVE W1,[010700,,TTIBUF-1] MOVEM W1,TTIPNT ;SET UP FOR FETCHING CHARS LATER. MOVEM W1,RBBLK+RUBOUT"RB.BEG ADDI W1,TTIBFL MOVEM W1,RBBLK+RUBOUT"RB.END MOVEI RUBOUT"A,CHTTO MOVEI RUBOUT"B,RBBLK CALL RUBOUT"INIT TTILI8: CALL RUBOUT"READ ;READ CHARACTERS UP TO BREAK CHAR. CAMN RUBOUT"A,[-1] JRST [ .IOT CHTTO,[^G] ;BUFFER FULL: DING, AND LET USER RUB OUT SOME. JRST TTILI8] JUMPL RUBOUT"A,TTILI1 ;OVER-RUBOUT => CRLF AND TRY AGAIN. MOVEI W2,0 DPB W2,RBBLK+RUBOUT"RB.PTR ;REPLACE BREAK CHAR WITH 0. CAIN RUBOUT"A,%TXCTL+"M JRST TTILI4 CALL CRLF ;IF BREAK WASN'T A CR, TYPE A CR, TLNN FR,FLMERG ;AND IF READING A COMMAND, REMEMBER TO RETURN TO DDT SETOM CTLCF ;AFTER EXECUTING IT. TTILI4: MOVE W1,TTIPNT ;COUNT THE CHARACTERS WE GOT. SET UP TTICNT. SETZM TTICNT TTILI2: CAMN W1,RBBLK+RUBOUT"RB.PTR JRST TTILI3 IBP W1 AOS TTICNT JRST TTILI2 TTILI3: SOSE TTICNT ;DON'T COUNT THE TERMINAL 0 IN TTICNT. RET ;RETURN IF LINE IS NON NULL. SKIPL (P) ;IF IT ISN'T A COMMAND, RETURN IT EVEN THOUGH NULL. RET SKIPGE CTLCF ;NULL COMMAND LINE ENDED BY ^C MEANS EXIT. JRST QUIT JRST TTILI9 ;OTHERWISE READ ANOTHER COMMAND LINE. ] IFN TNX,[ TTILI1: CALL CRLF SKIPE FLG20X ;ON A 20? JRST TTIL20 ;YES ;COME HERE AFTER NULL LINE. TTILI2: SETZM TTICNT ;NO CHARS READ YET. SKIPGE (P) MOUTI CHTTO,"# SKIPL (P) MOUTI CHTTO,"* MOVE C,[440700,,TTIBUF] MOVEM C,TTIPNT TTILUP: CALL TYI ;READ A CHAR FROM TTY. CAIN C,^M JRST TTICR ;^M MEANS ALL READ. CAIE C,^D CAIN C,^U JRST TTILI1 ;^U CANCELS CMD. CAIN C,177 JRST TTIRUB CAIN C,^L ;IF USER TYPES ^L, RETYPE THE BUFFERED INPUT. JRST TTICTL CAIN C,^Z MOVEI C,^C CAIN C,^C JRST TTICTC ;^C MEANS DO CMD, THEN VALRET :KILL. IDPB C,TTIPNT ;NORMAL CHAR. AOS TTICNT JRST TTILUP TTICTC: CALL CRLF ;INDICATE COMMAND HAS BEEN TERMINATED. TLNN FR,FLMERG ;^C DOES NOTHING IF INPUT TO MERGE. SETOM CTLCF ;REMEMBER TO VALRET WHEN CMD DONE. TTICR: SKIPL (P) JRST TTICR1 SKIPN TTICNT ;IF NULL COMMAND LINE, RETRY. JRST TTILI3 TTICR1: SETZ C, IDPB C,TTIPNT ; TERMINATE WITH ASCIZ MOVE C,[440700,,TTIBUF] MOVEM C,TTIPNT ;SET UP FOR REMOVAL OF CHARS. RET TTILI3: SKIPE CTLCF ;NULL LINE: JRST QUIT ;...IF ^C ENDED LINE. JRST TTILI2 TTICTL: MOVEI T,[ASCIZ /#/] ;COME HERE FOR ^L. SCREEN ALREADY CLEARED ON DISPLAY. SKIPL (P) MOVEI T,[ASCIZ /*/] CALL TYPMSG ;PRINT CRLF AND ASTERISK. MOVE TT,[440700,,TTIBUF] MOVE C,TTICNT ;THEN RETYPE THE BUFFERED INPUT. M.SOUT CHTTO,TT,C JRST TTILUP TTIRUB: SOSGE TTICNT ;IF NO CHAR TO RUB, RETRY. JRST TTILI1 LDB C,TTIPNT MOUTC CHTTO,C ;PRINT RUBBED CHAR. MOVSI C,070000 ADD C,TTIPNT JUMPGE C,TTIRU1 ;IF STILL IN SAME WD. MOVEI C,-1(C ) ;ELSE, MOVE TO END OF PREV. WD. HRLI C,010700 TTIRU1: MOVEM C,TTIPNT JRST TTILUP ;USE SYSTEM ROUTINES ON A 20 TTIL20: HRROI R3,[ASCIZ /#/] ;PROMPTING TEXT SKIPL (P) HRROI R3,[ASCIZ /*/] MOVE R1,R3 ;HAVE TO OUTPUT PROMPT BY HAND, SIGH PSOUT HRROI R1,TTIBUF MOVE R2,[RD%TOP+5*TTIBFL] RDTTY JRST RESTRT TLZ R2,-1 ;FIGURE COUNT SUBI R2,5*TTIBFL JUMPE R2,TTIL20 ;TRY AGAIN ON NULL LINE MOVNM R2,TTICNT SETO R2, ADJBP R2,R1 SETZ R1, DPB R1,R2 MOVE A,[440700,,TTIBUF] ;SET UP POINTER MOVEM A,TTIPNT ] ;IFN TNX ;COME HERE TO SEE IF THE COMMAND STRING IS JUST "?" OR "HELP". ;IF NOT, RETURNS. IF SO, PRINTS HELP (FROM INFO;SRCCOM >) ;AND RETURNS TO RELDEV. TRYHLP: SAVE TTIPNT SAVE TTICNT CALL TTINSP ;GO PAST INITIAL SPACES. CAIN C,"? JRST TRYHL1 ;"?" MIGHT BE START OF GOOD STUFF CAIE C,"H ;SO MIGHT "H". JRST TRYHLL ;ANYTHING ELSE => USER ISN'T ASKING FOR HELP. CALL TTICHU CAIE C,"E JRST TRYHLL CALL TTICHU CAIE C,"L JRST TRYHLL CALL TTICHU CAIE C,"P JRST TRYHLL TRYHL1: CALL TTINSP CAIE C,^M CAIN C,^C CAIA JRST TRYHLL ;USER WANTS HELP - GIVE IT TO HIM. CALL OPNHLP JRST ERRHLP TRYHL3: M.BIN CHIN1,C CAIN C,^L JRST RELDEV JUMPL C,RELDEV MOUTC CHTTO,C JRST TRYHL3 TRYHLL: REST TTICNT REST TTIPNT RET ;READ 1 CHAR FROM THE COMMAND STRING, THEN KEEP READING TILL READ A NON-SPACE. ;CONVERTS TO UPPER CASE. TTINSP: CALL TTICHU CAIN C,40 JRST TTINSP RET ;COME HERE TO HANDLE A COMMAND WITH /X IN IT. CMDXCT: SKIPE CMDFIL JRST ERRXCT ;/X INSIDE AN EXECUTE FILE?? SKIPLE TTICNT ;ANY EXTRA FILES SPECIFIED? JRST ERRXTRA M.MVCH CHIN1,CHCMD ;MAKE THE ALREADY OPEN 1ST INPUT FILE BE OUR COMMAND FILE. MOVE W1,INFB+$FDIR MOVEM W1,CMDIS ;MAKE INPUT DEV AND SNAME THE INPUT DEFAULTS MOVE W1,INFB+$FDEV MOVEM W1,CMDID MOVE W1,LSTFB+$FDIR MOVEM W1,CMDOS ;AND OUR OUTPUT DEV AND SNAME THE OUTPUT DEFAULTS MOVE W1,LSTFB+$FDEV CAMN W1,FSTTY MOVE W1,FSDSK MOVEM W1,CMDOD SETOM CMDFIL ;SAY WE ARE NOW EXECUTING A COMMAND FILE. JRST RELDEV ;GO READ THE NEXT COMMAND. ;COME HERE TO READ A COMMAND LINE FROM A COMMAND FILE. TTIFIL: SETZM TTICNT ;INITIALIZE THE COMMAND BUFFER EMPTY. MOVE BP,[440700,,TTIBUF] MOVEM BP,TTIPNT ;NOW SEE IF THERE ARE ANY MORE COMMANDS IN THE FILE. TTIFI0: M.BIN CHCMD,C TTIFI1: ANDI C,-1 CAIE C,^C ;EOF OR END OF 1ST PAGE => COMMAND FILE IS OVER. CAIN C,^L JRST TTIEOF CAIE C,"; ;ELSE, A COMAND LINE IS IDENTIFIED BY JRST TTIFI0 ;STARTING WITH ";;SRCCOM COMMAND ;;" IRPC X,,[;SRCCOM COMMAND ;;] M.BIN CHCMD,C CAIE C,"X JRST TTIFI1 TERMIN ;WE FOUND ANOTHER COMMAND LINE'S BEGINNING. ;NOW, EVERYTHING UP TO NEXT ^C, ^L, ^M OR ";;" IS PART OF THE COMMAND. TDZA W1,W1 TTIFI2: MOVE W1,C ;REMEMBER THE PREVIOUS CHAR FOR FINDING ";;". M.BIN CHCMD,C ANDI C,-1 CAIE C,^C CAIN C,^M JRST TTIFI3 CAIN C,^L ;STOP BEFORE A ^C, ^L OR ^M. JRST TTIFI3 CAIN C,"; ;BEFORE THE SECOND ";" OF A ";;", CAIE W1,"; AOSA TTICNT JRST TTIFI4 ;MUST STOP, AND FLUSH THE PREVIOUS ";". IDPB C,BP ;ELSE STORE THE CHAR AND COUNT IT. JRST TTIFI2 TTIFI4: SOS TTICNT DBP7J BP, TTIFI3: SETZ C, ;NOW WE HAVE READ IN A WHOLE LINE. IDPB C,BP ;SO MAKE IT ASCIZ MOVEI T,TTIBUF ;AND TYPE IT ON THE TTY SO USER CAN MONITOR PROGRESS. CALL TYPMS0 JRST CRLF TTIEOF: M.CLS CHCMD ;HERE AT END OF COMMAND FILE. SETZM CMDFIL ;STOP TRYING TO USE IT, AND COMMIT SUICIDE IF A ^C SKIPE CTLCF ;IS STILL LEFT FROM WHEN IT WAS SPECIFIED. JRST QUIT JRST TTILIN ;ELSE, READ FROM TTY. SUBTTL ITS - FILESPEC READER ;READ FILE SPEC. IFN ITS,[ RFILE: SETZM $F6FN2(FP) ;DEFAULT FN2 UP TO CALLER. RFILSW: SETZ CS, RFNAME: MOVE BP,[440600,,0] MOVEI 0,6 ;SET UP TO READ IN A FILENAME. MOVEM 0,RFILC SETZ 0, RFLOOP: CALL TTICHU ;READ A CHAR. UPPER CASE CAIN C,^Q JRST RFCTQ ;^Q QUOTES NEXT CHAR. CAIN C,", JRST RFSPAC ;COMMAS TERMINATE SPEC. CAIE C,"_ CAIG C," JRST RFSPAC ;THESE ALSO. CAIN C,": JRST RFCOL ;COLON SETS DEV. CAIN C,"; JRST RFSEM ;SEMI SETS SNAME. CAIN C,"/ JRST RFSPAC ;SLASH ENDS NAME. JRST RFNORM ;ALL OTHER CHARS. RFCTQ: CALL TTICHU ;READ UPPER CASE CHAR CAIGE C,40 JRST RFSPAC ;DON'T TRY TO QUOTE A CONTROL CHARACTER. RFNORM: MOVEI C,-40(C) ;CONV. TO SIXBIT. SOSL RFILC ;PUT IN NAME IF ROOM LEFT. IDPB C,BP JRST RFLOOP RFXCTB: MOVEM 0,$F6FN1(FP) MOVEM 0,$F6FN2(FP) MOVEM 0,$F6DEV(FP) MOVEM 0,$F6DIR(FP) SKIPA RFCOL: SKIPE 0 MOVEM 0,$F6DEV(FP) ;SET DEVICE FIELD. JRST RFNAME RFSEM: SKIPE 0 MOVEM 0,$F6DIR(FP) JRST RFNAME RFSPAC: JUMPE 0,RFSPA0 ;IF NAME WAS READ, XCT RFXCTB(CS) ;STORE IT, AOJ CS, ;INCR. STORING POS. TLNN FR,FLINDR JRST RFSPA0 CAIN CS,2 RET RFSPA0: CAIN C,^X ;AS 1ST NAME AVOIDS SETTING IT, ALLOWS FN2 TO BE SET. JRST [ JUMPN CS,RFNAME AOJA CS,RFNAME] CAIN C,40 JRST RFNAME ;SPACE -- GET ANOTHER NAME. CAIN C,^C MOVEI C,^M CAIE C,"/ RET ;NOT SLASH, RETURN. CALL RDSW ; AHA, READ SWITCH. JRST RFNAME ; THEN RETURN TO LOOP. ] ;IFN ITS SUBTTL TNX - FILESPEC READER IFN TNX,[ RFILE: SETZM $FVERS(FP) ; DEFAULT VERSION UP TO CALLER RFILSW: SETZM RDFLG ; SAY HAVEN'T READ FILESPEC YET. RFILE2: CALL TTICHR ; READ CHAR FROM LINE CAIN C,^M ; EOL? JRST RFILE8 ; YES, EXIT CAIN C,", ; COMMA? JRST RFILE8 ; ALSO EXIT CAIE C,"= ; EITHER OF THESE ARE VALID OUTPUT FILSPEC INDICATORS. CAIN C,"_ JRST RFILE8 CAIN C,"/ ; START OF SWITCH? JRST [ CALL RDSW ; YES, READ IT & CONTINUE. JRST RFILE2] CAIE C,^I CAIN C,40 JRST RFILE2 ; FLUSH WHITESPACE ; HERE HAVE FIRST CHAR OF FILENAME... MOVE W2,TTIPNT DBP7J W2, ; SKIP BACK ONE SKIPE RDFLG ; ALREADY READ A FILESPEC? JRST [ AOS TTICNT ; YES, DON'T READ THIS SPEC YET... JRST RFILE8] SYSCAL GTJFN,[[GJ%OFG+GJ%SHT] ? W2][$FJFN(FP) ? W2] JRST RFILE2 ; IF FAIL, IGNORE THAT CHAR. DBP7J W2, ; WON, BACK PAST TERMINATING CHAR MOVEM W2,TTIPNT ; AND STORE BACK UPDATED PTR ; REALLY SHOULD UPDATE TTICNT TOO... CALL JFNSTB ; STORE FILENAME SPEC IN FB SYSCAL RLJFN,[$FJFN(FP)] JFCL SETZM $FJFN(FP) ; FILESPEC READ... SETOM RDFLG ; SAY SO, SO IF SEE ANOTHER WILL STOP SETZM TTICNT SKIPA W2,TTIPNT ; GET BP IN ORDER TO RESET CNT PROPERLY RFILE6: AOS TTICNT ILDB C,W2 CAIE C,^C CAIN C,^M CAIA JUMPN C,RFILE6 JRST RFILE2 RFILE8: RET ; RETURN .SCALAR RDFLG ; -1 WHEN FILESPEC READ ] ;IFN TNX SUBTTL SWITCH PROCESSING ;FOR SWITCH "A, SET OR CLEAR BIT D ACCORDING TO B. DEFINE SWITCH A,B,D CAIN C,"A HRR!B!I BP,D TERMIN RDSW: CALL TTICHU ; READ A SWITCH (SHOULD BE NEXT CHAR). SETZ BP, SWITCH !,O,FLOVRD ;/! - FORCE COMPARISON BETWEEN A FILE AND ITSELF SWITCH @,O,FLINDR ;/@ - GO INDIRECT THROUGH A COMPARISON FILE ;TO FIND THE FILE NAMES TO USE. SWITCH A,O,FLARCH ;/A - APPEND OUTPUT TO FRONT OF EXISTING FILE. SWITCH B,O,FLALL ;/B - DON'T IGNORE BLANK LINES. SWITCH C,O,FLCMNT ;/C - IGNORE COMMENTS. CAIN C,"D PJRST SWDISN ;/D - DISOWN SELF. SWITCH E,O,FLENDL ;/E - PRINT THE MATCHING LINES THAT END THE ;RUN OF DIFFERENCES. SWITCH F,O,FLFLAG+FLALL+FLMERG ;/F - GEN COPY OF FILE 2 WITH CHANGED LINES ;FLAGGED WITH VERTICAL BARS. SWITCH I,O,FLMERG+FLISWT+FLALL ;/I - /M, BUT ANSWER ALL QUESTIONS WITH "I". SWITCH K,O,FLCASE ;/K - IGNORE ALPHABETIC CASE DIFFERENCES SWITCH L,O,FLLABL ;/L - EACH HEADER LINE MENTIONS PREVIOUS LABEL. SWITCH M,O,FLALL+FLMERG ;/M - MERGE FILES. SWITCH S,O,FLSPAC ;/S - IGNORE SPACES. SWITCH W,O,FLFNUM ;/W - PRINT FILE # ON EACH LINE. SWITCH X,O,FLXCTF ;/X - EXECUTE COMMANDS FROM FILE SWITCH Y,O,FLXLBL ;/Y - ANY UNINDENTED TEXT IS A LABEL. CAIL C,"1 ;DIGIT - SET NUMLIN. CAILE C,"9 CAIA JRST [MOVEI C,-"1(C) ;SET NUM. EXTRA LINES TO MATCH MOVEM C,NUMLIN ;TO THE DIGIT, -1. RET] JUMPE BP,ERRSW ;ERROR UNLESS ONE OF ABOVE SWITCHES. TLO FR,(BP) ;SET THE FLG. RET ;SWITCH DONE, RETURN. SUBTTL ERROR MESSAGES/HANDLING ;COME HERE AFTER FAILING INPUT OR OUTPUT OPEN. OPENL: IFN ITS,.LOGOUT CALL LSTFIL ;PRINT NAME OF LOSING FILE (WHAT FP POINTS TO). MOUTI CHTTO,^I CALL TYLERR ;TYPE LAST ERROR JRST ERRFIN ERRXTR: JSP T,ERRMSG ASCIZ "Extra input files specified" ERRHLP: MOVEI T,[ASCIZ "Can't find help file!"] CALL TYPMSG ; JRST OPENL JRST ERRFIN ERRIND: JSP T,ERRMSG ASCIZ "Bad format /@ indirect file" ERRIN2: JSP T,ERRMSG ASCIZ "Can't use /@ or /X with second input file" ERRIN3: JSP T,ERRMSG ASCIZ "Can't use /@ or /X with third input file" ERR3NM: JSP T,ERRMSG ASCIZ "Three input files but /M not specified" ERRXCT: JSP T,ERRMSG ASCIZ "Recursive /X attempted" ERRARC: JSP T,ERRMSG ASCIZ "Can't archive and merge at once" ERRSW: JSP T,ERRMSG ASCIZ "Illegal switch" ERRMSG: CALL TYPMSG ;FOR SIMPLE ERROR MESSAGES; TYPE & DROP THRU ;ALL ERROR MESSAGES COME THROUGH HERE. ERRFIN: IFN ITS,.RESET CHTTI, ; FLUSH TTY INPUT BUFFER IFN TNX,CFIBF SETZM CMDFIL ;STOP READING COMMAND FILE. M.CLS CHCMD SETZM CTLCF ;DON'T KILL SELF; READ ANOTHER CMD STRING INSTEAD. ;COMMAND TERMINATION, SUCCESSFUL OR NOT, ALWAYS COMES THROUGH HERE. RELDEV: M.CLS CHIN1 M.CLS CHIN2 M.CLS CHMRG IFN ITS,[ MOVE W1,TTYSTS TLNE W1,%TSMOR SYSCAL TTYSET,[MOVEI CHOUT ? TTYST1 ? TTYST2 ? W1] JFCL ] M.CLS CHOUT SKIPE CMDFIL ;EXECUTING A FILE => READ MORE FROM IT. JRST RELDE1 IFN ITS,.LOGOUT ;CAN'T GET ANOTHER CMD IF DISOWNED. SKIPE CTLCF ;EXIT IF USER GAVE ^C. JRST QUITX RELDE1: CALL CRLF JRST RESTRT ;ELSE, GET NEW CMD. ;ROUTINES FOR OUTPUTING ERROR MESSAGES TYPMSG: IFN ITS,.LOGOUT ;CAN'T PRINT MSG WITHOUT TTY. CALL CRLF ;OUTPUT A CARRIAGE RETURN TYPMS0: HRLI T,440700 ;THIS IS POINTER FOR ERROR MESSAGE TYPMS1: ILDB C,T JUMPE C,CPOPJ CALL TYO JRST TYPMS1 ; TYPM - FOR USE WITH "TYPE" MACRO. STACK HAS ADDR OF ASCIZ STR. TYPM: PUSH P,C PUSH P,T MOVE T,-2(P) ; GET ADDR OF ASCIZ CALL TYPMSG ; OUTPUT POP P,T POP P,C SUB P,[1,,1] ; FLUSH ARG RET ;OUTPUT 6BIT WD IN 0 TO TTY. TTOSIX: MOVE BP,0 TTOSI0: SETZ TT, ROTC TT,6 ;GET NEXT CHAR. MOVEI TT," (TT) ;CONV. 6BIT TO ASCII. MOUTC CHTTO,TT JUMPN BP,TTOSI0 RET ; OUTPUT DECIMAL # IN 0 TO TTY. TTODEC: IDIVI 0,10. HRLM W1,(P) SKIPE 0 CALL TTODEC HLRZ W1,(P) ADDI W1,"0 MOUTC CHTTO,W1 RET TYO: MOUTC CHTTO,C RET CRLF: MOUTI CHTTO,^M MOUTI CHTTO,^J RET SUBTTL Auxiliary ITS Routines IFN ITS,[ ; GETJCL - Get JCL input ; W1/ <.OPTION var> GETJCL: SETZM TTIBUF TLNE W1,OPTCMD ; Don't do the .BREAK unless superior says so. .BREAK 12,[5,,TTIBUF] SKIPN TTIBUF RET MOVE W1,[440700,,TTIBUF] ; If have command string from superior, MOVEM W1,TTIPNT ; set up to read from it. SETZ CS, GTJCL2: ILDB C,W1 ; Count chars. in it. CAIE C,^M CAIN C,0 CAIA AOJA CS,GTJCL2 MOVEM CS,TTICNT ; Save num. chars to read. AOS (P) ; Success return. RET ; TYLERR - Type last error TYLERR: .SUSET [.RBCHN,,C] SYSCAL STATUS,[C ? MOVEM ERRFIL+2] ERRHLT .OPEN CHERR,ERRFIL ERRHLT TYLER2: M.BIN CHERR,C CAIN C,^M RET MOUTC CHTTO,C JRST TYLER2 ERRFIL: SIXBIT/ ERR/ 3 ? 0 ; LSTFIL - Print name of current file on LST ior TTY. LSTFIL: MOVE 0,$F6DEV(FP) CAMN 0,FSDSK JRST LSTFI1 CALL TTOSIX ; Print dev if not DSK. MOUTI CHTTO,": LSTFI1: MOVE 0,$F6DIR(FP) ; Print sname CAMN 0,DEFDIR ; If different from user's. JRST LSTFI2 CALL TTOSIX MOUTI CHTTO,73 ; "; LSTFI2: MOVE 0,$F6FN1(FP) CALL TTOSIX ; Print 1st name. MOUTI CHTTO,40 ; Space MOVE 0,$F6FN2(FP) JRST TTOSIX ; , 2nd name. SWDISN: .OPEN CHTTI,[SIXBIT/ NUL/] ERRHLT .OPEN CHTTO,[SIXBIT/ !NUL/] ERRHLT .VALUE [ASCIZ/:DISOWN :VK /] ; Give back tty. RET ; TYI - Read char from TTY, return in C TYI: .IOT CHTTI,C RET ; OPNRDW - Open filblk for reading, word mode ; OPNRDA - Open filblk for reading, ascii mode ; FP/ ,, ; Skip returns if opened. OPNRDW: SAVE W1 HRLZI W1,.UII JRST OPNRD2 OPNRDA: SAVE W1 HRLZI W1,.UAI ; Actually 0 OPNRD2: HLR W1,FP SYSCAL OPEN,[W1 ? $F6DEV(FP) ? $F6FN1(FP) ? $F6FN2(FP) ? $F6DIR(FP)] CAIA AOS -1(P) REST W1 RET ; RENMLO - Rename listing file ; W1/ RENMLO: SYSCAL RENMWO,[W1 ? LSTFB+$FNAME ? LSTFB+$FEXT] JFCL RET QUIT: .BREAK 16,140000 ; Die and echo ":KILL" QUITX: .BREAK 16,160000 ; Die, announce "Finished" if not current OPNHLP: SYSCAL OPEN,[MOVEI CHIN1 ? ['DSK,,] ['SRCCOM] ? [SIXBIT/>/] ? [SIXBIT/INFO/]] RET AOS (P) RET ] ;IFN ITS SUBTTL TNX - Auxiliary Routines IFN TNX,[ ; SEE20X - See if running under 20x or 10x .SCALAR FLG20X ; -1 if 20x, 0 if 10x. SEE20X: SETZM FLG20X SYSCAL SYSGT,[['LOADTB]][B ? B] SKIPN B ; If LOADTB is not defined SETOM FLG20X ; It must be a twenex RET QUIT: QUITX: HALTF JRST RESTRT ; OPNWR - Open filblk for writing, ascii mode ; FP/ ,, OPNWR: SAVE W1 SAVE W2 MOVE W2,[070000,,OF%WR] ; Mode for char write CALL GETJFO ; Get output jfn JRST OPNRD8 JRST OPNRD5 ; Rest is same as OPNRD. ; OPNRDW - Open filblk for reading, word mode ; OPNRDA - Open filblk for reading, ascii mode ; FP/ ,, ; Skip returns if opened. OPNRDW: SAVE W1 SAVE W2 MOVE W2,[440000,,OF%RD] ; Mode for full-wd JRST OPNRD2 OPNRDA: SAVE W1 SAVE W2 MOVE W2,[070000,,OF%RD] ; Mode for char OPNRD2: CALL GETJFI ; Get input jfn JRST OPNRD8 ; Failed OPNRD5: SYSCAL OPENF,[$FJFN(FP) ? W2] JRST [ SYSCAL CLOSF,[$FJFN(FP)] JFCL JRST OPNRD8] PUSH P,$FJFN(FP) HLRZ W1,FP POP P,JFNCHS(W1) CALL JFNSTB AOS -2(P) OPNRD8: REST W2 REST W1 RET OPNHLP: PUSH P,R1 PUSH P,R2 MOVSI R1,(GJ%OLD+GJ%SHT) HRROI R2,[HLPFIL] ; Filename defined as macro GTJFN JRST OPNHL7 ; Failed. HRRZS R1 PUSH P,R1 MOVE B,[070000,,OF%RD] OPENF JRST [ POP P,R1 CLOSF JFCL JRST OPNHL7] POP P,R1 MOVEM R1,JFNCHS+CHIN1 AOS -2(P) OPNHL7: POP P,R2 POP P,R1 POPJ P, ; RENMLO - Rename listing file ; For moment, we don't hack temp filename, so this is a no-op. RENMLO: RET TYI: SAVE R1 TYI2: PBIN IFN 10X,[ CAIN R1,37 MOVEI R1,^M ] CAIN R1,^J ; Actually for 20x only JRST TYI2 MOVE C,R1 REST R1 RET SWDISN: TYPE "Cannot disown on this losing system; continuing." RET LSTFIL: PJRST TYPFB ; TYLERR - Type last error TYLERR: SKIPA A,[-1] TERSTR: MOVE A,ERRCOD HRLI A,.FHSLF SYSCAL ERSTR,[[-1,,ERSTRB] ? A ? [-LERSTR,,]][A ? B ? B] JRST TERST7 ; undefined err #? HALT ; destination bad? SETZ B, IDPB B,A ; Ensure ASCIZ. MOVEI T,ERSTRB PJRST TYPMSG ; TYPR ERSTRB ; POPJ P, TERST7: TYPE "Unknown error" POPJ P, LERSTR==80. .VECTOR ERSTRB(/5) ; RCHST - Set up filename string of input file as part of header output. RCHST: MOVEI A,CHIN1(FR) ; What a crock. MOVE A,JFNCHS(A) ; Get jfn for file MOVE B,RCHSTP(FR) ; Get bp to dest buffer SYSCAL JFNS,[B ? A ? [111110,,1]][B] SETZ A, IDPB A,B ; Ensure asciz RET ] ;IFN TNX SUBTTL TNX JCL reading ; This routine is taken from MIDAS and so has some CCL hackery that ; currently is commented out, but at some future time might prove useful. IFN TNX,[ ; GETJCL - Read "JCL" - RSCAN buffer or nnnMID.TMP file (from CCL) GETJCL: SETZM TTIPNT IFN 0,[ SKIPE CCLFLG ; Started at CCL location? JRST JCLIN5 ; Yep, go snarf stuff specially. ] SKIPN FLG20X ; Is this Tenex? JRST [ MOVEI R1,.PRIIN ; Yes BKJFN ; see what previous character was RET ; *Gasp* PBIN CAIE R1,^_ ; Tenex newline? SETOM TTIPNT ; No, set flag saying "TTY but no prompt" RET] ; and skip the Twenex hackery below SETZ R1, ; If not, check RSCAN. RSCAN ; See if have anything in RSCAN buffer. RET ; Huh? Shouldn't happen, but ignore it. JUMPLE R1,APOPJ ; Also return if char cnt says nothing there. MOVNI R3,(R1) ; Aha, set up cnt for SIN HRROI R2,TTIBUF MOVEI R1,.PRIIN ; Now ready for business... SIN LDB R1,R2 ; Now examine wages thereof CAIE R1,^M ; Last char CR? JRST [ MOVEI R1,^M IDPB R1,R2 ; If not, make it so. JRST .+1] SETZ R1, IDPB R1,R2 ; Must also ensure ASCIZ. MOVE B,[440700,,TTIBUF] ; If the rescan line starts with "RUN ", skip that. IRPC X,,[RUN ] ILDB A,B CAIE A,"X JRST JCLIN4 TERMIN CAIA JCLIN4: MOVE B,[440700,,TTIBUF] ; Now flush the name of the file we were run from. ILDB A,B CAILE A,40 JRST .-2 ; Flush until random ctl seen (space, ^M) CAIE A,40 ; If it wasn't a space, RET ; then forget about the whole thing. JCLIN3: MOVE C,B ; Now flush spaces. Save last ptr for chars. ILDB A,B CAIN A,40 JRST JCLIN3 CAIN A,^M ; And is first non-space something besides CR? RET ; Bah, there wasn't anything in the JCL!! MOVEM C,TTIPNT ; Else save ptr to start of real goods. MOVE W1,C SETZ CS, GTJCL2: ILDB C,W1 ; Count chars. in it. CAIE C,^M CAIN C,0 CAIA AOJA CS,GTJCL2 MOVEM CS,TTICNT ; Save num. chars to read. AOS (P) ; Success return. RET IFN 0,[ ; TNX snarf of CCL file. No such thing as tmpcor, so just ; look for real file with appropriate name. JCLIN5: SETZM CCLFLG ; Want 0 in case abort out, will reset if win. GJINF ; Get job # in R3 HRROI R1,CMBUF ; Use CMBUF to form filename string. MOVEI R2,(R3) MOVE R3,[NO%LFL+NO%ZRO+<3_18.>+10.] NOUT ; ship out job num in 3 digits, radix 10. HALT HRROI R2,[ASCIZ /MID.TMP/] SETZ R3, SOUT ; Flesh out rest of filename string. SETZ R2, ; Make sure it's ASCIZ. BOUT MOVE R1,[GJ%OLD+GJ%SHT] ; Use short-form GTJFN HRROI R2,CMBUF ; and gobble name from CMBUF. GTJFN RET ; If failed, forget it. MOVE R2,[070000,,OF%RD] ; Read 7-bit bytes OPENF RET ; Bah HRROI R2,CMBUF ; Gobble stuff up. MOVEI R3,CMBFL*5 ; Read until buffer full, MOVEI R4,^J ; or LF seen. SIN JUMPLE R3,APOPJ ; Forget it if too big for buffer!! MOVE R2,[440700,,CMBUF] ; Aha, we've got something, so set MOVEM R2,CMPTR ; pointer to slurped stuff. SETOM CCLFLG HRROI R2,UTIBUF ; Slurp rest into larger buffer, MOVNI R3,UTIBFL*5 ; using count only. SIN JUMPGE R3,APOPJ ; Refuse to hack grossly large file. ADDI R3,UTIBFL*5 JUMPLE R3,APOPJ ; if nothing read, need write nothing out. HRLI R1,(CO%NRJ) ; Don't release JFN, CLOSF ; but stop reading from file. RET MOVE R2,[070000,,OF%WR] ; Now try to hack write access. OPENF RET MOVE R2,R1 ; Source becomes destination... HRROI R1,UTIBUF ; and UTIBUF becomes source, MOVNS R3 ; for just as many bytes as were read. SOUT MOVEI R1,(R2) ; done, now just close file. CLOSF ; (this time, release JFN). RET SETOM CCLMOR ; say that more CCL remains. RET ] ;IFN 0 FOR NOW ] ;IFN TNX SUBTTL TENEX misc. Filename Routines, FS string storage IFN TNX,[ .SEE FSDSK ; Part of this page is NOT conditionalized!! ; To handle filenames of ASCIZ strings instead of SIXBIT words, each ; word has instead a byte pointer to an ASCIZ string. For purposes of ; easy comparison, all of these bp's point into FNBUF, and a routine ; (FNCHK) is provided which checks a just-stored string and returns a bp ; to either this string, if unique, or to a previously stored string if ; it is the same as the one just stored (which is then flushed). Thus ; strings can be compared for equality simply by a comparison of their ; byte pointers. While not necessary, strings are stored beginning on ; word boundaries for easier hacking. ; <# files>**+<# wds for constants> IFNDEF MAXIND,MAXIND==10 ; # files LFNBUF==*5*3+20 ; Enough to hold strings for all output files, ; all translated files, and all .insrt files encountered. ; Later a GC'er can be hacked up so that of the latter only ; enough for the max .insrt level need be allocated. FNBUF: BLOCK LFNBUF ; Macro to easily define constant strings for comparison purposes DEFINE DEFSTR &STR& 440700,,%%FNLC %%LSAV==. LOC %%FNLC ASCIZ STR %%FNLC==. LOC %%LSAV TERMIN %%FNLC==FNBUF ] ; IFN TNX!!! ; If not assembling for TENEX, the following strings become ; simple SIXBIT values. This makes it possible to write simple ; code to work for both TENEX and non-TENEX without messy conditionals. IFE TNX,[EQUALS DEFSTR,SIXBIT] ; This stuff defines various BP's into FNBUF to ; use for comparison purposes later. FSDSK: DEFSTR /DSK/ FSTTY: DEFSTR /TTY/ FSNUL: DEFSTR /NUL/ FSCMP: DEFSTR /COMPAR/ FSCMPA: DEFSTR /CMPARC/ FSFLGD: DEFSTR /FLAGGD/ IFN ITS, FSDMF2:DEFSTR />/ ; default merge FN2 IFN TNX, FSDMF2:DEFSTR // IFN ITS, FVLOW: DEFSTR /-<010700,,>] ; bump BP to point canonically at next. MOVEM B,FNBWP FNCHK: HRRZ B,FNBWP ; See if write ptr CAML B,FNBEP ; has hit end of FNBUF, and ETF [ASCIZ /Filename buffer overflow/] ; barf horribly if so. MOVE A,FNBBP ; A - bp to start of existing string MOVE AA,FNBLWP ; AA - bp to start of new string to store FNCHK2: MOVEI T,(A) ; T - current addr being checked, existing str MOVEI TT,(AA) ; TT - current addr, new str CAIL T,(TT) ; If addrs are same, or overran somehow, JRST [ MOVE A,AA ; didn't find any match, accept new string. MOVE B,FNBWP MOVEM B,FNBLWP ; Set up new last-write-ptr POPJ P,] FNCHK3: MOVE B,(T) CAMN B,(TT) ; Compare strings, full word swoops. JRST [ TRNE B,377 ; equal, last char zero? AOJA T,[AOJA TT,FNCHK3] ; no, continue for whole string ; Found it! Flush just-stored string, don't want duplicate. MOVEM AA,FNBWP ; Clobber write ptr to previous value. POPJ P,] ; Not equal, move to next string to compare MOVEI B,377 ; Check for ASCIZ, TDNE B,(T) ; moving to end of current string AOJA T,.-1 HRRI A,1(T) ; and updating BP to point at new string. JRST FNCHK2 ; (T gets pointed there too at FNCHK2). ] ;IFN TNX IFN TNX,[ ; TYPFB - Type out FB pointed to by F TYPFB: SKIPE B,$FDEV(F) ; First, device name? JRST [ PUSHJ P,TYPZ MOVEI A,": PUSHJ P,TYOERR JRST .+1] SKIPE B,$FDIR(F) ; Directory? JRST [ MOVEI A,"< PUSHJ P,TYOERR PUSHJ P,TYPZ MOVEI A,"> PUSHJ P,TYOERR JRST .+1] SKIPE B,$FNAME(F) PUSHJ P,TYPZ MOVEI A,". PUSHJ P,TYOERR SKIPE B,$FEXT(F) PUSHJ P,TYPZ MOVEI A,". ; 20X uses "." to set off version, ; TLNN FF,FL20X ; but 10X uses ";". SKIPN FLG20X MOVEI A,"; PUSHJ P,TYOERR HRRE A,$FVERS(F) JUMPL A,[MOVM B,A ; Is possible to have -1, -2, etc. MOVEI A,"- PUSHJ P,TYOERR MOVE A,B JRST .+1] PUSHJ P,DPNT ; Version # output in decimal. SKIPE $FTEMP(F) TYPE ";T" ; May be temporary. SKIPE B,$FPROT(F) JRST [ TYPE ";P" PUSHJ P,TYPZ JRST .+1] SKIPE B,$FACCT(F) JRST [ TYPE ";A" PUSHJ P,TYPZ JRST .+1] POPJ P, ; Takes BP in B, outputs to TYOERR until zero byte seen. TYPZ: CAIA PUSHJ P,TYOERR ILDB A,B JUMPN A,TYPZ+1 POPJ P, DPNT: MOVE 0,A ; This entry pt for code borrowed from midas PJRST TTODEC TYOERR: MOVE C,A ; Ditto. PJRST TYO ] ; IFN TNX IFN TNX,[ ; JFNSTR - Get filename strings for active JFN. ; A/ active JFN ; F/ addr of filename block to clobber. ; JFNSTB - Same, but ignores A and assumes JFN is already stored in block. ; Clobbers A,C JFNSTB: SKIPA A,$FJFN(F) ; JFNSTB gets the JFN from block itself. JFNSTR: MOVEM A,$FJFN(F) ; whereas JFNSTR stores it there... MOVSI D,-NJSTRF ; Set up aobjn thru table. JFNST2: PUSH P,T SYSCAL JFNS,[FNBWP ? $FJFN(F) ? JSTRFX+1(D)][FNBWP] POP P,T MOVE C,JSTRFX(D) ; Now get index to place it belongs in file block, CAIN C,$FVERS ; and check for this, because JRST [ MOVE A,FNBLWP ; it wants to be a number, not a string. MOVEM A,FNBWP ; Zap write pointer back to forget string, PUSHJ P,CVSDEC ; and quickly convert before anything clobbers it. JRST JFNST4] ; Skip over the FNCHKZ call. MOVE A,FNBLWP ; Get previous write ptr CAMN A,FNBWP ; and compare to make sure something written. TDZA A,A ; If nothing, store zero. PUSHJ P,FNCHKZ ; Fix up string, and get BP to it. JFNST4: ADDI C,(F) ; make it an addr, and MOVEM A,(C) ; store BP. (or value, for $FVERS) ADDI D,1 AOBJN D,JFNST2 POPJ P, ; Filblk idx, output format wd for JFNS call JSTRFX: $FDEV ? 100000,, $FDIR ? 010000,, $FNAME ? 001000,, $FEXT ? 000100,, $FVERS ? 000010,, NJSTRF==<.-JSTRFX>/2 ; CVSDEC - Converts ASCIZ string to decimal, assumes only digits seen. ; A/ BP to ASCIZ ; Returns value in A, clobbers nothing else. CVSDEC: PUSH P,B PUSH P,C MOVE C,A SETZ A, JRST CVSDC3 CVSDC2: IMULI A,10. ADDI A,-"0(B) CVSDC3: ILDB B,C JUMPN B,CVSDC2 POP P,C POP P,B POPJ P, ; CVSSIX - Converts ASCIZ string to SIXBIT word. ; A/ BP to ASCIZ string, ; Returns SIXBIT word in A. Clobbers nothing else. CVSSIX: PUSH P,B PUSH P,C PUSH P,D MOVE D,A SETZ A, MOVE B,[440600,,A] JRST CVSSX3 CVSSX2: CAIL C,140 SUBI C,40 ; Uppercase force SUBI C,40 ; cvt to 6bit IDPB C,B ; deposit TLNN B,770000 ; If BP at end of word, JRST CVSSX5 ; leave loop. CVSSX3: ILDB C,D JUMPN C,CVSSX2 CVSSX5: POP P,D POP P,C POP P,B POPJ P, ] ; IFN TNX IFN TNX,[ ; Get a JFN for current FILBLK (in F) and stick it into $FJFN(F). ; A should hold flags in LH to use in 1st wd of block. ; GETJFI - sets usual flags for input ; GETJFO - sets " " output ; GETJFN - takes whatever A holds. GETJFO: SKIPA A,[GJ%FOU+GJ%NEW] ; If hacking output, ask for new version. GETJFI: MOVSI A,(GJ%OLD) ; If hacking input, file must exist. GETJFN: PUSHJ P,TFMAP ; Stick filblk stuff into GTJFN scratch block. PUSH P,R1 PUSH P,R2 MOVEI R1,GTJBLK SETZ R2, GTJFN JRST [ MOVEM R1,ERRCOD ; failure, save error code. JRST GETJF5] HRRM R1,$FJFN(F) ; Win, save JFN. AOS -2(P) GETJF5: POP P,R2 ; Can't return in ACs cuz don't know what R1 etc are, POP P,R1 ; and might clobber them here. POPJ P, .SCALAR ERRCOD ; TFMAP - Map Tenex filenames from filblk pointed to by F into ; standard scratch block for long-form GTJFN. ; A/ ,,0 ; flags will go into LH of .GJGEN. ; Clobbers only A. TFMAP: HRR A,$FVERS(F) ; Put version # in RH SKIPE $FTEMP(F) ; If asking for temp file, TLO A,(GJ%TMP) ; set appropriate flag. MOVEM A,GTJBLK+.GJGEN IRP FROM,,[$FDEV,$FDIR,$FNAME,$FEXT,$FPROT,$FACCT,$FJFN]TO,,[.GJDEV,.GJDIR,.GJNAM,.GJEXT,.GJPRO,.GJACT,.GJJFN] MOVE A,FROM(F) MOVEM A,GTJBLK+TO TERMIN MOVE A,[.NULIO,,.NULIO] MOVEM A,GTJBLK+.GJSRC ; Don't hack I/O in gtjfn. POPJ P, .VECTOR GTJBLK(10.) ; Need exactly this many wds for non-extended long call ] ;IFN TNX SUBTTL TNX - SUPPORT FOR I/O MACROS IFN TNX,[ ; TAKES -1(P)/ , (P)/ AND OUTPUTS TOUTC: EXCH R1,-1(P) ; GET JFN EXCH R2,(P) ; AND CHAR BOUT ; OUT IT GOES. REST R2 ; RESTORE ACS AND RETURN REST R1 RET ; TINC - TAKES -1(P)/ , (P)/ AND INPUTS FROM CHAN TO LOC TINC: EXCH R1,-1(P) ; GET JFN PUSH P,R2 BIN ERJMP [HRROI R2,^C ; EOF (20X ONLY) JRST .+1] MOVEM R2,@-1(P) ; STORE BYTE IN DESIRED LOC POP P,R2 SUB P,[1,,1] ; FLUSH LOC FROM STACK POP P,R1 RET ; TINS - INPUT STRING ; TAKES T/ ADDR--> ? ? TINS: SAVE R1 SAVE R2 SAVE R3 MOVE R1,@(T) ; GET JFN MOVE R2,@1(T) ; AND BP MOVN R3,@2(T) ; AND -COUNT SIN ERJMP .+1 ; ASSUME EOF AND PTRS UPDATED PROPERLY. ; THIS ONLY WINS ON 20X! MOVNM R3,@2(T) ; RESTORE NEW CNT MOVEM R2,@1(T) ; AND NEW BP REST R3 REST R2 REST R1 RET ] ;IFN TNX PATCH: BLOCK 100 CONSTA ;ITS BEGP:: ;BEGINNING OF STORAGE ZEROED AT INIT. JUNK: 0 PPSET: BLOCK LPDL ;PUSH DOWN LIST STORAGE BLOCK 20 FLUSHP: BLOCK 1 ;P SAVED FOR RESTORATION IF A --MORE-- IS FLUSHED. ;0 => NOT POSSIBLE TO FLUSH NOW. ERRCNT: BLOCK 1 ;DIFFERENCES COUNTER (0 MEANS NO DIFFERENCES) LBUFP: LBUFP1::BLOCK 1 ;POINTER TO BEGINNING OF LINE STORAGE FOR FILE #1 LBUFP2: BLOCK 1 ;DITTO FILE #2 LBUFP3: BLOCK 1 NLINES: NLINE1::BLOCK 1 ;# OF LINES OF FILE 1 NOW IN CORE NLINE2: BLOCK 1 NLINE3: BLOCK 1 EOFFL1: BLOCK 1 ;-1 => LAST NEXTLN ON FILE 1 WAS NO-OP'ED DUE TO EOF. EOFFL2: BLOCK 1 EOFFL3: BLOCK 1 NCOMP1: BLOCK 1 ;HOW MANY LINES DIFF IS CONSIDERING FROM FILE 1 NCOMP2: BLOCK 1 NCOMP3: BLOCK 1 HBUF1: BLOCK WPL ;HOLDS TITLE FROM FIRST FILE HBUF2: BLOCK WPL ;FROM SECOND FILE HBUF3: BLOCK WPL IFN ITS,[ RCHSTB: BLOCK 10. ;BLOCK WRITTEN INTO BY .RCHST ;WORD 0 RH DEV NAME, LH IF NON-ZERO THEN DEVICE NAME TO PRINT ;WRD 1 FNAM1 ;WRD 2 FNAM2 ;WRD 3 SYSTEM NAME ;WRD 4 NON-NEGATIVE => .ACCESS POINTER ;REST ROOM FOR EXPANSION OF SYSTEM CALL ] PAGNUM: BLOCK 3 ;PAGE NUMBERS FOR THE TWO FILES, AT THE LEVEL OF RDLINE. ;THAT IS, THE PAGE # THAT THE NEXT LINE READ WILL START ON. LINNUM: BLOCK 3 ;LINE NUMBERS FOR THE FILES, AT RDLINE LEVEL. CHRNUM: BLOCK 3 ;# OF CHARS RDLINE HAS READ SO FAR FROM EACH FILE. LLABEL: BLOCK 3*LNLBLN ;LNLBLN (4) WDS/FILE, 0 OR ASCIZ OF LAST LABEL AND A COLON. MRGOUT: BLOCK 3 ;/M NON-ZERO MEANS OUTPUT TO MERGE FILE ALL ;/M LINES BEFORE WIPING OUT IN "MOVEUP" ROUTINE ;/M ALWAYS 0 IF /M NOT TYPED LPHONY: BLOCK 1 ; -1 IFF LAST LINE OUTPUT BY MOVEUP DIDN'T END IN A CRLF, ;EXCEPT 1 => ENDED IN JUST A CR. 0 => ENDED IN A CRLF. MRGLEN==2 ;/M LEAVE ROOM FOR 2 WORDS (10 CHAR) OF MERGE COMMAND. MRGCOM: BLOCK MRGLEN ;/M BUFFER FOR MERGE COMMAND BLOCK 1 ;/M GUARANTEE A NULL TERMINATION MRGBYT: BLOCK 1 ;/M BYTE POINTER TO MERGE COMMAND STRING MRGUFL: BLOCK 1 ;-1 => OUTPUTTING DIFFERENCES IN /F MODE; FROM MRGU1 TO MOVEUP. OUTTTY: BLOCK 1 ;-1 => CHOUT IS OUTPUTTING TO A TTY. IFN ITS,[ TTYSTS: BLOCK 1 ;SAVED TTYSET OF CHANNEL CHOUT, FOR RESTORATION AT RELDEV. TTYST1: BLOCK 1 TTYST2: BLOCK 1 ] NUMTMP: BLOCK 1 ;TEMP FOR NUMLIN TEMPF1: BLOCK 1 ;TEMP FOR F1 TEMPF2: BLOCK 1 ;TEMP FOR F2 TEMPF3: BLOCK 1 RFILC: 0 ;TEMP. FOR RFILE. LSTEXP: 0 ;-1 => A BACKARROW WAS PRESENT IN COMMAND STRING. FILBF1: BLOCK FILBFL ;FILE 1 BUFFER. FILBE1=.-1 ASCIC// FILPT1: 0 ;FILE 1 BUFFER PTR. FILEP1: 0 ;FILE 1 B.P. TO THE ^C AFTERWHAT WAS READ IN. FILBF2: BLOCK FILBFL ;FILE 2 BUFFER, FILBE2=.-1 ASCIC// FILPT2: 0 ;FILE 2 BUFFER PTR. FILEP2: 0 FILBF3: BLOCK FILBFL ;FILE 3 BUFFER. FILBE3=.-1 ASCIC// FILPT3: 0 ;FILE 3 BUFFER PTR. FILEP3: 0 ;FILE 3 B.P. TO THE ^C. MRGBF: BLOCK MRGBSZ/5 ;BUFFER FOR MERGE OUTPUT MRGBP: 0 ;B.P. FOR STUFFING BUFFER. MRGCT: 0 ;# CHARS SPACE LEFT IN BUFFER. PNTDBF: BLOCK 12./5+1 ;BUFFER FOR DECIMAL PRINT. ENDP:: ;END OF STORAGE THAT'S ZEROED BEFORE EVERY COMMAND. DEFDIR: 0 ;INITIAL (DEFAULT) DIRECTORY. CMDFIL: 0 ;-1 => READING FROM THE FILE OPEN ON CHCMD CMDIS: 0 ;DEFAULT INPUT DIR WHILE EXECUTING COMMAND FILE CMDID: 0 ;DEFAULT INPUT DEVICE CMDOS: 0 ;DEFAULT OUTPUT DIR CMDOD: 0 ;DEFAULT OUTPUT DEVICE CTLCF: 0 ;IF NOT 0, COMMIT SUICIDE AFTER FINISHING COMMAND. COLMAX: <-1>_-1 ;/M MAX COLUMN TYPED OUT ON /M DIALOG ;/M CHANGED BY C COMMAND LINMAX: <-1>_-1 ;/M MAX LINS TO TYPE OUT ON /M NUMLIN: MATCH-1 ;# LINES FOR A MATCH SEG1: 10000 ;START OF SEGMENT FOR FILE 1 LINES SEG2: 201000 ;START OF SEGMENT FOR FILE 2 LINES SEG3: 401000 ;START OF SEGMENT FOR FILE 3 LINES TTIBUF: BLOCK 30 ;COMMAND BUFFER. TTIBFL==.-TTIBUF TTIPNT: 0 ;BYTE POINTER INTO TTIBUF. TTICNT: 0 ;NUM. UNREAD CHARS LEFT IN TTIBUF. CONSTANTS FOO: VARIABLES -1 ENDCOR: END BEG