Google
 

Trailing-Edge - PDP-10 Archives - BB-FP64A-SB_1986 - 10,7/decnet/dntatl/dntatl.mac
There are 9 other files named dntatl.mac in the archive. Click here to see a list.
;DSKB:DNTATL.MAC[10,44,S] Edit by -TL- [10,44] on 15-May-85 at 14:54:45
;Support the ethernet
;DSKB:DNTATL.MAC[10,44,S] Edit by -TL- [10,44] on 09-May-85 at 13:59:16
;Format ROUTER control messages,add /OCTAL/AREA
;DSKB:DNTATL.MAC[10,44,S] Edit by -TL- [10,44] on 07-May-85 at 11:07:19
;Fix SWIL conditionals.  Make local messages use the right Byte Pointer.
; UPD ID= 13, SNARK:<6.1.UTILITIES>DNTATL.MAC.28,  22-Jun-84 13:58:25 by GROSSMAN
;Increase DECnet buffer size to prevent program from blowing up on Ethernet
; packets.
;SNARK:<6.1.UTILITIES>DNTATL.MAC.14  2-Apr-84 17:37:04, Edit by NICHOLS
;Add input and output circuit typeout
;WORK:<NICHOLS>DNTATL.MAC.56  1-Feb-84 21:16:06, Edit by NICHOLS
;Fix date/time typout
;WORK:<NICHOLS>DNTATL.MAC.23 24-Jan-84 15:59:49, Edit by NICHOLS
;Add code to handle Phase IV router header and its pad byte
;SNARK:<6.1.UTILITIES>DNTATL.MAC.4 20-Jan-84 11:36:24, Edit by NICHOLS
;Add Phase IV NI routing for ROUTER data messages.
	TITLE	DNTATL - Format a DECnet-20 Trace
	SUBTTL	W. G. Nichols
	SALL
	.DIRECTIVE FLBLST

	OPDEF OPEN  [050000,,0]	;GET AROUND KEVIN'S BAD MACSYM
	OPDEF CLOSE [070000,,0] ;DITTO

DEFINE XP(SYM,VAL),<SYM==:VAL>

	XP FTLIST,0		;NON-0 TO DISABLE XLISTS
	XP FTSWIL,1		;NON-0 FOR TOPS-10 SWIL

	XP FTOPS10,1		;NON-0 FOR TOPS-10 VERSION
	XP FTOPS20,0		;NON-0 FOR TOPS-20 VERSION

	XP NDSPL,^D9		;NODES PER OUTPUT LINE OF ROUTING MSG

IFN FTOPS10,<
	SEARCH D36PAR,MACTEN,UUOSYM,MACSYM
IFN FTSWIL,<
	SEARCH	SWIL
	.REQUEST REL:SWIL
>; END IFN FTSWIL
IFE FTSWIL,<
	SEARCH	SCNMAC
	.REQUEST REL:SCAN
>; END IFE FTSWIL
>; END IFN FTOPS10
IFN FTOPS20,<
	SEARCH D36PAR,MONSYM,MACSYM,SCNMAC
	.REQUEST REL:SCAN
>; END IFN FTOPS20

	PRGID='DNTATL'		;NAME OF THIS PROGRAM
	PRGABR='DNT'		;3 CHR ABBREVIATION USED FOR PROG.

	DNTWHO==0
	DNTVER==1		;MAJOR VERSION
	DNTMIN==0		;MINOR VERSION
	DNTEDT==5		;EDIT NUMBER

	HSGAD==600000		;STARTING ADDR OF HISEG

	TWOSEG	HSGAD		;WE'LL HAVE A SHARABLE HI-SEG
;Note that these BEGSTRs are copied in MSGTRC, the program which
;makes the trace file.

FTSHOW==0

BEGSTR FH			;File Header
	WORD	LNG		;Length of this header
	FIELD	FLG,9		;Flags to indicate what kind of entry
	FIELD	TYP,9		;Entry Type
		XP TYP.FH,1	;  Entry type of header record
	HWORD	MGL		;Length of a message block
	WORD	UPT		;UPTIME corresponding to UDT below
	WORD	UDT		;Universal Date/Time corresp to UPTIME
	WORD	PVR		;Trace program version number (loc 137)
	WORD	MVR		;Monitor Version (location 137)
	WORD	CFG,5		;CONFIG string from this monitor
ENDSTR

BEGSTR MH			;Message Header
	WORD	LNG		;Length of the entire entry
	FIELD	FLG,6		;Flags to indicate what kind of entry
	FIELD	IOL,3		;Input, output or local
		XP IOL.IN,1	;Input (avoid zero for error detection)
		XP IOL.OT,2	;Output message
		XP IOL.LO,3	;Local message
	FIELD	TYP,9		;Entry Type
		XP TYP.MH,2	;  Entry type of message record
	HWORD	LST		;Cumulative number of messages lost
	WORD	UPT		;UPTIME as of entry (reliable time stamp)
	WORD	UDT		;Universal date/time (readable time stamp)
	WORD	OMB		;Original MB pointer
	WORD	ILN		;Input line ID (or zero if none)
	WORD	OLN		;Output line ID (or zero if none)
ENDSTR
;The format of an ACKNUM field

;This structure is expected to be used to pull apart a value held
;in a register.

BEGSTR AK
	FILLER 20		;ONLY THE RIGHTMOST 16 BITS COUNT
	FIELD PNT, 1		;FLAG SET IF FIELD IS PRESENT
	FIELD QAL, 3		;QUALIFIER:
		AK$QAK==0	;  0 IS ACK
		AK$QNK==1	;  1 IS NAK, 2 & 3 ARE RESERVED
		AK$CAK==2	;  2 IS CROSS-SUB CHANNEL ACK
		AK$CNK==3	;  3 IS CROSS-SUB CHANNEL NAK
	FIELD NUM, 12		;THE ACK NUMBER, WE KNOW THIS IS RT-JUSTIFIED
ENDSTR				; NEGATIVE IF HIGH BIT OF BYTE IS SET
				; SEE LOADE MACRO (E IS AS IN HRRE)


;This structure is expected to be used to pull apart a value held
;in a register.

BEGSTR LS			;THE LSFLAGS FIELD OF A LINK SERVICE MESSAGE
	FILLER 28		;ONLY THE RIGHTMOST 8 BITS COUNT
	FIELD ZRO,4		;MUST BE ZERO
	FIELD INT,2		;INTERPRETATION
		LS.INR==0	;NORMAL DATA REQUEST
		LS.IOT==1	;OTHER DATA REQUEST (2 & 3 RESERVED)
	FIELD MOD,2		;THE ON/OFF INDICATOR
		LS.MNC==0	;NO CHANGE, CODE USES JUMPE
		LS.MOF==1	;TURN SUBLINK OFF (IGNORED ON "OTHER")
		LS.MON==2	;TURN SUBLINK ON  (IGNORED ON "OTHER")
		LS.MRS==3	;RESERVED
ENDSTR


;This structure is expected to be used to pull apart a value held
;in a register.

BEGSTR SV			;THE SERVICES FIELD OF A CI OR CC MSG
	FIELD FL1,32		;FILLER 1, CHECK FOR ALL ZEROES
	FIELD OPT,2		;THE FLOW CONTROL OPTION, SEE FCM.xx
	FIELD FL2,2		;FILLER 2, CHECK FOR BEING "01"
		SV$FL2==1	;MAGIC NUMBER THAT SVFL2 MUST BE
ENDSTR
	SUBTTL	Macros

DEFINE SMEAR(ac,start,end,value),<
	MOVX ac,value
	MOVEM ac,start
	MOVE ac,[XWD start,start+1]
	BLT ac,end
>

DEFINE	$LIST,<	LIST
>
DEFINE	$XLIST,<IFE FTLIST,<XLIST
>>

	$LIST


DEFINE	VRSN. (PROG),<
	BYTE  (3) PROG'WHO (9) PROG'VER (6) PROG'MIN (18) PROG'EDT
>
	.JBVER=137		;JOBDAT LOC FOR VERSION NUMBER
	LOC	.JBVER
	VRSN.	DNT
	RELOC
	SUBTTL	Accumulator Definitions

	FLAG=0			;FLAGS, CONTINUOUS THROUGH ALL CALLS
				;ZEROED BEFORE EACH CALL TO .TSCAN
				;SEE BIT DEFINITIONS BELOW

	T1=1			;WORK... T1 AND T2 MUST BE 1 & 2
	T2=2
	T3=3			;AND T3 AND T4 MUST BE 3 & 4
	T4=4			;FOR COMPATIBILITY WITH SCAN & WILD
	T5=5
	T6=6			;T6 IS USED AS INDEX FOR MSD BYTE PTRS

	N=7			;SAME AS IN SCAN
	C=10			;SAME AS IN SCAN

	MBO=11			;OFFSET TO SUBTRACT FROM PTRS INTO MSG BLK
	MS=12			;POINTER TO CURRENT MSD IN MSG BLK

	P1=13			;PRESERVED ACs
	P2=14

;	??=15

	CX=16			;SUPER-TEMP FOR MACROS
	.SAC==CX		; ALTERNATE NAME FOR CX FOR SOME MACROS
	P=17			;STACK POINTER
	SUBTTL	Compile-Time Variables

	OPDEF	CALL	[PUSHJ	P,]
	OPDEF	RET	[POPJ	P,]
	OPDEF	RETSKP	[JRST	RSKP]
	OPDEF	CALLRET	[JRST]

;CHANNEL ASSIGNMENTS

XP	F.FIN,1			;CHANNEL FOR INPUT FILE.
XP	F.FOUT,2		;CHANNEL FOR OUTPUT FILE.

;DEFAULT DEVICE NAMES

XP	INDFT,'DSK   '		;DEFAULT INPUT DEVICE
XP	OUTDFT,'DSK   '		;DEFAULT OUTPUT DEVICE.

;Block lengths
XP	%XPBSZ,^D2000		;MAX BUFFER SIZE DECnet USES

XP	LN$PDL,^D100		;LENGTH OF PUSH DOWN LIST
XP	FOPLEN,^D7		;LENGTH OF NON-PRIV FILOP. BLOCK
XP	PTHLNG,^D9		;LENGTH OF A PATH BLOCK
XP	LN$ENT,^D9		;LENGTH OF EXTENDED ENTER BLOCK
XP	LN$LKP,^D9		;LENGTH OF EXTENDED LOOKUP BLOCK

; MSG$ is followed by the three letter error code, one of  the
; indicators  ERR,  WRN, or INF for which class of message, an
; optional S to save all accumulators, and the  message  text.
; it  will  force  out any TTY buffers, issue the file name if
; not yet done, then issue the message correctly prefixed.

DEFINE	MSG$(code$,level$,savef$,text$),<
	$XLIST
E..'code$:!
IFIDN <savef$><S>,<	PUSH P,T1
			PUSH P,T2
			PUSH P,T3
			PUSH P,T4>
	LEVL$$=="%"
IFIDN <level$><ERR>,<LEVL$$=="?">
	MOVE	T1,[XWD PRGABR,''code$'']
	MOVE	T2, [XWD LEVL$$,[ASCIZ "text$"] ]
	$LIST
	CALL	.ERMSG##	;;TYPE THE ERROR MESSAGE.
	$XLIST
IFIDN <savef$><S>,<	POP P,T4
			POP P,T3
			POP P,T2
			POP P,T1>
	$LIST
>

DEFINE	ERROR(code,text,label),<
  IFNB <label>,<JRST [>
  IFB  <label>,<CALL [>
		SKIPE TYPFIL	;;SKIP IF NO OUTPUT FILE BEING USED
		  OUT F.FOUT,	;;SYNCH ERROR MSG IF OUT DEV IS TTY
		PUSH P,TYPFIL
		SETZM TYPFIL	;;DIRECT .TCHAR OUTPUT TO TTY NOW
		MSG$(code,ERR,S,<text>)
		CALL .TCRLF##
		POP P,TYPFIL
  IFNB <label>,<JRST label>
  IFB  <label>,<RET>
		]
>

DEFINE FMTERR(text,label),<
  IFNB <label>,<JRST [>
  IFB  <label>,<CALL [>
		CALL .TCRLF##
		WRTSTR <?Format error: text>
  IFNB <label>,<JRST label>
  IFB  <label>,<RET>
		]
>
;Macros for writing to the output file

DEFINE WRTSTR(string),<
	CALL [	JSP T1,.TSTRG##
		ASCIZ `string`]
>
	SUBTTL	General Impure Storage

;Locations which are set at start-up time and never cleared.

	RELOC			;INTO THE LOWSEG

;The stack:

PLIST:	BLOCK	LN$PDL+1

CCLF1:	BLOCK	1		;1 IF CCL ENTRY, 0 IF NORMAL
INICOR:	BLOCK	1		;SIZE OF CORE BEFORE ANY EXPANSION
INIFF:	BLOCK	1		;INITIAL SETTING OF .JBFF
TYPFIL:	BLOCK	1		;NON-ZERO IF TYPOUT IS TO TYPE TO FILE
	SUBTTL	Not-File-Specific Switch Definitions

SCMFWA:!			;START OF FS.NFS SWITCHES CLEARED TO -1
SCNLLA:	BLOCK 1			;PUT CHOSEN LOCAL LINK ADDRESS HERE
SCNRLA:	BLOCK 1			;PUT CHOSEN REMOTE LINK ADDRESS HERE
SCNNOD:	BLOCK 1			;PUT CHOSEN NODE ADDRESS HERE
SCNARE:	BLOCK 1			;PUT CHOSEN AREA NUMBER HERE
SCNOCT:	BLOCK	1		;=1 IF /OCTAL
SCNRTR:	BLOCK 1			;NON-ZERO TO INCLUDE ROUTER CONTROL MSGS
SCNDAT: BLOCK 1			;NON-ZERO TO INCLUDE DATA PORTION OF MSGS
SCMLWA==.-1

	SCNLEN==.FXLEN		;LENGTH OF A SCAN SPEC INCLUDING LOCAL LOAD

SCNFWA:!			;START OF SCAN AREA CLEARED TO 0
SCNIN:	BLOCK	SCNLEN		;PLACE TO PUT INPUT SPEC
SCNOUT:	BLOCK	SCNLEN		;PLACE TO PUT OUTPUT SPEC

;Trace Record Collection Areas

RHDRLN:	BLOCK	1		;LENGTH OF ROUTER HDR ON THIS MSG
				; -1 IF MSG IS ROUTER CONTROL
LSTCNT:	BLOCK	1		;LAST LOST COUNT WE SAW (MHLST FIELD)
SKPCNT:	BLOCK	1		;NUMBER OF RECORDS SKIPPED BY CHKMSG

FILHDR:	BLOCK	FH.LEN		;BLOCK TO HOLD FILE HEADER RECORD
MSGHDR:	BLOCK	MH.LEN		;BLOCK TO HOLD MESSAGE HEADER RECORD
MSGBLK:	BLOCK	MB.LEN		;BLOCK TO HOLD MESSAGE BLOCK
USERDA:	BLOCK	<%XPBSZ+3>/4	;USER DATA GOES HERE

SEQBFR:	BLOCK	<%XPBSZ+3>/4	;BUILD A SEQUENTIAL MSG HERE
SEQPTR:	BLOCK	1		;BYTE PTR INTO SEQBFR
SEQCNT:	BLOCK	1		;LENGTH OF REST OF SEQUENTIAL MESSAGE
SEQLEN:	BLOCK	1		;INITIAL LENGTH OF SEQUENTIAL MESSAGE

CHKOFF:	BLOCK	1		;CHKMSG'S OFFSET TO START OF RTR HDR

;Input I/O areas

FOPLKP:	BLOCK	FOPLEN		;ARG BLK FOR FILOP. LOOKUP
OPNIN=FOPLKP+.FOIOS		;ALLOW OLD NAMES

LKPBLK:	BLOCK	LN$LKP+1	;LOOKUP BLK FOR INPUT FILE.
LKPBLE=.-1

LKPPTH:	BLOCK	PTHLNG		;PATH BLK FOR LKPBLK
LKPPTE=.-1			;LIMIT OF BLT SMEARING
				;INPUT BUFF RING HDR IS IN .WILD
FOPFIL:	BLOCK	2
	FOPFLN==.-FOPFIL

SPCFIL:	BLOCK	.FOFMX+1
	SPCLEN==.-SPCFIL
;Output I/O areas

IFN FTOPS20,<
	.FOIOS==1		;OUTPUT BLOCK IN FILOP BLOCK
	.FOBRH==3		;BUFFER RING HEADERS IN FILOP BLOCK
	.BFPTR==1		;BUFFER RING HEADER POINTER WORD
	.BFCTR==2		;BUFFER RING HEADER COUNTER WORD
	IO.ERR==740000		;IO ERRORS MASK
	IO.EOF==20000		;END OF FILE ERROR FLAG
	.IOASC==0		;ASCIZ MODE I/O
	.IOBIN==14		;BINARY MODE I/O
>;END IFN FTOPS20

FOPENT:	BLOCK	FOPLEN		;ARG BLK FOR FILOP. ENTER
OPNOUT=FOPENT+.FOIOS		;ALLOW USE OF OLD NAMES

ENTBLK:	BLOCK	LN$ENT+1	;ENTER BLOCK FOR OUTPUT FILE.
ENTBLE=.-1

ENTPTH:	BLOCK	PTHLNG		;PATH BLOCK FOR .STOPB AND ENTBLK
ENTPTE=.-1			;LIMIT OF BLT SMEARING

H.FIN:	BLOCK	3		;BUFFER HEADER FOR INPUT.
H.FOUT:	BLOCK	3		;BUFFER HEADER FOR OUTPUT.

SCNLWA==.-1			;LAST OF WORK AREA CLEARED TO 0

;Now put the rest in the High Segment

	RELOC
	SUBTTL	SCAN Switch Tables.

DEFINE ND(name,value),<IFNDEF name,name=:value> ;DM NEEDS THIS

;Define the defaults for switches:
;	First arg is 3-chr abbrieviation used for this switch.
;	Second arg is maximum allowed value.
;	Third arg is absent default (AD.xxx)
;		(not used by SCAN, for application use only).
;	Fourth arg is present default (PD.xxx)
;		(used by SCAN unless FS.VRQ specified)

;	Name	Max	Absent	Present
;	xxx	MX.xxx	AD.xxx	PD.xxx
;	----	------	------	-------
DM	LLA,	  177777, 0,	0	;/LLA (LOCAL LINK ADDRESS)    
DM	RLA,	  177777, 0,	0	;/RLA (REMOTE LINK ADDRESS)    
DM	NOD,	     377, 0,	0	;/NODE 
DM	ARE,	      77, 0,	0	;/AREA (Area number for /NODE)
; See SCNMAC.MAC for definition of macros used here.
;
; An asterisk before a switch name in this  table  means  that
; this   switch  has  abbreviation  priority  over  any  other
; switches in  the  list.
;
;REMEMBER to update HLPSTR when updating the switches

DEFINE	SWTCHS,<
	$XLIST
SP LLA,SCNLLA,.SWOCT##,LLA,FS.NFS!FS.VRQ
SP RLA,SCNRLA,.SWOCT##,RLA,FS.NFS!FS.VRQ
SP NODE,SCNNOD,.SWDEC##,NOD,FS.NFS!FS.VRQ
SP AREA,SCNARE,.SWDEC##,ARE,FS.NFS!FS.VRQ
SN OCTAL,SCNOCT,FS.NFS
SN RTRCTL,SCNRTR,FS.NFS
SN DATA,SCNDAT,FS.NFS
	$LIST
>;END OF SWTCHS
;Now build the tables.
	DOSCAN (SWT)
	SUBTTL HLPSTR - The HELP string

HLPSTR:	ASCIZ	\

The commands are in the traditional SCAN format:

	output-file-spec = input-file-spec /switches

The input to DNTATL is the file output by DNSNUP which contains DECnet
messages in internal format. The output from DNTATL is a text file
representing those messages and their DECnet headers. The user data
portion of the messages are put out first in octal bytes, then in ASCII.

Default input extension is .MSG
Default output extension is .TXT

The default for all switches is to output everything.

The switches are:

[NO]DATA	[Don't] show data part of messages.
[NO]OCTAL	[Don't] show interpreted pats of message in octal too
[NO]RTRCTL	[Don't] show Router Control messages.
NODE:n		Show only those messages to or from Node n.
		If /NODE is specified, /NORTRCTL becomes the default.
AREA:n		/NODE value is in area n
LLA:n		Show only those messages whose Local Link Address is n.
RLA:n		Show only those messages whose Remote Link Address is n.

To find the Link Address of a logical link, first run DNTATL (perhaps
with /NORTRCTL/NODE:n) to find the interesting series of messages.
Note the DLA (Destination Link Address) of an input message or the SLA
(Source Link Address) of an output message.  This is the Local Link
Address to be used with the /LLA:n switch.  The Remote Link Address is
the same with source and destination reversed.

\
	SUBTTL	Startup

DNTATL:
IFN FTOPS10,<
	TDZA	T1,T1		;NON-CCL ENTRY
	  MOVEI	T1,1		;CCL ENTRY
	MOVEM	T1,CCLF1	;STORE FOR LATER
>;END IFN FTOPS10
	RESET			;CLEAR ALL I/O

	SETZM	TYPFIL		;DIRECT .TCHAR OUTPUT TO TTY NOW

IFN FTOPS10,<
	HRRZ	T1,.JBREL	;GET FIRST-TIME CORE SIZE
	MOVEM	T1,INICOR
	HRRZ	T1,.JBFF	;GET INITIAL .JBFF
	MOVEM	T1,INIFF	;SAVE FOR LATER
>;END IFN FTOPS10
	MOVE	P,[IOWD LN$PDL,PLIST] ;STACK

;Fall through to next page
	SUBTTL	Call .ISCAN

;From previous page

;.ISCAN--SUBROUTINE TO INITIALIZE COMMAND SCANNER
;CALL	AC1=XWD LENGTH,BLOCK
;
;	BLOCK+0=PROTOCOL VERSION WORD: <MAJOR>,,<MINOR>
;	BLOCK+1=0 OR IOWD PTR TO A LIST OF LEGAL MONITOR COMMANDS
;		IF 0, NO RESCAN IS DONE
;	BLOCK+2=RH 0 OR SIXBIT CCL NAME
;		  IF 0, NO CCL MODE
;		LH 0 OR ADDRESS OF STARTING OFFSET
;	BLOCK+3=RH 0 OR ADDRESS OF CHARACTER TYPEOUT ROUTINE
;		  IF 0, OUTCHR WILL BE DONE FROM T1
;		LH 0 OR ADDRESS OF CHARACTER INPUT ROUTINE
;			MUST SAVE ALL ACS, CHAR IN P4
;	BLOCK+4=0 OR POINTER (XWD LEN,BLOCK) TO INDIRECT FILE BLOCK
;		  .FXDEV NE 0 TO USE BLOCK
;	BLOCK+5=RH 0 OR ADDRESS OF MONRET ROUTINE
;		LH 0 OR ADDRESS OF PROMPT ROUTINE
;			CALLED WITH CHAR IN RH(T1), LH(T1) HAS
;			    0 FOR FIRST LINE, -1 FOR CONTINUATION LINES
;	BLOCK+6=LH FLAGS
;		RH (FUTURE)
;VALUE	AC1=INDEX IN TABLE OF COMMANDS IF FOUND(0,1,...), ELSE -1


IFN FTSWIL,<MOVE T1,[4,,[12,,%%FXVE> ;MAJOR,,MINOR SCAN VERSION
IFE FTSWIL,<MOVE T1,[3,,[>
			IOWD 1,[PRGABR]
			CCLF1,,PRGABR
			0,,TYPOUT]]
	CALL	.ISCAN##


;Fall through to next page
	SUBTTL	Driving Loop

DNTLOP:	RELEASE	F.FIN,		;RELEASE INPUT CHANNEL
	RELEASE F.FOUT,		;RELEASE OUTPUT CHANNEL
	SETZM	TYPFIL		;DIRECT .TCHAR OUTPUT TO TTY NOW
	CALL	$SCAN		;GET FILE SPECS FROM .TSCAN
	  JRST	DNTLOP		;ERROR, TRY AGAIN
	CALL	$DFALT		;DEFAULT THE NAMES & EXTENSIONS
	CALL	$OPEN		;OPEN INPUT & OUTPUT FILES
	  JRST	DNTLOP		;ERROR, TRY AGAIN
	SETOM	TYPFIL		;DIRECT .TCHAR OUTPUT TO FILE NOW
	CALL	REDHDR		;READ TRACE FILE'S HEADER
	  JRST	DNTCLS		;END OF FILE OR ERROR

DNTFMT:	CALL	REDMSG		;READ NEXT RECORD INTO MSG BLK
	  JRST	DNTCLS		;END OF FILE OR ERROR
	CALL	FMTMSG		;FORMAT & OUTPUT THIS RECORD
	  JRST	DNTCLS		;ERROR WRITING OUTPUT FILE
	JRST	DNTFMT		;GO GET NEXT RECORD

DNTCLS:	CALL	$CLOSE		;CLOSE INPUT & OUTPUT FILES
	JRST	DNTLOP		;SEE IF USER WANTS MORE
	SUBTTL	Routines for SCAN's input from TTY

;.TSCAN--SUBROUTINE FOR TRADITIONAL COMMAND SCANNER
;ARGS	AC1=XWD LENGTH,BLOCK
;	BLOCK+0=0 OR IOWD POINTER TO LIST OF SWITCH NAMES
;			(IOWD XXXXXL,XXXXXN)
;	BLOCK+1=LH ADDRESS OF DEFAULT SWITCH TABLE (XXXXXD)
;		RH ADDRESS OF PROCESSOR SWITCH TABLE (XXXXXM)
;	BLOCK+2=LH ADDRESS OF (FUTURE)
;		RH ADDRESS OF SWITCH POINTERS FOR STORING (XXXXXP)
;	BLOCK+3=LH TYPE OF HELP (0=NONE, 1=STRING, 2=SUBROUTINE)
;		  IF GT 77, NAME OF PROGRAM IN WHOLE WORD
;		  IF -1 IN WORD, USE JOB TABLE
;		RH LOCATION OF HELP
;	BLOCK+4=LH 0 OR SUBROUTINE TO CLEAR ALL ANSWERS
;		RH 0 OR SUBROUTINE TO CLEAR FILE ANSWERS
;	BLOCK+5=LH SUBROUTINE TO ALLOCATE INPUT FILE AREA
;		RH SUBROUTINE TO ALLOCATE OUTPUT FILE AREA
;		  BOTH RETURN T1=START OF AREA, T2=LENGTH
;	BLOCK+6=LH 0 OR SUBROUTINE TO MEMORIZE STICKY DEFAULTS
;		RH 0 OR SUBROUTINE TO APPLY STICKY DEFAULTS
;	BLOCK+7=LH 0 OR SUBROUTINE TO CLEAR STICKY DEFAULTS
;		RH FLAGS TO CONTROL SCAN:
;		   1B18=MORE THAN ONE OUTPUT SPEC POSSIBLE
;		   1B19=ALLOW INPUT SWITCHES ON OUTPUT AND VV
;	BLOCK+10=LH (FUTURE)
;		 RH 0 OR ROUTINE TO STORE SWITCH VALUES
;			;ENTERRED WITH T1=VALUE, T2=POINTER
;			;NON-SKIPS IF SCAN SHOULD NOT STORE
;			;SKIPS IF SCAN SHOULD STORE (T1-2 OK)

;Back here after each command is complete

$SCAN:
IFN FTSWIL,<MOVE T1,[12,,[12,,%%FXVE> ;MAJOR,,MINOR SCAN VERSION
IFE FTSWIL,<MOVE T1,[11,,[>
			IOWD SWTL, SWTN
			SWTD,,SWTM
			0,,SWTP
			1,,HLPSTR 	;HELP IS STRING,,ADDR OF STRING
			SCNCLA,,SCNCLF
			SCNAIN,,SCNAOT
			FILSTK,,APLSTK
			CLRSTK,,0
			0,,0 ] ]
	CALL	.TSCAN##		;SCAN THE LINE
; Check SWITCH.INI

IFN FTSWIL,<MOVE T1,[5,,[12,,%%FXVE>	;MAJOR,,MINOR SCAN VERSION
IFE FTSWIL,<MOVE T1,[4,,[>
			IOWD SWTL,SWTN
			SWTD,,SWTM
			0,,SWTP
			PRGID]]		;get help from HLP:PRGID
	CALL	.OSCAN##	;GET OPTIONS IF ANY
	RETSKP			;SUCCESS RETURN.
;Routine to allocate output spec area

SCNAOT:	SMEAR	T1,SCNOUT,SCNOUT+SCNLEN-1,0
	MOVEI	T1,SCNOUT	;POINT TO AREA
	MOVEI	T2,SCNLEN	; AND LENGTH
	RET			;RETURN

;Routine to allocate input spec area
SCNAIN:	SMEAR	T1,SCNIN,SCNIN+SCNLEN-1,0
	MOVEI	T1,SCNIN	;POINT TO AREA
	MOVEI	T2,SCNLEN	; AND LENGTH
	RET			;RETURN

;Routine to clear SCAN results

SCNCLA:	SMEAR	T1,SCNFWA,SCNLWA,0  ;CLEAR AREA
	SMEAR	T1,SCMFWA,SCMLWA,-1 ; AND SWITCHES
	RET

SCNCLF:
CLRSTK:
APLSTK:
FILSTK:	RET
	SUBTTL $DFALT -- Default the SCAN Blocks

$DFALT:

;Default the input file spec

IFN FTSWIL,<
	MOVE T4,.FXFLD+SCNIN	;GET THE 'FIELDS-SPECIFIED' WORD
	HRLOI T1,'MSG'		;DEFAULT EXTENSION IS .MSG
	TXNN T4,FX.UEX		;USER SPECIFY AN EXTENSION?
	 MOVEM T1,.FXEXT+SCNIN	;NO, SPECIFY .MSG

;Default the output file spec

	MOVE T4,.FXFLD+SCNOUT	;GET THE 'FIELDS-SPECIFIED' WORD
	HRLOI T1,'TXT'		;DEFAULT EXTENSION IS .TXT
	TXNN T4,FX.UEX		;USER SPECIFY AN EXTENSION?
	 MOVEM T1,.FXEXT+SCNOUT	;NO, SPECIFY .TXT
	MOVE T1,.FXNAM+SCNIN	;GET INPUT FILE NAME
	TXNN T4,FX.UNM		;IF USER DIDN'T SPECIFY
	 MOVEM T1,.FXNAM+SCNOUT	;USE FOR OUTPUT
>;END IFN FTSWIL

;Default the /RTRCTL switch from the other switches

	SKIPL SCNRTR		;HAS USER SPECIFIED /RTRCTL OR /NORTRCTL?
	JRST DFALT1		;YES, DON'T OVERRIDE USER
	MOVE T1,SCNLLA		;NO, ARE OTHER RESTRICTION
	AND  T1,SCNRLA		; SWITCHES
	AND  T1,SCNNOD		; USED?
	AOJE T1,DFALT1		;JUMP IF ALL WERE -1 (DEFAULT)
	SETZM SCNRTR		;AT LEAST ONE RESTRICTION, SAY /NORTRCTL
DFALT1:	RET
	SUBTTL $OPEN -- Open Input & Output Devices

;.STOPB -- ROUTINE TO TURN SCAN BLOCK INTO OPEN/LOOKUP BLOCKS
;  WILD-CARDS ARE ILLEGAL
;CALL:	MOVEI	T1,SCAN BLOCK
;		LH(T1)=LENGTH IF .GT. 24
;	MOVEI	T2,OPEN BLOCK (3 WORDS)
;	MOVEI	T3,LOOKUP BLOCK (6 WORDS OR MORE)
;		LH(T3)=LENGTH IF .GT. 6
;	MOVEI	T4,PATH BLOCK (9 WORDS)
;	PUSHJ	P,.STOPB
;	  ERROR RETURN IF WILD-CARDS
;	SKIP RETURN IF SETUP OK
;USES T1-4

$OPEN:	MOVEI T1,LN$LKP		;GET LENGTH OF A LOOKUP BLOCK
	MOVEM T1,LKPBLK+0	;STORE IN LENGTH WORD

	MOVEI T1,SCNIN		;PTR TO SCAN BLK
	MOVEI T2,OPNIN		;PTR TO OPEN BLK
	MOVX T3,<LN$LKP,,LKPBLK> ;LENGTH,,PTR TO LOOKUP BLOCK
	MOVEI T4,LKPPTH		;PTR TO LOOKUP'S PATH BLK
	CALL .STOPB##
	  ERROR WNI,<Wildcards not supported>,RTN

	MOVEI T1,LN$ENT		;GET LENGTH OF AN ENTER BLOCK
	MOVEM T1,ENTBLK+0	;STORE IN LENGTH WORD

	MOVEI T1,SCNOUT		;PTR TO SCAN BLK
	MOVEI T2,OPNOUT		;PTR TO OPEN BLK
	MOVX T3,<LN$ENT,,ENTBLK> ;LENGTH,,PTR TO ENTER BLOCK
	MOVEI T4,ENTPTH		;PTR TO ENTER'S PATH BLK
	CALL .STOPB##
	  ERROR WNO,<Wildcards not supported>,RTN

	MOVX T1,.IOBIN		;INPUT FILE IN BINARY MODE
	MOVEM T1,OPNIN
	MOVEI T1,H.FIN		;GET IBUF ADDR FROM SCAN
	MOVEM T1,FOPLKP+.FOBRH
	OPEN F.FIN,OPNIN	;OPEN INPUT FILE
	  ERROR COI,<Cannot Open Input Device>,RTN
	LOOKUP F.FIN,LKPBLK
	  ERROR CFI,<Cannot Find Input File>,RTN

	MOVX T1,.IOASC		;OUTPUT FILE IN ASCII MODE
	MOVEM T1,OPNOUT
	MOVSI T1,H.FOUT		;GET OBUF ADDR
	MOVEM T1,FOPENT+.FOBRH
	OPEN F.FOUT,OPNOUT	;OPEN OUTPUT FILE
	  ERROR COO,<Cannot Open Output Device>,RTN
	ENTER F.FOUT,ENTBLK
	  ERROR CFO,<Cannot Find Output File>,RTN

	RETSKP
$CLOSE:	CLOSE F.FIN,		;CLOSE INPUT FILE
	CLOSE F.FOUT,		;CLOSE OUTPUT FILE
	RET			;NOTHING MORE FOR NOW
	SUBTTL REDHDR -- Read Header from Input File

REDHDR:	CALL INBYT		;GET LENGTH OF HEADER RECORD
	  RET			;PROPOGATE ERROR RETURN
	CAIE T1,FH.LEN		;IS IT THE LENGTH WE'RE EXPECTING?
	  ERROR BLN,<Header in trace file is of unexpected length>,RTN
	STOR T1,FHLNG,+FILHDR	;'TIS RIGHT LENGTH, STORE IT

	MOVE T1,[XWD -<FH.LEN-1>,FILHDR+1] ;PTR TO HEADER RECORD STORAGE
				; (MINUS LENGTH FIELD ALREADY STORED)
	CALL REDBLK		;READ A BLOCK FROM INPUT FILE
	  RET			;PROPOGATE ERROR RETURN

	LOAD T1,FHTYP,+FILHDR	;GET TYPE OF THIS RECORD
	CAIE T1,TYP.FH		;IS THIS A HEADER RECORD?
	  ERROR BHT,<First record in file not a header record>,RTN
	LOAD T1,FHMGL,+FILHDR	;GET LENGTH OF A MSG BLK FROM HEADER
	CAIE T1,MB.LEN		;IS IT WHAT WE THINK IT SHOULD BE?
	  ERROR MLW,<Message Block Length is wrong in Header Record>,RTN
	WRTSTR <Trace from monitor >
	MOVEI T1,FILHDR+FH.CFG	;PTR TO CONFIG STRING FROM HEADER
	CALL .TSTRG##		;WRITE ASCIZ STRING TO OUTPUT FILE
	CALL .TCRLF##

	DMOVE T1,[XWD	F.FIN,.FOFIL
		  XWD	SPCLEN,SPCFIL]
	DMOVEM T1,FOPFIL
	MOVE T1,[XWD FOPFLN,FOPFIL]
	FILOP. T1,		;Get real file spec
IFSKP.
	WRTSTR <Trace file: >
	MOVE T1,SPCFIL+.FOFDV	;Device
	CALL .TSIXN##
	MOVEI T1,":"
	CALL .TCHAR##
	MOVE T1,SPCFIL+.FOFFN
	CALL .TSIXN##
	MOVEI T1,"."
	CALL .TCHAR##
	HLLZ T1,SPCFIL+.FOFEX
	CALL .TSIXN##
	MOVEI T1,"["
	CALL .TCHAR##
	MOVE T1,SPCFIL+.FOFPP
	CALL .TXWDW##
	MOVEI T4,SPCFIL
DO.
	SKIPN .FOFSF(T4)
	 JRST ENDLP.
	MOVEI T1,","
	CALL .TCHAR##
	MOVE T1,.FOFSF(T4)
	CALL .TSIXN##
	AOJA T4,TOP.
ENDDO.
	MOVEI T1,"]"
	CALL .TCHAR##
	CALL .TCRLF##
ENDIF.

	WRTSTR <Monitor version >
	LOAD T1,FHMVR,+FILHDR	;GET MONITOR VERSION FROM FILE HEADER
	CALL .TVERW##		;TYPE OUT A VERSION WORD
	WRTSTR <, DNSNUP version >
	LOAD T1,FHPVR,+FILHDR	;GET PROGRAM VERSION FROM FILE HEADER
	CALL .TVERW##		;TYPE OUT A VERSION WORD
	WRTSTR <, DNTATL version >
	MOVE T1,.JBVER		;GET MY VERSION FROM JOBDAT
	CALL .TVERW##		;TYPE OUT A VERSION WORD
	CALL .TCRLF##		;WRITE A CRLF
	WRTSTR <DNTATL switches: >
	MOVEI T1,[ASCIZ "/RTRCTL"]
	SKIPN SCNRTR		;TEST THE /RTRCTL VALUE
	MOVEI T1,[ASCIZ "/NORTRCTL"]
	CALL .TSTRG##
	MOVEI T1,[ASCIZ " /DATA"]
	SKIPN SCNDAT		;TEST THE /DATA VALUE
	MOVEI T1,[ASCIZ " /NODATA"]
	CALL .TSTRG##
	MOVEI T1,[ASCIZ " /OCTAL"]
	SKIPG SCNOCT		;TEST /OCTAL
	 MOVEI T1,[ASCIZ " /NOOCTAL"] ;NOT SPECIFIED OR /NOOCT
	CALL .TSTRG##
	WRTSTR < /NODE:>
	MOVE T1,SCNNOD		;PICK UP THE /NODE VALUE
	CALL .TDECW##		; WHICH IS IN DECIMAL
	WRTSTR < /AREA:>
	MOVE T1,SCNARE		;PICK UP THE /AREA VALUE
	CALL .TDECW##		; WHICH IS IN DECIMAL
	WRTSTR < /LLA:>
	MOVE T1,SCNLLA		;PICK UP THE LOCAL LINK ADDRESS
	CALL .TOCTW##		; WHICH IS IN OCTAL
	WRTSTR < /RLA:>
	MOVE T1,SCNRLA		;PICK UP THE REMOTE LINK ADDRESS
	CALL .TOCTW##		; WHICH IS IN OCTAL
	CALL .TCRLF##

	WRTSTR <Trace started >
	LOAD T1,FHUDT,+FILHDR	;GET INTERNAL DATE & TIME FROM FILE HDR
	CALL .TTADL		;TYPE IT OUT, LONG FORM
	WRTSTR <, UPTIME >
	LOAD T1,FHUPT,+FILHDR	;GET UPTIME FROM FILE HDR
	CALL .TJIFY		;TYPE IT OUT TOO
	CALL .TCRLF##		;WRITE A CRLF
	RETSKP			;SUCCESS RETURN
	SUBTTL REDMSG -- Read Message from Input File

;Returns:
;	MBO/	Offset to be subtracted from ptrs into message block
;		to point into MSGBLK
;	MS/	Pointer to current MSD in MSGBLK

REDMSG:	SAVEAC P1

;Read in the record header

	MOVE T1,[XWD -<MH.LEN>,MSGHDR] ;AOBJN PTR TO MSG RECORD HEADER
	CALL REDBLK		;READ A BLOCK FROM INPUT FILE
	  RET			;PROPOGATE ERROR RETURN

	LOAD T1,MHTYP,+MSGHDR	;GET TYPE OF THIS RECORD
	CAIE T1,TYP.MH		;IS IT A MESSAGE?
	  ERROR BMT,<Expected a message record, didn't get one>,RTN

;Read in the message block

	MOVE T1,[XWD -<MB.LEN>,MSGBLK] ;AOBJN PTR TO MESSAGE BLOCK
	CALL REDBLK		;READ A BLOCK FROM INPUT FILE
	  RET			;PROPOGATE ERROR RETURN

;Read in the user data block (if there is one)

	LOAD T1,MHLNG,+MSGHDR	;GET LENGTH OF THIS WHOLE RECORD
	SUBI T1,<MH.LEN+MB.LEN>	;SUBTRACT LENGTHS OF RECORD HDR & MSG BLK
	JUMPLE T1,REDMG1	;JUMP IF NO USER DATA TO READ
	MOVNS T1		;MAKE NEGATIVE FOR AOBJN PTR
	HRLZ T1,T1		;PUT IN LH FOR AOBJN PTR
	HRRI T1,USERDA		;POINT TO USER DATA RECORD
	CALL REDBLK		;READ USER DATA INTO USER DATA RECORD
	  RET			;PROPOGATE ERROR RETURN
REDMG1:
;Set up MBO & MS to point to original msg blk and first MSD therein

	LOAD MBO,MHOMB,+MSGHDR	;PICK UP ORIGINAL ADDRESS OF MSG BLK
	SUBI MBO,MSGBLK		;OFFSET FROM MHMBO ADDR TO MSGBLK
	LOAD MS,MBFMS,+MSGBLK	;PICK UP PTR TO FIRST MSD
	JUMPE MS,REDNMG		;RETURN NO MESSAGE IF NO MSDs
	SUB MS,MBO		;MUST BE FULL-WORD SUBTRACT FOR EXT ADDR

	CALL MSGLEN		;GET LENGTH OF THIS MESSAGE
	  JRST REDNMG		;RETURN NO MESSAGE
	MOVEM T1,SEQLEN		;STORE LENGTH OF WHOLE MESSAGE
	MOVEM T1,SEQCNT		;INITIALIZE 'REST OF MSG' COUNTER
	MOVE P1,[POINT 8,SEQBFR] ;POINT TO PLACE WHERE WE'LL REBUILD MSG
	MOVEM P1,SEQPTR		;INITIALIZE BYTE PTR TO SEQUENTIAL MSG
REDMG2:	CALL RED1BY		;GET A BYTE OF MSG FROM MSG BLK
	  RETSKP		;ALL DONE WHEN NO MORE
	IDPB T1,P1		;STORE IN SEQUENTIAL MSG
	JRST REDMG2		;GET NEXT BYTE


REDNMG:	SETZM SEQLEN		;NO MSG, ZERO THE LENGTH
	SETZM SEQCNT		; AND THE GETnBY LENGTH
	RETSKP			;SUCCESS RETURN (NOT A FILE ERROR)
	SUBTTL	FMTMSG - Format a DECnet Message

;The message will have been read into MSGHDR and MSGBLK by REDMSG
;before this routine is called.

FMTMSG:

;First, check for lost messages

	LOAD T1,MHLST,+MSGHDR	;GET NEW CUMULATIVE LOST COUNT
	CAMG T1,LSTCNT		;SAME AS WE HAD BEFORE?
	JRST FMTMS1		;YES, NO PROBLEM

	CALL .TCRLF##
	WRTSTR <**********************************************************>
	CALL .TCRLF##
	WRTSTR <********    >
	LOAD T1,MHLST,+MSGHDR	;GET CUMULATIVE TOTAL AGAIN
	SUB T1,LSTCNT		;GET NUMBER WE JUST LOST
	ADDM T1,LSTCNT		;STORE NEW CUMULATIVE LOST COUNT
	PUSH P,T1		;SAVE LOST COUNT
	CALL .TDECD		;OUTPUT IN DECIMAL
	WRTSTR < message>
	POP P,T2		;RESTORE LOST COUNT
	MOVEI T1,"S"+40		;LOWER CASE
	CAIE T2,1		;PRETTY-PRINT
	CALL .TCHAR##		; THE PLURALS
	WRTSTR < lost due to congestion in DNSNUP>
	CALL .TCRLF##
	WRTSTR <**********************************************************>
	CALL .TCRLF##
FMTMS1:	CALL CHKMSG		;SEE IF WE WANT THIS MESSAGE
	  RETSKP		;NO, ITS BEEN COUNTED AS SKIPPED

	CALL .TCRLF##
	CALL .TCRLF##

	LOAD T1,MHUDT,+MSGHDR	;GET INTERNAL DATE & TIME
	CALL .TTADS		;TYPE IT OUT, SHORT FORM
	WRTSTR <, Uptime: >
	LOAD T1,MHUPT,+MSGHDR	;GET UPTIME STAMP FROM MSG HEADER
	CALL .TJIFY		;TYPE OUT TIME FROM JIFFIES

	CALL .TTABC##		;A TAB
	LOAD T1,MHIOL,+MSGHDR	;GET INPUT,OUTPUT,LOCAL CODE
	CAXE T1,IOL.IN		;IS THIS AN INPUT MESSAGE?
	JRST FMTMS2		;NO, MUST BE OUTPUT OR LOCAL
	WRTSTR <Input >
	CALL FMTCNT		;TYPE OUT MSG'S BYTE COUNT
	  RET			;PROPOGATE ERROR
	JRST FMTMS5		;END OF INPUT CODE

FMTMS2:	CAXN T1,IOL.OT		;IS THIS AN OUTPUT MESSAGE?
	JRST FMTMS3		;YES
	WRTSTR <Local >		;NO, MUST BE LOCAL
	JRST FMTMS4		;CONTINUE

FMTMS3:	WRTSTR <Output >
FMTMS4:	CALL FMTCNT		;TYPE OUT MSG'S BYTE COUNT
	  RET			;PROPOGATE ERROR
	LOAD T1,NMCNT,+MSGBLK	;GET # OF TIMES MSG WAS SENT
	CAIG T1,1		;IF FIRST TRANSMISSION OR
	JRST FMTMS5		; WE DON'T KNOW, DON'T SAY ANYTHING
	WRTSTR <, Transmission #>
	LOAD T1,NMCNT,+MSGBLK	;GET # OF TIMES MSG WAS SENT AGAIN
	CALL .TDECD		;TYPE SEND COUNT IN DECIMAL
FMTMS5:	CALL .TCRLF##

;Fall through to next page
;Handle the Router header (from previous page)

	LOAD T1,MHIOL,+MSGHDR	;GET INPUT,OUTPUT,LOCAL CODE
	CAXN T1,IOL.LO		;IS THIS A LOCAL MESSAGE?
	IFSKP.			;IF NOT, TYPE OUT CIRCUIT ID
	  WRTSTR <	Circuit: >
	  LOAD T1,MHILN,+MSGHDR	;GET LINE ID (DNSNUP SETS UP ILN = OLN)
	  CALL .TCKT
	  CALL .TCRLF##
	ENDIF.

	SKIPG SCNOCT		;/OCTAL?
	 JRST FMTMS6		;NO
	CALL FMTOCT		;YES, DUMP IT ALL AS OCTAL
	 JFCL
	CALL .TCRLF##		;SOME WHITESPACE
	CALL .TCRLF##
FMTMS6:

;Fall through to next page
;Handle the Router header (from previous page)

	MOVEI T1,1		;PEEK AT FIRST BYTE OF MSG
	CALL GTO1BY		;PEEK AT FIRST BYTE OF THE ROUTER HDR
	  FMTERR No router header,RSKP
	TRZN T1,200		;IS THIS A PAD BYTE?
	IFSKP.
	  MOVE P1,T1		;SAVE PAD COUNT
	  DO.
	    CALL GET1BY		;EAT A PAD BYTE
	      FMTERR No router header,RSKP
	    SOJG P1,TOP.	;LOOP OVER ALL PAD BYTES
	  ENDDO.
	  MOVEI T1,1		;PEEK AT FIRST BYTE OF MSG
	  ADD T1,CHKOFF		;ADD IN OFFSET TO START OF RTR HDR
	  CALL GTO1BY		;PEEK AT FIRST BYTE OF THE ROUTER HDR
	    FMTERR No router header,RSKP
	ENDIF.

;See if this is a local message w/o a ROUTER header

	TXNE T1,RM%EVL		;IF EVOLUTION BIT IS ON
	  JRST PH2TST		; WE KNOW ITS A PHASE II MSG
	MOVEI T2,3		;MAKE LOW-2-BIT MASK
	AND T2,T1		;ISOLATE LOW 2 BITS
	JRST @[	z NORHDR	;PHASE II OR LOCAL W/O RTR HDR
		z PH3CTL	;PHASE III CONTROL HDR
		z PH3DAT	;PHASE III DATA MESSAGE
		z PH3CTL](T2)	;PHASE III CONTROL HDR


PH2TST:	TXNE T1,RM%MB1		;EVOLUTION WAS ON, HOW ABOUT MB1?
	  JRST PH2RTR		;OFF, THERE IS NO ROUTING HDR

NORHDR:	LOAD T1,MHIOL,+MSGHDR	;GET INPUT,OUTPUT,LOCAL CODE
	CAXN T1,IOL.LO		;IS THIS AN INPUT MESSAGE?
	JRST NSPHDR		;YES, SKIP ROUTER HEADER PRONOUNCEMENT
	WRTSTR <	Phase II message without routing header>
	CALL .TCRLF##
	JRST NSPHDR		;TYPE OUT NSP AND BEYOND

PH2RTR:	WRTSTR <	Phase II routing not supported>
	CALL .TCRLF##
	CALLRET FMTOCT		;OUTPUT PHASE II AS STRING
PH3CTL:	WRTSTR <	Phase III/IV routing control message>
	CALL .TCRLF##
	CALL GET1BY		;GET THE FLAGS BYTE
	 FMTERR No control flags,RSKP
	TXNE T1,360		;ANY RESERVED BITS ON?
	 FMTERR Reserved bits set,FMTOCT
	LDB T1,[POINT 3,T1,34]	;GET MESSAGE TYPE
	JRST @[	RTRINI		;(0) DISPATCH
		RTRVER		;(1)
		RTRHEL		;(2)
		RTRL1R		;(3)
		RTRL2R		;(4)
		RTRERH		;(5)
		RTREEH		;(6)
		RTRRMT](T1)	;(7) AS REQUIRED
;Router initialization
RTRINI:	SAVEAC P1
	WRTSTR <	ROUTER initialization from node >
	CALL GET2BY
	 FMTERR No source node,FMTOCT
	CALL .TNODE
	CALL .TCRLF##
	CALL GET1BY		;TTINFO
	 FMTERR No TTINFO,FMTOCT
	MOVE P1,T1
	WRTSTR <	Type: >
	MOVEI T1,2+1
	AND T1,P1
	MOVE T1,[[ASCIZ /Resvd/]
		 [ASCIZ /Level II router/]
		 [ASCIZ /Level I router/]
		 [ASCIZ /Endnode/]](T1)
	CALL .TSTRG##
	TXNN P1,14
	 JRST RTRIN1
	WRTSTR <, >
	TXNE P1,4
	 WRTSTR <verification>
	MOVEI T1,"&"
	TXC P1,14
	TXCN P1,14
	 PUSHJ P,.TCHAR##
	TXNE P1,10
	 WRTSTR <blocking>
	WRTSTR < requested>

RTRIN1:	CALL .TCRLF##
	CALL .TBLKS		;DO BLOCKSIZE
	CALL .TTIVR
	SOS SEQCNT		;ALLOW FOR "RESERVED IMAGE FIELD"
	CALL GET2BY
	 PJRST RTRIN2		;Not present in phase III
	PUSH P,T1
	WRTSTR <, Hello timer: >
	POP P,T1
	CALL .TDECD
RTRIN2:	CALL .TCRLF##
	AOS SEQCNT		;IN CASE WE WANT TO PRINT IT
	CALL GET1BY		;GET THE IMAGE COUNT
	 FMTERR Missing reserved image field count,FMTOCT
	SKIPE T1		;SEE IF WHAT WE EXPECT
	 FMTERR Non-null reserved image field,FMTOCT
	RETSKP
;Router verification
RTRVER:	SAVEAC P1
	WRTSTR <	ROUTER verification from node >
	CALL GET2BY
	 FMTERR No source node,FMTOCT
	CALL .TNODE
	CALL .TCRLF##
	WRTSTR <	Length: >
	CALL GET1BY		;GET BYTE COUNT
	 FMTERR No verification count,FMTOCT
	CALL .TDECD
	WRTSTR <, Data: >
	CALLRET FMTSTR		;DATA
;Router hello and test
RTRHEL:	SAVEAC P1
	WRTSTR <	ROUTER hello and test from node >
	CALL GET2BY
	 FMTERR No source node, FMTOCT
	CALL .TNODE
	CALL .TCRLF##
	WRTSTR <	Length: >
FMTTST:	CALL GET1BY		;BYTE COUNT
	 FMTERR No hello count,FMTOCT
	MOVE P1,T1
	CALL .TDECD
DO.
	SOJL P1,ENDLP.		;EXIT WHEN DONE
	CALL GET1BY		;GET A BYTE
	 FMTERR Length wrong in image field,FMTOCT
	CAIN T1,252		;Correct data?
	IFSKP.
	  PUSH P,T1
	  FMTERR Test data wrong -- first bad byte = 
	  POP P,T1
	  PUSHJ P,.TOCTW##
	  RETSKP
	ENDIF.
	JRST TOP.
ENDDO.
	CALL .TCRLF##
	RETSKP
;Router level 1 routing
RTRL1R:	SAVEAC <P1,P2>
	CALL .TTABC##
	MOVEI T1,^D4		;FIRST NODE'S DATA IF PHASE III
	ADD T1,CHKOFF		;OFFSET TO START OF HDR
	CALL GTO1BY		;GET THAT BYTE
	 FMTERR No data in routing message, FMTOCT
	MOVE P2,T1
	SKIPE P2		;IF ZERO, ASSUME PHASE IV
	 WRTSTR <Phase III routing message from node >
	SKIPN P2		;IF NOT, PHASE III
	 WRTSTR <Phase IV Level I routing message from node >
	CALL GET2BY
	 FMTERR No source node, FMTOCT
	CALL .TNODE
	CALL .TCRLF##

	SETZ P1,		;CHECKSUM
	SKIPN P2		;PHASE III?
	 AOJ P1,		;NO, DIFFERENT CHECKSUM
	MOVE P2,SEQCNT		;BYTES LEFT
	SUBI P2,2		;SAVE 2 FOR CHECKSUM
	PUSH P,SEQPTR		;WE'LL NEED ANOTHER PASS
	PUSH P,SEQCNT
	SKIPE P1		;PHASE IV?
	 CALL GET1BY		;YES, SKIP RESERVED BYTE
	  JFCL
	LSH	P2,-1		;CONVERT TO NODES
DO.
	CALL GET2BY		;GET FROM MESSAGE
	 FMTERR Routing count wrong,[POP P,SEQCNT
				POP P,SEQPTR
				JRST FMTOCT]
	ADD P1,T1		;SUM THE CHECKSUM
	SOJG P2,TOP.		;LOOP FOR ALL
ENDDO.
	CALL GET2BY		;GET FROM MESSAGE
	 FMTERR No checksum in rtg message,[POP P,SEQCNT
				POP P,SEQPTR
				JRST FMTOCT]
	POP P,SEQCNT
	POP P,SEQPTR
	EXCH T1,P1
	CALL CKSNRM
	CAMN T1,P1		;IS OURS = HIS?
IFSKP.
	FMTERR Routing checksum wrong computed = 
	PUSH P,T1
	CALL .TOCTW##
	POP P,T1
	WRTSTR <, message = >
	MOVE T1,P1
	CALL .TOCTW##
ENDIF.
	CALL GET1BY		;GET A BYTE
	 FMTERR No routing data,FMTOCT
	JUMPE T1,RTRL14		;JUMP IF PHASE IV

;APPARENTLY, THIS IS PHASE III
	AOS SEQCNT		;BACK UP ONE BYTE
	MOVNI T1,1		;AND THE POINTER
	ADJBP T1,SEQPTR
	MOVEM T1,SEQPTR		;...
	MOVE P1,SEQCNT		;BYTES LEFT
	SUBI P1,2		;LESS CHECKSUM
	TRNE P1,1		;BETTER BE EVEN
	 FMTERR Odd length routing message,FMTOCT
	LSH P1,-1		;MAKE NUMBER OF NODES
	MOVEI P2,1		;FIRST NODE NUMBER
	MOVEI T1,[ASCIZ /Node/]	;TYPE OF SEGMENT
	CALL FMTRTS		;FORMAT A ROUTING SEGMENT
	RETSKP			;THAT SEEMS LIKE ALL

;THIS APPEARS TO BE A PHASE IV MESSAGE.
RTRL14:	MOVNI T1,2		;CHECKSUM SIZE
	ADDM T1,SEQCNT		;PRETEND MESSAGE IS SMALLER
;LOOP OVER EACH SEGMENT
RTR4SG:	CALL GET2BY		;READ COUNT OF NODES IN SEGMENT
	 RETSKP			;NO MORE, DONE
	MOVE P1,T1		;SAVE NUMBER OF NODES
	CALL GET2BY		;GET FIRST NODE IN MESSAGE
	 FMTERR Invalid routing segment header,FMTOCT
	MOVE P2,T1		;SAVE THAT
	MOVEI T1,[ASCIZ /Node/]	;TYPE OF SEGMENT
	CALL FMTRTS		;FORMAT THIS SEGMENT
	JRST RTR4SG		;LOOP TO END
;HERE TO FORMAT A ROUTING SEGMENT
;T1/ [ASCIZ/ NODE/ or /AREA/]
;P1/ NUMBER OF NODES IN SEGMENT
;P2/ NODE NUMBER OF FIRST NODE
FMTRTS:	PUSH P,T1
	CALL .TCRLF##
	POP P,T1
	PUSHJ P,.TSTRG##
	PUSH P,P1
	MOVEI P1,NDSPL		;NODES PER LINE
DO.
	WRTSTR <	Cost hp>
	SOJG P1,TOP.
ENDDO.
	CALL .TCRLF##
	POP P,P1
DO.
	MOVE T1,P2		;FIRST NODE ON LINE
	CALL .TDECW##		;PRINT IT
	MOVEI T4,NDSPL		;NODES PER LINE
	DO.
		CALL .TTABC##	;TAB
		CALL GET2BY	;READ ROUTING DATA
		 FMTERR Routing segment count wrong,[RET]
		CAIE T1,77777	;UNREACHABLE?
		IFSKP.
			WRTSTR <---- -->
		ELSE.
			PUSH P,T1	;SAVE DATA
			ANDI T1,1777	;COST FIELD
			CALL .TDEC4	;OUTPUT IT
			CALL .TSPAC##	;SPACE
			POP P,T1	;DATA
			LSH T1,-^D10	;TOSS THAT
			MOVEI T2," "	;FILL
			CALL .TDEC2##	;HOPS
		ENDIF.
		SOJLE P1,FMTRSE	;IF NO MORE NODES, END SEGMENT
		SOJG T4,TOP.
	ENDDO.
	ADDI P2,NDSPL		;NEXT NODE NUMBER
	CALL .TCRLF##
	JRST TOP.		;CONTINUE ON NEXT LINE
ENDDO.
FMTRSE:	CALL .TCRLF##		;CRLF
	CALL .TCRLF##
	WRTSTR <			-------->
	CALLRE .TCRLF##
;Router level 2 routing
RTRL2R:	SAVEAC <P1,P2>
	WRTSTR <	Phase IV Level II routing message from node >
	CALL GET2BY
	 FMTERR No source node, FMTOCT
	CALL .TNODE
	CALL .TCRLF##

	MOVEI P1,1		;PHASE IV CHECKSUM
	MOVE P2,SEQCNT		;BYTES LEFT
	SUBI P2,2		;SAVE 2 FOR CHECKSUM
	PUSH P,SEQPTR		;WE'LL NEED ANOTHER PASS
	PUSH P,SEQCNT
	CALL GET1BY		;YES, SKIP RESERVED BYTE
	 JFCL
	LSH	P2,-1		;CONVERT TO NODES
DO.
	CALL GET2BY		;GET FROM MESSAGE
	 FMTERR Routing count wrong,[POP P,SEQCNT
				POP P,SEQPTR
				JRST FMTOCT]
	ADD P1,T1		;SUM THE CHECKSUM
	SOJG P2,TOP.		;LOOP FOR ALL
ENDDO.
	CALL GET2BY		;GET FROM MESSAGE
	 FMTERR No checksum in rtg message,[POP P,SEQCNT
				POP P,SEQPTR
				JRST FMTOCT]
	POP P,SEQCNT
	POP P,SEQPTR
	EXCH T1,P1
	CALL CKSNRM
	CAMN T1,P1		;IS OURS = HIS?
IFSKP.
	FMTERR Routing checksum wrong computed = 
	PUSH P,T1
	CALL .TOCTW##
	POP P,T1
	WRTSTR <, message = >
	MOVE T1,P1
	CALL .TOCTW##
ENDIF.
	CALL GET1BY		;GET A BYTE
	 FMTERR No routing data,FMTOCT

	MOVNI T1,2		;CHECKSUM SIZE
	ADDM T1,SEQCNT		;PRETEND MESSAGE IS SMALLER
;LOOP OVER EACH SEGMENT
RT24SG:	CALL GET2BY		;READ COUNT OF NODES IN SEGMENT
	 RETSKP			;NO MORE, DONE
	MOVE P1,T1		;SAVE NUMBER OF NODES
	CALL GET2BY		;GET FIRST NODE IN MESSAGE
	 FMTERR Invalid routing segment header,FMTOCT
	MOVE P2,T1		;SAVE THAT
	MOVEI T1,[ASCIZ /Area/]	;TYPE OF SEGMENT
	CALL FMTRTS		;FORMAT THIS SEGMENT
	JRST RT24SG		;LOOP TO END
;Router Ethernet router hello
RTRERH:	SAVEAC P1
	WRTSTR <	Ethernet ROUTER hello>
	CALL .TTIVR		;PRINT TIVER
	WRTSTR < from node >
	CALL .TENOD
	CALL .TCRLF##		;AND CRLF
	CALL .TINFO		;PRINT IINFO, CRLF
	CALL .TBLKS		;PRINT BLOCKSIZE
	WRTSTR <, Desig RTR pri: >
	CALL GET1BY		;GET PRIORITY
	 FMTERR Missing priority,RSKP
	CALL .TDECD
;	WRTSTR <, Area: >
	CALL GET1BY
	 FMTERR Missing area,RSKP
	SKIPE	T1		;CURRENTLY RESERVED
	 FMTERR Non-zero area byte,RSKP
;	CALL .TDECD
	WRTSTR <, Hello timer: >
	CALL GET2BY		;HELLO TIME
	 FMTERR Missing Hello Timer,RSKP
	CALL .TDECD
	WRTSTR	<, MPD: >
	CALL GET1BY
	 FMTERR Missing MPD,RSKP
;	SKIPE T1		;Hmmm, this shouldn't be, but is
;	 FMTERR Non-zero MPD byte,RSKP	;Currently reserved
	CALL .TDECD
	CALL .TCRLF##
	SAVEAC <P1,P2>
	CALL GET1BY		;GET BYTE COUNT OF E-LIST
	 FMTERR Missing E-list,RSKP
	MOVE P2,T1		;BYTES IN E-LIST
DO.
	CALL .TCRLF##		;SPACE BEFORE HEADER
REPEAT 7,<
	SOJL P2,ENDLP.		;UNTIL NO MORE BYTES
	CALL GET1BY		;GET NEXT BYTE OF NAME
	 FMTERR Missing E-list byte,RSKP
	SKIPE T1		;OK?
	 FMTERR Nonzero logical ethernet name,RSKP
>
	SOJL P2,.+2		;ERROR IF NONE
	CALL GET1BY		;GET COUNT FOR THIS R/S LIST
	 FMTERR Missing R/S list count,RSKP
	MOVE P1,T1		;SAVE
	MOVEI T4,NDSPL/2	;NODES PER LINE
    DO.
	WRTSTR	<	  Node	T Pri>
	SOJG T4,TOP.
    ENDDO.
	CALL .TCRLF##
  DO.
	MOVEI T4,NDSPL/2	;NODES PER LINE
    DO.
	CALL .TTABC##
	SUBI P1,5		;ETHERNET ADDRESS
	SOJL P1,ENDLP.		;EXIT IF DONE
	SUBI P2,5		;AGAIN FOR ENTIRE LIST
	SOJL P2,[FMTERR E-list exhausted before R/S list,RSKP]
	CALL .TENDF		;ETHERNET ADDRESS
	CALL .TSPAC##
	SOJL P1,.+3		;ERROR IF OUT OF BYTES
	SOJL P2,.+2		;...
	CALL GET1BY		;GET PRISTATE BYTE
	 FMTERR PRISTATE byte missing,RSKP
	PUSH P,T1		;SAVE
	TRNN T1,200		;CHECK STATE
	IFSKP.
	  MOVEI T1,"T"		;TWO-WAY
	ELSE.
	  MOVEI T1," "
	ENDIF.
	CALL .TCHAR##		;TYPE CHAR
	POP P,T1		;PRIORITY
	ANDI T1,177		;ONLY 7 BITS
	CALL .TDEC4		;SPACE + 3 DIGITS
	SOJG T4,TOP.		;DO R/S PAIRS TILL EOL
    ENDDO.
	CALL .TCRLF##		;PRINT CRLF
	JUMPG P1,TOP.		;CONTINUE IF MORE BYTES IN THIS R/S LIST
  ENDDO.
	CALL .TCRLF##		;CRLF
	WRTSTR <			-------->
	CALL .TCRLF##
	JRST TOP.		;DO FOR ALL E-LIST ENTRIES
ENDDO.
	RETSKP
;Router Ethernet endnode hello
RTREEH:	SAVEAC P1
	WRTSTR <	Ethernet endnode hello>
	CALL .TTIVR		;PRINT TI VERSION
	WRTSTR < from node >
	CALL .TENOD
	CALL .TCRLF##		;AND CRLF
	CALL .TINFO		;PRINT IINFO, CRLF
	CALL .TBLKS		;PRINT BLOCKSIZE
;	WRTSTR <, Area: >
	CALL GET1BY
	 FMTERR Missing area,RSKP
	SKIPE T1
	 FMTERR Non-zero AREA byte,RSKP	;Currently reserved
;	CALL .TDECD
	WRTSTR <, Verif seed: >
REPEAT 7,<
	CALL GET1BY
	 FMTERR Missing SEED,RSKP
	CALL .TDECW##
	CALL .TCOMA##
>
	CALL GET1BY
	 FMTERR Missing SEED,RSKP
	CALL .TDECW##
	CALL .TCRLF##
	WRTSTR <	Neighbor node: >
	CALL .TENOD
	WRTSTR <, Hello timer: >
	CALL GET2BY		;HELLO TIME
	 FMTERR Missing Hello Timer,RSKP
	CALL .TDECD
	WRTSTR	<, MPD: >
	CALL GET1BY
	 FMTERR Missing MPD,RSKP
;	SKIPE T1		;Hmmm, this shouldn't be, but is
;	 FMTERR Non-zero MPD byte,RSKP	;Currently reserved
	CALL .TDECD
	WRTSTR <, Test data length: >
	CALLRET FMTTST			;FORMAT AND RETURN
;Ethernet message formatting subroutines
DEFINE HEX(NUM),<.ZZW==<.ZZC==0>
IRPC NUM,<.ZZCH=="NUM"-"0"
	  IFG .ZZCH-^D9,<.ZZCH==.ZZCH-<<"A"-"0">-^D10>>
	  .ZZW==.ZZW+<.ZZCH>B<3+<.ZZC*4>>
	  IFE .ZZC-^D7,<EXP .ZZW;;	32BITS/WD
		      .ZZW==0
		      .ZZC==-1>
	  .ZZC==.ZZC+1>
IFN .ZZC,<EXP .ZZW>
PURGE .ZZW,.ZZC,.ZZCH>

RTRHIO:	HEX(AA0004000000)	;HIGH ORDER ROUTER ADDRESS

;Output an ethernet node address
.TENDF:	SAVEAC <P1>		;SAVE A FLAG
	SETO P1,		;FIXED FORMAT
	JRST TENODE
.TENOD:	SAVEAC <P1>
	SETZ P1,		;VBL FMT
TENODE:	PUSH P,[0]
REPEAT 4,<
	CALL GET1BY		;GET A BYTE
	  FMTERR No destination node address,TPOPJ
	EXCH T1,(P)		;SAVE NEW,GET OLD
	LSH T1,^D8		;MOVE LOW BYTE TO LEFT
	IORM T1,(P)		;SAVE RESULT
>
	POP P,T1		;GET LOW ORDER ETHERNET ADDRESS
	LSH T1,4		;NOW IT'S BEEN IDPB'D, LOW-HIGH, IN HEX
	CAME T1,RTRHIO		;CORRECT?
	 SKIPN T1		;Zero means "none"
	CAIA
NDNERR:	 FMTERR Ethernet message with non-DECnet address,RTN
	PUSH P,T1		;SAVE RESULT
	CALL GET2BY		;DEST ADDR IS 2 BYTES
	  FMTERR No destination node address,TPOPJ
	POP P,T2		;GET BYTES SO FAR
	JUMPE T2,[JUMPN T1,NDNERR ;IF ZERO HIORD BUT NZ NODE, ERROR
		  WRTSTR <<none>>
		  RET]
	SKIPL P1		;CHECK DESIRED FORMAT
IFSKP.				;IF FIXED
	PUSH P,T1		;SAVE NODE NUMBER
	LSH T1,-^D10		;GET AREA
	MOVEI T2," "		;SPACE FILL
	CALL .TDEC2##		;PRINT AREA
	CALL .TDOT		;"."
	POP P,T1		;NODE
	ANDI T1,1777		;AND ONLY NODE
	PUSHJ P,.TDEC4		;4 DIGITS
ELSE.
	CALL .TNODE		;TYPE NODE ADDRESS IN DECIMAL
ENDIF.
	RET
;OUTPUT IINFO BYTE
.TINFO:	SAVEAC <P1>
	CALL GET1BY		;IINFO
	 FMTERR No IINFO,FMTOCT
	MOVE P1,T1
	WRTSTR <	Type: >
	MOVEI T1,2+1
	AND T1,P1
	MOVE T1,[[ASCIZ /Resvd/]
		 [ASCIZ /Level II router/]
		 [ASCIZ /Level I router/]
		 [ASCIZ /Endnode/]](T1)
	CALL .TSTRG##
	TXNN P1,104
	 JRST TINFO1
	WRTSTR <, >
	TXNE P1,4
	 WRTSTR <verification>
	MOVEI T1,"&"
	TXC P1,104
	TXCN P1,104
	 PUSHJ P,.TCHAR##
	TXNE P1,100
	 WRTSTR <blocking>
	WRTSTR < requested>

TINFO1:	CALL .TCRLF##
	TXNN P1,270		;ANY MORE BITS?
	 RET			;NO
	WRTSTR <	>
	TXZE P1,10		;REJECT
	 WRTSTR <Reject flag>
	TXNE P1,270		;MORE?
	 CALL .TCOMA##		;YES
	TXZE P1,20		;VERIF FAIL
	 WRTSTR <Verification failed>
	TXNE P1,270		;MORE
	 CALL .TCOMA##
	TXZE P1,40		;NO MULTICAST
	 WRTSTR <No multicast traffic>
	TXNE P1,270		;MORE
	 CALL .TCOMA##
	TXZE P1,200
	 WRTSTR	 <IINFO bit 7>
	CALLRET	.TCRLF##
;Router Reserved message type
RTRRMT:	FMTERR Reserved router message type,FMTOCT
;Here if we have a Phase III/IV data message

PH3DAT:	WRTSTR <	Phase III/IV data message, control byte: >
	CALL GET1BY		;EAT BYTE WE'VE BEEN PEEKING AT
	  FMTERR No router header,RSKP
	CALL .TOCTW
	CALL .TCRLF##

	TXNE T1,4		;IS THIS PHASE IV FROM ETHERNET?
	JRST PH4DAT		;YES

	WRTSTR <	Dest node: >
	CALL GET2BY		;DEST ADDR IS 2 BYTES
	  FMTERR No destination node address,RSKP
	CALL .TNODE		;TYPE NODE ADDRESS IN DECIMAL
	WRTSTR <, Source node: >
	CALL GET2BY		;SOURCE ADDR IS 2 BYTES
	  FMTERR No destination node address,RSKP
	CALL .TNODE		;TYPE NODE ADDRESS IN DECIMAL
	WRTSTR <, Visits: >
	CALL GET1BY		;VISIT COUNT IS 1 BYTE
	  FMTERR No visit count,RSKP
	CALL .TDECD		;TYPE VISIT COUNT IN DECIMAL
	CALL .TCRLF##
	JRST NSPHDR		;GO OUTPUT NSP HEADER

PH4DAT:	WRTSTR <	Dest area:   > ;LINE UP DEST WITH SOURCE FIELDS
	CALL GET1BY
	  FMTERR No destination area,RSKP
	CALL .TDECD
	WRTSTR <, Dest subarea:   > ;LINE UP DEST WITH SOURCE FIELDS
	CALL GET1BY
	  FMTERR No destination subarea,RSKP
	CALL .TDECD
	WRTSTR <, Dest node:   > ;LINE UP DEST WITH SOURCE FIELDS
	CALL .TENOD		;TYPE ETHERNET NODE
	CALL .TCRLF##
	WRTSTR <	Source area: >
	CALL GET1BY
	  FMTERR No source area,RSKP
	CALL .TDECD
	WRTSTR <, Source subarea: >
	CALL GET1BY
	  FMTERR No source subarea,RSKP
	CALL .TDECD
	WRTSTR <, Source node: >
	CALL .TENOD		;TYPE ETHERNET NODE
	CALL .TCRLF##
	WRTSTR <	Next Level Two: >
	CALL GET1BY		;NL2 IS 1 BYTE
	  FMTERR No NL2 field,RSKP
	CALL .TDECD
	WRTSTR <, Visits: >
	CALL GET1BY		;VISIT COUNT IS 1 BYTE
	  FMTERR No visit count field,RSKP
	CALL .TDECD		;TYPE VISIT COUNT IN DECIMAL
	WRTSTR <, Service Class: >
	CALL GET1BY		;SERVICE CLASS
	  FMTERR No service class field,RSKP
	CALL .TDECD
	WRTSTR <, Protocol type: >
	CALL GET1BY		;PROTOCOL TYPE
	  FMTERR No protocol type field,RSKP
	CALL .TDECD
	CALL .TCRLF##
	JRST NSPHDR		;GO OUTPUT NSP HEADER
;Output length of message

FMTCNT:	MOVE T1,SEQLEN		;GET LENGTH OF MESSAGE
	CALL .TDECD		;DECIMAL
	WRTSTR < bytes>
	RETSKP


;Output the rest of the message as a user data field (image with count)

FMTUDA:	CALL .TCRLF##
	WRTSTR <	User Data Length: >
	CALL GET1BY		;GET LENGTH (FIRST BYTE)
	  SETZ T1,		;NO MORE DATA, TELL USER WE HAVE ZERO
	PUSH P,T1		;SAVE VALUE WE'RE TYPING
	CALL .TDECD		;THERE IS A LENGTH, TYPE IN DECIMAL
	POP P,T1		;RECOVER VALUE WE TYPED
	SKIPN SCNDAT		;USER SAY /NODATA?
	RETSKP			;YES, LEAVE NOW
	JUMPE T1,RSKP		;NO, LEAVE NOW IF LENGTH WAS ZERO
	WRTSTR <, Data: >	;WE HAVE DATA, ANNONCE THE FACT
	CALLRET FMTSTR		;TYPE REST AS AS A STRING

;FMTCDA is same as FMTUDA, except length is rest of message instead of
;contents of first byte

FMTCDA:	WRTSTR <, Connect Data Length: >
	MOVE T1,SEQCNT		;GET REMAINING LENGTH OF MESSAGE
	CALL .TDECD		;THERE IS A LENGTH, TYPE IN DECIMAL
	SKIPG SEQCNT		;ANY USER DATA TO TYPE?
	RETSKP			;NO, LEAVE NOW
	WRTSTR <, Data: >	;WE HAVE DATA, ANNONCE THE FACT
	CALLRET FMTSTR		;TYPE REST AS AS A STRING
;Output the rest of the message as octal bytes and as ASCII

FMTSTR:	CALL FMTOCT		;FIRST OUTPUT IN OCTAL
	  RET
	CALL .TCRLF##		;MAKE SOME ROOM BETWEEN OCTAL & ASCII
	CALL FMTASC		;THEN IN ASCII
	  RET
	RETSKP

;Here to put out the string in octal bytes

FMTOCT:	SAVEAC P1
	SKIPG SEQCNT		;ANYTHING THERE?
	  RETSKP		;NO, SUCCESS NOW

	PUSH P,SEQCNT		;SAVE REMAINING LENGTH OF MSG
	PUSH P,SEQPTR		; AND BYTE PTR TO IT
FMTST1:	MOVEI P1,^D20		;WE'LL PUT (P1) BYTES ON A LINE
	CALL .TCRLF##		;START WITH A FRESH LINE FOR P1'S COUNT
FMTST2:	CALL GET1BY		;GET A BYTE FROM CURRENT MSG
	  JRST FMTST5		;DONE WHEN NO MORE BYTES TO READ
	PUSH P,T1		;SAVE OUR BYTE
	TRNE T1,700		;NEED ANY FILLER?
	JRST FMTST4		;NO, BIG NUMBER
	TRNE T1,70		;YES, NEED 2 FILLERS?
	JRST FMTST3		;NO, MEDIUM NUMBER
	CALL .TSPAC##		;YES, LITTLE NUMBER
FMTST3:	CALL .TSPAC##		;FILL FOR MEDIUM NUMBER
FMTST4:	POP P,T1		;RESTORE OUR BYTE
	CALL .TOCTW##		;TYPE OUT BYTE IN OCTAL
	SOJLE P1,FMTST1		;NEXT LINE IF THIS LINE FILLED
	CALL .TSPAC##		;NO, THEN TYPE A SPACE
	JRST FMTST2		;LOOP UNTIL DONE

FMTST5:	POP P,SEQPTR		;RESTORE BYTE PTR TO MSG
	POP P,SEQCNT		; AND ITS LENGTH
	RETSKP
;Here to put out the string in ASCII

FMTASC:	SAVEAC P1
	SKIPG SEQCNT		;ANYTHING THERE?
	  RETSKP		;NO, SUCCESS NOW

FMTST6:	CALL GET1BY		;GET A BYTE FROM CURRENT MSG
	  JRST FMTST8		;ONE MORE CRLF, THEN SUCCESS
	ANDI T1,177		;TURN OFF THE PARITY BIT FOR COMPARES
	CAIL T1,40		;PRINTING CHAR?
	JRST FMTST7		;YES
	CAIE T1,15		;MAYBE NOT, IS IT A CR
	CAIN T1,12		; OR LF
	JRST FMTST7		;YES
	CAIN T1,11		;OR TAB
	JRST FMTST7		;YES
	PUSH P,T1		;NO, SAVE CHAR
	MOVEI T1,"^"		;PRINT A 'CONTROL' SIGNAL
	CALL .TCHAR##
	POP P,T1		;RESTORE OUR CHAR
	ADDI T1,100		;DECONTROL IT
FMTST7:	CALL .TCHAR##		;TYPE OUT BYTE IN ASCII
	JRST FMTST6		;LOOP UNTIL DONE

FMTST8:	CALL .TCRLF##		;BACK TO LEFT MARGIN
	RETSKP			;SUCCESS
;Check to see if we want to talk about this message
;
;Call:	SEQBFR set up by REDMSG for GETnBY
;	CALL CHKMSG
;	  "Don't do it" return
;	"Do it" return

CHKMSG:	SAVEAC <P1,P2>
	MOVEI T1,1		;PEEK AT FIRST BYTE OF MSG
	CALL GTO1BY		;PEEK AT FIRST BYTE OF THE ROUTER HDR
	  FMTERR No router header,RSKP
	SETZM CHKOFF		;ASSUME NO PAD BYTE
	TRZN T1,200		;IS THIS A PAD BYTE?
	IFSKP.
	  MOVEM T1,CHKOFF	;YES, STORE OFFSET TO START OF RTR HDR
	  ADDI T1,1		;PEEK AT NEW FIRST
	  CALL GTO1BY		; BYTE OF THE ROUTER HDR
	    FMTERR No router header,RSKP
	ENDIF.

;See if this is a local message w/o a ROUTER header

	TXNE T1,RM%EVL		;IF EVOLUTION BIT IS ON
	  JRST CHKMG0		; WE KNOW ITS A PHASE II MSG
	ANDI T1,7		;ISOLATE LOW 3 BITS
	MOVE T1,[DEC 0		;(0)PHASE II OR LOCAL W/O RTR HDR
		 DEC -1		;(1)PHASE III/IV CONTROL HDR
		 DEC 6		;(2)PHASE III/IV SHORT FORM DATA HDR
		 DEC -1		;(3)PHASE III/IV CONTROL HDR
		 DEC 0		;(4)PHASE II OR LOCAL W/O RTR HDR
		 DEC -1		;(5)PHASE III/IV CONTROL HDR
		 DEC 21		;(6)PHASE IV LONG FORM DATA HDR
		 DEC -1](T1)	;(7)PHASE III/IV CONTROL HDR
	JRST CHKMG1		;WE HAVE THE ROUTER HEADER LENGTH NOW

CHKMG0:	TXNN T1,RM%MB1		;EVOLUTION WAS ON, HOW ABOUT MB1?
	 TDZA T1,T1		;NO, LOCAL OR PH2 WITH ZERO LENGTH RTR HDR
	  MOVX T1,-1		;YES, PH2 RTR HDR, -1 SAYS ROUTER CONTROL
CHKMG1:	MOVEM T1,RHDRLN		;STORE ROUTER HDR LENGTH
	JUMPL T1,[SKIPN SCNRTR	;IF THIS IS ROUTING MSG, DO WE WANT THEM?
		  JRST CHKMGF	;NO
		  JRST CHKMGS]	;YES
				;T1 STILL HAS RHDRLN IN IT
	SKIPG SCNNOD		;USER HAVE A NODE IN MIND?
	JRST CHKMG8		;NO
	JUMPE T1,CHKMG8		;YES, IGNORE IF NO ROUTER HDR ON THIS MSG
				;T1 STILL HOLDS LENGTH OF ROUTER HDR
	MOVEI P1,2		;ASSUME SHORT FORM ROUTER HDR, AND
	MOVEI P2,4		; SET UP P1,P2 AS POSITION OF DEST,SRC ADDRS
	CAIE T1,^D21		;IS IT LONG FORM?
	IFSKP.			;YES...
	  MOVEI P1,^D8		;LONG FORM DEST ADDR POSITION
	  MOVEI P2,^D16		; AND SOURCE ADDR POSITION
	ENDIF.
	LOAD T1,MHIOL,+MSGHDR	;GET INPUT,OUTPUT,LOCAL CODE
	CAXE T1,IOL.OT		;IS THIS AN OUTPUT MESSAGE?
	 SKIPA T1,P2		;NO, POINT TO SOURCE NODE ADDR
	  MOVE T1,P1		;YES, POINT TO DEST NODE ADDR
	ADD T1,CHKOFF		;ADD IN OFFSET TO START OF RTR HDR
	CALL GTO2BY		;PEEK AT 2 BYTE FIELD
	  JRST CHKMGF		;NO NODE ADDR, MUST NOT BE INTERESTING
	LDB T2,[POINT 6,T1,35-10];GET AREA
	ANDI T1,1777		;PARE DOWN TO INTRA-AREA NODE NUMBER
	CAME T1,SCNNOD		;IS THIS THE INDICATED NODE ADDRESS?
	JRST CHKMGF		;NO, IGNORE IT
	SKIPG SCNARE		;/AREA SPECIFIED?
	 JRST CHKMG8		;NO, DON'T COMPARE
	CAME T2,SCNARE		;YES, DOES IT MATCH THIS MESSAGE?
	 JRST CHKMGF		;NO, IGNORE IT
CHKMG8:	SKIPG SCNLLA		;USER HAVE A LOCAL LINK ADDRESS IN MIND?
	JRST CHKMG2		;NO
				;YES
	LOAD T1,MHIOL,+MSGHDR	;GET INPUT,OUTPUT,LOCAL CODE
	CAXE T1,IOL.OT		;IS THIS AN OUTPUT MESSAGE?
	 CAXN T1,IOL.LO		; OR A LOCAL MESSAGE?
	  SKIPA T1,[DEC 4]	;YES, POINT TO SOURCE LINK ADDR
	   MOVEI T1,2		;NO, POINT TO DEST LINK ADDR
	ADD T1,RHDRLN		;ADD IN LENGTH OF THIS MSG'S RTR HDR
	ADD T1,CHKOFF		;ADD IN OFFSET TO START OF RTR HDR
	CALL GTO2BY		;PEEK AT 2 BYTE FIELD
	  JRST CHKMGF		;NO LINK ADDR, MUST NOT BE INTERESTING
	CAMN T1,SCNLLA		;IS THIS THE INDICATED LINK ADDRESS?
	JRST CHKMG3		;YES, ACCEPT THIS MESSAGE
	LOAD T1,MHIOL,+MSGHDR	;NO, GET INPUT,OUTPUT,LOCAL CODE
	CAXE T1,IOL.LO		;IS THIS A LOCAL MESSAGE?
	JRST CHKMGF		;NO, FAIL
	MOVEI T1,2		;YES, POINT TO DEST LINK ADDR TOO
	ADD T1,RHDRLN		;ADD IN LENGTH OF THIS MSG'S RTR HDR
	ADD T1,CHKOFF		;ADD IN OFFSET TO START OF RTR HDR
	CALL GTO2BY		;PEEK AT 2 BYTE FIELD
	  JRST CHKMGF		;NO LINK ADDR, MUST NOT BE INTERESTING
	CAME T1,SCNLLA		;IS THIS THE INDICATED LINK ADDRESS?
	JRST CHKMGF		;NO, FAIL

CHKMG2:	SKIPG SCNRLA		;USER HAVE A REMOTE LINK ADDRESS IN MIND?
	JRST CHKMG3		;NO
				;YES
 	LOAD T1,MHIOL,+MSGHDR	;GET INPUT,OUTPUT,LOCAL CODE
	CAXE T1,IOL.IN		;IS THIS AN INPUT MESSAGE?
	 SKIPA T1,[DEC 2]	;NO, POINT TO DEST LINK ADDR
	  MOVEI T1,4		;YES, POINT TO SOURCE LINK ADDR
	ADD T1,RHDRLN		;ADD IN LENGTH OF THIS MSG'S RTR HDR
	ADD T1,CHKOFF		;ADD IN OFFSET TO START OF RTR HDR
	CALL GTO2BY		;PEEK AT 2 BYTE FIELD
	  JRST CHKMGF		;NO LINK ADDR, MUST NOT BE INTERESTING
	CAMN T1,SCNRLA		;IS THIS THE INDICATED LINK ADDRESS?
	 JRST CHKMG3		;YES, LETS LOOK AT IT
	LOAD T1,MHIOL,+MSGHDR	;NO, GET INPUT,OUTPUT,LOCAL CODE
	CAXE T1,IOL.OT		;IS THIS A LOCAL MESSAGE?
	 JRST CHKMGF		;NO, FAIL
	MOVEI T1,4		;YES, POINT TO SOURCE LINK ADDR
	ADD T1,RHDRLN		;ADD IN LENGTH OF THIS MSG'S RTR HDR
	ADD T1,CHKOFF		;ADD IN OFFSET TO START OF RTR HDR
	CALL GTO2BY		;PEEK AT 2 BYTE FIELD
	  JRST CHKMGF		;NO LINK ADDR, MUST NOT BE INTERESTING
	CAME T1,SCNRLA		;IS THIS THE INDICATED LINK ADDRESS?
	JRST CHKMGF		;NO, IGNORE IT

CHKMG3:	;Put more tests here
;If we get here, we'll look at the msg

CHKMGS:	SKIPG SKPCNT		;HAVE WE SKIPPED ANY RECORDS?
	RETSKP			;NO, SUCCESS RETURN NOW
	CALL .TCRLF##		;MAKE A LITTLE
	CALL .TCRLF##		; ROOM FOR THE SKIP MESSAGE
	WRTSTR <***  Skipped >	;YES, TELL USER ABOUT IT
	MOVE T1,SKPCNT		;GET NUMBER WE SKIPPED
	CALL .TDECD		;DECIMAL
	WRTSTR < message>
	MOVE T2,SKPCNT		;GET NUMBER WE SKIPPED AGIAN
	MOVEI T1,"S"+40		;LOWER CASE
	CAIE T2,1		;PRETTY-PRINT
	CALL .TCHAR##		; THE PLURALS
	WRTSTR < due to selection switches  ***>
	CALL .TCRLF##
	SETZM SKPCNT		;START SKIP COUNT ANEW NOW
	RETSKP			;SUCCESS RETURN


;Here to ignore the message

CHKMGF:	AOS SKPCNT		;WE'RE SKIPPING A RECORD
	RET			;"NO GO" RETURN
;Handle the NSP header
;
;Call:	SEQBFR set up by REDMSG for GETnBY
;	CALL NSPHDR
;	  Error Return
;	Normal Return

NSPHDR:	SAVEAC P1
	CALL GET1BY		;GET NSP MESSAGE TYPE FIELD
	  FMTERR No NSP message type byte,RSKP
	LSH T1,-2		;LOW-ORDER 2 BITS ALWAYS ZERO
	MOVE P1,T1		;SAVE MESSAGE TYPE
	CAILE P1,NSPTLN		;LEGAL MSG TYPE?
	JRST [	CALL .TOCTW##	;NO, OUTPUT MESSAGE TYPE
		CALL .TSPAC##	;WRITE A SPACE
		CALLRET FMTSTR]	;OUTPUT REST OF MSG AS A STRING
	CALL .TTABC##		;YES, OUTPUT REST OF MSG ACCORDING TO TYPE
	HLRZ T1,NSPTBL(P1)	;GET NAME OF MESSAGE TYPE
	CALL .TSTRG##		;WRITE NAME STRING
	WRTSTR <, >		;SET UP FOR TYPE-SPECIFIC ROUTINE'S OUTPUT

	HRRZ T1,NSPTBL(P1)	;GET ROUTINE ADDR FROM RH OF TABLE ENTRY
	CALL (T1)		;OUTPUT MESSAGE ACCORDING TO MSG TYPE
	  RET			;ERROR OF SOME SORT
	RETSKP			;SUCCESS
;Table of Message Type names and Routine addresses

DEFINE MGTYPS,<			;{subtype,type}
	MSGTYP (NoBEom,RCVMDS)	; 0:   {0,0}
	$XLIST
	MSGTYP (DATACK,RCVACK)	; 1:   {0,1}
	MSGTYP (NOP,   RCVNOP)	; 2:   {0,2}
	MSGTYP (<0,3>, FMTSTR)	; 3:   {0,3}
	MSGTYP (LNKSRV,RCVLKS)	; 4:   {1,0}
	MSGTYP (OTHACK,RCVACK)	; 5:   {1,1}
	MSGTYP (CI,    RCVCI)	; 6:   {1,2}
	MSGTYP (<1,3>, FMTSTR)	; 7:   {1,3}
	MSGTYP (Bom,   RCVBGS)	;10:   {2,0}
	MSGTYP (CA,    RCVCA)	;11:   {2,1}
	MSGTYP (CC,    RCVCC)	;12:   {2,2}
	MSGTYP (<2,3>, FMTSTR)	;13:   {2,3}
	MSGTYP (INTRPT,RCVONS)	;14:   {3,0}
	MSGTYP (<3,1>, FMTSTR)	;15:   {3,1}
	MSGTYP (DI,    RCVDI)	;16:   {3,2}
	MSGTYP (<3,3>, FMTSTR)	;17:   {3,3}
	MSGTYP (Eom,   RCVENS)	;20:   {4,0}
	MSGTYP (<4,1>, FMTSTR)	;21:   {4,1}
	MSGTYP (DC,    RCVDC)	;22:   {4,2}
	MSGTYP (<4,3>, FMTSTR)	;23:   {4,3}
	MSGTYP (<5,0>, FMTSTR)	;24:   {5,0}
	MSGTYP (<5,1>, FMTSTR)	;25:   {5,1}
	MSGTYP (<5,2>, FMTSTR)	;26:   {5,2}
	MSGTYP (<5,3>, FMTSTR)	;27:   {5,3}
	MSGTYP (BomEom,RCVONS)	;30:   {6,0}
	MSGTYP (<6,1>, FMTSTR)	;31:   {6,1}
	MSGTYP (ReCI,  RCVCI)	;32:   {6,2}
	$LIST
>;END OF MGTYPS MACRO

DEFINE MSGTYP(type,routine,upto,sublink,ack,respond,flow),<
	XWD [ASCIZ /type/],routine
>

NSPTBL:	MGTYPS
NSPTLN==.-NSPTBL-1
	SUBTTL	NSP Message Type Routines -- Data message
RCVBGS:				;BEGSEG message
RCVMDS:				;MIDSEG message
RCVENS:				;ENDSEG message
RCVONS:				;ONYSEG or INTRPT message
	CALL DLASLA		;PUT OUT DLA AND SLA
	  RET			;PROPOGATE ERROR
	CALL ACKSEG		;PUT OUT ACK AND/OR SEGNUM
	  RET			;PROPOGATE ERROR
	CALL .TCRLF##
	WRTSTR <	User Data Length: >
	MOVE T1,SEQCNT		;GET REMAINING MSG LENGTH
	CALL .TDECD		;TYPE OUT LENGTH
	SKIPE SCNDAT		;USER SAY /NODATA?
	SKIPG T1,SEQCNT		;YES, GET REMAINING MSG LENGTH AGAIN
	RETSKP			;LEAVE NOW IF NO DATA TO TYPE
	WRTSTR <, User Data: >
	CALLRET FMTSTR		;PUT OUT REST OF MSG AS A STRING
	SUBTTL	NSP Message Type Routines -- ACK message

RCVACK:				;ACK message (Data or Other)
	CALL DLASLA		;PUT OUT DLA AND SLA
	  RET			;PROPOGATE ERROR
	CALL ACKFLD		;PUT OUT ACK FIELD ONLY
	  RET			;PROPOGATE ERROR
	CALL .TCRLF##
	RETSKP
	SUBTTL	NSP Message Type Routines -- LNKSRV message

RCVLKS:	SAVEAC P1		;LNKSRV message
	CALL DLASLA		;PUT OUT DLA AND SLA
	  RET			;PROPOGATE ERROR
	CALL ACKSEG		;PUT OUT ACK AND/OR SEGNUM
	  RET			;PROPOGATE ERROR
	CALL .TCRLF##
	CALL .TTABC##		;NEW LINE STARTS WITH A TAB

	CALL GET1BY		;GET LSFLAGS FIELD
	  FMTERR No link service flags byte,RSKP
	MOVE P1,T1		;SAVE FLAGS BYTE IN P1

	CALL GET1BY		;GET FCVAL FIELD
	  FMTERR No link service value byte,RSKP
	TRNE T1,200		;TEST THE SIGN BIT OF THE BYTE
	ORCMI T1,377		;ITS NEGATIVE, EXTEND THE SIGN
	CALL .TDECD		;OUTPUT # OF DRQs (DECIMAL)
	WRTSTR < credits on >
	LOAD T2,LSINT,+P1	;GET INTERPRETATION FIELD
	MOVEI T1,[ASCIZ /Data/]
	CAIE T2,LS.INR		;IS IT 'DATA' SUBLINK?
	MOVEI T1,[ASCIZ /Other/]
	CALL .TSTRG##
	WRTSTR < sublink, >

	LOAD T1,LSMOD,+P1	;GET MODIFIER FIELD
	MOVE T1,[[ASCIZ /no change to off flag/]
		 [ASCIZ /turn sublink OFF/]
		 [ASCIZ /turn sublink ON/]
		 [ASCIZ /?reserved modifier value?/]](T1)
	CALL .TSTRG##		;YES, TYPE IT
	CALL .TCRLF##
	RETSKP
	SUBTTL	NSP Message Type Routines -- CI message

RCVCC:				;CC message
	CALL RCVCIC		;COMMON CI/CC CODE
	  RET			;PROPOGATE ERROR
	CALLRET FMTUDA		;FINISH OFF WITH USER DATA

RCVCI:				;CI message
	CALL RCVCIC		;COMMON CI/CC CODE
	  RET			;PROPOGATE ERROR
	CALLRET FMTCDA		;FINISH OFF WITH CONNECT DATA


RCVCIC:	CALL DLASLA		;PUT OUT DLA AND SLA
	  RET			;PROPOGATE ERROR
	WRTSTR <, Flow Control: >
	CALL GET1BY		;GET SERVICES BYTE (EXTENSIBLE!)
	  FMTERR No services byte,RSKP
	LOAD T1,SVOPT,+T1	;GET FLOW CONTROL OPTION
	MOVE T1,[[ASCIZ /None/]
		 [ASCIZ /Segment/]
		 [ASCIZ /Message/]
		 [ASCIZ /Illegal/]](T1)
	CALL .TSTRG##

	WRTSTR <, NSP Version: >
	CALL GET1BY		;VERSION FIELD (EXTENSIBLE!)
	  FMTERR No INFO field,RSKP
	CALL .TOCTW##

	CALL .TCRLF##
	WRTSTR <	Segsize: >
	CALL GET2BY		;GET SEGMENT SIZE BYTES
	  FMTERR No segsize field,RSKP
	CALL .TDECD
	RETSKP			;SUCCESS RETURN
	SUBTTL	NSP Message Type Routines -- CA message

RCVCA:				;CA message
	WRTSTR <DLA: >		;CONNECT ACK ONLY HAS A DLA FIELD
	CALL GET2BY		; WHICH IS 2 BYTES
	  FMTERR No dest link address bytes,RSKP
	CALL .TOCTW##		;LINK ADDRESSES IN OCTAL
	CALL .TCRLF##
	RETSKP
	SUBTTL	NSP Message Type Routines -- DI message

RCVDI:				;DI message
	CALL DLASLA		;PUT OUT DLA AND SLA
	  RET			;PROPOGATE ERROR
	WRTSTR <, Reason: >
	CALL GET2BY		;GET REASON CODE
	  FMTERR No reason code,RSKP
	CALL RSNTXT		;GET PTR TO REASON TEXT IN T1
	CALLRET FMTUDA		;FORMAT THE USER DATA
	SUBTTL RSNTXT - Type Out Text for DECnet Reject Reason

;RSNTXT - Type Out Text for DECnet Reject Reason
;
;Call:	T1/ The Reason Code
;	CALL	RSNTXT
;	Normal Return


DEFINE RSNMAC(code,text),<
	CAIN	T1,code
	MOVEI	T2,[ASCIZ |code: text|]
>

RSNTXT::MOVEI	T2,0		;SO WE KNOW IF NO REASON HAS MATCHED

	RSNMAC RSNDBO,Disconnected/Rejected by Object
	RSNMAC RSNRES,No Resources
	RSNMAC RSNUNN,Unrecognized Node Name
	RSNMAC RSNRNS,Remote Node Shut Down
	RSNMAC RSNURO,Unrecognized Object
	RSNMAC RSNIOF,Invalid Object Name Format
	RSNMAC RSNOTB,Object Too Busy
	RSNMAC RSNABM,Abort by Management
	RSNMAC RSNABO,Abort by Object
	RSNMAC RSNINF,Invalid Node Name Format
	RSNMAC RSNLNS,Local Node Shut Down
	RSNMAC RSNACR,Access Control Rejection
	RSNMAC RSNNRO,No Response from Object
	RSNMAC RSNNUR,Node Unreachable
	RSNMAC RSNNLK,No Link
	RSNMAC RSNDSC,Disconnect Complete
	RSNMAC RSNIMG,Image Field Too Long
	JUMPE	T2,RSNT.1	;JUMP IF NO MATCH FOUND
	MOVE	T1,T2		;MOVE TO T1 FOR .TSTRG
	CALL	.TSTRG##	;GOT A MATCH, TYPE OUT TEXT
	RET

RSNT.1:	PUSH	P,T1		;NO MATCH, TYPE OUT CODE IN DECIMAL
	MOVEI	T1,[ASCIZ /Unknown reason code: /]
	CALL	.TSTRG##
	POP	P,T1
	CALL	.TDECD
	RET
	SUBTTL	NSP Message Type Routines -- DC message

RCVDC:				;DC message
	CALL DLASLA		;PUT OUT DLA AND SLA
	  RET			;PROPOGATE ERROR
	WRTSTR <, Reason: >
	CALL GET2BY		;GET REASON CODE
	  FMTERR No reason code,RSKP
	CALL RSNTXT		;TYPE OUT REASON TEXT
	CALL .TCRLF##
	RETSKP
	SUBTTL	NSP Message Type Routines -- NOP message

RCVNOP:				;NOP message
	CALL DLASLA		;PUT OUT DLA AND SLA
	  RET			;PROPOGATE ERROR
	CALL ACKSEG		;PUT OUT ACK AND/OR SEGNUM
	  RET			;PROPOGATE ERROR
	CALL .TCRLF##
	WRTSTR <	Test Data: >
	CALLRET FMTSTR		;PUT OUT REST OF MSG AS A STRING
	SUBTTL	DLASLA - Output DLA and SLA for a Message


DLASLA:	WRTSTR <DLA: >
	CALL GET2BY		;DLA IS 2 BYTES LONG
	  FMTERR No dest link address bytes,RSKP
	CALL .TOCTW##		;LINK ADDRESSES ARE OCTAL
	WRTSTR <, SLA: >
	CALL GET2BY		;SLA IS 2 BYTES LONG
	  FMTERR No source link address bytes,RSKP
	CALL .TOCTW##		;LINK ADDRESSES ARE OCTAL
	RETSKP			;SUCCESS RETURN


ACKFLD:	SAVEAC P1
	CALL GET2BY		;ACK & SEG BOTH 2 BYTES LONG
	  FMTERR No ACK field in ACK message,RSKP
	MOVE P1,T1		;SAVE ACK OR SEGNUM FIELD
	CALL ACKPRT		;(P1)PRINT ACK FIELD
				;SEE IF THERE IS A PHASE 4 CROSS-CHNL ACK
	CALL GET2BY		;ACK & SEG BOTH 2 BYTES LONG
	  RETSKP		;ACK MESSAGE HAS NO FIELDS AFTER 'ACK'
	MOVE P1,T1		;SAVE ACK OR SEGNUM FIELD
	CALL ACKPRT		;(P1)PRINT ACK FIELD
	RETSKP			;SUCCESS RETURN

ACKSEG:	SAVEAC P1
ACKSG1:	CALL GET2BY		;ACK & SEG BOTH 2 BYTES LONG
	  FMTERR No segment number,RSKP
	MOVE P1,T1		;SAVE ACK OR SEGNUM FIELD
	TXNN P1,AKPNT		;IS ACK PRESENT?
	JRST ACKSG2		;NO, THIS IS A SEG NUMBER

	CALL ACKPRT		;(P1)PRINT ACK FIELD
	JRST ACKSG1		;TRY NEXT, MIGHT BE PHASE 4 CROSS-CHNL ACK

ACKSG2:	TXNN P1,40000		;ACK DELAY set?
	JRST ACKSG3		; -no
	WRTSTR <, ACKDLY: ON >
ACKSG3:	WRTSTR <, SEGNUM: >
	MOVE T1,P1		;RECOVER SEGMENT NUMBER
	ANDI T1,7777		;ONLY 12 BITS COUNT, IGNORE QUAL FIELD
	CALL .TDECD		;(T1)WRITE SEGMENT NUMBER IN DECIMAL
	RETSKP			;SUCCESS RETURN


ACKPRT:	LOAD T2,AKQAL,+P1	     ;GET QUALIFIER (ACK OR NAK)
	MOVEI T1,[ASCIZ /, ACK: /]   ;ASSUME ITS AN ACK
	CAIN T2,AK$QNK		     ;IS IT A NAK?
	MOVEI T1,[ASCIZ /, NAK: /]   ;YES
	CAIN T2,AK$CAK		     ;IS IT A CROSS-SUBCHNL ACK?
	MOVEI T1,[ASCIZ /, CCACK: /] ;YES
	CAIN T2,AK$CNK		     ;IS IT A CROSS-SUBCHNL NAK?
	MOVEI T1,[ASCIZ /, CCNAK: /] ;YES
	CALL .TSTRG##
	LOAD T1,AKNUM,+P1	     ;GET THE ACKNUM VALUE
	CALLRET .TDECD		     ;TYPE IT OUT IN DECIMAL
	SUBTTL	Byte Manipulation Routines

;GETnBY - Get next n bytes from the current message block
;
;Set up by REDMSG
;
;Call:	SEQPTR/ Byte pointer into SEQBFR
;	SEQBFR/ The message all in one sequential lot
;	SEQCNT/ Remaining length of message in SEQBFR
;	CALL GETnBY
;	  'No more' return
;	Normal return with value in T1

GET1BY:	SOSGE SEQCNT		;ANY MORE TO EAT?
	RET			;NO, 'NO MORE' RETURN
	ILDB T1,SEQPTR		;LOAD UP THE BYTE
	RETSKP			;SUCCESS RETURN


GET2BY:	MOVNI T1,2		;WE'LL NEED TWO BYTES
	ADDB T1,SEQCNT		;SUBTRACT 2 FROM COUNT
	JUMPL T1,RTN		;'NO MORE' RETURN
	ILDB T1,SEQPTR		;GET LOW-ORDER BYTE
	ILDB T2,SEQPTR		; THEN HIGH-ORDER BYTE
	LSH T2,10		;SHIFT HIGH-ORDER LEFT 8 BITS
	IOR T1,T2		;MAKE UP 16-BIT VALUE
	RETSKP			;SUCCESS RETURN
;GTOnBY - Get indicated n bytes from the current message block
;
;Set up by REDMSG
;
;Call:	T1/ Offset to beginning of byte (first byte is offset ONE)
;	SEQPTR/ Byte pointer into SEQBFR
;	SEQBFR/ The message all in one sequential lot
;	SEQCNT/ Remaining length of message in SEQBFR
;	CALL GETnBY
;	  'Out-of-range' return
;	Normal return with value in T1

GTO1BY:	CAMLE T1,SEQLEN		;.LEQ. LENGTH OF MESSAGE?
	RET			;NO, 'OUT-OF-RANGE' RETURN
	ADJBP T1,[POINT 8,SEQBFR] ;YES, MAKE A BYTE PTR TO INDICATED BYTE
	LDB T1,T1		;LOAD UP THE BYTE
	RETSKP			;SUCCESS RETURN

GTO2BY:	CAML T1,SEQLEN		;.LEQ. LENGTH-1 OF MESSAGE?
	RET			;NO, 'OUT-OF-RANGE' RETURN
	ADJBP T1,[POINT 8,SEQBFR] ;YES, MAKE A BYTE PTR TO FIRST BYTE
	LDB T2,T1		;LOAD UP LOW-ORDER BYTE
	ILDB T1,T1		;LOAD UP HIGH-ORDER BYTE
	LSH T1,10		;SHIFT LEFT 8 BITS TO MAKE IT HIGH-ORDER
	IOR T1,T2		;MAKE UP 16-BIT VALUE
	RETSKP
;RED1BY - Get next byte from the current message block
;
;Called only by REDMSG
;
;Call:	MS/ Ptr to current MSD
;	MBO/ Offset from monitor address to MSGBLK
;	CALL GETnBY
;	  'No more' return
;	Normal return with value in T1

RED1BY:	DO.
	  LOAD T1,MDBYT,(MS)	;NUMBER OF BYTES LEFT IN THIS MSD
	  JUMPG T1,ENDLP.       ;JUMP IF STILL SOME LEFT
	  LOAD MS,MDNXT,(MS)	;POINT TO NEXT MSD
	  JUMPE MS,RTN		;NON-SKIP RET IF EMPTY
	  SUB MS,MBO		;ADJUST MSD ADDRESS WITH OFFSET
	  JRST TOP.		;CHECK OUT THIS MSD NOW
	ENDDO.

	LOAD T2,MHIOL,+MSGHDR   ;GET INPUT/OUTPUT/LOCAL INDICATOR
	MOVEI T1,MD.PTR(MS)     ;ASSUME INPUT
	CAIE T2,IOL.IN		;BUT IF OUTPUT OR LOCAL
	 MOVEI T1,MD.AUX(MS)    ;  ... USE OUTPUT'S BYTE PTR

	MOVE T2,(T1)            ;GET BYTE POINTER CALLER WILL USE
	TLZN T2,17		;ERASE MONITOR'S INDEX
	IFSKP.                  ;IF THERE WAS ONE...
	  LOAD T3,MDALA,(MS)	;GET ALLOCATED ADDRESS OF DATA
	  SUB T3,MBO		;ADJUST TO MSGBLK
	  CAIGE T3,MSGBLK+MB.LEN ;IS THE RESULT
	   CAIG  T3,MSGBLK      ; INSIDE THE MSG BLK?
	    MOVEI T3,USERDA     ;NO, MUST BE IN USER DATA BLK
	  ADD T2,T3		;ADD INDEX INTO Y FIELD OF BYTE PTR
	  MOVEM T2,(T1)         ;RESTORE UPDATED BYTE PTR
	ENDIF.
	DECR MDBYT,(MS)		;ACCOUNT FOR BYTE WE READ
	ILDB T1,(T1)            ;GET NEXT BYTE TO RETURN IN T1
	RETSKP                  ;SUCCESS RETURN
	SUBTTL MSGLEN - Returns remaining message length

;MSGLEN - Returns remaining message length
;
;Call:	MS & MBO set up by REDMSG
;	CALL MSGLEN
;	  Error return
;	Normal return with length in T1

MSGLEN:	SETZ T1,		;COLLECT TOTAL COUNT HERE
	SKIPN T4,MS		;DON'T DISTURB CALLER'S MS
	  RETSKP		;IF NO MSD, LENGTH IS ZERO
MSGLN1:	OPSTR <ADD T1,>,MDBYT,(T4) ;NUMBER OF BYTES LEFT IN THIS MSD
	LOAD T4,MDNXT,(T4)	;POINT TO NEXT MSD
	JUMPE T4,RSKP		;SUCCESS RETURN WHEN WE GET TO END
	SUB T4,MBO		;ADJUST NEW MSD ADDRESS WITH OFFSET
	JRST MSGLN1		;ADD IN THE NEXT MSD
	SUBTTL	Input/Output Routines

;REDBLK - Read the next data block from trace file into memory
;
;Call:	T1/	AOBJN Pointer to block to fill
;	CALL REDBLK
;	  Error Return (eg, EOF)
;	Normal Return

REDBLK:	SAVEAC P1
	MOVE P1,T1		;SAVE AOBJN PTR IN P1

REDBL1:	CALL INBYT		;GET NEXT WORD FROM INPUT FILE
	  RET			;PROPOGATE ERROR RETURN
	MOVEM T1,(P1)		;STORE WORD IN TARGET BLOCK
	AOBJN P1,REDBL1		;LOOP OVER WHOLE BLOCK
	RETSKP			;SUCCESS RETURN
;TYPOUT - Called from SCAN

TYPOUT:	SKIPE TYPFIL		;IF FLAG SET, WRITE OUTPUT TO FILE
	  JRST .OTBYT		;YES
	OUTCHR T1		;NO, OUTPUT DIRECTLY TO TTY
	RET			;ALWAYS TAKE NON-SKIP RET

;Call with byte to be output in T1

.OTBYT::
.OTBY1:!SOSGE H.FOUT+.BFCTR	;H.FOUT = HEADER FOR FILE OUTPUT
	  JRST OUTBYN		;NO ROOM, GET A NEW BUFFER
	IDPB T1,H.FOUT+.BFPTR	;THE NORMAL OUTPUT DEPOSIT BYTE.
	RET			;SUCCESS RETURN

OUTBYN:	CALL .OTBUF		;OUTPUT THE BUFFER
	  RET			;"DON'T CONTINUE" RETURN
	JRST .OTBY1		;GOT A BUFFER, GO COUNT IT DOWN



;CALL	CALL	.OTBUF
;	  "DON'T CONTINUE" RETURN
;	"OK" RETURN

.OTBUF:	OUT	F.FOUT,
	  RETSKP		;OK RETURN: SUCCESS

	ERROR OUT,<Error from OUT UUO>
	EXIT
;INBYT -- GET NEXT BYTE FROM DATA FILE
;CALL:	CALL	INBYT
;	  ERROR RETURN IF END-OF-FILE
;	NORMAL RETURN WITH BYTE IN T1

INBYT:	SOSGE H.FIN+.BFCTR	;SEE IF BYTE IN BUFFER
	  JRST INBYT1		;NO--READ SOME MORE OF FILE
	ILDB T1,H.FIN+.BFPTR	;FETCH BYTE
	RETSKP			;SUCCESS RETURN

INBYT1:	CALL INBUF		;INPUT A BUFFER
	  RET			;"DON'T CONTINUE" RETURN
	JRST INBYT		;"OK" RETURN

;CALL	CALL	INBUF
;	  "DON'T CONTINUE" RETURN
;	"OK" RETURN

INBUF:	IN	F.FIN,		;READ A BUFFER
	  RETSKP		;OK TO PROCEED: SUCCESS
				;ERROR, CHECK IT OUT
	GETSTS	F.FIN, T1
	TXNN	T1, IO.ERR	;ANY ERRORS?
	  JRST	INBUF1		;NO, TEST FOR EOF
	ERROR INP,<Error in file input>
	EXIT

INBUF1:	TXNN	T1, IO.EOF	;HAVE WE SEEN EOF?
RSKP:	  AOS	(P)		;NO--GET MORE DATA
RTN:	RET			;YES--"DON'T CONTINUE" RETURN

TPOPJ1:	AOS -1(P)
TPOPJ:	POP P,T1
	RET
	SUBTTL Miscellaneous Routines


;Call:	T1/ Circuit ID
;	CALL .TCKT
;	Normal Return

.TCKT:	SAVEAC <P1>
	MOVE P1,T1		;PRESERVE CIRCUIT-ID
	LOAD T1,LIDEV,+P1	;GET THE DEVICE TYPE RIGHT JUSTIFIED
	CAILE T1,0		;IS THE DEVICE TYPE WITHIN RANGE?
	CAILE T1,DEVTLN
	JRST [MOVE T1,P1	;NO - JUST OUTPUT IT IN OCTAL
	      JRST .TOCTW]
	MOVE T1,DEVTAB(T1)	;GET THE NAME OF THE DEVICE
	CALL .TSIXN##		;TYPE IT OUT
	MOVEI T1,"-"		;TYPE THE "-"
	CALL .TCHAR
	LOAD T1,LIKON,+P1	;NOW GET THE CONTROLLER (CPU) NUMBER
	CALL .TOCTW		;TYPE IT OUT
	LOAD T1,LIDEV,+P1	;GET DEVICE TYPE
	CAXN T1,LD.DMR		;A DMR?
	 RET			;YES, CIRCUIT NAME IS DMR-N ONLY
	MOVEI T1,"-"		;TYPE THE "-"
	CALL .TCHAR
	LOAD T1,LIUNI,+P1	;AND LAST DO THE UNIT NUMBER
	CALL .TOCTW		;TYPE IT AND RETURN
	LOAD T1,LIDEV,+P1	;GET DEVICE TYPE
	CAXE T1,LD.CIP		;IS THIS A CI DEVICE?
	RET			;NO
	MOVEI T1,"."		;YES, TYPE
	CALL .TCHAR		; A DOT
	LOAD T1,LIDRP,+P1	;LOAD THE DROP NUMBER (PORT ON THE CI)
	CALLRET .TDECW##	;TYPE IT IN DECIMAL AND RETURN TO CALLER


DEVTAB:	SIXBIT /TST/		;TEST BED DRIVER
	SIXBIT /DTE/		;DTE
	SIXBIT /KDP/		;KDP
	SIXBIT /DDP/		;DDP
	SIXBIT /CI/		;CI
IFN FTOPS20,<
	SIXBIT /NI/		;NI
>
IFN FTOPS10,<
	SIXBIT /ETH/		;ETH
>
	SIXBIT /DMR/		;DMR
DEVTLN==.-DEVTAB

	SUBTTL Miscellaneous Routines

;CKSNRM - Make full word checksum into 16 bit checksum
;
; Call: 
;	T1/ Full word checksum
;
; Return: 
;	RET			;WITH T1 CONTAINING THE 16 BIT CHECKSUM
;
; Uses: T1-T2

CKSNRM:	MOVE T2,T1		;GET A COPY OF THE CHECKSUM
	TDZE T2,[EXP ^-177777]	;IF ANY OVERFLOW, CLEAR IT
	JRST [LSH T1,-^D16	;ADD OVERFLOW BACK INTO
	      ADDB T2,T1	; THE LOW ORDER BYTES
	      JRST .-1]		;LOOP UNTIL DONE
	RET			;RETURN
.TTIVR:	WRTSTR <, Version >
	CALL GET1BY
	 FMTERR No TIVER,RTN
	CALL .TDECD
	CALL GET1BY
	 FMTERR No TIVER,RTN
	CALL .TDECD
	CALL GET1BY
	 FMTERR No TIVER,RTN
	CALLRET .TDECW##

.TBLKS:	WRTSTR <	Block size: >
	CALL GET2BY
	 FMTERR No BLKSIZE,RTN
	CALLRET .TDECD
;Call:	T1/ value (node number)
;	CALL .TNODE
;	Normal Return

.TNODE:	PUSH P,T1		;SAVE WHOLE NODE NUMBER
	ASH T1,-12		;GET AREA NUMBER ONLY
	CALL .TDECD		;PRINT IT WITH A DOT FOLLOWING
	POP P,T1		;RECOVER WHOLE NODE NUMBER
	ANDI T1,1777		;GET NODE-WITHIN-AREA NUMBER
	CALLRET .TDECW##	;PRINT WITHOUT DOT FOLLOWING

;Call:	T1/ value
;	CALL .TDECD
;	Normal Return

.TDECD:	CALL .TDECW##		;TYPE T1 IN DECIMAL
.TDOT:	MOVEI T1,"."		;LOAD UP A DECIMAL POINT
	CALLRET .TCHAR		;FOLLOWED BY A DECIMAL POINT



IFN FTOPS10,<
.TTADS:				;TYPE OUT DATE/TIME, SHORT FORM
.TTADL:				;TYPE OUT DATE/TIME, LONG FORM
	CALLRET .TDTTM##	;CALL SCAN'S TYPOUT ROUTINE
>;END IFN FTOPS10

IFN FTOPS20,<			;ALREADY MSECS ON TOPS20
.TTADL:	SKIPA T3,[ -1 ]		;TYPE OUT DATE/TIME, LONG FORM
.TTADS:	 MOVSI T3,200001	;TYPE OUT DATE/TIME, SHORT FORM
	MOVE T2,T1		;DATE/TIME IN AC 2
	MOVEI T1,1(P)		;POINTER TO STRING SPACE
	HRLI T1,440700		;MAKE IT A 7-BIT POINTER FOR .TSTRG, BELOW
	ADJSP P,20		;MAKE SOME STRING SPACE
	PUSH P,T1		;SAVE PTR TO STRING SPACE
	ODTIM			;OUTPUT DATE/TIME JSYS
	ERJMP .+1		;IGNORE ERRORS FOR NOW
	SETZ T2,		;MAKE A NULL
	IDPB T2,T1		;STORE AT END OF DATE/TIME STRING FOR ASCIZ
	POP P,T1		;PTR TO START OF STRING SPACE AGAIN
	CALL .TSTRG##		;OUTPUT ASCIZ STRING
	ADJSP P,-20		;CLEAR STACK
	RET			;ONLY RETURN
>;END IFN FTOPS20
.TJIFY:
IFN FTOPS10,<			;ALREADY MSECS ON TOPS20
	IMULI T1,^D1000		;JIFFIES TO MSECS
	IDIVI T1,^D60		; WITHOUT LOSING PRECISION
>;END IFN FTOPS10
	IDIV T1,[^D3600000]	;GET HOURS, WITH MINUTES IN REMAINDER
	PUSH P,T2		;SAVE REST
	MOVEI T2," "		;FILL WITH SPACE
	CALL .TDEC2##		;TYPE TWO DIGITS
	CALL .TCOLN##		;TYPE COLON
	POP P,T1		;RESTORE REST
	IDIVI T1,^D60000	;GET MINS
	PUSH P,T2		;SAVE REST
	CALL TDEC2Z		;TYPE TWO DIGITS WITH 0 FILLER
	CALL .TCOLN##		;TYPE COLON
	POP P,T1		;RESTORE THE REST
	IDIVI T1,^D1000		;GET SECONDS
	PUSH P,T2		;SAVE REMAINDER
	CALL TDEC2Z		;TYPE SECONDS
	MOVEI T1,"."		;GET A DOT
	CALL .TCHAR##		;TYPE IT
	POP P,T1		;RESTORE MILLISECOND REMAINDER
	CAILE T1,^D99		;SEE IF THREE DIGITS
	CALLRET .TDECW##	;YES, JUST TYPE IT AND LEAVE NOW
	PUSH P,T1		;NO, PUT MSECS BACK ON THE STACK
	MOVEI T1,"0"		;FILL WITH A ZERO
	CALL .TCHAR##		;TYPE
	POP P,T1		;FINISH OFF WITH 2 MORE DIGITS
TDEC2Z:	MOVEI T2,"0"		;FILL WITH 0
	CALLRET .TDEC2##	;FINISH OFF WITH 2 DECIMAL DIGITS

.TDEC4:	PUSH P,T1		;SAVE NUMBER
	CAIG T1,^D999
	 PUSHJ P,.TSPAC##
	MOVE T1,(P)
	CAIG T1,^D99
	 PUSHJ P,.TSPAC##
	MOVE T1,(P)
	CAIG T1,^D9
	 PUSHJ P,.TSPAC##
	POP P,T1
	CALLRE .TDECW##
	SUBTTL Extra Routines

IFN FTOPS20,<

.HELPR::RET			;TOPS20 HAS NO HELPER

>;END IFN FTOPS20

IFN FTOPS10,<

G::	PUSH P,.JBOPC		;PICK UP OLD PC (FOR DDT RETURN)
	POPJ P,			;RETURN, IGNORING LH, SAVING ALL ACS

>;END IFN FTOPS10

;This should be last

LITRAL::$XLIST			;LIT
	LIT
	$LIST
	SUBTTL	End of Program

	END	DNTATL