.TITLE SMG -- SOURCE FILE MERGE .IDENT /X0103A/ ; ; AUTHOR: JOHN HARPER ; DATE: 23-SEP-76 ; .SBTTL MACROS AND DATA AREAS .MCALL CALL,RETURN,FCSMC$,DIR$,QIOW$,GCMLB$,GCML$,CSI$,EXIT$S .MCALL CSI$1,CSI$2,CSI$SW,CSI$SV,CSI$ND .MCALL OPEN$,OFNB$,OFID$,FINIT$ FCSMC$ .MACRO SAVREG JSR R5,SAVREG .ENDM .MACRO ERROR OPT,FMT,A1,A2,A3,A4,A5,A6,A7,A8,A9 PRINT ,,A1,A2,A3,A4,A5,A6,A7,A8,A9 .ENDM ERROR .MACRO PRINT OPT,FMT,A1,A2,A3,A4,A5,A6,A7,A8,A9 $$$ERR=0 $$$FIL=0 $$$DIA=0 $$$FNA=0 $$$FCE=0 $$$=0 .IRP XXX, $$$'XXX=1 .ENDR .IRP XXX, .IF NB,XXX $$$=$$$+1 MOV XXX,-(SP) .ENDC .ENDR .IF NE,$$$FIL MOV R0,-(SP) .ENDC MOV (PC)+,-(SP) .BYTE $$$+$$$FIL .BYTE <$$$ERR*EF.ERR>!<$$$FIL*EF.FIL>!<$$$DIA*EF.DIA>!<$$$FCE*EF.FCE> .IF NE,$$$FNA MOV #FMT,-(SP) .IFF .PSECT FORMAT $$$=. .ASCIZ \FMT\ .PSECT CODE MOV #$$$,-(SP) .ENDC CALL PRINT .ENDM PRINT .PSECT FORMAT RW,D .PSECT CODE RW,I .PSECT DATA RW,D .SBTTL DEFINITIONS AND MISCELLANEOUS DATA ;THIS PROGRAM IS DESIGNED TO ACCEPT SEVERAL SLP CORRECTION ;FILES AND APPLY THEM TO A SINGLE BASELINE FILE, MERGING ;CORRECTIONS. WHERE THE CORRECTIONS COLLIDE, USER MUST SORT ;OUT THE DIFFERENT VERSIONS. ;+ ; FIRST SOME ODD WORDS AND BYTES ;- CNFNO: .WORD 0 ; CURRENT CONFLICT NUMBER WITHIN FILE BUFADR: .WORD 0 ; START OF CURRENT INPUT LINE BUFLEN: .WORD 0 ; LENGTH OF CURRENT INPUT LINE CURCOR: .WORD 0 ; FDB ADDRESS OF CURRENT CORRECTION FILE LINNO: .WORD 0 ; LINE NUMBER OF CURRENT PRIMARY INPUT LINE LSTMOD: .WORD 0 ; ADR OF LAST CORRECTION FDB IN USE SPSAV: .WORD 0 ; INITIAL STACK POINTER EOFFLG: .BYTE 0 ; FLAG FOR CORRECTION EOF SEEN EXITFL: .BYTE 0 ; FORCE EXIT, DON'T REPROMPT .EVEN ;+ ; NOW SOME FLAG BITS ;- IF.ED ==001 ; EOF SEEN ON CORRECTION FILE IF.OPN ==002 ; CORRECTION FILE HAS BEEN SUCCESSFULLY OPENED FL.CO ==001 ; CONTINUATION REQUIRED AFTER THIS FILE EF.FIL ==001 ; ERROR INCLUDES FILESPEC EF.DIA ==002 ; ERROR IS DIAGNOSTIC EF.ERR ==004 ; MESSAGE IS AN ERROR MESSAGE EF.FCE ==010 ; PRINT FCS ERROR CODE AS WELL AS FILENAME ;+ ; NOW SOME FILE RELATED STUFF ;- CMDLUN ==1 ; LUN FOR COMMAND I/O ERRLUN ==2 ; LUN FOR ERROR MESSAGES PRILUN ==3 ; LUN FOR PRIMARY INPUT OUTLUN ==4 ; LUN FOR OUTPUT CORLUN ==5 ; LUN FOR FIRST CORRECTION FILE MSCEFN ==1 ; EVENT FLAG FOR VARIOUS SYNCHRONOUS THINGS PRIEFN ==2 ; EVENT FLAG FOR PRIMARY INPUT OUTEFN ==3 ; EVENT FLAG FOR OUTPUT COREFN ==4 ; EVENT FLAG FOR CORRECTION INPUT ;+ ; NOW THE NUMBER OF SIMULTANEOUS CORRECTION FILES ;- NUMCOR =12. ; THAT'S ENOUGH FOR NOW! .SBTTL FDBS, ETC ;+ ; FIRST THE FDB FOR THE PRIMARY INPUT FILE ;- PRIINP: FDBDF$ FDRC$A FD.PLC,INPBUF,132. FDOP$A PRILUN,,PRIDFN,FO.RD FDBF$A PRIEFN PRIDFN: NMBLK$ ,MAC INPBUF: .BLKB 132. ;+ ; NOW THE OUTPUT FDB ;- OUTFDB: FDBDF$ FDAT$A R.VAR,FD.CR FDRC$A FDOP$A OUTLUN,,OUTNMB,FO.WRT FDBF$A OUTEFN OUTNMB: NMBLK$ ;+ ; NOW DEFINE THE FORMAT OF THE ADDITIONAL WORDS AT THE END OF A ; CORRECTION FDB ;- I.NI ==S.FDB+2 ; LINE AT WHICH NEXT CORRECTION BEGINS I.IL ==I.NI+2 ; LENGTH IN LINES OF SECTION TO BE DELETED AT NEXT CORRECTION I.FL ==I.IL+2 ; FLAGS BYTE I.XX ==I.FL+1 ; SPARE BYTE I.FSV ==I.XX+1 ; FILE INFO SAVE AREA I.SZ ==I.FSV+12. ; SIZE IN BYTES OF EXTNEDED FDB MODINP: $$$=0 .REPT NUMCOR ; ONE FOR EACH OF MAXIMUM NUMBER OF CORRECTION FILES FDBDF$ FDRC$A FD.PLC,CORBUF,132. FDOP$A CORLUN+$$$,,CORNMB,FO.RD FDBF$A COREFN,,1 .BLKB I.SZ-S.FDB $$$=$$$+1 .ENDR MODEND: ; END OF CORRECTION FILE FDB'S CORNMB: NMBLK$ ,SLP CORBUF: .BLKB 132. FSRSZ$ 3 ; ALLOW FOR 3 OPEN FILES ;NOTE COMMAND LOOKS LIKE ;SMG OUT=MASTER,CORR1[,CORR2[,CORR3[,...]]] .SBTTL MAIN PROGRAM ;+ ; THIS IS THE MAIN PROGRAM WHICH CONTROLS ALL THAT GOES ON. ;- .PSECT CODE .ENABL LSB SMG:: FINIT$ ; SET UP FCS CLRB EXITFL ; DON'T EXIT YET 10$: MOV SP,SPSAV ; REMEMBER STACK LEVEL CLR CNFNO ; CLEAR SOME IMPURE DATA CLR CURCOR ; SHOW NO CORRECTION FILE OPEN CLR LINNO ; START AT LINE ZERO CLRB EOFFLG ; CAN'T FINISH YET CALL GETCMD ; GET A COMMAND LINE BCS EXIT ; J IF EOF CALL SETUP ; SET UP FOR COMPARISON CALL MERGE ; DO THE ,MERGE TST CNFNO ; ANY CONFLICTS SEEN? BEQ 20$ ; J IF NOT ERROR ,<%D CONFLICTS FOUND>,CNFNO 20$: ABORT: CALL CLSALL ; CLOSE ALL FILES MOV SPSAV,SP ; RESTORE STACK AFTER ABORT TSTB EXITFL ; MUST EXIT NOW? BEQ 10$ ; LOOP IF NOT EXIT: EXIT$S ; GET OUT .DSABL LSB .SBTTL GETCMD -- READ COMMAND AND SET UP FILES ;+ ; THIS ROUTINE IS CALLED TO READ ALL THE COMMAND LINES FOR A SINGLE OPERATION ; AND OPEN AND SET UP ALL FILES. THERE MAY BE MORE THAN ONE COMMAND LINE, ; SO LONG AS THE LAST FILESPEC OF ALL BUT THE LAST HAS THE '/CO' SWITCH ON ; IT. THE FIRST COMMAND LINE GOES: ; ; OUTPUT=PRIMARY INPUT, CORRECTION 1, CORRECTION 2,... ; ; OTHERS CONTAIN JUST CORRECTION FILES. ; ; THE FILENAME AND EXTENSION FOR THE OUTPUT FILE ARE DEFAULTED FROM THE ; PRIMARY INPUT FILE. THE FILENAME (ONLY) FOR THE CORRECTION FILES ALSO ; COMES FROM THERE. ; ; ON EXIT, ALL FILES HAVE BEEN OPENED. ; ; CC-C IS SET IF A LEGAL EOF HAS BEEN SEEN. ;- .PSECT DATA GCMLB: GCMLB$ 3,SMG,,CMDLUN CSI$ .EVEN CSIBLK: .BLKB C.SIZE CORSW: CSI$SW CO,FL.CO CSI$ND .PSECT CODE .ENABL LSB GETCMD: SAVREG ; KEEP CLEAN GCML$ #GCMLB ; GET A COMMAND LINE BCC 10$ ; J IF NO PROBLEM CMPB G.ERR(R0),#GE.EOF ; WAS IT END OF INPUT? SEC ; ASSUME SO BNE 5$ ; J IF NOT JMP 80$ ; ELSE GET OUT 5$: JMP GCLERR ; ERROR IF NOT EOF 10$: CSI$1 #CSIBLK,GCMLB+G.CMLD+2,GCMLB+G.CMLD ; CHECK SYNTAX OF COMMAND BCC 11$ ; SKIP IF OK JMP CSIERR ; ELSE REPORT SYNTAX ERROR 11$: CSI$2 ,INPUT ; PARSE PRIMARY INPUT FILE OPEN$ #PRIINP,,,#CSIBLK+C.DSDS ; OPEN INPUT FILE BCC 20$ ; J IF NO PROBLEM ERROR , 20$: MOV #OUTNMB+N.FNAM,R2 ; GET OUTPUT DEFAULT NAMEBLOCK MOV #CORNMB+N.FNAM,R3 ; AND CORRECTION DEFAULT NAMEBLOCK MOV R0,R1 ; COPY PRIMARY INPUT FDB ADR ADD #F.FNAM,R1 ; POINT TO FILENAME IN NAMEBLOCK MOV (R1),(R2)+ ; COPY FILENAME TO OUTPUT MOV (R1)+,(R3)+ ; AND TO CORRECTION MOV (R1),(R2)+ ; ... MOV (R1)+,(R3)+ ; ... MOV (R1),(R2)+ ; ... MOV (R1)+,(R3)+ ; ... MOV (R1)+,(R2)+ ; AND COPY EXT TO OUTPUT FILE CSI$2 #CSIBLK,OUTPUT ; NOW PARSE OUTPUT FILESPEC BCC 23$ ; SKIP IF OK JMP CSIERR ; J TO REPORT ERROR 23$: BITB #CS.MOR,C.STAT(R0) ; IS THIS THE ONLY OUTPUT FS? BEQ 25$ ; J IF SO ERROR <>, ; ELSO COMPLAIN 25$: MOV #OUTFDB,R0 ; GET FDB ADDRESS MOV R0,R1 ; FORM FNB ADR IN R1 ADD #F.FNB,R1 ; MOV #CSIBLK+C.DSDS,R2 ; GET DATASET DESCRIPTOR TO R2 MOV F.DFNB(R0),R3 ; NOW GET DEFAULT NAMEBLOCK CALL .PARSE ; SET UP OUTPUT FNB BCS OFLERR ; COMPLAIN IF SOMETHING WRONG MOV #CSIBLK,R0 ; GET THE CSI BLOCK ADR AGAIN MOV #MODINP,R1 ; GET START OF MODIFICATION FDB LIST MOV #CS.INP,C.TYPR(R0) ; SET UP TO READ INPUT FILESPECS 30$: CSI$2 #CSIBLK,,#CORSW ; GET NEXT INPUT FS BCS CSIERR ; J IF ERROR SEEN OPEN$ R1,,,#CSIBLK+C.DSDS ; OPEN THE CORRECTION FILE BCC 40$ ; J IF NO PROBLEM ERROR , 40$: CALL CLSFIL ; CLOSE FILE AND SAVE INFO BISB #IF.OPN,I.FL(R0) ; SHOW FILE SUCCESSFULLY OPENED BITB #CS.MOR,CSIBLK+C.STAT ; ANY MORE INPUT FILES? BNE 60$ ; J IF SO BITB #FL.CO,CSIBLK+C.MKW1 ; /CO SWITCH SEEN? BEQ 70$ ; J IF NOT, MUST BE END OF INPUT GCML$ #GCMLB ; ELSE GET ANOTHER LINE BCC 50$ ; J IF NO PROBLEM CMPB G.ERR(R0),#GE.EOF ; EOF SEEN ON COMMAND INPUT? BNE GCLERR ; GO ANALYSE IF NOT INCB EXITFL ; ELSE SHOW MUST EXIT ERROR <>, ; ELSE COMPLAIN 50$: CSI$1 #CSIBLK,GCMLB+G.CMLD+2,GCMLB+G.CMLD ; CHECK SYNTAX BCS CSIERR ; J IF BAD SYNTAX BITB #CS.EQU,C.STAT(R0) ; IS THERE AN EQUAL SIGN? BEQ 55$ ; J IF NOT ERROR <>,<'=' ILLEGAL ON CONTINUATION LINE> ; ELSE COMPLAIN 55$: MOVB #CS.OUT,C.TYPR(R0) ; SET UP TO READ OUTPUT FILESPECS NOW 60$: ADD #I.SZ,R1 ; ADVANCE TO NEXT CORRECTION FDB CMP R1,#MODEND ; STILL SOME LEFT? BLO 30$ ; LOOP IF SO ERROR <>, ; ELSE COMPLAIN 70$: MOV R1,LSTMOD ; REMEMBER LAST MODFICATION FILE OFNB$ #OUTFDB ; NOW ACTUALLY CREATE OUTPUT FILE BCS OFLERR ; GO AWAY IF BAD 80$: RETURN ; RETURN WITH CC-C SET UP .DSABL LSB CSIERR: ERROR <>, OFLERR: ERROR , .ENABL LSB GCLERR: CMPB G.ERR(R0),#GE.OPR ; OPEN FAILURE ON INDIRECT FILE? BNE 10$ ; J IF NOT ERROR , 10$: ERROR <>, .DSABL LSB .SBTTL SETUP -- SET UP CORRECTION FILE TABLES AND FDBS ;+ ; AS WITH ANY MERGE OPERATION, WE MUST START OFF BY LEARNING THE FIRST ; 'TRANSACTION' OF EACH 'UPDATE' (CORRECTION) FILE. NORMALLY, THE FIRST ; LINE OF EACH FILE WILL BE A COMMAND, SO WE READ IT AND TRY TO PROCESS ; AS SUCH. WE MUST HOWEVER ALLOW FOR THE POSSIBILITY THAT A FILE WILL ; START WITH AN INSERTION, IN WHICH CASE WE 'REWIND' THE FILE USING ; .MARK/.POINT. ;- SETUP: SAVREG ; KEEP CLEAN MOV #MODINP,R0 ; GET FIRST CORRECTION FILE 10$: CLR I.NI(R0) ; CLEAR NEXT LINE TO GO MOV R0,R3 ; GET FDB TO RIGHT REGISTER CALL SELCOR ; AND SELECT THIS CORRECTION FILE CALL .MARK ; REMEMBER CURRENT POSITION CALL RDLIN ; READ THE FIRST LINE CALL CKCMD ; SEE IF THERE'S A COMMAND BCS 20$ ; J IF SO - ALL SET UP CLR I.NI(R0) ; ELSE SAY NEXT LINE IS ZERO CLR I.IL(R0) ; INSERTION HAS ZERO LENGTH CALL .POINT ; RESET POSITION TO START OF FILE 20$: ADD #I.SZ,R0 ; POINT TO NEXT FDB CMP R0,LSTMOD ; ANY MORE TO DO? BLOS 10$ ; J IF SO RETURN ; ELSE GO AWAY .SBTTL CLSALL -- CLOSE ALL FILES ;+ ; THIS ROUTINE DOES AS THE NAME SUGGESTS ;- CLSALL: SAVREG ; KEEP CLEAN CLOSE$ #OUTFDB ; CLOSE OUTPUT FILE CLOSE$ #PRIINP ; AND INPUT FILE MOV CURCOR,R0 ; GET CORRECTION FILE BEQ 10$ ; J IF NONE CLOSE$ R0 ; ELSE CLOSE IT CLR CURCOR ; AND SHOW NOT OPEN 10$: RETURN ; NOW GO AWAY .SBTTL MAIN LOOP ;+ ; THIS IS THE LOOP OF SMG WHICH DOES THE ACTUAL WORK. IT FINDS WHICH ; OF THE MERGE FILES HAS THE LOWEST NUMBERED 'NEXT LINE' AND COPIES THE ; INPUT FILE UNTIL IT REACHES THIS LINE. IT THEN DELETES AS MANY LINES ; AS NECESSARY FROM THE INPUT FILE AND COPIES FROM THE REQUIRED ; CORRECTION FILE, THEN RESUMES COPYING THE MAIN FILE. BEFORE DOING THIS ; IT SCANS ALL CORRECTION FILES TO SEE IF THERE ARE ANY CONFLICTS; IF SO, ; ALL CORRECTIONS AND THE ORGINAL ARE COPIED AND IT IS UP TO THE USER ; TO SORT OUT WHAT TO DO. ;- .ENABL LSB .PSECT DATA STARS: .ASCIZ /**************************************************************/ .EVEN .PSECT CODE MERGE: SAVREG ; KEEP CLEAN LOOP: CALL FNDCOR ; FIND THE NEXT CORRECTION FILE MOV #PRIINP,R0 ; GET FDB FOR PRIMARY INPUT FILE SUB LINNO,R2 ; SUBTRACT CURRENT LINE NUMBER BEQ 40$ ; J IF ALREADY AT THE RIGHT PLACE 30$: CALL RDLIN ; GET A LINE FROM THE PRIMARY FILE BCC 35$ ; J IF NOT EOF TSTB EOFFLG ; EOF ALLOWED YET? BNE 110$ ; RETURN IF SO BR 100$ ; ELSE SAY ERROR 35$: CALL OUTLIN ; OUTPUT THE LINE SOB R2,30$ ; LOOP TILL UP TO THE CORRECTION 40$: MOV R3,R0 ; GET FDB FOR CORRECTION FILE MOV I.NI(R0),R4 ; GET START LINE OF CORRECTION ADD I.IL(R0),R4 ; FIND END OF RANGE MOV #MODINP,R1 ; GET MODIFICATION TABLE 50$: CMP R1,R0 ; IS THIS THE CURRENT FILE? BEQ 60$ ; J IF SO - CAN'T CONFLICT CMP R4,I.NI(R1) ; DOES THIS CORRECTION OVERLAP? BLO 60$ ; SKIP IF NOT CALL CNFLCT ; ELSE PROCESS THE CONFLICT BR LOOP ; AND GO AGAIN 60$: ADD #I.SZ,R1 ; GO TO NEXT CORRECTION FILE CMP R1,LSTMOD ; AT END OF TABLE YET? BLOS 50$ ; J IF NOT MOV I.IL(R0),R1 ; NO CONFLICT - GET # LINES TO DELETE BEQ 80$ ; J IF THIS IS AN INSERTION MOV R0,R2 ; SAVE CORRECTION FILE 70$: MOV #PRIINP,R0 ; GET PRIMARY FILE AGAIN CALL RDLIN ; READ A LINE BCS 100$ ; J IF EOF SOB R1,70$ ; LOOP TIL DONE MOV R2,R0 ; RETRIEVE CORRECTION FILE 80$: CALL RDLIN ; READ A CORRECTION LINE BCS 90$ ; J IF EOF - ILLEGAL CALL CKCMD ; SEE IF IT'S A COMMAND BCS LOOP ; FINISHED THIS CORRECTION IF SO CALL OUTLIN ; ELSE OUTPUT IT BR 80$ ; AND LOOP 90$: ERROR , 100$: ERROR , 110$: RETURN .DSABL LSB .SBTTL CNFLCT -- HANDLE CORRECTION FILE CONFLICT ;+ ; COME HERE WHEN THE SCOPE OF ONE CORRECTION OVERLAPS ANOTHER. WE OUTPUT ; THE FIRST CORRECTION, THEN THE SECOND. WE MUST CHECK FOR CONFLICT BETWEEN ; MORE THAN TWO CORRECTION FILES BY UPDATING THE END OF THE CORRECTION SCOPE ; AND THEN SCANNING THE CORRECTION TABLE AGAIN. WHEN THERE ARE NO MORE ; CONFLICTS WE OUTPUT ALL THE PART OF THE PRIMARY INPUT FILE COVERED BY ; THE CONFLICT. ;- .ENABL LSB CNFLCT: MOV R4,R5 ; SAVE CURRENT END OF CONFLICT INC CNFNO ; INCREMENT CONFLICT NUMBER PRINT ,STARS ; PRINT A LINE OF STARS PRINT ,STARS ; AND ANOTHER PRINT <>,<***** START OF CONFLICT %3<%D%3> *****>,CNFNO 5$: PRINT ,STARS ; ANOTHER LINE OF STARS PRINT ,<***** CORRECTION FILE %19<%X%19> (CONFLICT %3<%D%3>) *****>,CNFNO 10$: CALL RDLIN ; READ A LINE OF THE CONFLICT FILE BCS 20$ ; J IF EOF CALL CKCMD ; IS IT A COMMAND? BCS 30$ ; J IF SO CALL OUTLIN ; ELSE OUTPUT THE LINE BR 10$ ; AND LOOP 20$: ERROR , 30$: CALL FNDCOR ; FIND NEXT CORRECTION TO GO CMP R5,I.NI(R3) ; IS THIS PAST CURRENT END OF CONFLICT? BLO 50$ ; J IF SO - THIS IS END OF CONFLICT MOV I.NI(R3),R4 ; FIND END OF SCOPE OF NEXT CORRECTION ADD I.IL(R3),R4 ; ... MOV R3,R0 ; COPY FDB ADDRESS TO READ FROM CMP R5,R4 ; PAST END OF CONFLICT? BHIS 5$ ; LOOP IF NOT MOV R4,R5 ; ELSE SET NEW END BR 5$ ; AND THEN LOOP 50$: MOV #PRIINP,R0 ; GET PRIMARY FILE PRINT ,STARS ; PRINT A LINE OF STARS PRINT ,<***** PRIMARY INPUT FILE %19<%X%19> *****> PRINT ,STARS ; ANOTHER LINE OF STARS SUB LINNO,R5 ; SUBTRACT TO GET LENGTH BEQ 70$ ; J IF PRIMARY FILE NOT INVOLVED 60$: CALL RDLIN ; GET A LINE BCS 80$ ; LOOP IF EOF CALL OUTLIN ; ELSE OUTPUT THE LINE SOB R5,60$ ; LOOP TIL DONE 70$: PRINT ,STARS ; PRINT A FINAL LINE OF STARS PRINT ,STARS ; AND ANOTHER FOR GOOD MEASURE RETURN ; GO AWAY NOW 80$: ERROR , .DSABL LSB .SBTTL FNDCOR -- FIND NEXT CORRECTION TO GO ;+ ; THIS ROUTINE SCANS ALL THE CORRECTION FILES TO FIND THE ONE WITH ; THE LOWEST LINE NUMBER FOR THE NEXT CORRECTION. ; ; INPUTS: ; ; NONE ; ; OUTPUTS: ; ; R2 LINE NUMBER OF CORRECTION ; R3 FDB ADDRESS FOR CORRECTION FILE ;- .ENABL LSB FNDCOR: SAVREG ; KEEP CLEAN MOV #MODINP,R0 ; GET START OF CORRECTION FILE TABLE MOV R0,R3 ; AND COPY MOV #65535.,R2 ; START WITH A VERY HIGH NUMBER 10$: CMP I.NI(R0),R2 ; IS THIS ONE LOWER THAN BEST SO FAR? BHIS 20$ ; J IF NOT MOV I.NI(R0),R2 ; ELSE THIS IS BEST MOV R0,R3 ; MAKE IT RESULT TOO 20$: ADD #I.SZ,R0 ; MOVE TO NEXT FILE CMP R0,LSTMOD ; END OF TABLE YET? BLOS 10$ ; LOOP IF NOT 30$: BITB #IF.ED,I.FL(R3) ; IS THIS AN EOF? BEQ 40$ ; J IF NOT INCB EOFFLG ; ELSE SHOW NO MORE CORRECTIONS 40$: CALL SELCOR ; SELECT CORRECTION FILE FOR INPUT MOV R2,S$R2(SP) ; SET UP CALLER'S R2 MOV R3,S$R3(SP) ; AND R3 RETURN ; AND GO AWAY .DSABL LSB .SBTTL RDLIN -- READ A LINE FROM A FILE ;+ ; THIS ROUTINE IS CALLED TO READ A LINE FROM THE CURRENT FILE. IT PERFORMS ; ERROR CHECKING AND LOOKS FOR EOF. ; ; INPUTS: ; ; R0 FDB ADDRESS OF FILE ; ; OUTPUTS: ; ; BUFADR ADDRESS OF START OF RECORD ; BUFLEN LENGTH OF RECORD ; CC-C SET IF EOF SEEN ; ; IF AN ERROR OTHER THAN EOF IS SEEN A FATAL ERROR IS REPORTED AND THE ; ROUTINE DOES NOT RETURN. ;- .ENABL LSB RDLIN: ;SAVREG ; KEEP CLEAN GET$ R0 ; READ A LINE BCC 10$ ; J IF NOTHING WRONG CMPB F.ERR(R0),#IE.EOF ; WAS IT EOF? SEC ; ASSUME SO BEQ 20$ ; AND J IF TRUE ERROR , 10$: MOV F.NRBD+2(R0),BUFADR ; COPY RECORD ADR MOV F.NRBD(R0),BUFLEN ; AND LENGTH CMP R0,#PRIINP ; IS THIS THE PRIMARY INPUT FILE CLC ; CLEAR CARRY ANYWAY BNE 20$ ; J IF NOT INC LINNO ; ELSE INCREMENT LINE NUMBER BNE 20$ ; ** J IF NOT TOO MANY LINES ERROR , ; ELSE COMPLAIN 20$: RETURN ; ****>> GET OUT .DSABL LSB .SBTTL CKCMD -- CHECK CURRENT LINE FOR COMMAND ;+ ; THIS ROUTINE IS CALLED TO EXAMINE THE LINE CURRENTLY DESCRIBED BY ; BUFADR AND BUFLEN TO SEE IF IT CONTAINS A COMMAND, I.E. A LINE ; BEGINNING WITH ONE OF THE WARNING CHARACTERS '<', '-', '/' OR '@'. ; THE ACTION IS: ; ; '<' STRIP ONE CHARACTER FROM THE LINE, RETURN INDICATING NO COMMAND ; '-' SET UP I.NI AND I.LI IN THE FDB TO CORRESPOND TO THIS INSERTION ; COMMAND ; '/' SET UP FDB TO SHOW END OF CORRECTION FILE SEEN ; '@' ISSUE DIAGNOSTIC ERROR MESSAGE ; ; INPUTS: ; ; R0 FDB ADDRESS ; ; OUTPUTS: ; ; CC-C SET IF TRUE COMMAND SEEN, I.E. CURRENT INSERTION SHOULD TERMINATE ; FDB MAY BE ALTERED AS DESCRIBED ABOVE ;- .ENABL LSB CKCMD: SAVREG ; KEEP CLEAN MOV BUFADR,R1 ; GET BUFFER ADDRESS MOV BUFLEN,R2 ; AND LENGTH BEQ 65$ ; J IF NULL LINE - CAN'T BE A COMMAND CMPB (R1),#'< ; IS IT ESCAPE CHARACTER? BNE 10$ ; J IF NOT INC BUFADR ; ELSE BUMP BUFFER PAST IT DEC BUFLEN ; DECREASE LENGTH BR 65$ ; AND GET OUT 10$: CMPB (R1),#'/ ; IS IT CORRECTION EOF? BNE 20$ ; J IF NOT MOV #65535.,I.NI(R0) ; SET UP VERY HIGH LINE NUMBER CLR I.IL(R0) ; CLEAR INSERTION LENGTH BISB #IF.ED,I.FL(R0) ; SHOW FILE ENDED BR 60$ ; AND SHOW COMMAND 20$: CMPB (R1),#'- ; IS IT START OF INSERTION? BNE 50$ ; J IF NOT INC R1 ; ELSE GO TO NEXT CHAR DEC R2 ; ADJUST LENGTH CALL GETNUM ; GET A NUMBER CMP R3,I.NI(R0) ; DOES THIS REPRESENT A STEP BACKWARDS? BLO 30$ ; J IF SO MOV R3,I.NI(R0) ; ELSE SET UP INSERTION POSITION TST R2 ; ANYTHING ELSE ON LINE? BEQ 40$ ; J IF NOT, JUST AN INSERTION CMPB (R1)+,#', ; COMMA AS SEPARATOR? BNE 30$ ; J IF NOT DEC R2 ; ADJUST LENGTH CALL GETNUM ; GET END OF INSERTION SUB I.NI(R0),R3 ; SUBTRACT START POSITION DEC I.NI(R0) ; AND ADJUST FOR DELETION BLO 30$ ; J IF END LESS THAN START INC R3 ; ADJUST TO START AT ONE MOV R3,I.IL(R0) ; SET # LINES TO DELETE IN FDB TST R2 ; ANYTHING ELSE ON LINE? BEQ 60$ ; J IF SO, OK 30$: ERROR , 40$: CLR I.IL(R0) ; JUST INSERTION, CLEAR LENGTH TO DELETE BR 60$ ; DONE NOW 50$: CMPB (R1),#'@ ; IS THIS INDIRECT FILE? BNE 65$ ; J IF NOT, MUST BE JUST INSERTION LINE ERROR , BR 65$ ; TREAT AS INSERTION 60$: SEC ; SHOW COMMAND SEEN BR 70$ ; AND GET OUT 65$: CLC ; SHOW COMMAND NOT SEEN 70$: RETURN ; GO AWAY .DSABL LSB .SBTTL SELCOR -- SELECT CORRECTION FILE ;+ ; TO SAVE SPACE, THERE IS ONLY EVER ONE CORRECTION FILE OPEN AT A TIME. ; THIS ROUTINE IS CALLED TO OPEN THE REQUIURED FILE AND CLOSE ANY OTHER ; THAT MAY BE OPEN. ; ; INPUTS: ; ; R3 FDB ADDRESS OF FILE TO OPEN ;- .ENABL LSB SELCOR: SAVREG ; KEEP CLEAN MOV CURCOR,R0 ; GET CURRENTLY OPEN FILE BEQ 10$ ; J IF NONE CMP R0,R3 ; IS IT CURRENT FILE? BEQ 30$ ; J IF SO - DO NOTHING CALL CLSFIL ; CLOSE FILE AND REMEMBER POSITION 10$: MOV S$R3(SP),R0 ; GET REQUIRED FDB MOV R0,R4 ; COPY FDB ADR ADD #I.FSV+12.,R4 ; POINT PAST FILE SAVE AREA MOV -(R4),F.FNB+4(R0) ; AND RESTORE ALL THREE WORDS OF FID MOV -(R4),F.FNB+2(R0) ; ... MOV -(R4),F.FNB(R0) ; ... OFID$ R0 ; RE-OPEN THE FILE BCC 20$ ; J IF OK ERROR , 20$: MOV -(R4),R3 ; GET POSITION INFO MOV -(R4),R2 ; ... MOV -(R4),R1 ; ... CALL .POINT ; RE-POSITION FILE MOV R0,CURCOR ; REMEMBER THIS IS CURRENT 30$: RETURN ; AND GO AWAY .DSABL LSB .SBTTL CLSFIL -- CLOSE CURRENT CORRECTION FILE ;+ ; THIS ROUTINE IS CALLED TO CLOSE THE FILE WHOSE FDB ADR IS IN R0, ; HAVING FIRST SAVED ALL THE INFORMATION REQUIRED TO RE-OPEN IT ; AT THE SAME PLACE. ; ; INPUTS: ; ; R0 FDB ADR ;- CLSFIL: SAVREG ; KEEP CLEAN CALL .MARK ; FIRST GET POSITION INFO IN FILE MOV R0,R4 ; COPY FDB ADR ADD #I.FSV,R4 ; AND POINT TO SAVE AREA MOV R1,(R4)+ ; NOW SAVE POSITION INFO... MOV R2,(R4)+ ; ... MOV R3,(R4)+ ; ... MOV F.FNB(R0),(R4)+ ; NOW SAVE FILE ID MOV F.FNB+2(R0),(R4)+ ; ... MOV F.FNB+4(R0),(R4)+ ; ... CLOSE$ R0 ; NOW CLOSE THE FILE RETURN ; AND GO AWAY .SBTTL GETNUM -- READ DECIMAL NUMBER ;+ ; THIS ROUTINE IS USED TO READ A DECIMAL NUMBER AS PART OF A COMMAND ; IN A CORRECTION FILE. ; ; INPUTS: ; ; R1 FIRST CHARACTER IN NUMBER ; R2 NUMBER OF CHARS REMAINING ON LINE ; ; OUTPUTS: ; ; R1 TERMINATOR ADDRESS ; R2 NUMBER OF CHARS LEFT ON LINE ; R3 NUMBER READ ;- .ENABL LSB GETNUM: MOV R0,-(SP) ; SAVE R0 CLR R3 ; CLEAR PARTIAL RESULT 10$: TST R2 ; ANYTHING LEFT ON LINE? BEQ 30$ ; J IF NOT MOVB (R1)+,R0 ; GET THE NEXT BYTE SUB #'0,R0 ; MAKE INTO DIGIT VALUE BMI 20$ ; J IF NOT DIGIT CMPB R0,#9. ; IS IT TOO BIG? BHI 20$ ; J IF SO MUL #10.,R3 ; ELSE MULTIPLY PARTIAL RESULT ADD R0,R3 ; ADD IN DIGIT DEC R2 ; ADJUST COUNT BR 10$ ; AND LOOP 20$: DEC R1 ; BACK UP OVER TERMINATOR 30$: MOV (SP)+,R0 ; RESTORE R0 RETURN ; AND GET OUT .DSABL LSB .SBTTL OUTLIN -- OUTPUT A LINE TO OUTPUT FILE ;+ ; THIS ROUTINE IS CALLED FOR ALL OUTPUT, OTHER THAN THAT VIA THE ; PRINT MACRO, TO THE OUTPUT FILE. APART FROM A PUT$ IT ALSO ; CHECKS FOR ERRORS. IT MAY BE EXPANDED TO INCLUDE AN AUDIT TRAIL. ; ; INPUTS: ; ; BUFADR ADDRESS OF LINE TO OUTPUT ; BUFLEN LENGTH OF LINE TO OUTPUT ;- .ENABL LSB OUTLIN: MOV R0,-(SP) ; KEEP CLEAN PUT$ #OUTFDB,BUFADR,BUFLEN ; OUTPUT A LINE BCC 10$ ; J IF OK ERROR , ; SAY BAD 10$: MOV (SP)+,R0 ; RESET R0 RETURN ; GO AWAY .DSABL LSB .SBTTL PRINT -- PRINT A FORMATTED LINE OR ERROR MESSAGE ;+ ; THIS ROUTINE IS CALLED BY THE PRINT AND ERROR MACROS TO OUTPUT A ; FORMATTED LINE. IT IS CALLED WITH THE STACK LOOKING LIKE: ; ; .WORD RETURN ADDRESS ; .WORD FORMAT DESCRIPTOR IN EDMSG FORMAT ; .BYTE FLAGS BYTE (SEE BELOW) ; .BYTE NUMBER OF ARGS ON STACK ; .WORD ARG1,ARG2,... ; ; THE EXACT INTERPRETATION OF THIS DEPENDS ON THE FLAGS BYTE: ; ; EF.ERR THIS IS AN ERROR MESSAGE WHICH SHOULD BE OUTPUT TO TI ; AND PRECEDED BY 'SMG -- *FATAL*'. THE CURRENT RUN SHOULD ; BE ABORTED AFTERWARDS ; EF.DIA IS THIS IS SET AND EF.ERR, THIS IS ONLY A '*DIAG*' ERROR ; AND CONTROL SHOULD RETURN AFTERWARDS. ; EF.FIL THE FIRST ARGUMENT ON THE STACK IS THE ADDRESS OF AN FDB ; AND SHOULD BE EXPANDED INTO THE CORRESPONDING NAMEBLOCK ; IN THE FORMAT REQUIRED FOR %X IN EDMSG ;- ;+ ; LOCAL DATA ;- .PSECT DATA PRTRTN: .WORD 0 ; SAVED RETURN ADDRESS PRTFMT: .WORD 0 ; SAVED FORMAT DESCRIPTOR ADDRESS PRTCTL: PRTSZE: .BYTE 0 ; SIZE OF ARGUMENT LIST PRTFLG: .BYTE 0 ; FLAGS BYTE PRTR5: .WORD 0 ; SAVED R5 PRTR2: .WORD 0 ; SAVED R2 PRTR1: .WORD 0 ; SAVED R1 PRTR0: .WORD 0 ; SAVED R0 PRTBUF: .BLKB 100. ; BUFFER FOR ERROR OR MESSAGE OUTPUT DIAGPR: .ASCIZ /SMG -- *DIAG* / ; PREFIX FOR DIAGNOSTIC ERRORR FTLPR: .ASCIZ /SMG -- *FATAL* / ; PREFIX FOR FATAL ERROR .EVEN ERRDPB: QIOW$ IO.WLB,ERRLUN,MSCEFN,,,, .PSECT CODE .ENABL LSB PRINT: MOV R0,PRTR0 ; SAVE REGISTERS (CAN'T USE STACK) MOV R1,PRTR1 ; ... MOV R2,PRTR2 ; ... MOV R5,PRTR5 ; ... MOV (SP)+,PRTRTN ; GET RETURN ADDRESS MOV (SP)+,PRTFMT ; GET FORMAT DESCRIPTOR MOV (SP)+,PRTCTL ; GET FLAGS BYTE AND LENGTH MOVB PRTFLG,R5 ; GET CONTROL FLAGS BITB #EF.FIL,R5 ; GOT TO EXPAND A FNB? BEQ 20$ ; J IF NOT MOV (SP)+,R0 ; ELSE GET FDB ADDRESS BITB #EF.FCE,R5 ; FCS ERROR WANTED TOO? BEQ 5$ ; J IF NOT CLR -(SP) ; ELSE MAKE ROOM INC PRTSZE ; AND ALLOW IN STACK ADJUSTMENT BISB F.ERR(R0),(SP) ; SET ERROR CODE NEGB (SP) ; AND MAKE POSITIVE 5$: ADD #F.FNB+N.FVER+2,R0 ; GET TOP OF INTERESTING PART MOV #/2,R1 ; GET # WORDS TO TRANSFER 10$: MOV -(R0),-(SP) ; COPY ONE ARG SOB R1,10$ ; LOOP TIL DONE MOVB PRTSZE,R2 ; GET SIZE OF ARG BLOCK ON STACK ADD #/2,R2 ; ALLOW FOR FNB MOVB R2,PRTSZE ; AND RESET STACK ADJUSTMENT 20$: MOV #PRTBUF,R0 ; GET ADDRESS OF OUTPUT BUFFER BITB #EF.ERR,R5 ; IS THIS AN ERROR? BEQ 40$ ; J IF NOT MOV #DIAGPR,R3 ; ASSUME DIAGNOSTIC BITB #EF.DIA,R5 ; WELL? BNE 30$ ; J IF CORRECT MOV #FTLPR,R3 ; ELSE GET 'FATAL' PREFIX 30$: MOVB (R3)+,(R0)+ ; COPY A BYTE BNE 30$ ; LOOP IF NOT ZERO DEC R0 ; BACK UP OVER TERMINATOR 40$: MOV PRTFMT,R1 ; GET FORMAT STRING MOV SP,R2 ; COPY ARG LIST ADDRESS CALL $EDMSG ; FORMAT THE MESSAGE MOV R0,R1 ; COPY FIRST UNUSED BYTE SUB #PRTBUF,R1 ; AND MAKE LENGTH BITB #EF.ERR,R5 ; WAS THIS AN ERROR? BNE 50$ ; J IF SO PUT$ #OUTFDB,#PRTBUF,R1 ; ELSE OUTPUT THE LINE TO OUTPUT FILE BR 60$ ; AND SKIP 50$: MOV R1,ERRDPB+Q.IOPL+2 ; SET UP ERROR DPB DIR$ #ERRDPB ; OUTPUT THE MESSAGE BITB #EF.DIA,R5 ; DIAGNOSTIC ERROR? BNE 60$ ; J IF SO JMP ABORT ; ELSE ABANDON THE RUN 60$: MOVB PRTSZE,R1 ; GET STACK ADJUSTMENT ASL R1 ; MAKE INTO BYTES ADD R1,SP ; AND ADJUST... MOV PRTR5,R5 ; RESTORE THE REGISTERS MOV PRTR2,R2 ; MOV PRTR1,R1 ; MOV PRTR0,R0 ; JMP @PRTRTN ; NOW RETURN VIA SAVED RETURN ADR .DSABL LSB .SBTTL SAVREG -- SAVE/RESTORE REGISTERS COROUTINE ;+ ; THIS IS THE WELL-KNOWN REGISTER SAVE COROUTINE. ;- S$R0=2 S$R1=4 S$R2=6 S$R3=10 S$R4=12 S$R5=14 SAVREG: MOV R4,-(SP) ; SAVE R4 MOV R3,-(SP) ; AND R3 MOV R2,-(SP) ; AND R2 MOV R1,-(SP) ; AND R1 MOV R0,-(SP) ; AND R0 MOV R5,-(SP) ; NOW PUSH CALLER'S ADDRESS MOV S$R5(SP),R5 ; RETRIEVE CALLER'S CALLER'S R5 CALL @(SP)+ ; COCALL THE CALLER .IRP XX, MOV (SP)+,XX ; RESTORE REGISTER XX .ENDR RETURN ; NOW RETURN TO CALLER'S CALLER .END SMG