Google
 

Trailing-Edge - PDP-10 Archives - AP-D471B-SB_1978 - go.bli
There are no other files named go.bli in the archive.
!***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:
		<LH> - NUMBER OF WORDS IN MESSAGE TEXT
		<RH> - NUMBER OF CHARACTERS IN MESSAGE TEXT
	WORDS 3 THROUGH 3+WORD 2 <LH> -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])<FIRSTINCR>;		! 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]<WORDINCR>,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]<RH> 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]<WORDINCR>,.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]<WORDINCR>,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]<WORDINCR>,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<WORDINCR>,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)<WORDINCR>,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]<WORDINCR>,.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<FIRSTINCR>,1))
		ELSE (WRITE(.LINEPTR,1,OTYPE<FIRSTINCR>,1));

	IF .CURREP[SEQSEL] ISNOT 0			! PRINT SEQUENCE NUMBERS
	THEN BEGIN
		CNVCHR(.RECORD[SEQNUM]<LH>,NUM,10);	! CONVERT TO CHAR
		COL _ 8-.NUM[LANGTH];			! WANT TO RIGHT JUSTIFY IN FIELD
		WRITE(.LINEPTR,.COL,NUM[STRING]<FIRSTINCR>,.NUM[LANGTH]);
		IF .RECORDTYPE IS XOUTPUT		! MEANS PRINT OUT SEQ NUM
		THEN BEGIN
			CNVCHR(.RECORD[SEQNUM]<RH>,NUM,10);! MAKE IT CHAR
			WRITE(.LINEPTR,0,LEFTP<FIRSTINCR>,0);! INCLOSE IT IN ('S
			WRITE(.LINEPTR,0,NUM[STRING]<FIRSTINCR>,.NUM[LANGTH]);
			WRITE(.LINEPTR,0,RIGHTP<FIRSTINCR>,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]<FIRSTINCR>,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]<FIRSTINCR>,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]<FIRSTINCR>,0);
			WRITE(.LINEPTR,0,COLON<FIRSTINCR>,0)
		END;
		WRITE(.LINEPTR,0,RECORD[MPPFIL]<FIRSTINCR>,0);
		WRITE(.LINEPTR,0,LEFTB<FIRSTINCR>,0);
		CNVCHR(.RECORD[MPPPPN]<LH>,NUM,8);
		WRITE(.LINEPTR,0,NUM[STRING]<FIRSTINCR>,0);
		WRITE(.LINEPTR,0,COMMA<FIRSTINCR>,0);
		CNVCHR(.RECORD[MPPPPN]<RH>,NUM,8);
		WRITE(.LINEPTR,0,NUM[STRING]<FIRSTINCR>,0);
		WRITE(.LINEPTR,0,RIGHTB<FIRSTINCR>,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]<FIRSTINCR>,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]<FIRSTINCR>,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<FIRSTINCR>;
			ESI<FIRSTINCR>;
			EMI<FIRSTINCR>;
			EGI<FIRSTINCR>;
			EPI<FIRSTINCR>;
		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<RH> _ 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<FIRSTINCR>);		! GET TODAY'S DATE
	CNVBTM(MSTIME(),CHRTIM<FIRSTINCR>);		! 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 ...