!***COPYRIGHT (C) 1974, 1975, 1976, 1977 DIGITAL EQUIPMENT CORP., MAYNARD, MASS.*** %% % THIS MODULE IMPLEMENTS THE GO COMMAND. IT LOOPS, READING RECORDS FROM THE INPUT FILE, DECIDING IF THE RECORD SHOULD BE PRINTED, AND PRINTS IT IF NECESSARY, FOR EACH REPORT, IN PARALLEL. ROUTINES IN THIS MODULE: GOERR - GENERATES ERROR MESSAGES TO REPORT FILE READR - READS A RECORD READC - READS A CHUNK ACCEPT - DECIDES IF RECORD BELONGS IN REPORT PRINTR - PRINTS A RECORD PRINTC - PRINTS A CHUNK GO - CONTROLS EVERYBODY ELSE JOURNAL RECORD FORMAT ======= ====== ====== INPUT RECORDS: WORD 1 - WORD COUNT OF ALL THE WORDS IN THE RECORD WORD 2 - CHECKSUM OF ALL WORDS IN THE RECORD (EXCLUDING THE CHECKSUM WORDS) WORD 3 - TRANSACTION SEQUENCE NUMBER WORD 4 - DATE OF THIS MESSAGE (RESULT OF DATE UUO) WORD 5 - TIME OF THIS MESSAGE (RESULT OF MSTIME UUO) WORDS 6 THROUGH 8 - SOURCE TERMINAL NAME (ASCIZ) WORD 9 - SIZE OF TRANSACTION CODE IN CHARACTERS (CALL N THE LENGTH IN WORDS) WORDS 10 THROUGH 9+N - TRANSACTION CODE (ASCII) WORD 10+N - NUMBER OF CHUNKS IN RECORD WORDS 11+N THROUGH M - CHUNKS IN THIS RECORD WORD M+1 - CHECKSUM OF THIS RECORD, SAME AS WORD 2 OUTPUT RECORD: WORD 1 - WORD COUNT WORD 2 - CHECKSUM WORD 3 - TRANSACTION SEQUENCE NUMBER WORD 4 - DATE WORD 5 - TIME WORDS 6 THROUGH 7 - MESSAGE CLASS (ASCIZ) WORDS 8 THROUGH 12 - FILE SPEC OF MPP THAT RAN WORDS 8 AND 9 - DEVICE (ASCIZ) WORDS 10 AND 11 - FILE (ASCIZ) WORD 12 - DEC PPN WORD 13 - COUNT OF DESTINATIONS IN THIS RECORD (CALL IT N) WORDS 14 THROUGH 13+N*3 - THREE WORD DESTINATIONS (ASCIZ) WORD 14+N*3 - CHUNK COUNT WORDS 15+N*3 THROUGH M - CHUNKS IN THIS RECORD WORD M+1 - CHECKSUM, SAME AS WORD 2 CHUNK FORMAT: WORD 1: BITS(0-5) - BYTE POSITION BITS(6-11) - BYTE SIZE (ASSUMED TO BE 7) BITS(12-17) - END INDICATOR OF MESSAGE EPI = 4 EGI = 3 EMI = 2 ESI = 1 NONE = 0 BITS(18-35) - GARBAGE BITS 0-11 FORM A PROTOTYPE BYTE POINTER TO SOMEWHERE IN THE FIRST WORD OF TEXT WORD 2: - NUMBER OF WORDS IN MESSAGE TEXT - NUMBER OF CHARACTERS IN MESSAGE TEXT WORDS 3 THROUGH 3+WORD 2 -1 : MESSAGE TEXT (ASCII) CHECKSUM: THE CHECKSUM IS THE EXCLUSIVE-OR OF ALL THE WORDS IN THE RECORD (INCLUDING THE WORD COUNT) EXCEPT THE TWO CHECKSUM WORDS THEMSELVES. % %% MODULE GOX (MLIST,FSAVE,TIMER=EXTERNAL(SIX12)) = BEGIN REQUIRE COMMON.BLI; REQUIRE ENTRY.BLI; OWN WORDSREAD,WORDCNT,CHECKSUM,OLDCHECKSUM,RECORDTYPE, CHUNKPTR,RECORD,RECORDNUM,FIRDST,IOCODE,LASTCSM, LASTWRD,TCDERR,DSTERR,CHKERR; MAP REPBLK CURREP, CHUNK CHUNKPTR, JOURNALREC RECORD; MACRO READ(BYTEPOINTER,BYTECOUNT) = IF (IOCODE _ INBYT(.INCHNL,BYTECOUNT,BYTEPOINTER)) ISNOT OK THEN BEGIN ! WE HAVE NON-NORMAL RETURN IF .IOCODE IS -1 ! IS IT I/O ERROR? THEN BEGIN ! YES ERTEXT(35); ! PRINT MSG PRTSPC(.INCHNL) END; RETURN FALSE ! RETURN FALSE FOR BOTH ERROR AND EOF END$; COMMENT(GOERR); ! SUBROUTINE GOERR ! ========== ===== ! THIS ROUTINE WRITES ERROR MESSAGES RESULTING FROM ! ERRORS IN THE JOURNAL FILE. ! LAST MODIFIED ON 30 AUG 74 BY JG. ROUTINE GOERR (MSG) = BEGIN BIND MESSAGES = PLIT( %TCDERR% PLIT ASCIZ '***** TRANSACTION CODE GREATER THAN 175 CHARACTERS IN NEXT RECORD.', %DSTERR% PLIT ASCIZ '***** MORE THAN 100 DESTINATIONS IN NEXT RECORD.', %CHKERR% PLIT ASCIZ '***** CHUNK TEXT GREATER THAN 150 CHARACTERS.', %CSMERR% PLIT ASCIZ '***** CHECKSUM ERROR IN PREVIOUS RECORD.', %WRDERR% PLIT ASCIZ '***** WORD COUNT ERROR IN PREVIOUS RECORD.', %EOFERR% PLIT ASCIZ '***** UNEXPECTED EOF FROM INPUT FILE.', %BSTERR% PLIT ASCIZ '***** IMPROPER START OF RECORD. ATTEMPTING TO RESYNC.'), CHECKERR = PLIT ASCIZ 'CHECKSUM', WORDERR = PLIT ASCIZ 'WORD COUNT'; LOCAL TEXTPTR,NUM[5],LINEPTR,HDRPTR; MAP HEADER HDRPTR; HDRPTR _ .CURREP[PAGEHEADPTR]; ! GET POINTER TO HEADER BLOCK LINEPTR _ .HDRPTR[LINEOT]; ! AND THE OUTPUT LINE TEXTPTR _ (.MESSAGES[.MSG]); ! CHOOSE THE PROPER MESSAGE TEXT IF .MSG IS 3 %CSMERR% ! THIS MUST GO TO THE TTY ALSO THEN IF .LASTCSM ISNOT .RECORDNUM ! BUT ONLY ONCE THEN BEGIN LASTCSM _ .RECORDNUM; ! MAKE SURE IT IS ONLY ONCE CNVCHR(.RECORDNUM,NUM,10); TTYOTS(0,CHECKERR); ERTEXT(38); TTYOVR(NUM); TTYOTN(0,PLIT ASCII '.') END; IF .MSG IS 4 %WRDERR% ! SAME AS FOR CSMERR THEN IF .LASTWRD ISNOT .RECORDNUM THEN BEGIN LASTWRD _ .RECORDNUM; CNVCHR(.RECORDNUM,NUM,10); TTYOTS(0,WORDERR); ERTEXT(38); TTYOVR(NUM); TTYOTN(0,PLIT ASCII '.') END; IF NOT .CURREP[PRTSEL] AND .MSG ISNOT 5 %EOFERR%! SUPPRESS ALL BUT EOFERR FOR RECORDS NOT PRINTED THEN RETURN TRUE; IF .MSG LEQ 2 OR .MSG IS 5 ! SKIP A LINE IN THE OUTPUT FILE FOR THESE THEN IF PUTSKP() IS FALSE THEN RETURN FALSE; IF UPDATE(.LINEPTR,1,.TEXTPTR,0) IS FALSE ! MOVE TEXT TO LINE THEN RETURN FALSE; PUTLIN(.LINEPTR,CLEAR) ! AND PRINT IT END; COMMENT(READR); ! SUBROUTINE READR ! ========== ===== ! THIS ROUTINE READS THE FIRST PART OF EACH RECORD ! FROM THE JOURNAL FILE. IT FILLS IN THE RECORD ! BLOCK DIFFERENTLY, DEPENDING ON WHICH KIND OF ! RECORD IT IS. THE RECORD BLOCK FORMAT IS SUCH ! THAT WE HAVE ROOM FOR THE OUTPUT RECORD FIELDS ! AND THE FIRST 10 DESTINATIONS. THUS IF THE RECORD ! TYPE IS INPUT, THE UNUSED WORDS (35) ARE FILLED ! WITH THE TRANSACTION CODE. THIS IS WHY THE FIRST ! DESTINATION BLOCK IS KLUDGEY - IT REALLY SITS RIGHT ! AFTER THE RECORD ITSELF. BUT BY HAVING A POINTER ! TO IT IN THE RECORD BLOCK, WE DON'T HAVE TO ! SPECIAL CASE THE FIRST ONE. THE CHUNKS ARE ! NOT READ IN USING THIS ROUTINE ! LAST MODIFIED ON 3 SEP 74 BY JG. GLOBAL ROUTINE READR = BEGIN LOCAL CODECNT,DESTSREAD,DSTBLKPTR,EXTRA,SPACE[3]; LABEL READDESTS; MAP DESTBLOCK DSTBLKPTR; % WE START BY READING THE FIRST 9 WORDS OF THE RECORD, WHICH WE KNOW ARE CONSTANT LENGTH FIELDS FOR EACH TYPE % DO READ(WORDCNT,0) ! READ THE WORD COUNT WHILE .WORDCNT EQL 0; ! SKIP ZERO WORD COUNTS WHILE .WORDCNT NEQ -1 DO !IF NOT BOR (BEGIN OF RECORD) BEGIN GOERR(5); !COMPLAIN DO ! AND TRY TO RESYNC READ( WORDCNT,0) UNTIL .WORDCNT EQL -1; READ(WORDCNT,0) END; READ(WORDCNT,0); ! GET THE REAL WORD COUNT READ(RECORD[SEQNUM],7); ! READ 7 WORDS INTO THE RECORD BLOCK WORDSREAD _ 9; INCR I FROM RECORD[SEQNUM] TO RECORD[SEQNUM]+6 ! CHECKSUM THOSE 7 WORDS DO CHECKSUM _ .CHECKSUM XOR ..I; IF .RECORD[SEQNUM] IS 0 THEN BEGIN ! YES, IT'S AN INPUT RECORD % FOR INPUT RECORDS WE HAVE ONLY TO READ IN THE TRANSACTION CODE % RECORDTYPE _ XINPUT; ! SET THE TYPE CODECNT _ .RECORD[TCDSIZ]/5; ! CALCULATE TCDSIZ IN WORDS IF .RECORD[TCDSIZ] MOD 5 GTR 0 ! ROUND UPWARD THEN CODECNT _ .CODECNT+1; % HERE WE ASSUME THAT CODECNT IS NOT GREATER THAN 35 % EXTRA _ 0; IF .CODECNT GTR 35 ! BUT LET US INFORCE OUR ASSUMPTIONS THEN BEGIN EXTRA _ .CODECNT-35; ! THE EXTRA STUFF WILL BE THROWN AWAY CODECNT _ 35; RECORD[TCDSIZ] _ 175; ! DON'T FORGET THE LENGTH IN CHARS TCDERR _ TRUE ! GO WILL PRINT A MSG A THE RIGHT TIME END; READ(RECORD[TCDSTR],.CODECNT); INCR I FROM RECORD[TCDSTR] TO RECORD[TCDSTR]+.CODECNT-1 DO CHECKSUM _ .CHECKSUM XOR ..I;! NOW CHECKSUM THEM WORDSREAD _ .WORDSREAD+.CODECNT; ! UPDATE THE TOTAL READ IF .EXTRA GTR 0 THEN DECR I FROM .EXTRA-1 TO 0 ! READ AND THROW AWAY THE EXTRE WORDS DO BEGIN READ(SPACE,0); CHECKSUM _ .CHECKSUM XOR .SPACE; WORDSREAD _ .WORDSREAD+1 END END ELSE BEGIN ! ARRIVE HERE FOR OUTPUT RECORDS % FOR OUTPUT RECORDS WE MUST READ THE REST OF THE MPP FILE SPEC AND A VARIABLE NUMBER OF THREE WORD DESTINATIONS % RECORDTYPE _ XOUTPUT; ! SET THE TYPE READ(RECORD[MPPFIL],4); ! READ REST OF FIXED LENGTH PART OF RECORD INCR I FROM RECORD[MPPFIL] TO RECORD[MPPFIL]+3 DO CHECKSUM _ .CHECKSUM XOR ..I;! CHECKSUM THEM WORDSREAD _ .WORDSREAD+4; ! AND UPDATE THE COUNT EXTRA _ 0; IF .RECORD[DSTCNT] GTR 100 ! WE HAVE TO SET SOME LIMIT THEN BEGIN EXTRA _ .RECORD[DSTCNT]-100; RECORD[DSTCNT] _ 100; DSTERR _ TRUE ! REMIND GO END; DESTSREAD _ 0; ! HONEST, WE HAVEN'T READ ANY YET! DSTBLKPTR _ .RECORD[DESPTR]; ! GET PTR TO KLUDGEY FIRST DEST BLOCK READDESTS: REPEAT BEGIN ! LOOP UNTIL WE HAVE ALL OF THEM INCR I FROM 1 TO 10 ! THEY MUST BE READ IN 10 AT A TIME DO BEGIN DESTSREAD _ .DESTSREAD+1;! WE ARE GOING TO READ ONE IF .DESTSREAD GTR .RECORD[DSTCNT] ! BUT NOT IF WE HAVE THEM ALL THEN LEAVE READDESTS; READ(DSTBLKPTR[.I],3);! READ 3 WORD DESTINATION INCR J FROM DSTBLKPTR[.I] TO DSTBLKPTR[.I]+2 DO CHECKSUM _ .CHECKSUM XOR ..J;! CHECKSUM THE WORDS WORDSREAD _ .WORDSREAD+3 ! AND UPDATE THE COUNT END; ! FINISHED THESE 10 IF .DSTBLKPTR[DSTNEX] IS NULL ! ARE THERE ANY MORE DEST BLKS ON THE CHAIN? THEN IF (DSTBLKPTR[DSTNEX] _ ALLOC(DSTBLKSIZ)) IS NULL ! NO, GET ONE THEN RETURN FALSE; ! COUNDN'T GET ONE DSTBLKPTR _ .DSTBLKPTR[DSTNEX] ! SWITCH DEST BLOCKS END; ! LOOP UNTIL END OF DESTS OR WORLD IF .EXTRA GTR 0 THEN DECR I FROM .EXTRA-1 TO 0 ! READ AND THROW AWAY THE EXTRA DESTINATIONS DO BEGIN READ(SPACE,3); INCR J FROM SPACE TO SPACE+2 DO CHECKSUM _ .CHECKSUM XOR ..J; WORDSREAD _ .WORDSREAD+3 END END; % WE NOW HAVE READ ALL THE INFORMATION THAT CAN BE OF DIFFERENT FORMAT FOR EACH TYPE. WHAT REMAINS IS THE CHUNKS COUNT AND THE CHUNKS THEMSELVES, WHICH ARE READ IN FROM ANOTHER ROUTINE % READ(RECORD[CHKCNT],0); ! LAST ITEM BEFORE CHUNKS IS THE COUNT CHECKSUM _ .CHECKSUM XOR .RECORD[CHKCNT]; ! DON'T FORGET THE CHECKSUM! WORDSREAD _ .WORDSREAD+1; ! NOR THE COUNT TRUE ! NO ERRORS END; COMMENT(READC); ! SUBROUTINE READC ! ========== ===== ! THE ROUTINE READS CHUNK FROM THE JOURNAL FILE. ! IT IS INDEPENDENT OF THE RECORD TYPE. ! LAST MODIFIED ON 30 AUG 74 BY JG. GLOBAL ROUTINE READC = BEGIN LOCAL COUNT,EXTRA,SPACE; READ((.CHUNKPTR),2); ! GET BYTE POINTER AND COUNT WORDS CHECKSUM _ .CHECKSUM XOR ..CHUNKPTR; ! CHECKSUM THE FIRST CHECKSUM _ .CHECKSUM XOR .(.CHUNKPTR+1); ! AND THE SECOND WORDSREAD _ .WORDSREAD+2; ! MUST KEEP COUNT EVEN HERE EXTRA _ 0; IF .CHUNKPTR[MSGLNW] GTR 30 ! SHOULD NEVER HAPPEN, BUT ... THEN BEGIN EXTRA _ .CHUNKPTR[MSGLNW]-30; CHUNKPTR[MSGLNW] _ 30; CHUNKPTR[MSGLNC] _ 150; ! AGAIN, DON'T FORGET THE LENGTH IN CHARS CHKERR _ TRUE ! REMIND GO TO PRINT MSG END; READ(CHUNKPTR[MESAGE],.CHUNKPTR[MSGLNW]);! READ CHUNK TEXT INCR I FROM CHUNKPTR[MESAGE] TO CHUNKPTR[MESAGE]+.CHUNKPTR[MSGLNW]-1 DO CHECKSUM _ .CHECKSUM XOR ..I; ! CHECKSUM THE TEXT WORDSREAD _ .WORDSREAD+.CHUNKPTR[MSGLNW]; ! UPDATE COUNT BY LENGTH IN WORDS IF .EXTRA GTR 0 THEN DECR I FROM .EXTRA-1 TO 0 ! READ AND THROW WAWY REST OF MSG TEXT DO BEGIN READ(SPACE,0); CHECKSUM _ .CHECKSUM XOR .SPACE; WORDSREAD _ .WORDSREAD+1 END; TRUE ! NO PROBLEMS END; COMMENT(ACCEPT); ! SUBROUTINE ACCEPT ! ========== ====== ! THIS ROUTINE DETERMINES IF THE JOURNAL RECORD ! PRESENT IS TO BE INCLUDED IN THE CURRENT REPORT. ! IT CONCERNS ITSELF ONLY WITH THE CONSTRAINT ! BLOCKS AND THE IOBSEL FLAG. ! LAST MODIFIED ON 15 AUG 74 BY JG. GLOBAL ROUTINE ACCEPT = BEGIN IF .CURREP[IOBSEL] ISNOT XBOTH THEN BEGIN IF .CURREP[IOBSEL] IS XINPUT AND .RECORDTYPE ISNOT XINPUT THEN RETURN FALSE; IF .CURREP[IOBSEL] IS XOUTPUT AND .RECORDTYPE ISNOT XOUTPUT THEN RETURN FALSE END; CURREP[PRTSEL] _ TRUE END; COMMENT(PRINTR); ! SUBROUTINE PRINTR ! ========== ====== ! THE ROUTINE PRINTS THE SPECIFIED ! FIELDS OF THE JOURNAL RECORD. ! LAST MODIFIED ON 30 AUG 74 BY JG. GLOBAL ROUTINE PRINTR = BEGIN LOCAL NUM[5],HDRPTR,LINEPTR,COL,DESTSPERLINE, DESTSTHISBLOCK,DESTSPRINTED,DSTBLKPTR, ROOM,CHARSLEFT,TCDBPTR; LABEL PRINTDESTS; MAP DESTBLOCK DSTBLKPTR, HEADER HDRPTR, PRINTLINE LINEPTR; BIND ITYPE = PLIT ASCII 'I', OTYPE = PLIT ASCII 'O', COLON = PLIT ASCII ':', LEFTB = PLIT ASCII '[', COMMA = PLIT ASCII ',', RIGHTB = PLIT ASCII ']', RIGHTP = PLIT ASCII ')', LEFTP = PLIT ASCII '('; MACRO WRITE(LPTR,COLNUM,SPTR,CNT) = IF UPDATE(LPTR,COLNUM,SPTR,CNT) ISNOT OK THEN RETURN FALSE$; HDRPTR _ .CURREP[PAGEHEADPTR]; ! GET PTR TO HEADER BLOCK LINEPTR _ .HDRPTR[LINEP2]; ! GET PTR TO FIRST FIELD HEADER LINE IF .LINEPTR[LINECT] IS 0 ! IF THERE ARE NO FIELDS TO BE PRINTED AND (NOT .CURREP[TXTSEL] ! AND WE ARE NOT PRINING TEXTS OR .RECORD[CHKCNT] LEQ 0) ! OR THERE ARE NO TEXTS TO PRINT THEN RETURN TRUE; ! THEN WE DO NOTHING HERE LINEPTR _ .HDRPTR[LINEOT]; ! NOW GET PTR TO OUTPUT LINE IF PUTSKP() IS FALSE ! SKIP LINE BEFORE EACH TRANSACTION THEN RETURN FALSE; IF .CURREP[IOBSEL] IS XBOTH ! SET FIRST COLUMN TO "I" OR "O" THEN IF .RECORDTYPE IS XINPUT THEN (WRITE(.LINEPTR,1,ITYPE,1)) ELSE (WRITE(.LINEPTR,1,OTYPE,1)); IF .CURREP[SEQSEL] ISNOT 0 ! PRINT SEQUENCE NUMBERS THEN BEGIN CNVCHR(.RECORD[SEQNUM],NUM,10); ! CONVERT TO CHAR COL _ 8-.NUM[LANGTH]; ! WANT TO RIGHT JUSTIFY IN FIELD WRITE(.LINEPTR,.COL,NUM[STRING],.NUM[LANGTH]); IF .RECORDTYPE IS XOUTPUT ! MEANS PRINT OUT SEQ NUM THEN BEGIN CNVCHR(.RECORD[SEQNUM],NUM,10);! MAKE IT CHAR WRITE(.LINEPTR,0,LEFTP,0);! INCLOSE IT IN ('S WRITE(.LINEPTR,0,NUM[STRING],.NUM[LANGTH]); WRITE(.LINEPTR,0,RIGHTP,0) END END; IF .CURREP[DATSEL] ISNOT 0 ! PRINT DATES THEN BEGIN IF COLUMN(.LINEPTR,.CURREP[DATSEL]) ISNOT OK ! FIND RIGHT COLUMN THEN RETURN FALSE; LINEPTR[LINEBP] _ CNVBDT(.RECORD[DATBIN],.LINEPTR[LINEBP]);! SHOVE CONVERTED DATE IN LINE LINEPTR[LINECT] _ .LINEPTR[LINECT]+12; ! UPDATE CHAR CNT LINEPTR[LINEPO] _ .LINEPTR[LINEPO]+12 ! UPDATE POSITION END; IF .CURREP[TIMSEL] ISNOT 0 ! PRINT TIMES THEN BEGIN IF COLUMN(.LINEPTR,.CURREP[TIMSEL]) ISNOT OK ! FIND RIGHT COLUMN THEN RETURN FALSE; LINEPTR[LINEBP] _ CNVBTM(.RECORD[TIMBIN],.LINEPTR[LINEBP]);! SHOVE CONVERTED TIME IN LINE LINEPTR[LINECT] _ .LINEPTR[LINECT]+8; ! UPDATE CHAR CNT LINEPTR[LINEPO] _ .LINEPTR[LINEPO]+8 ! UPDATE POSITION END; IF .CURREP[SORSEL] ISNOT 0 AND .RECORDTYPE IS XINPUT ! PRINT SOURCE TERMINAL FOR OUTPUT RECORDS THEN BEGIN WRITE(.LINEPTR,.CURREP[SORSEL],RECORD[SORNAM],0) END; IF .CURREP[CODSEL] ISNOT 0 AND .RECORDTYPE IS XINPUT ! PRINT TRANSACTION CODES FOR INPUT RECORDS THEN BEGIN % SINCE IN READR WE ASSUMED THAT THE TRANSACTION CODE COULD BE UP TO 175 CHARS (35 WORDS), WE MUST INSURE THAT IT WILL NOT OVERFLOW THE PRINTLINE BUFFER (AND THE PRINTED LINE). IF IT WILL, WE MUST PRINT IT ON MORE THAN ONE LINE % IF .RECORD[TCDSIZ] LEQ LINESIZE-.CURREP[CODSEL]+1 THEN BEGIN ! IT WILL FIT ON ONE LINE WRITE(.LINEPTR,.CURREP[CODSEL],RECORD[TCDSTR],0) END ELSE BEGIN ! HERE WE MUST BREAK IT UP ROOM _ LINESIZE-.CURREP[CODSEL]+1;! CALCULATE HOW ROOM THERE IS ON LINE CHARSLEFT _ .RECORD[TCDSIZ]; ! CHARS LEFT TO PRINT WHILE .CHARSLEFT GTR .ROOM DO BEGIN TCDBPTR _ BYTOFF(RECORD[TCDSTR],.RECORD[TCDSIZ]-.CHARSLEFT); NOTE THAT PREVIOUS LINES GET WRITTEN HERE, SEE LATER COMMENT ABOUT DESTS WRITE(.LINEPTR,.CURREP[CODSEL],.TCDBPTR,.ROOM);! WRITE THIS PORTION CHARSLEFT _ .CHARSLEFT-.ROOM ! DECREMENT CHARSLEFT BY AMOUNT PRINTED END; IF .CHARSLEFT GTR 0 ! A FEW LAST CHARS TO PICK UP THEN BEGIN TCDBPTR _ BYTOFF(RECORD[TCDSTR],.RECORD[TCDSIZ]-.CHARSLEFT); WRITE(.LINEPTR,.CURREP[CODSEL],.TCDBPTR,.CHARSLEFT) END END END; IF .CURREP[MPPSEL] ISNOT 0 AND .RECORDTYPE IS XOUTPUT ! PRINT MPP'S FOR OUTPUT RECORDS THEN BEGIN IF COLUMN(.LINEPTR,.CURREP[MPPSEL]) ISNOT OK ! FIND RIGHT COLUMN THEN RETURN FALSE; IF .RECORD[MPPDEV] ISNOT NULL ! DEVICE MAY NOT BE THERE THEN BEGIN WRITE(.LINEPTR,0,RECORD[MPPDEV],0); WRITE(.LINEPTR,0,COLON,0) END; WRITE(.LINEPTR,0,RECORD[MPPFIL],0); WRITE(.LINEPTR,0,LEFTB,0); CNVCHR(.RECORD[MPPPPN],NUM,8); WRITE(.LINEPTR,0,NUM[STRING],0); WRITE(.LINEPTR,0,COMMA,0); CNVCHR(.RECORD[MPPPPN],NUM,8); WRITE(.LINEPTR,0,NUM[STRING],0); WRITE(.LINEPTR,0,RIGHTB,0) END; IF .CURREP[CLSSEL] ISNOT 0 AND .RECORDTYPE IS XOUTPUT ! PRINT MSG CLASS FOR OUTPUT RECORDS THEN BEGIN WRITE(.LINEPTR,.CURREP[CLSSEL],RECORD[MSGCLS],0) END; % SEE HOW SNEAKY WE ARE IN PRINTING THE DESTINATIONS! WHEN WE HAVE INSERTED ALL THE DESTINATIONS THAT WILL FIT ON ONE LINE, WE SIMPLY GO BACK TO THE FIRST COLUMN (CURREP[DSTSEL]) AND SHOVE MORE IN. UPDATE (WHICH CALLS COLUMN) WILL AUTOMATICALLY WRITE OUT EACH LINE WHEN THIS HAPPENS. NOTE HOWEVER THAT THE LAST LINE OF DESTINATIONS (WHICH MAY BE THE ONLY ONE) WILL ALWAYS BE LEFT FOR THE CALL TO PUTLIN FOLLOWING THIS SECTION % IF .CURREP[DSTSEL] ISNOT 0 AND .RECORDTYPE IS XOUTPUT ! PRINT DESTS FOR OUTPUT RECORDS THEN BEGIN DESTSPERLINE _ (133-.CURREP[DSTSEL])/14;! SQUEEZE AS MANY AS POSIBLE ON LINE DESTSTHISBLOCK _ 0; ! COUNTS UP TO 10 REPEATEDLY DESTSPRINTED _ 1; ! MUST START AT ONE TO WORK RIGHT DSTBLKPTR _ .RECORD[DESPTR]; ! GET PTR TO FIRST DEST BLOCK PRINTDESTS: REPEAT INCR I FROM 1 TO .DESTSPERLINE ! LOOP BY LINE DO BEGIN IF .DESTSPRINTED GTR .RECORD[DSTCNT] ! THATS ALL! THEN LEAVE PRINTDESTS; IF .DESTSTHISBLOCK IS 10 ! MUST GET NEW BLOCK THEN DSTBLKPTR _ .DSTBLKPTR[DSTNEX]; WRITE(.LINEPTR,.CURREP[DSTSEL]+(.I-1)*14,DSTBLKPTR[.DESTSPRINTED],0); DESTSTHISBLOCK _ .DESTSTHISBLOCK+1;! INCREMENT THIS BLOCK DESTSPRINTED _ .DESTSPRINTED+1 ! AND TOTAL PRINTED END END; IF .LINEPTR[LINEPO] GTR 2 ! I.E., THERE IS SOMETHING OTHER THAN "I" OR "O" THEN PUTLIN(.LINEPTR,CLEAR) ! THEN PRINT IT ELSE TRUE END; COMMENT(PRINTC); ! SUBROUTINE PRINTC ! ========== ====== ! THIS ROUTINE PRINTS CHUNKS. ! LAST MODIFIED ON 23 AUG 74 BY JG. GLOBAL ROUTINE PRINTC = BEGIN LOCAL BYTPTR,HDRPTR,LINEPTR; BIND NONE = PLIT ASCIZ '(NONE)', ESI = PLIT ASCIZ 'ESI', EMI = PLIT ASCIZ 'EMI', EGI = PLIT ASCIZ 'EGI', EPI = PLIT ASCIZ 'EPI'; MAP HEADER HDRPTR; HDRPTR _ .CURREP[PAGEHEADPTR]; ! GET HEADER PTR LINEPTR _ .HDRPTR[LINEOT]; ! TO FIND THE LINE BYTPTR _ CASE .CHUNKPTR[ENDIND] OF ! GET BYTE PTR TO PROPER END INDICATOR SET NONE; ESI; EMI; EGI; EPI; TES; IF UPDATE(.LINEPTR,17,.BYTPTR,0) IS FALSE ! PRINT THE END INDICATOR THEN RETURN FALSE; BYTPTR<24,12> _ .CHUNKPTR[PROBYT]; ! PROTOTYPE BYTE POPINTER BYTPTR _ CHUNKPTR[MESAGE]; ! IS AN INCREMENT TYPE PTR % WE MUST MAKE SURE THAT THE CHUNK TEXT, WHICH COULD BE UP TO 150 CHARS (30 WORDS), DOES NOT OVERFLOW THE PRINTLINE BUFFER AND THE PRINTED LINE ITSELF % IF .CHUNKPTR[MSGLNC] LEQ 108 THEN BEGIN ! WILL FIT ON ONE LINE IF UPDATE(.LINEPTR,25,.BYTPTR,.CHUNKPTR[MSGLNC]) IS FALSE THEN RETURN FALSE END ELSE BEGIN ! WELL IT MUST FIT ON TWO IF UPDATE(.LINEPTR,25,.BYTPTR,108) IS FALSE THEN RETURN FALSE; BYTPTR _ ADDBYT(.BYTPTR,108); IF UPDATE(.LINEPTR,25,.BYTPTR,.CHUNKPTR[MSGLNC]-108) IS FALSE THEN RETURN FALSE END; IF PUTLIN(.LINEPTR,CLEAR) IS FALSE ! ACTUALLY WRITE THE LINE HERE THEN RETURN FALSE; TRUE ! EVERYTHING WENT OK END; COMMENT(GO); ! SUBROUTINE GO ! ========== == ! THIS ROUTINE IS THE MAIN CONTROLER FOR THE ! GENERATION OF REPORTS. THE "SORT" AND "TALLY" ! OPTIONS HAVE NOT BEEN IMPLEMENTED. ! LAST MODIFIED ON 29 AUG 74 BY JG. GLOBAL ROUTINE GO = BEGIN LOCAL TEMP,ENDCHECKSUM; LABEL JOURNALREAD,FINAL,EOFERR; ROUTINE TALLY1 = TRUE; ! DUMMY ROUTINE THAT TALLIES STATISTICS ROUTINE TALLY2 = TRUE; ! DUMMY ROUTINE THAT PRINTS RESULTS OF TALLY1 IF .INCHNL IS -1 ! MUST HAVE AN INPUT FILE THEN BEGIN TTYOTS(0,PLIT ASCIZ 'INPUT'); ERTEXT(34); IF SEMI() THEN ERTEXT(4); RETURN FALSE END; IF .OTCHNL IS -1 ! MUST HAVE AN OUTPUT FILE THEN BEGIN TTYOTS(0,PLIT ASCIZ 'OUTPUT'); ERTEXT(34); IF SEMI() THEN ERTEXT(4); RETURN FALSE END; IF .FIRREP IS NULL ! MUST HAVE REPORTS TO DO, ALSO! THEN BEGIN ERTEXT(36); IF SEMI() THEN ERTEXT(4); RETURN FALSE END; CNVBDT(DATE(),CHRDAT); ! GET TODAY'S DATE CNVBTM(MSTIME(),CHRTIM); ! GET NOW'S TIME CURREP _ .FIRREP; WHILE .CURREP ISNOT NULL ! LOOP FOR EVERY REPORT DO BEGIN IF MAKHDR() IS FALSE ! MAKE A PAGE HEADER THEN RETURN FALSE; IF PUTPAG(.CURREP[PAGEHEADPTR]) IS FALSE ! AND PRINT IT THEN RETURN FALSE; CURREP _ .CURREP[NEXTREPORT] ! GO TO NEXT REPORT END; IF (RECORD _ ALLOC(JRNRECSIZ)) IS NULL ! ALLOCATE WORKING STORAGE THEN RETURN FALSE; IF (CHUNKPTR _ ALLOC(CHUNKSIZ)) IS NULL ! " " " THEN RETURN FALSE; IF (FIRDST _ ALLOC(DSTBLKSIZ)) IS NULL ! " " " THEN RETURN FALSE; RECORDNUM _ 1; LASTCSM _ 0; LASTWRD _ 0; JOURNALREAD: REPEAT BEGIN ! LOOP UNTIL EOF OR I/O ERROR RECORD[DESPTR] _ RECORD[DESPTR]+1; ! INITIALZE DESPTR IN CASE IT IS OUTPUT RECORD RECORD[DESPTR]+1 _ .FIRDST; TCDERR _ DSTERR _ CHKERR _ FALSE; ! CLEAR ANY ERROR FLAGS FROM READR OR READC WORDSREAD _ 0; ! JUST STARTING THIS RECORD IF READR() IS FALSE ! LEAVE ONLY ON EOF OR ERROR THEN LEAVE JOURNALREAD; CURREP _ .FIRREP; WHILE .CURREP ISNOT NULL ! LOOP FOR EVERY REPORT DO BEGIN CURREP[PRTSEL] _ FALSE; ! RESET RECORD PRINT SELECT IF ACCEPT() ! SEE IT WE USE IT THEN BEGIN ! PRINT AND TALLY IF .TCDERR THEN IF GOERR(0) IS FALSE THEN LEAVE JOURNALREAD; IF .DSTERR THEN IF GOERR(1) IS FALSE THEN LEAVE JOURNALREAD; IF PRINTR() IS FALSE THEN LEAVE JOURNALREAD; IF .CURREP[TALLYPTR] ISNOT NULL THEN TALLY1() END; CURREP _ .CURREP[NEXTREPORT] ! PROCESS RECORD FOR REST OF REPORTS END; DECR I FROM .RECORD[CHKCNT]-1 TO 0 ! NOW WE TAKE CARE OF THE CHUNKS DO BEGIN IF READC() IS FALSE ! READ A CHUNK THEN LEAVE JOURNALREAD; CURREP _ .FIRREP; WHILE .CURREP ISNOT NULL ! FOR EVERY REPORT DO BEGIN ! IF ITS OK THEN PRINT IT IF .CHKERR AND .CURREP[PRTSEL] THEN IF GOERR(2) IS FALSE THEN LEAVE JOURNALREAD; IF .CURREP[PRTSEL] AND .CURREP[TXTSEL] THEN IF PRINTC() IS FALSE THEN LEAVE JOURNALREAD; CURREP _ .CURREP[NEXTREPORT] ! NEXT REPORT END END; IF (IOCODE _ INBYT(.INCHNL,0,ENDCHECKSUM)) ISNOT OK ! READ FINAL CHECKSUM THEN BEGIN IF .IOCODE IS -1 ! USUAL ERROR CHECKING THEN BEGIN ERTEXT(35); PRTSPC(.INCHNL) END ELSE ERTEXT(37); LEAVE JOURNALREAD END; WORDSREAD _ .WORDSREAD+1; ! LAST WORD TO COUNT ! IF .OLDCHECKSUM NEQ .CHECKSUM OR .OLDCHECKSUM NEQ .ENDCHECKSUM ! MUST BE CHECKSUM ERROR SOMEWHERE ! THEN BEGIN ! CURREP _ .FIRREP; ! WHILE .CURREP ISNOT NULL ! DO BEGIN ! IF GOERR(3) IS FALSE ! THEN LEAVE JOURNALREAD; ! CURREP _ .CURREP[NEXTREPORT] ! END ! END; IF .WORDSREAD NEQ .WORDCNT ! MUST BE A WORD MISCOUNT SOMEWHERE THEN BEGIN CURREP _ .FIRREP; WHILE .CURREP ISNOT NULL DO BEGIN IF GOERR(4) IS FALSE THEN LEAVE JOURNALREAD; CURREP _ .CURREP[NEXTREPORT] END END; RECORDNUM _ .RECORDNUM+1 ! INCREMENT RECORD COUNT END; % WE LEFT THE JOURNALREAD LOOP ON INPUT FILE EOF OR I/O ERROR. IF THERE WAS AN I/O ERROR THE MESSAGE HAS ALREADY BEEN GIVEN. HERE WE WE CHECK FOR UNEXPEXTED EOF, WHICH PROBABLY MEANS SOME FORM OF INTERNAL INCONSISTENCY IN THE JOURNAL FILE % EOFERR: IF .WORDSREAD ISNOT 0 AND .IOCODE IS 0 THEN BEGIN ERTEXT(37); CURREP _ .FIRREP; WHILE .CURREP ISNOT NULL DO BEGIN IF GOERR(5) IS FALSE THEN LEAVE EOFERR; CURREP _ .CURREP[NEXTREPORT] END END; CLOFIL(.INCHNL,CLEAR); ! CLOSE INPUT FILE CLOFIL(.OTCHNL,CLEAR); ! CLOSE THE OUTPUT FILE INIT(NOCLEAR); ! CLEAR EVERYTHING BUT NO RESET UUO IF SEMI() THEN ERTEXT(4) ! SCAN TO ; FOR END OF COMMAND END; END ELUDOM; ! END OF GO COMMAND ...