Google
 

Trailing-Edge - PDP-10 Archives - bb-bt99s-bb - 10,7/networ/networ.mac
There are 9 other files named networ.mac in the archive. Click here to see a list.
TITLE	NETWORK Program to list the nodes in a network
	SUBTTL	S. Sullivan/SES/RCB	20-Jul-89

	SALL			;Pretty	listings
	.DIREC	FLBLST		;Prettier listings

	.TEXT	\/SYMSEG:HIGH/LOCALS\

COMMENT@

COPYRIGHT (c) DIGITAL EQUIPMENT CORPORATION 1979,1988,1990.
ALL RIGHTS RESERVED.	


THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED AND COPIED
ONLY  IN  ACCORDANCE  WITH  THE	 TERMS	OF  SUCH LICENSE AND WITH THE
INCLUSION OF THE ABOVE COPYRIGHT NOTICE.  THIS SOFTWARE	OR ANY	OTHER
COPIES THEREOF MAY NOT BE PROVIDED OR OTHERWISE	MADE AVAILABLE TO ANY
OTHER PERSON.  NO TITLE	TO AND OWNERSHIP OF THE	 SOFTWARE  IS  HEREBY
TRANSFERRED.

THE INFORMATION	IN THIS	SOFTWARE IS SUBJECT TO CHANGE WITHOUT  NOTICE
AND  SHOULD  NOT  BE  CONSTRUED	 AS A COMMITMENT BY DIGITAL EQUIPMENT
CORPORATION.

DIGITAL	ASSUMES	NO RESPONSIBILITY FOR THE USE OR RELIABILITY  OF  ITS
SOFTWARE ON EQUIPMENT WHICH IS NOT SUPPLIED BY DIGITAL.
@
	SUBTTL	Edit history

COMMENT	@
[1]	Add the	/TYPE: switch to determine a node by its type
[2]	Fix the	core freeing code in CLRDAT to not zero	DDT when loaded
[3]	Fix the	BLT in CLRDAT so it does not initalize MATCH to	-1
[4]	Fix the	.ISCAN call so indirect	files are illegal if logged out
[5]	Make sure the user can't get into a "*"	mode if	not logged in
[6]	Take care of the way the NODE. UUO error returns easier	now
[7]	Make CONC use .ISLGI in	SCAN to	be consistant in checking if logged in
[10]	We saved the temps too early in	the OFLINE routine
[11]	Make sure that we are able to recover from a node in a "funny" state
[12]	Buffer TTY output to reduce monitor overhead
[13]	Change "NODE" in output	to "Node"
[14]	Change the HOST	switch to be HOSTESS to	be monitor compatable
[15]	Make the program Reenterable by	setting	up .JBREN
[16]	Change the way TRMOP. errors are handled and fix
	miscellaneous bugs.
[17]	Make a zero low	segment. Remove	EXPs and replace with BLOCK.
[20]	Don't allow "*"	mode if	not logged in...only can do when we
	get control because SCAN has a matching	bug, before we get it.
[21]	Add a reset instruction	because	the dispatch through RUNAME
	or RUNAMC in COMCON or the RUN/R command will not do a
	reset unless the program is gotten from	DSK. This means
	that if	the sharable dormant high seg was there	and there
	was no low seg an address check	was the	result.
[22]	Fix OFLINE and correct other error recovery problems
[23]	Add the	/TOPOLOGY,/COST, and /SORT switches and	fix some
	more small bugs	including a stack phase	problem	when we
	used the default case (null node name).
[24]	Fix the	output from /TOPOLOGY so final node,cost pair is
	preceeded by a tab.
[25]	Version	2! Add DECnet to the program. Reorganize the structure
	to make	it easier to add new networks as they come along.
	Also, fix some bugs
[26]	Fix /LINKS to work consistantly, consolidate code in the
	DECnet listing routines.
[27]	Fix to work with new DNET. uuo,	as per MCO 10716.

%2(27)	Shipped	with 7.02

[30]	Fix to work with DECnet	Phase IV.
[31]	Update copyright notice	for 7.03.
[32]	Teach how to report non-named nodes on DECnet display

33	RDH	16-Apr-85
	De-PRGEND this beast. Call version 3.

34	RDH	16-Apr-85
	Add LAT service junk.

35	LEO	4-Sep-85
	Do Copyrights.

36	WXD	3-Oct-85
	Teach about DECnet endnode support.

Become version 3A.

37	RCB	6-Nov-86
	Fix LAT support.

40	RCB	26-Nov-86
	More fixes to LAT support.

41	RCB	12-May-87
	Fix LAT support to account for MCO 13392.

42	RCB	25-May-87
	Fix LAT support to defer the header line until we find a need to
	type it.

43	RCB	14-Jun-88
	Fix for FTNET on but M.NET off.

44	RCB	14-Jul-88
	Fix OUTC to preserve T1 like SCAN expects of its .TCHAR routines.

45	RCB	20-Jul-89
	Take advantage of SCAN edit 674 to allow /NOSORT without cluttering
	the switch table.

@
	SUBTTL	Constants, symbols, and	registers

	SEARCH UUOSYM,JOBDAT,MACTEN,SCNMAC

	.REQUE	REL:SCAN.REL
	.REQUE	REL:HELPER.REL

	TWOSEG	400000			;So the	program	will have two segments

;** Define the version word

	CUSTVR==0			;Customer version
	DECVER==3			;DEC version
	DECMVR==3			;DEC minor version
	DECEVR==45			;DEC edit number

	NETVER==<BYTE(3)CUSTVR(9)DECVER(6)DECMVR(18)DECEVR>

	LOC	137

	NETVER



;** Set	up .JBINT for interrupt	trapping

	LOC	134			;Set PC	at .JBINT and
	EXP	INTBLK			;make it point to our interrupt	block

;** Set	up .JBREN to allow users to "Reenter" the program

	LOC	124			;Set PC	at .JBREN
	EXP	START+1			;Begin at CCL start address

	RELOC				;Set back to the high segment


COPYRIGHT (c) DIGITAL EQUIPMENT	CORPORATION 1979,1990. ALL RIGHTS RESERVED.
\;END COPYRIGHT MACRO
;REGISTER DEFINITIONS

F==0		;Flags
	F.SEL==1B0
	F.HED==1B1
T1==1		;Temps
T2==2
T3==3
T4==4
P1==5		;Save registers
P2==6
P3==7		;For passing arguments to SCAN
P4==10
T5==11
T6==12
T7==13
CN==14		;Current node we are processing
L1==15		;First loop counter
L2==16		;Second	loop counter
P==17		;Stack pointer


;DEFINITIONS NOT YET IN	UUOSYM

DN%ARE==176000			;DECnet	area number
DN%NOD==001777			;DECnet	node number field
;Program parameters

MAXSPC==^D100		;The max number	of specs we will allow
DNMAX==^D1024		;The max number	of DECnet nodes	we support
DNINFL==40		;Size of DNINF block
MAXNOD==200		;The max number	of ANF nodes we can handle
NODDLN==100		;Size of NODE. block data buffer
LTMAX==6*^D200		;The max size of LAT links list we can handle
BLKSIZ==.FXLEN		;Number	of words allocated to each Scan	block
PREALO==MAXNOD/10	;How many nnode specs to preallocate for
MAXNFE==MAXNOD/2	;Maximum # of non-fatal	errors we will allow
MAXCOR==10000		;The maximum amount of core we allow (in words)
MO.CHR==400000		;Character mode	 bit
DEFWID==^D72		;Define	our default width
PSIZ==100		;Number	of words in the	stack
	SUBTTL	Impure storage

	RELOC		;Set to	low segment for	data and stack

PDL:	BLOCK	PSIZ		;Stack

;** Interrupt block

INTBLK:	BLOCK	1		;4 words long,,interrupt handler
	BLOCK	1		;No message control,, 2	^C
LASTPC:	BLOCK	1		;User PC stored	here when interrupted
INTYPE:	BLOCK	1		;interrupt type	in LH
	SUBTTL	UUO  argument blocks

STDAT:!			;Start of core to be zeroed on initalization

LTLCNT:	BLOCK	1			;How many LAT TTYs are connected
LTLINK:	BLOCK	LTMAX			;List of LAT terminal connections
LATUNM:	BLOCK	2			;User name for link info
LATPRG:	BLOCK	1			;Program name for link info
LATPPN:	BLOCK	1			;PPN for link info
LATJOB:	BLOCK	1			;Job for link info
LATTNM:	BLOCK	1			;TTY name for link info
LATPNM:	BLOCK	22			;Port name for link info
NOPBLK:	BLOCK	.NOPNM+1		;NETOP. arg block

DNLOOP:	BLOCK	1			;AOBJN loop counter
DNLOC:	BLOCK	1			;SIXBIT	name of	local node
DNADR:	BLOCK	1			;Local node network address
DNLST:	BLOCK	DNMAX			;Max size of DECnet network
DNBIT:	BLOCK	DNMAX			;Parallel table	to DNLST for flags
	DN.LST==400000			;*don't	list this node
	DN.ONL==200000			;*this node is on-line
	DN.ACT==100000			;*this node is active
DNBLK:	BLOCK	20			;Size of info block
DNCNT:	BLOCK	1			;Count of nodes	returned
DNMCNT:	BLOCK	1			;Count of nodes	matched	by specs
DNINF:	BLOCK	DNINFL			;DNET. UUO block for info
DNLINE:	BLOCK	5			;String	block for line descriptor
	DNLINN==<<.-DNLINE>*5>-1	;How many bytes	for the	descriptor

;** Argument block for the NODE. UUO's .NDNDB function

NODBLK:	BLOCK	1		;NODE. UUO arg block
CURNOD:	BLOCK	1		;Current node number
FLDNUM:	BLOCK	1		;Field number we want
DATBLK:	BLOCK	NODDLN		;Data area

;** Argument block for the TRMOP. UUO's	.TOWID function

TTWID:	BLOCK	1		;Function code to get TTY width
UDX:	BLOCK	1		;Our TTY's UDX

;** argument block for the NODE. UUO's .NDLND function
;   This generates a list of all the nodes in the network by number

NODNUM:	BLOCK	1		;Header	for UUO
NODBIN:	BLOCK	MAXNOD		;The list of the node numbers
NODNAM:	BLOCK	MAXNOD		;The list of the node names
	SUBTTL	Tables to allow	wildcarding node names
;** List of valid node spec's

SPCCNT:	BLOCK	1		;Count of valid	specs
SPCFLG:	BLOCK	MAXSPC		;List for flags	pertaining to specs
	;LH bits - non error conditions
	SP.ANF==400000		;Node found in the ANF10 network
	SP.DEC==200000		;Node found in the DECnet network
	SP.LAT==100000		;Node found in LAT network
	;RH bits - error conditions
	SP.NNN==400000		;Node not found
	SP.NWD==200000		;Node went away	while processing
SPCLST:	BLOCK	MAXSPC		;List of node specs we have read
WLDLST:	BLOCK	MAXSPC		;List of wild card masks

;** Our	model of an NDB. We copy the nodes NDB here so we can get it easier

NNM:	BLOCK	1		;Node number
SNM:	BLOCK	1		;Node name in sixbit
SID:	BLOCK	10		;Software ID (asciz)
DAT:	BLOCK	10		;Software date (asciz)
LMA:	BLOCK	1		;Last NCL message assigned
LMS:	BLOCK	1		;Last NCL ACK message sent
LAR:	BLOCK	1		;Last NCL ACK recieved
LAP:	BLOCK	1		;Last NCL ACK processed
LMR:	BLOCK	1		;Last NCL message recieved
LMP:	BLOCK	1		;Last NCL message processed
LAS:	BLOCK	1		;Last NCL ACK sent
MOM:	BLOCK	1		;Maximum outstanding message counter
TOP:	BLOCK	20		;Network topology table	in the form
				;XWD Level , Node
CNF:	BLOCK	20		;Configuration table in	the form
				;XWD Object , Number
ENDB:	BLOCK	1		;End of	our NDB
	SUBTTL	Scan related switces

;** Scan switch	storage

FIRSW:!				;Start of switch area
WIDWD:	BLOCK	1		;/WIDTH:nn switch.
FASWD:	BLOCK	1		;Short listing switch
SILWD:	BLOCK	1		;/SILENCE switch
ANF10W:	BLOCK	1		;/ANF10	switch
DECNWD:	BLOCK	1		;/DECNET switch
LATNWD:	BLOCK	1		;/LAT switch
URCHWD:	BLOCK	1		;/UNREACHABLE switch
HEADWD:	BLOCK	1		;/HEADERS switch
BRIEWD:	BLOCK	1		;/BRIEF	switch
TOPWD:	BLOCK	1		;/TOPOLOGY switch
ERRWD:	BLOCK	1		;/ERROR	switch
COSTWD:	BLOCK	1		;/COST switch
SORTWD:	BLOCK	1		;/SORT switch
LINKWD:	BLOCK	1		;/LINKS	switch

;** The	following ^d13 locations must be contigous and in the same order

MCRWD:	BLOCK	1		;Switch	for nodes with "MCR"
TTYWD:	BLOCK	1		;Switch	for nodes with "TTY"
CDRWD:	BLOCK	1		;Switch	for nodes with "CDR"
LPTWD:	BLOCK	1		;Switch	for nodes with "LPT"
PTRWD:	BLOCK	1		;Switch	for nodes with "PTR"
PTPWD:	BLOCK	1		;Switch	for nodes with "PTP"
PLTWD:	BLOCK	1		;Switch	for nodes with "PLT"
MTAWD:	BLOCK	1		;Switch	for nodes with "MTA"
DTAWD:	BLOCK	1		;Switch	for nodes with "DTA"
TSKWD:	BLOCK	1		;Switch	for nodes with "TSK"
RDAWD:	BLOCK	1		;Switch	for nodes with "RDA"
CDPWD:	BLOCK	1		;Switch	for ndoes with "CDP"
DDPWD:	BLOCK	1		;Switch	for nodes with "DDP"
	NDEV==.-MCRWD		;Length	of table of device switches

TYPWD:	BLOCK	1		;Value for the /TYPE switch
LASTSW:!			;Last switch location
;** Other random variables used	in odd places

JOB:	BLOCK	1		;Our job number
MATCH:	BLOCK	1		;Count of matches or match errors
CARWID:	BLOCK	1		;The width we are using
FIRSTL:	BLOCK	1		;Count of times	through	the SHOLST code
SBMCNT:	BLOCK	1		;Count of Scan block error message
OFFSET:	BLOCK	1		;The starting offset
WMATCH:	BLOCK	1		;Flag for status of a wildcard search
HPOS:	BLOCK	1		;The current horizontallocation	of the carriage
NFECNT:	BLOCK	1		;Number	of non-fatal errors
OUTCON:	BLOCK	1		;Output	control	word
ANFCNT:	BLOCK	1		;Count of nodes	that were found	to match specs
FTANF:	BLOCK	1		;-1 means monitor has ANF10 software
FTDEC:	BLOCK	1		;-1 means monitor has DECnet software
FTEND:	BLOCK	1		;-1 means DECnet running as ethernet endnode
FTLAT:	BLOCK	1		;-1 means monitor has LAT software
TEMP:	BLOCK	BLKSIZ+1	;Our scratch area

;** TTY	buffer space

NCHAR:	BLOCK	1		;Number	of characters in the buffer
BUFFP:	BLOCK	1		;Pointer into the buffer
BUFFER:	BLOCK	^D100		;TTY buffer
	BUFSIZ==<<.-BUFFER> * 5	> - 2	;Number	of characters in the buffer
	SUBTTL	Scan block storage area

;** Counters to	keep track of the Scan block allocation

OUTFIL:	BLOCK	1		;Number	of output specs
INFIL:	BLOCK	1		;Number	of input specs
NUMBLK:	BLOCK	1		;Number	of scan	blocks allocated so far

;** Default area to store Scan blocks.
;   Must be at the end of core incase we want to expand

SBLKS:	BLOCK	PREALO*BLKSIZ	;Make large enough to hold 1 Scan block

ENDAT:!				;End of	our low	seg to be zeroed
	SUBTTL	Start up and main loop code

	RELOC			;Back to pure code

;** Here to get	the show on the	road

START:	TDZA	P,P			;Run start
	MOVEI	P,1			;CCL start
	MOVEM	P,OFFSET		;Save starting offset for Scan
	MOVE	P,[IOWD PSIZ,PDL]	;Set up	the stack
	RESET				;RESET to prevent address checks
	MOVEI	T1,START		;Get the reenter address
	MOVEM	T1,.JBREN		;  and set it up
	PUSHJ	P,INITIA		;Clear the data	base...
	PUSHJ	P,FLUSH			;Set up	the output buffer header
	PUSHJ	P,ISCN			;Initalize Scan
;	JRST	LOOP			;Fall into the main loop

;** Here to process the	main loop

LOOP:	PUSHJ	P,TSCN			;SCAN a	command	line
	PUSHJ	P,DISECT		;Parse the node spec's
	PUSHJ	P,ANF10			;Check out the ANF10 network
	PUSHJ	P,DECNET		;Check out the DECnet network
	PUSHJ	P,LATSER		;Check out the LAT 'network'
	PUSHJ	P,ERRSCN		;Check if node constraints too tight
LOOP1:	SKIPE	OFFSET			;Did we	CCL start?
	  JRST	FINISH			;Yes, exit and flush buffers
	PUSHJ	P,.ISLGI		;Are we	logged in?
	  JRST	FINISH			;No, exit and flush buffers
	PUSHJ	P,FLUSH			;Output	anything in the	buffer
	PUSHJ	P,INITIA		;Clear the data	base...
	PUSHJ	P,FLUSH			;Set up	our buffer headers again
	JRST	LOOP			;and look for another line of input
	SUBTTL	Data initialization routine
;** Routine to reset the data areas

INITIA:	HLRZ	T1,.JBSA		;Reduce	our core back to small
	SKIPN	.JBDDT			;Don't lose VMDDT
	CORE	T1,			;as we should be.
	  JFCL				;We don't care
	MOVE	T2,OFFSET		;Save our start	address	offset
	MOVE	T1,[STDAT,,STDAT+1]	;Get the start and end of impure data
	SETZM	STDAT			;Zero the first	word
	BLT	T1,ENDAT-1		;to the	last word
	SETOM	FIRSW			;Set the first location	of the
	MOVE	T1,[FIRSW,,FIRSW+1]	;Switch	block to -1, then
	BLT	T1,LASTSW-1		;The last one
					;*All switchs must be initalized
					;to -1 or Scan won't work right
	MOVE	T1,[INT,,INTBLK]	;initalize interrupt control block
	BLT	T1,INTBLK+IBLKLN	;from data in the high seg
	MOVEI	T1,.TOWID		;Set up	the argument block for TTY width
	MOVEM	T1,TTWID		;So we can find	his TTY's width
	MOVEI	T1,MAXNOD+1		;The max number	of nodes we can	handle
	MOVEM	T1,NODNUM		;So we can build tables	of nodes
	ADDI	T1,2			;Fix the value for the
	MOVEM	T1,NODBLK		;.NDNDB	function of the	NODE. UUO
	MOVEM	T2,OFFSET		;Restore the offset
	PJOB	T2,			;Get our job number
	MOVEM	T2,JOB			;Save it
	TRMNO.	T2,			;Get our TTY's UDX
	  SETO	T2,			;No, TRMNO. error, default is -1
	MOVEM	T2,UDX			;Yes, save it in TRMOP.	argument block
	MOVEI	T1,.TOWID		;TRMOP.	width function
	MOVE	T3,[XWD	2,T1]		;Set up	to get the TTY width
	TRMOP.	T3,			;Try for it
	  MOVEI	T3,DEFWID		;Error,	use the	default	width!
	MOVEM	T3,CARWID		;Save for other	routines
	SETZ	T1,			;There is no function zero
	NODE.	T1,			;Get an error
	SKIPE	T1			;UUO not implemented (AC unchanged)?
	SETO	T1,			;No, set the flag
	MOVEM	T1,FTANF		;Remember ANF-10 flag
	MOVE	T4,[%CNST2]		;Get the monitor status	word
	GETTAB	T4,			;...
	  PUSHJ	P,GTABER		;GETTAB	error? tell user and die
	TLNN	T4,(ST%D36)		;DECnet	here?
	TDZA	T1,T1			;No, zero the flag
	SETO	T1,			;Yes, set the flag
	MOVEM	T1,FTDEC		;Remember DECnet flag
	TLNN	T4,(ST%END)		;DECnet ethernet endnode?
	TDZA	T1,T1			;No, zero the flag
	SETO	T1,			;Yes, set the flag
	MOVEM	T1,FTEND		;Remember DECnet ethernet endnode flag
	MOVEI	T1,T2			;Point to pseudo-LATOP block
	SETZ	T2,			;Invalid length word
	LATOP.	T1,			;Try it
	CAIE	T1,LAADC%		;Get the right error return?
	TDZA	T1,T1			;No, have no LAT service
	SETO	T1,			;Yes, we win
	MOVEM	T1,FTLAT		;Save flag
	POPJ	P,			;Done...return
	SUBTTL	ANF10 processing loop

;** Here to do the ANF10 network display

ANF10:	SKIPE	FTANF			;Do we have ANF10 software?
	SKIPN	ANF10W			;Did we	have /NOANF?
	  POPJ	P,			;Yes just return
	SKIPLE	LINKWD			;/LINKS??
	SKIPLE	ANF10W			;Specify /ANF10?
	 CAIA				;Sense is wrong
	  POPJ	P,			;YES, skip ANF10 output
	SKIPG	ANF10W			;Specify /ANF10?
	SKIPG	DECNWD			;Specify DECnet	list?
	 CAIA				;Sense is wrong
	  POPJ	P,			;Yes, just return
	SKIPG	ANF10W			;Specify /ANF10?
	SKIPG	LATNWD			;Specify LAT list?
	 CAIA				;Sense is wrong
	  POPJ	P,			;Yes, just return
	PUSHJ	P,ANFTAB		;Build the ANF10 tables
	PUSHJ	P,ANFWLD		;Resolve ANF10 wildcarded node names
	SKIPN	ANFCNT			;Do we have anything to	print?
	  POPJ	P,			;No, quit now and save computes
	PUSHJ	P,ANFHEA		;Do ANF10 headers
	MOVN	L1,NODNUM		;Negate	the number of nodes
	HRLZS	L1			;Make it an AOBJN counter
ANFLOP:	HRRZ	CN,NODBIN(L1)		;Get the current node number
	MOVSI	T1,SP.ANF		;Do we want to list this node?
	TDNN	T1,NODBIN(L1)		;???
	  JRST	ANFLO1			;Nope!
	PUSHJ	P,BLDNDB		;Build a copy of the node's NDB
	  JRST	ANFLO1			;Skip the rest,	not quite there
	PUSHJ	P,SELECT		;Does node meet	switch constraints?
	TXNE	F,F.SEL			;Is the	node selected for printing?
	  PUSHJ	P,PRINFO		;Yes, Print selected info
ANFLO1:	AOBJN	L1,ANFLOP		;Increment and loop till done
	PJRST	CRLFH			;Finish	with a CRLF
;Here to print the ANF10 header, if we have any	nodes to print and
;if we did not specify /NOHEADERS

ANFHEA:	SKIPN	HEADWD			;Did they say no headers?
	  POPJ	P,			;Yes, don't!
	MOVEI	T1,[ASCIZ \[ANF10 network: connected to \] ;Say	what we	are doing
	PUSHJ	P,.TSTRG##		;...
	MOVE	T3,UDX			;Get our TTY's UDX
	GTNTN.	T3,			;Change	to NODE,,LINE
	  SETZ	T3,			;Don't care, catch it later
	HLRZS	T3			;Make the node number
	MOVEI	T2,2			;No, set up an argument	block
	MOVE	T1,[.NDRNN,,T2]		;and an	ac
	NODE.	T1,			;Use NODE. UUO to check	node
	  JRST	[MOVEI	T1,[ASCIZ \??????\]	;Unknown
		 PUSHJ	P,.TSTRG##	;Type it
		 JRST	.+2]		;Continue
	PUSHJ	P,.TSIXN##		;and type it
	MOVEI	T1,"("			;Open paren for the number
	PUSHJ	P,.TCHAR##		;...
	MOVE	T1,T3			;Get the local node's number
	PUSHJ	P,.TOCTW##		;Type it in octal
	MOVEI	T1,[ASCIZ \), located at \]	;Close the node name
	PUSHJ	P,.TSTRG##		;Type it out
	HRROI	T3,.GTLOC		;Get where we are located
	GETTAB	T3,			;Do the	GETTAB
	  SETZ	T3,			;Don't care, catch it later
	MOVEI	T2,2			;No, set up an argument	block
	MOVE	T1,[.NDRNN,,T2]		;and an	ac
	NODE.	T1,			;Use NODE. UUO to check	node
	  JRST	[MOVEI	T1,[ASCIZ \??????\]	;Unknown
		 PUSHJ	P,.TSTRG##	;Type it
		 JRST	.+2]		;Continue
	PUSHJ	P,.TSIXN##		;and type it
	MOVEI	T1,[ASCIZ \(\]		;Open paren for	the number
	PUSHJ	P,.TSTRG##		;...
	MOVE	T1,T3			;Get the local node's number
	PUSHJ	P,.TOCTW##		;Type it in octal
	MOVEI	T1,[ASCIZ \), \]	;Close the node name
	PUSHJ	P,.TSTRG##		;Type it out
	MOVE	T1,NODNUM		;Get the node number
	PUSHJ	P,.TDECW##		;Type the number of nodes
	MOVE	T1,NODNUM		;Get the node number
	CAIG	T1,1			;Is it singular	or plural
	  SKIPA	T1,[[ASCIZ \ node]\]]	;Singular
	MOVEI	T1,[ASCIZ \ nodes]\]	;Plural
	PUSHJ	P,.TSTRG##		;...
	PJRST	CRLFH			;Cap off ANF header with a <CR><LF>
;** Here to resolve the	wild cards in the node spec's we got

ANFWLD:	SKIPN	T1,SPCCNT		;Do we have any	specs
	  JRST	ANFWL4			;None, take the	default
	MOVN	L1,T1			;Get the negative count	of specs
	HRLZS	L1			;Make an AOBJN pointer
ANFWL1:	MOVE	T3,SPCLST(L1)		;Get the name
	SKIPN	T4,WLDLST(L1)		;Is this a wild	card entry?
	  PUSHJ	P,ANFWL6		;No, make sure it's a name and -1 mask
	ANDCAM	T4,T3			;Mask it
	SETZ	T1,			;Clear the match counter
	MOVN	L2,NODNUM		;Get count of known nodes
	HRLZS	L2			;Make an AOBJN pointer
ANFWL2:	MOVE	T2,NODNAM(L2)		;Get a node name
	ANDCAM	T4,T2			;Mask it
	CAME	T2,T3			;Match?
	  JRST	ANFWL3			;No, Try the next one
	AOS	ANFCNT			;Increment the count of	nodes found
	MOVSI	T1,SP.ANF		;Yes, Flag it to be listed
	IORM	T1,SPCFLG(L1)		;Mark the match	in the spec flags
	IORM	T1,NODBIN(L2)		;Mark the match	in known node list
ANFWL3:	AOBJN	L2,ANFWL2		;Loop over all known nodes
ANFWL8:	AOBJN	L1,ANFWL1		;And all node specs
	POPJ	P,			;Return

;Here to set up	for the	default	case
ANFWL4:	MOVN	T1,NODNUM		;Get the number	of nodes
	HRLZ	T1,T1			;Make an AOBJN pointer
	MOVSI	T2,SP.ANF		;"LIST NODE" Flag
ANFWL5:	IORM	T2,NODBIN(T1)		;Flag all nodes
	AOBJN	T1,ANFWL5		;Loop over all nodes
	AOS	ANFCNT			;Increment the count of	matches
	POPJ	P,			;Return

;Here to setup mask for	the non-wilcarded case
ANFWL6:	JUMPE	T3,.POPJ##		;Forget it if explicit blank name
	MOVEI	T2,2			;No, set up an argument	block
ANFWL7:	MOVE	T1,[.NDRNN,,T2]		;and an	ac
	NODE.	T1,			;Use NODE. UUO to check	node
	  POPJ	P,			;Error,	Use what we have to use
	MOVE	T3,T1			;Put it	where it's expected
	TLNN	T1,777777		;Is what we have a name?
	  JRST	ANFWL7			;Try for a SIXBIT result
	POPJ	P,			;No, Just return
;** Here to build our network tables, this is our snapshot of the network

ANFTAB:	MOVE	T1,[XWD	.NDLND,NODNUM]	;Set up	ac for NODE. UUO
	NODE.	T1,			;Can we	get the	table of node numbers?
	  PUSHJ	P,NODERR		;No, tell user why and die
	MOVEM	T1,NODNUM		;Stash the number of nodes in network
	MOVE	T1,SORTWD		;Get the sort status
	JUMPL	T1,ANFTA1		;No switch, default to sorted
	CAIE	T1,SRT.DF		;Default sort?
	CAIN	T1,SRT.NU		;Did the user type /SORT:NUMBER
ANFTA1:	  PUSHJ	P,ANFSRT		;Yes, Sort the numbers
	MOVN	L2,NODNUM		;Negate	the number of nodes
	HRLZS	L2			;Make it an AOBJN counter
	MOVEI	T3,2			;Get the argument block	length
ANFTA2:	MOVE	T4,NODBIN(L2)		;Get a node number
	MOVE	T1,[XWD	.NDRNN,T3]	;Set up	T1 for NODE. UUO
	NODE.	T1,			;Can we	change number to sixbit	name?
	  SETZ	T1,			;No, make it a zero name and wing it
	MOVEM	T1,NODNAM(L2)		;Yes, stash in ajacent table of	names
	AOBJN	L2,ANFTA2		;Loop till done
	MOVE	T1,SORTWD		;Get the sort status
	CAIN	T1,SRT.NA		;Did the user type /SORT:NAME
	  PUSHJ	P,ANFNSR		;Yes, Sort them	by name
CPOPJ:	POPJ	P,			;Return

;** Here to shellsort the node names gotten above

ANFNSR:	HRRZ	T1,NODNUM		;T1=Number_of_nodes
ANFNS1:	LSH	T1,-1			;T1=T1/2
	JUMPE	T1,CPOPJ		;IF T1=0 then RETURN
	MOVEI	T2,1			;T2=1
ANFNS2:	HRRZ	T3,T2			;T3=T2
ANFNS4:	HRRZ	T4,T3
	ADDI	T4,(T1)			;T4=T3+T1
	MOVE	T5,<NODNAM-1>(T4)	;T5=node[T3+T1]
	CAML	T5,<NODNAM-1>(T3)	;IF node[T3] <=	node[T3+T1]
	JRST	ANFNS3			;then GOTO SORT3
	EXCH	T5,<NODNAM-1>(T3)
	MOVEM	T5,<NODNAM-1>(T4)	;exchange

	MOVE	T5,<NODBIN-1>(T4)	;Exchange the node numbers too
	EXCH	T5,<NODBIN-1>(T3)
	MOVEM	T5,<NODBIN-1>(T4)	;exchange
	SUBI	T3,(T1)			;T3=T3-T1
	JUMPG	T3,ANFNS4		;IF T3>=1 GOTO SORT4
ANFNS3:	HRRZ	T5,NODNUM		;delayed T2=T2+1
	SUBI	T5,1(T1)		;then comparison
	CAILE	T2,(T5)			;IF T2>N-T1 then
	  AOJA	T2,ANFNS1		;GOTO SORT1
	AOJA	T2,ANFNS2		;ELSE GOTO SORT2
;** Here to shellsort the node numbers gotten above

ANFSRT:	HRRZ	T1,NODNUM		;T1=Number_of_nodes
ANFSR1:	LSH	T1,-1			;T1=T1/2
	JUMPE	T1,CPOPJ		;IF T1=0 then RETURN
	MOVEI	T2,1			;T2=1
ANFSR2:	HRRZ	T3,T2			;T3=T2
ANFSR4:	HRRZ	T4,T3
	ADDI	T4,(T1)			;T4=T3+T1
	MOVE	T5,<NODBIN-1>(T4)	;T5=node[T3+T1]
	CAML	T5,<NODBIN-1>(T3)	;IF node[T3] <=	node[T3+T1]
	JRST	ANFSR3			;then GOTO SORT3
	EXCH	T5,<NODBIN-1>(T3)
	MOVEM	T5,<NODBIN-1>(T4)	;exchange
	SUBI	T3,(T1)			;T3=T3-T1
	JUMPG	T3,ANFSR4		;IF T3>=1 GOTO SORT4
ANFSR3:	HRRZ	T5,NODNUM		;delayed T2=T2+1
	SUBI	T5,1(T1)		;then comparison
	CAILE	T2,(T5)			;IF T2>N-T1 then
	  AOJA	T2,ANFSR1		;GOTO SORT1
	AOJA	T2,ANFSR2		;ELSE GOTO SORT2
	SUBTTL	Build a	node data block

;** Here to build a copy of the	node's NDB in our space

BLDNDB:	HRRZM	CN,NNM			;Stash node number
	HRRZM	CN,CURNOD		;Again for NODE. UUO
	MOVEI	T1,2			;Set up	the field number
	MOVEM	T1,FLDNUM		;for the NODE. UUO
	MOVE	T2,CN			;Get the current node #
	MOVE	T3,[.NDRNN,,T1]		;Set up	the AC
	NODE.	T3,			;Try to	get the	name
	  JRST	BLDND2			;Oops, node in a funny state
	MOVEM	T3,SNM			;Stash it
	MOVE	T1,[.NDNDB,,NODBLK]	;Set up	the ac
	AOS	FLDNUM			;Point to next field in	NDB
	NODE.	T1,			;Get next info?
	  JRST	BLDND3			;No, investigate
	MOVE	T3,[DATBLK,,SID]	;Yes, set up to	BLT software ID
	BLT	T3,DAT			;to our	NDB copy
	AOS	FLDNUM			;Point to software date	field
	NODE.	T1,			;Get more info?
	  JRST	BLDND4			;No, investigate
	MOVE	T3,[DATBLK,,DAT]	;Yes, set up to	BLT date
	BLT	T3,LMA			;to our	NDB copy
	AOS	FLDNUM			;Point to next field
	MOVE	L2,[-10,,LMA]		;make loop counter for one word	fields
BLDND1:	NODE.	T1,			;Get the info?
	  JRST	BLDND4			;No, investigate
	MOVE	T2,DATBLK		;Yes, move it to
	MOVEM	T2,(L2)			;our NDB copy
	AOS	FLDNUM			;Increment to point to next field
	AOBJN	L2,BLDND1		;Loop till done
	NODE.	T1,			;Get the topology table?
	  JRST	BLDND5			;No, investigate
	MOVE	T3,[DATBLK,,TOP]	;Yes, copy topology table
	BLT	T3,CNF			;to our	NDB copy
	AOS	T3,FLDNUM		;Point to the configuration field
	NODE.	T1,			;Can we	get it?
	  JRST	BLDND6			;No, investigate
	MOVE	T3,[DATBLK,,CNF]	;Yes, BLT it to
	BLT	T3,ENDB			;our NDB copy
	AOS	(P)			;Skip return for success
	POPJ	P,			;Return

BLDND2:	SETZM	SNM			;Zero the info we can not get
BLDND3:	SETZM	SID			;...
BLDND4:	SETZM	DAT			;...
BLDND5:	SETZM	TOP			;...
BLDND6:	SETZM	CNF			;...
	PJRST	OFLINE			;Tell the user
	SUBTTL	ANF10 output routines

;** Here to decide whether or not to print a node. The decision	is
;   based on the selection of /<device-name> switches.
;   A skip return is taken if the node is not to be printed.

SELECT:	MOVSI	T1,-NDEV		;Make a	AOBJN pointer to switch	words
	TXO	F,F.SEL
SELEC0:	SKIPLE	MCRWD(T1)		;Switch	selected for a match?
	  JRST	[SKIPGE	DECNWD		;Did we	specify	DECnet listing?
		 SETZM	DECNWD		;No, don't list	if device switch
		 SKIPGE	LATNWD		;Did we specify a LAT listing?
		 SETZM	LATNWD		;No, suppress on device switch(es)
		 PUSHJ	P,SEL0		;Yes, Look for a match
		 TXZA	F,F.SEL		;No match, clear the selected flag
		 JRST	SELEC1		;Continue
		 POPJ	P,]		;No match, return
	SKIPN	MCRWD(T1)		;Switch	selected for a non-match?
	  JRST	[PUSHJ	P,SEL0		;Yes, Look for a match
		 CAIA			;Opposite sense	from before
		 TXZA	F,F.SEL		;No match, clear the selected flag
		 JRST	SELEC1		;Continue
		 POPJ	P,]		;No match, return
SELEC1:	AOBJN	T1,SELEC0		;Loop through all switches
	SETO	T1,			;Make T1 -1
	CAMN	T1,TYPWD		;Did we	specify	/TYPE:?
	  JRST	SELEC4			;No, don't check it
	MOVE	T1,TYPWD		;Get the type we are looking for
	MOVEI	T2,SID			;Point to the software ID
	PUSHJ	P,ASCSIX		;See if	it matches
	  TXZ	F,F.SEL			;No Match, Clear the print flag
SELEC4:	AOS	MATCH			;Count the number of matches
	POPJ	P,			;We want to print this node, just return

;Subroutine to see if a	device type is in the NDB The device type
;is in the RH of T1
;CALL	PUSHJ	P,SEL0
;	  Return with no match
;	Return with a match

SEL0:	MOVSI	T2,-NDEV		;AOBJN pointer to the configuration info
SEL1:	SKIPN	CNF(T2)			;No more devices?
	  POPJ	P,			;None, just return, no match
	HLRZ	T3,CNF(T2)		;Get the object	type
	CAIN	T3,(T1)			;Are they the same device?
	  AOSA	(P)			;Skip return means we will print it
	AOBJN	T2,SEL1			;No, loop till found or	NDEV
	POPJ	P,			;...
;** Routine to compare the first six characters	of an ASCIZ string
;   with the SIXBIT value it T1
;
;   call:	T1=SIXBIT\value\
;		T2=[ASCIZ\string\]
;	PUSHJ	P,ASCSIX
;	  <no match>	;First six chars of string converted to	sixbit in T2
;	<match>

ASCSIX:	PUSHJ	P,.PSH4T##		;Save the temps
	MOVSI	T1,-6			;Set up	an AOBJN pointer
	SETZB	T4,TEMP			;Clear temps where necessary
	HRLI	T2,(POINT 7)		;Byte pointer for the asciz string
	MOVE	T3,[POINT 6,TEMP]	;Byte pointer for sixbit conversion
ASCSI1:	ILDB	T4,T2			;Get a byte from the string
	SUBI	T4," "			;Make SIXBIT
	JUMPLE	T4,ASCEOS		;Is the	character a space?
	IDPB	T4,T3			;Place into the	save byte
	AOBJN	T1,ASCSI1		;Loop about 6 times
ASCEOS:	PUSHJ	P,.POP4T##		;Restore the temps
	CAMN	T1,TEMP			;Is it the same??
	  AOSA	(P)			;Yes, do the skip return
	  MOVE	T2,TEMP			;No, copy what we had to T2
	POPJ	P,			;Return
;** Here to print the information about	a node.
;   This routine dispatches according to the switches selected:
;   /SILENCE, /FAST, /BRIEF, /WIDTH, /TOPOLOGY
;
;   destroys many registers

PRINFO:	AOS	MATCH			;If here we must have had a match
	SKIPLE	SILWD			;/SILENCE?
	  POPJ	P,			;Yes, Just return...errors only!
PRINF1:	SKIPLE	TOPWD			;If /TOPOLOGY was specified
	  JRST	PRTOPO			; then go print	it
	SKIPG	FASWD			;/NOFAST or default?
	  PUSHJ	P,PFIRST		;Yes, print the	first line
	SKIPLE	FASWD			;/FAST?
	  PUSHJ	P,SHOLST		;Yes, do a short list
	SKIPG	FASWD			;/FAST?
	  JRST	PRINF2			;No, /BRIEF is the default
	SKIPE	BRIEWD			;Did he	say /BRIEF?
	  POPJ	P,			;Yes, don't print configuration
PRINF2:	SKIPG	BRIEWD			;Here if /NOBRIEF or default
	  PUSHJ	P,PCONF			;No, print the configuration
PRINF3:	POPJ	P,			;Return	to loop
;** Here to print the first line in the	default	format
;

PFIRST:	MOVEI	T1,[ASCIZ \Node	\]	;Print the lead	word
	PUSHJ	P,.TSTRG##		;...
	MOVE	T1,SNM			;Get the sixbit	node name
	PUSHJ	P,.TSIXN##		;and print it
	PUSHJ	P,.TTABC##		;followed by a <tab>
	MOVEI	T1,"("			;Get a <left-paren>
	PUSHJ	P,.TCHAR##		;and print it
	MOVE	T1,NNM			;Get out node number
	PUSHJ	P,.TOCTW##		;and print it in octal
	MOVEI	T1,")"			;Get a <right-paren>
	PUSHJ	P,.TCHAR##		;and print it
	PUSHJ	P,.TTABC##		;followed by a <tab>
	MOVEI	T1,^D28			;This is our horizontal	position
	MOVEM	T1,HPOS			;so set	it
	MOVEI	T1,SID			;Point at the software ID (asciz)
	PUSHJ	P,KILBLK		;And kill leading blanks
	PUSHJ	P,TCARE			;and print it carefully
	PUSHJ	P,.TTABC##		;followed by a <tab>
	MOVEI	T1,DAT			;Point to the software date (asciz)
PSTCRL:	PUSHJ	P,TCARE			;and print it carefully
	PJRST	CRLFH			;Cap off with a <CR><LF>
;Here to print topology	information for	a node
;P1 points to topo, p2 = count

PRTOPO:	SETZ	P2,			;Clear the count of chars printed
	MOVEI	T1,[ASCIZ \Node	\]	;Lead off with "node<tab>"
	PUSHJ	P,.TSTRG##		;...
	MOVE	T1,SNM			;Get the name
	PUSHJ	P,.TSIXN##		; and print it
	PUSHJ	P,.TTABC##		;Print a <TAB>
	MOVEI	T1,"("			;Get an	open paren
	PUSHJ	P,.TCHAR##		; and print it
	MOVE	T1,NNM			;Get the node's	number
	PUSHJ	P,.TOCTW##		; and print it
	MOVEI	T1,")"			;Finally, get the close	paren
	PUSHJ	P,.TCHAR##		; and print it
	PUSHJ	P,.TTABC##		;Print another <TAB>
	MOVEI	P2,30			;3 <TAB>s bring	us to col # ^D24
	MOVEM	P2,HPOS			;Save our horizontal position

;Set up	to output the topology information

	MOVEI	P1,TOP			;Get the address of the	topology
	SKIPE	(P1)			;Check if has neighbors
	JRST	PRTOP3			;Yes, skip ","<TAB> the first time
	MOVEI	T1,[ASCIZ \None\]	;No, get the string
	PJRST	PSTCRL			; and tell the user

;Here to type a	comma in the correct place

PRTOP2:	MOVEI	T1,[ASCIZ \, \]		;Point to ","<space>
	CAIE	P2,10			;No ","<TAB> if	CRLFH called
	PUSHJ	P,TCARE			;type it

;Here to print the neighbor's node number

PRTOP3:	MOVE	P2,HPOS			;Get the horizontal position
	HRRZ	T1,(P1)			;Get the neighbors node number
	PUSHJ	P,FLATSO		;Account for the size
	PUSHJ	P,.TOCTW##		; and print it in octal
	SKIPE	COSTWD			;Should	we print the link costs?
	  PUSHJ	P,PRCOST		;Print the link	costs
	SKIPE	1(P1)			;See if	there are any more entrys
	AOJA	P1,PRTOP2		; and if so, go	process	them
	PUSHJ	P,CRLFH			;Cap off the topology/cost line
	SKIPN	BRIEWD			;Check for configuration typeout
	  PUSHJ	P,PCONF			;Yes, do the configuration
	POPJ	P,			;No more neighbors to process
;Here to print the link	costs

PRCOST:	HLRZ	T1,(P1)			;Get the link's	cost
	PUSHJ	P,FLATSD		;Account for the size
	ADDI	P2,2			;Allow for the ")" & "("
	MOVE	T1,P2			;Save P2
	SUB	T1,HPOS			;Get the length	of the string
	CAML	P2,CARWID		;exceeded the carrage width?
	  PUSHJ	P,CRLFH			;Yes, <CRLF> now
	ADDM	T1,HPOS			;add the length	of the string
	MOVE	P2,HPOS			;Restore the horizontal	postion
	MOVEI	T1,"("			;Get an	open paren
	PUSHJ	P,.TCHAR##		; and print it
	HLRZ	T1,(P1)			;Get the link's	cost
	PUSHJ	P,.TDECW##		; and print it in decimal
	MOVEI	T1,")"			;Finish	off the	entry
	PJRST	.TCHAR##		; with a close paren
;** Routines to	count (in P2) the number of chars used in the printed
;   representation of the item in T1.

FLATSN:	PUSH	P,T1			;Here for counting names
	MOVEM	P2,HPOS			;Save the horizontal position
FLATN1:	SKIPE	T1			;If we haven't zeroed the whole	wd
	JRST	[LSH T1,6		;yet, then shift the name
		 AOJA P2,FLATN1]	;and count it
	CAML	P2,CARWID		;Can this fit??
	  PUSHJ	P,CRLFH			;Too big to fit, <CRLF>	now
	MOVE	P2,HPOS			;Restore the local count
	POP	P,T1			;Restore the name
	POPJ	P,			;and return

FLATSO:	PUSH	P,T1			;Here for octal	numbers
	MOVEM	P2,HPOS			;Save the horizontal position
	SKIPE	T1			;Worry about a zero
FLATO1:	SKIPE	T1			;if we're not done yet
	JRST	[LSH T1,-3		;divide	the number by 8
		 AOJA P2,FLATO1]	;and count the digit
	CAML	P2,CARWID		;Can this fit??
	  PUSHJ	P,CRLFH			;Too big to fit, <CRLF>	now
	MOVE	P2,HPOS			;Restore the local count
	POP	P,T1			;restore the number
	POPJ	P,			;and return

FLATSD:	PUSH	P,T1			;Here for decimal numbers
	SKIPE	T1			;Make sure zero	counts 1
FLATD1:	SKIPE	T1			;If there are still more digits
	JRST	[IDIVI T1,5+5		;divide	by 10
		 AOJA P2,FLATD1]	;and count the char
	MOVEM	P2,HPOS			;Save the horizontal position
	POP	P,T1			;Restore the number
	POPJ	P,			;and return
;** Here to print the configuration information

PCONF:	MOVE	P1,[XWD	-20,CNF]	;Make a	AOBJN pointer
	PUSHJ	P,.TTABC##		;Type a	<tab>
	MOVEI	T5,10			;and set up horizontal position
PCONF1:	SKIPN	(P1)			;Any more devices?
	JRST	PCONF2			;No, all done
	HLRZ	T1,(P1)			;Yes, get the configuration word
	MOVE	T1,CTAB(T1)		;and the asciz name string
	PUSHJ	P,.TSTRG##		;and print it
	HRRZ	T1,(P1)			;Get how many
PCONF3:	IDIVI	T1,^D10			;and find the number of	digits
	ADDI	T5,1			;add one to the	horizontal position
	JUMPG	T1,PCONF3		;loop till we have counted all digits
	HRRZ	T1,(P1)			;Get how many, again
	PUSHJ	P,.TDECW##		;and print it this time
	MOVEI	T1,"]"			;Get a <left bracket>
	PUSHJ	P,.TCHAR##		;and print it
	PUSHJ	P,.TSPAC##		;followed by a space
	ADDI	T5,6			;Add number of characters in the:
					;device	name [3]
					;brackets [2]
					;<space> [1]
					;to the	horizontal position
	PUSH	P,T5			;save T5
	ADDI	T5,11			;Add the max expected for the
					;next device
	CAMLE	T5,CARWID		;Do we exceed the TTY's	width?
	  JRST	PCONF4			;Yes, do a <CR><LF>
	POP	P,T5			;No, restore T5	and
	AOBJN	P1,PCONF1		;loop till done
PCONF2:	PJRST	CRLFH			;Cap off configuration line

PCONF4:	SKIPG	1(P1)			;any more devices?
	  JRST	PCONF5			;Yes, loop back
	PUSHJ	P,CRLFH			;Type a	<CR><LF>
	PUSHJ	P,.TTABC##		;and a <tab>
PCONF5:	POP	P,T5			;then restore T5
	MOVEI	T5,10			;Reset the horizontal position counter
	AOBJN	P1,PCONF1		;and loop back
;** routine to produce a listing of nodes in the network
;   by name and	number only on one or two lines

SHOLSS:	EXP	[ASCIZ/)/]			;Zero
	EXP	[ASCIZ/) /]			;One
	EXP	[ASCIZ/)  /]			;Two
	EXP	[ASCIZ/)   /]			;Three
	EXP	[ASCIZ/)    /]			;Four
	EXP	[ASCIZ/)     /]			;Five
	EXP	[ASCIZ/)      /]		;Six
	EXP	[ASCIZ/)       /]		;Seven
	EXP	[ASCIZ/)	/]		;Eight
	EXP	[ASCIZ/)	 /]		;Nine
	EXP	[ASCIZ/)	  /]		;Ten
	EXP	[ASCIZ/)	   /]		;Eleven
	EXP	[ASCIZ/)	    /]		;Twelve
	EXP	[ASCIZ/)	     /]		;Thirteen
	EXP	[ASCIZ/)	      /]	;Fourteen
	EXP	[ASCIZ/)	       /]	;Fifteen
	SPCPRT=^D12
SHOLST:	SKIPN	FIRSTL			;Is this the first spec?
	  PUSHJ	P,CRLFH			;Yes, do a <CR><LF>
	AOS	FIRSTL			;Count the number of specs we do
	MOVE	T2,HPOS			;Get our horizontal position
	ADDI	T2,SPCPRT		;INCREMENT by on tab to	get here
	IDIVI	T2,SPCPRT		;Worst case node spec
	IMULI	T2,SPCPRT		;Make the number of 12 bit tabs
	MOVEM	T2,HPOS			;Save it for later
	CAMLE	T2,CARWID		;Enough	space left?
	  JRST	[PUSHJ P,CRLFH		;Do a <CR><LF>
		 MOVEI	T1,SPCPRT	;Get new HPOS
		 MOVEM	T1,HPOS		;Save the new position
		 JRST	.+1]		;Continue
	SETZ	P1,			;Zero the position counter
	MOVE	T2,[POINT 6,SNM]	;Get the node name
	MOVEI	T1,6			;Max number of characters in a name
SHOLS0:	ILDB	T3,T2			;Get a character
	JUMPE	T3,SHOLS1		;Is it blank?
	ADDI	P1,1			;No, count characters in the spec
	SOJG	T1,SHOLS0		;Have we looked	at six characters?
SHOLS1:	ADDI	P1,2			;Done, account for parens
	SKIPA	T1,NNM			;Get the node number, allowing for zero
SHOLS2:	SKIPE	T1			;if we're not done yet
	JRST	[LSH T1,-3		;divide	the number by 8
		 AOJA P1,SHOLS2]	;and count the digit
	MOVE	T1,SNM			;Get the sixbit	node name
	PUSHJ	P,.TSIXN##		;Type the node name
	MOVEI	T1,"("			;Type a	left paren
	PUSHJ	P,.TCHAR##		;...
	HRRZ	T1,NNM			;Type the node number
	PUSHJ	P,.TOCTW##		;in octal...
	MOVEI	T1,SPCPRT		;Our normal tab	stop
	SUBI	T1,(P1)			;Subtract what we have
	MOVE	T1,SHOLSS(T1)		;to get	pointer	to fill	string
	PJRST	.TSTRG			;Finish	the entry
;** Here to do a carrage return/ line feed sequence
;   and	set HPOS (our horizontal position) to zero

CRLFH:	SETZM	HPOS			;Set the horizontal position back to
					;the left margin
	PJRST	.TCRLF##		;And do	a real <CR><LF>

;** Here to kill leading blanks	or tabs	from a string pointed to by T1
;   Returns with T1 pointing to	the start of the new string
;   * destroys P3

KILBLK:	PUSHJ	P,.PSH4T##		;Save the temps
	HRLI	T1,(POINT 7)		;Make T1 a byte	pointer
	MOVE	T3,T1			;Copy it
	MOVE	T4,T1			;Keep another copy
KILBL1:	ILDB	T2,T1			;Load a	byte
	CAIE	T2,11			;Is it a <TAB>?
	CAIN	T2,40			;Is it a <blank>
	  JRST	KILBL1			;Loop til we find a non-blank character
	CAMN	T1,T3			;Are the byte pointers different?
	  JRST	KILBL4			;No, return to the caller
KILBL2:	IDPB	T2,T3			;Deposit the current byte
	ILDB	T2,T1			;Get another byte
	JUMPN	T2,KILBL2		;Loop until zero byte
	IDPB	T2,T3			;and deposit it
KILBL4:	MOVE	T1,T4			;Init the pointer
KILBL5:	ILDB	T2,T1			;Get another byte
	JUMPE	T2,KILBL7		;Bind off at end
	CAIE	T2,40			;Is this a blank
	CAIN	T2,11			; or a <TAB>?
	JRST	KILBL5			;Yes, don't keep it if trailing
	MOVE	T4,T1			;No, make sure we keep this one
	JRST	KILBL5			;Loop over entire string
KILBL7:	IDPB	T2,T4			;Store the null after the last non-blank
	PUSHJ	P,.POP4T##		;Restore the temps
	POPJ	P,			;and return
;** here to type a asciz string	without	exceeding the page width
;   (if	possible).

TCARE:	PUSHJ	P,.PSH4T##		;Save the temps
	MOVE	T3,HPOS			;Get the current horizontal position
	HRLI	T1,(POINT 7)		;Make a	byte pointer
TCARE1:	ILDB	T2,T1			;Get the first byte
	CAIN	T2,"	"		;Is this a <tab>
	  JRST	[ADDI	T3,10		;Yes, add to get to the	next tab stop
		 TRZ	T3,7		;and get rid of	the remainder
		 JRST	.+2	]	;Continue with corrected HPOS
	AOS	T3			;Increment the string length
	JUMPN	T2,TCARE1		;Loop till the end of the string
	SOS	T3			;Correct for the Off By	One error
	MOVEM	T3,HPOS			;Save our horizontal position
	CAMLE	T3,CARWID		;Is this less than the width?
	  PUSHJ	P,CRLFH			;Reset HPOS and	do a CRLF
TCARE3:	PUSHJ	P,.POP4T##		;and restore the temps
	PJRST	.TSTRG##		;Type the string and return
	SUBTTL	DECnet processing loop

;ROUTINE to do the DECnet part of the program

DECNET:	SKIPE	FTDEC			;Is there DECnet software??
	SKIPN	DECNWD			;Did they say /NODECNET??
	  POPJ	P,			;Yes, just return
	SKIPG	DECNWD			;Did we	get /DECNET?
	SKIPG	ANF10W			;Did we	get /ANF10?
	 CAIA				;Wrong sense
	  POPJ	P,			;Don't output the DECnet list
	SKIPG	DECNWD			;Did we	get /DECNET?
	SKIPG	LATNWD			;Did we	get /LAT?
	 CAIA				;Wrong sense
	  POPJ	P,			;Don't output the DECnet list

;Set up	to get the list	of all DECnet nodes

	MOVE	T5,[.DNLNN,,DNMAX]	;Argument for DNET. list node function
	SKIPLE	URCHWD			;Check the unreachable switch
	TXOA	T5,DN.FLK		;List of known nodes
	TXO	T5,DN.FLR		;List of active	(reachable) nodes
	MOVEM	T5,DNLST		;Save the function code
	MOVEI	T5,DNLST		;Arg block for DNET.
	DNET.	T5,			;Get a list of node names
	  PUSHJ	P,DNETER		;Error,	Check it out
	MOVE	T3,.DNCNT(T5)		;Get the count of nodes
	MOVEM	T3,DNCNT		;Save it for later
	MOVNS	T3			;Make an AOBJN pointer
	HRLS	T3			;-count	in LH
	HRRI	T3,2(T5)		;Point at the first node name
	MOVEM	T3,DNLOOP		;Save it for later reference
	MOVE	T1,SORTWD		;Get the sort status
	JUMPL	T1,DECNE1		;No /SORT switch?
	CAIE	T1,SRT.DF		;Default sort?
	CAIN	T1,SRT.NA		;/SORT:NAME?
DECNE1:	  PUSHJ	P,DNSRT			;Yes, sort the DECnet nodes by name

;Continued on next page
;Continued from previous page

;Get the local node name

	MOVEI	T5,DNBLK		;Point to the DNET. arg	block
	MOVE	T2,[DN.FLE+<.DNLNN,,3>];Get the	local node name
	MOVEM	T2,.DNFFL(T5)		;Save the function
	DNET.	T5,			;Get the local node name
	  PUSHJ	P,DNETER		;Error,	Check it out
	MOVE	T1,.DNCNT+1(T5)		;Get the local node name
	MOVEM	T1,DNLOC		;Save it
	MOVEI	T5,DNINF		;Pointer to DNET. argument block
	MOVE	T2,[.DNNDI,,DNINFL]	;Get local node's network address
	MOVEM	T2,.DNFFL(T5)		;...
	MOVEM	T1,.DNNAM(T5)		;Store local node's name
	DNET.	T5,			;Get network address of	local node
	  PUSHJ	P,DNETER		;Error,	Check it out
	MOVE	T1,.DNADR(T5)		;Get local node's network address
	MOVEM	T1,DNADR		;Save for later
	PUSHJ	P,DECWLD		;Handle	wild cards
	SKIPN	DNMCNT			;Any spec's match?
	  POPJ	P,			;No, don't bother any more
	PUSHJ	P,DECHEA		;Print the header line if needed
	PUSHJ	P,CRLFH			;Lead off with a CRLF
	SKIPE	FTEND			;DECnet running as ethernet endnode?
	  POPJ	P,			;Yes, all done, return

;Continued on next page
;Continued from previous page

DECLST:	SKIPLE	TOPWD			;Did they say /TOPOLOGY??
	  JRST	DECTOP			;Yes, do the topology display
	HLLZ	L1,DNLOOP		;Get the DECnet	AOBJN pointer
DECLS1:	MOVSI	T3,DN.LST		;Get the list-it bit
	TDNN	T3,DNBIT+2(L1)		;Do we list it?
	  JRST	DECLS3			;No, try the next one

;Do we just want nodes with links?

	SKIPG	LINKWD			;/LINKS??
	  JRST	DECLS2			;no, skip the check
	PUSHJ	P,DECINF		;Build a node info block
	LDB	T1,[POINTR .DNLLI(T5),DN.LNK] ;Get active links
	JUMPE	T1,DECLS3		;Zero means ignore this	node
DECLS2:	MOVE	T2,HPOS			;Get our horizontal position
	ADDI	T2,10			;INCREMENT by on tab to	get here
	TRZ	T2,7			;Get rid of the	remainder
	MOVEM	T2,HPOS			;Save it for later
	CAMLE	T2,CARWID		;Enough	space left?
	  JRST	[PUSHJ P,CRLFH		;Do a <CR><LF>
		 MOVEI	T1,10		;Get new HPOS
		 MOVEM	T1,HPOS		;Save the new position
		 JRST	.+1]		;Continue
	MOVE	T1,DNLST+2(L1)		;Get the sixbit	node name
	TLNN	T1,770000		;Make sure we have a top character
	  JRST	[PUSH	P,T1		;[32] Remember node number
		 MOVEI	T1,"("		;[32] Blank, type number
		 PUSHJ	P,.TCHAR##	;
		 LDB	T1,[POINTR(0(P),DN%ARE)] ;[32] Area number
		 JUMPE	T1,DECL2B	;[32] Skip if none
		 PUSHJ	P,.TDECW##	;[32] Print area number
		 MOVEI	T1,"."		;
		 PUSHJ	P,.TCHAR##	;
	DECL2B:	 POP	P,T1		;[32] Node number back
		 ANDI	T1,DN%NOD	;[32] Except for area
		 PUSHJ	P,.TDECW##	;
		 MOVEI	T1,")"		;
		 PUSHJ	P,.TCHAR##	;
		 JRST	DECL2A]		;[32] Resume with tab
	PUSHJ	P,.TSIXN##		;Type the name
DECL2A:	PUSHJ	P,.TTABC##		;Print a <tab>
DECLS3:	AOBJN	L1,DECLS1		;Loop
	PJRST	CRLFH			;Finish	with a CRLF
;Get info about DECnet nodes

DECINF:	MOVEI	T5,DNINF		;Point to the DNET. UUO	block
	MOVE	T1,[.DNNDI,,DNINFL]	;Function,,block size
	MOVEM	T1,.DNFFL(T5)		;Save it
	MOVE	T1,DNLST+2(L1)		;Get the sixbit	node name
	MOVEM	T1,.DNNAM(T5)		;Save it
	DNET.	T5,			;Get the info
	  PUSHJ	P,DNETER		;DNET.error, check it out
	POPJ	P,			;Return



;Routine to print the DECnet header if there are any nodes to print and
;the user has not specified /NOHEADERS

DECHEA:	SKIPN	HEADWD			;Did they say no headers?
	  POPJ	P,			;Yes, just return
	MOVEI	T1,[ASCIZ \[DECnet	network: local node \]	;Print the leader
	PUSHJ	P,.TSTRG##		;...
	MOVE	T1,DNLOC		;Get the local node name
	PUSHJ	P,.TSIXN##		;and type it too
	MOVEI	T1,[ASCIZ \, \]		;Local node name
	PUSHJ	P,.TSTRG##		;...
	SKIPE	FTEND			;DECnet running as ethernet endnode?
	  JRST	[MOVEI	T1,[ASCIZ \running as an ethernet endnode]\]
		 PJRST	.TSTRG##]	;...
	SKIPG	T1,DNCNT		;Get the count of on-line nodes
	  JRST	[MOVEI	T1,[ASCIZ \no reachable	nodes]\]
		 PJRST	.TSTRG##]	;...
	PUSHJ	P,.TDECW##		;Type the number of nodes
	MOVEI	T1,[ASCIZ \ reachable\]
	SKIPG	URCHWD			;Just reachable?
	PUSHJ	P,.TSTRG##		;Yes, say so
	MOVE	T1,DNCNT		;Get the count back
	CAIG	T1,1			;More than one
	SKIPA	T1,[[ASCIZ \ node\]]	;singular
	MOVEI	T1,[ASCIZ \ nodes\]	;plural
	PUSHJ	P,.TSTRG##		;...
	LDB	T1,[POINTR(DNADR,DN%ARE)]	;Get network area number
	JUMPE	T1,.TRBRK##		;Finish	message	if no area number
	PUSH	P,T1			;Save area number a bit
	MOVEI	T1,[ASCIZ \ in area \]	;Add some explanation
	PUSHJ	P,.TSTRG##		;...
	POP	P,T1			;Get back area number
	PUSHJ	P,.TDECW##		;Type area number
	PJRST	.TRBRK##		;Finish	message	and return
;DECTOP	- print	the "topology" of the DECnet network
DECTOP:	MOVEI	T1,[ASCIZ \Name	Number	Line		Hops	L.Links	Delay
\]
	SKIPE	COSTWD			;Print the cost?
	MOVEI	T1,[ASCIZ \Name	Number	Line		Cost	Hops	L.Links	Delay
\]
	PUSHJ	P,.TSTRG##		;Type the header line
	HLLZ	L1,DNLOOP		;Get the DECnet	AOBJN pointer
DECTO1:	MOVSI	T3,DN.LST		;Get the list-it bit
	TDNN	T3,DNBIT+2(L1)		;Do we list it?
	  JRST	DECTO7			;No, try the next one
	PUSHJ	P,DECINF		;Build a node information block
	SKIPG	LINKWD			;/LINKS??
	  JRST	DECTO2			;no, skip the check
	LDB	T1,[POINTR .DNLLI(T5),DN.LNK] ;Get active links
	JUMPE	T1,DECTO7		;Zero means ignore this	node

;Identify the	node

DECTO2:	MOVE	T1,.DNNAM(T5)		;Get the node name
	TLNN	T1,770000		;Make sure we have a node name
	 SETZ	T1,			;Nope, don't type it out
	PUSHJ	P,.TSIXN##		;Type it
	MOVEI	T1,[ASCIZ \	(\]	;Tab over
	PUSHJ	P,.TSTRG##		;Type the string
	MOVE	T1,.DNADR(T5)		;Get the node number
	TXNN	T1,DN%ARE		;Is there an area number?
	  JRST	DECTO3			;No, continue
	LDB	T1,[POINTR(T1,DN%ARE)]	;Get area number
	PUSHJ	P,.TDECW##		;Type it
	MOVEI	T1,"."			;Add a seperator
	PUSHJ	P,.TCHAR##		;...
	MOVE	T1,.DNADR(T5)		;Get node number again
	ANDX	T1,DN%NOD		;Mask to just node within area
DECTO3:	PUSHJ	P,.TDECW##		;Type the node number
	MOVEI	T1,[ASCIZ \)	\]	;Tab over
	PUSHJ	P,.TSTRG##		;Type the string

;Continued on next page
;Continued from previous page

;See if the node is reachable

	LDB	T1,[POINTR .DNRTR(T5),DN.RCH]	;Is the	node reachable?
	JUMPE	T1,[MOVEI T1,[ASCIZ\Unreachable\]
		    PUSHJ P,.TSTRG##	;No, tell the user
		    JRST  DECTO6]	;Continue with the next	node

;Describe the	connection to the node

	MOVEI	T1,.DNCKT(T5)
	PUSHJ	P,.TSTRG##		;If non-zero type the name
	PUSHJ	P,.TTABC##		;Tab over for fill
	PUSHJ	P,.TTABC##		;Tab over

;Check for the /COST switch setting

	SKIPN	COSTWD			;Print the cost?
	  JRST	DECTO4
	LDB	T1,[POINTR .DNRTR(T5),DN.CST] ;Get the cost information
	PUSHJ	P,.TDECW##		;Print it
	PUSHJ	P,.TTABC##		;Tab over

DECTO4:	LDB	T1,[POINTR .DNRTR(T5),DN.HOP]
	PUSHJ	P,.TDECW##		;Print the number of hops
	PUSHJ	P,.TTABC##		;Tab over

;Tell	about the logical links	we have	to the node

DECTO5:	SKIPL	.DNLLI(T5)		;Do we have valid information?
	  JRST	DECTO6			;No, finish the	line
	LDB	T1,[POINTR .DNLLI(T5),DN.LNK] ;Get active links
	PUSHJ	P,.TDECW##		;Type it
	PUSHJ	P,.TTABC##		;Tab over
	LDB	T1,[POINTR .DNLLI(T5),DN.DLY] ;Get millisecond delay to	node
	PUSHJ	P,.TDECW##		;Type it
DECTO6:	PUSHJ	P,.TCRLF##		;end line
DECTO7:	AOBJN	L1,DECTO1		;Loop
	POPJ	P,			;Return
;Routine to select specific nodes to look at by	dissecting the scan blocks
;L1 = AOBJN pointer to the list	of DECnet node names in	SIXBIT

DECWLD:	SKIPN	L1,SPCCNT		;Do we have any	specs
	  JRST	DECWL4			;None, take the	default
	MOVNS	L1			;Get the negative count	of specs
	HRLZS	L1			;Make an AOBJN pointer
DECWL1:	MOVE	T3,SPCLST(L1)		;Get the name
	SKIPN	T4,WLDLST(L1)		;Is this a wild	card entry?
	  SETZ	T4,			;No, mask no names
	ANDCAM	T4,T3			;Mask it
	HLLZ	L2,DNLOOP		;Get count of known nodes
DECWL2:	MOVE	T2,DNLST+2(L2)		;Get a node name
	ANDCAM	T4,T2			;Mask it
	CAME	T2,T3			;Match?
	  JRST	DECWL3			;No, Try the next one
	AOS	DNMCNT			;Count nodes that match
	MOVSI	T5,SP.DEC		;Yes, Flag it to be listed
	IORM	T5,SPCFLG(L1)		;Mark the match	in the spec flags
	MOVSI	T5,DN.LST		;Flag node to be listed
	IORM	T5,DNBIT+2(L2)		;Mark the match	in known node list
DECWL3:	AOBJN	L2,DECWL2		;Loop over all known nodes
	AOBJN	L1,DECWL1		;And all node specs
	POPJ	P,			;Return

;Here to set up	for the	default	case

DECWL4:	HLLZ	T1,DNLOOP		;Get the number	of nodes
	MOVSI	T2,DN.LST		;"LIST NODE" Flag
DECWL5:	IORM	T2,DNBIT+2(T1)		;Flag all nodes
	AOBJN	T1,DECWL5		;Loop over all nodes
	AOS	DNMCNT			;Count a match
	POPJ	P,			;Return
	SUBTTL DNSRT - SHELLsort the DECnet nodes

;DNSRT:	T1=Number_of_nodes (N)
;DNSR1:	T1=T1/2
;	IF T1=0	then RETURN
;	T2=1
;DNSR2:	T3=T2
;DNSR4:	IF node[T3] <= node[T3+T1] goto	SORT3
;	EXCH(node[T3],node[T3+T1])
;	T3=T3-T1
;	IF T3>=1 then goto SORT4
;DNSR3:	T2=T2+1
;	IF T2>N-T1 then	goto SORT1
;	goto sort2

DNSRT:	HRRZ	T1,DNCNT		;T1=Number_of_nodes
DNSR1:	LSH	T1,-1			;T1=T1/2
	JUMPE	T1,CPOPJ		;IF T1=0 then RETURN
	MOVEI	T2,1			;T2=1
DNSR2:	HRRZ	T3,T2			;T3=T2
DNSR4:	HRRZ	T4,T3
	ADDI	T4,(T1)			;T4=T3+T1
	MOVE	T5,<DNLST+1>(T4)	;T5=node[T3+T1]
	MOVE	T6,<DNLST+1>(T3)	;T6=node[T3]
	TLC	T5,(1B0)		;FLIP SIGN BITS
	TLC	T6,(1B0)		;FOR UNSIGNED COMPARISON
	CAML	T5,T6			;IF node[T3] <=	node[T3+T1]
	JRST	DNSR3			;then GOTO SORT3
	TLC	T5,(1B0)		;RESTORE VALUE
	EXCH	T5,<DNLST+1>(T3)
	MOVEM	T5,<DNLST+1>(T4)	;exchange
	SUBI	T3,(T1)			;T3=T3-T1
	JUMPG	T3,DNSR4		;IF T3>=1 GOTO SORT4
DNSR3:	HRRZ	T5,DNCNT		;delayed T2=T2+1
	SUBI	T5,1(T1)		;then comparison
	CAILE	T2,(T5)			;IF T2>N-T1 then
	  AOJA	T2,DNSR1		;GOTO SORT1
	AOJA	T2,DNSR2		;ELSE GOTO SORT2
	SUBTTL	LAT processing routines

;Here to list info the LAT "network".
;
;As of this writing (18-Apr-85) the -10 doesn't support being itself a
;"LAT server", only a "LAT host", so we can only list servers since that
;is all we are listening for on the ethernet.
;
;Note also that since the LAT servers don't themselves broadcast their
;existence the -10 only knows about LAT servers that have in the past
;connected to the -10. As such, NETWORK can only type out a partial sum-
;mary of the LAT network.

LATSER:	SKIPE	FTLAT		;Have LATSER loaded?
	SKIPN	LATNWD		;Did we say /NOLAT?
	POPJ	P,		;No or yes, skip this
	SKIPG	LATNWD		;Did we say /LAT?
	SKIPG	ANF10W		;No, how about /ANF10?
	CAIA			;Sense is wrong
	POPJ	P,		;Skip LAT stuff
	SKIPG	LATNWD		;Did we say /LAT?
	SKIPG	DECNWD		;No, how about /DECNET?
	CAIA			;Sense is wrong
	POPJ	P,		;Skip LAT stuff
	SKIPLE	TOPWD		;Did we say /TOPOLOGY?
	SKIPLE	LATNWD		;Yes, how about /LAT?
	CAIA			;Sense is wrong
	POPJ	P,		;Skip default LAT list if /TOPOLOGY
	PUSHJ	P,LATINI	;[042] Type out a header if needed
	  POPJ	P,		;Fatal LATOP. error
	SKIPG	P1,T1		;Save number of known servers to be listed
	POPJ	P,		;None, just return now
	MOVEI	P3,DNLST	;Address of list of known servers
	SETZB	P2,HPOS		;Set up for output routines

;Loop listing info for each known server

LATLP:	MOVEI	T1,5		;Length
	MOVEI	T2,.LASAS	;And LATOP. function
	DMOVEM	T1,NODBLK+.LAACT;Set for LATOP. UUO
	MOVEI	T1,DNINFL	;Length
	MOVEI	T2,DNINF	;And address of aux buffer
	DMOVEM	T1,NODBLK+.LABCT;Set aux buffer for LATOP.
	MOVSI	T1,(POINT 7)	;7-bit byte pointer
	HRRI	T1,1(P3)	;Address of server name string (short block)
	MOVEM	T1,NODBLK+.LAQUA;Set for LATOP.
	HRRZ	T1,(P3)		;Get length of server name
	ADJBP	T1,NODBLK+.LAQUA;Point to last character of name
	SETZ	T2,		;Get a null terminator
	IDPB	T2,T1		;Make sure LATSER can find the name it gave us
	MOVEI	T1,NODBLK	;LATOP. UUO arg pointer to
	LATOP.	T1,		;Read info about LAT server
	  JRST	[PUSHJ	P,LATOPE	;LATOP. UUO error
		JRST	LATLP8]		;Advance to next server
	PUSHJ	P,LATWLD	;See if want to see this name
	  JRST	LATLP8		;Skip this LAT server
	HRRZ	T1,DNINF+5	;Get the link state
	SKIPLE	LINKWD		;If only want active servers,
	JUMPE	T1,LATLP8	;Skip idle ones
	AOS	MATCH		;Matched a LAT server
	MOVSI	T1,SP.LAT	;Found a LAT bit
	IORM	T1,SPCFLG(T4)	;Light for this node
	SKIPLE	SILWD		;See /SILENCE?
	JRST	LATLP8		;Yes, errors only
	PUSHJ	P,LATSHO	;Show info

LATLP8:	ADDI	P3,7		;Advance to next "short form" server block
	SOJG	P1,LATLP	;Loop for all LAT servers
	SKIPE	HPOS		;If not at BOL,
	PUSHJ	P,CRLFH		;Get there
	POPJ	P,		;Return successfully
;Here to obtain initial LAT info

LATINI:	TXO	F,F.HED		;[042] Assume no header desired
	MOVEI	T1,4		;Length of UUO arg block
	MOVEI	T2,.LASCH	;LAT function "Show Characteristics"
	DMOVEM	T1,NODBLK	;Stash for LATOP.
	MOVEI	T1,2*MAXNOD	;Size of aux area
	MOVEI	T2,NODBIN	;Address of aux area
	DMOVEM	T1,NODBLK+.LABCT;Set pointer to returned-data buffer
	MOVEI	T1,NODBLK	;LATOP. arg pointer to
	LATOP.	T1,		;Read general LAT host info
	 JRST	[CAIN	T1,NODBLK	;UUO unimplemented?
		JRST	NOLAT		;Yes, tell user no LAT here
		JRST	LATOPE]		;No, LATOP. UUO error
	MOVEI	T1,5		;Length of UUO arg block
	MOVEI	T2,.LASAS	;LAT function "Show Servers"
	DMOVEM	T1,NODBLK+.LAACT;Stash for LATOP.
	MOVEI	T1,2*DNMAX	;Length of aux buffer
	MOVEI	T2,DNLST	;Address of aux buffer
	DMOVEM	T1,NODBLK+.LABCT;Set pointer for returned-info
	SETZM	NODBLK+.LAQUA	;Want short-form blocks
	MOVEI	T1,NODBLK	;LATOP. arg pointer to
	LATOP.	T1,		;Read list of known LAT servers
	 JRST	LATOPE		;LATOP. UUO erorr
	PUSHJ	P,LATSRT	;Sort the server list appropriately
	SKIPLE	LINKWD		;If /LINKS was typed,
	PUSHJ	P,LATLSR	;Get and sort the list of connections
	SKIPLE	SPCCNT		;[042] Yes, are sure there'll be a header?
	TXZA	F,F.HED		;[042] No, allow it to print later
	PUSHJ	P,LATHEA	;[042] Yes, print it now
	HRRZ	T1,NODBIN+00	;[042] "N-ALLOC-CIRCUITS" (return value)
	JRST	.POPJ1##	;[042] Return success

;Type out the LAT header info

LATHEA:	PUSHJ	P,CRLFH		;Space down a line for neatness
	SKIPN	HEADWD		;User want a header?
	POPJ	P,		;No, all done here
	HRRZ	T1,NODBIN+00	;"N-ALLOC-CIRCUITS" (return value)
	PUSH	P,T1		;Hang onto it for a moment
	MOVEI	T1,[ASCIZ\[LAT service: local LAT host \]
	PUSHJ	P,.TSTRG##	;Start up the LAT header
	MOVEI	T1,NODBIN+24	;Our LAT host name
	PUSHJ	P,.TSTRG##	;Type out host name string
	MOVEI	T1,[ASCIZ\; \]	;Separating text
	PUSHJ	P,.TSTRG##	;'Twixt name and number
	SKIPN	T1,(P)		;Retrieve "N-ALLOC-CIRCUITS"
	JRST	[MOVEI T1,[ASCIZ\No\]  ;If "0" then
		PUSHJ	P,.TSTRG##	;Then type "No known..."
		JRST	.+2]		;Blunder onwards
	PUSHJ	P,.TDECW##	;Type number of known servers
	MOVE	T2,0(P)		;Restore number of known servers
	MOVEI	T1,[ASCIZ\ known server]\]  ;Cap off the LAT header text
	CAIE	T2,1		;Singular or plural?
	MOVEI	T1,[ASCIZ\ known servers]\]  ;Cap off the LAT header text
	PUSHJ	P,.TSTRG##	;With the closing bracket
	PUSHJ	P,.TCRLF##	;A <CR><LF>
	POP	P,T1		;Return number of servers in T1
	POPJ	P,		;[042] to caller
;Here to sort the list of LAT servers

LATSRT:	SKIPGE	T1,SORTWD	;Get the type of sorting requested
	MOVEI	T1,SRT.DF	;Default if no switch typed
	CAIE	T1,SRT.NA	;Sort by name?
	CAIN	T1,SRT.DF	; or default sorting?
	JRST	LATNSR		;Yes, sort by name string
	CAIE	T1,SRT.NU	;No, sort by number?
	POPJ	P,		;No, /NOSORT, so don't alter the order
	HRRZ	T1,NODBIN+00	;Get "N-ALLOC-CIRCUITS" (number of servers)
LATSR1:	LSH	T1,-1		;T1=T1/2
	JUMPE	T1,CPOPJ	;IF T1=0 THEN RETURN
	MOVEI	T2,1		;T2=1
LATSR2:	HRRZ	T3,T2		;T3=T2
LATSR3:	HRRZ	T4,T3
	ADDI	T4,(T1)		;T4=T3+T1
	IMULI	T4,7		;Account for lengths of entries
	IMULI	T3,7		; ...
	HLRZ	T5,DNLST-7(T3)	;Get NODNUM(T3)
	HLRZ	T6,DNLST-7(T4)	; and NODNUM(T4)
	CAIL	T6,(T5)		;IF node[T3] .LE. node[T4]
	JRST	LATSR4		; THEN GOTO SORT3
	PUSHJ	P,LATSWP	;exchange
	IDIVI	T3,7		;Back from offset to index
	SUBI	T3,(T1)		;T3=T3-T1
	JUMPG	T3,LATSR3	;IF T3 .GE. 1 THEN GOTO SORT4
LATSR4:	HRRZ	T5,NODBIN+00	;Delayed T2=T2+1
	SUBI	T5,1(T1)	;then comparison
	CAILE	T2,(T5)		;IF T2 .GT. N-T1 THEN
	AOJA	T2,LATSR1	;GOTO SORT1
	AOJA	T2,LATSR2	;ELSE GOTO SORT2

;Here to shellsort the LAT servers by name

LATNSR:	HRRZ	T1,NODBIN+00	;T1=N (the number of servers)
LATNS1:	LSH	T1,-1		;T1/=2
	JUMPE	T1,CPOPJ	;IF T1 .EQ. 0 THEN RETURN
	MOVEI	T2,1		;T2=1
LATNS2:	HRRZ	T3,T2		;T3=T2
LATNS3:	HRRZ	T4,T3
	ADDI	T4,(T1)		;T4=T3+T1
	IMULI	T4,7		;Account for length of entries
	IMULI	T3,7		; ...
	PUSHJ	P,LATCMP	;IF node[T3] .LE. node[T3+T1]
	  JRST	LATNS4		;THEN GOTO SORT4
	PUSHJ	P,LATSWP	;exchange
	IDIVI	T3,7		;Revert from offset to index
	SUBI	T3,(T1)		;T3-=T1
	JUMPG	T3,LATNS3	;IF T3 .GT. 0 THEN GOTO SORT3
LATNS4:	HRRZ	T5,NODBIN+00	;Delayed T2++
	SUBI	T5,1(T1)	;and comparison
	CAILE	T2,(T5)		;IF T2 .GT. N-1
	AOJA	T2,LATNS1	;THEN GOTO SORT1
	AOJA	T2,LATNS2	;ELSE GOTO SORT2

;Here to shellsort the LAT connections

LATLSR:	MOVEI	T1,4		;Length of UUO block
	MOVEI	T2,.LASTC	;LAT function "Show Terminal Connections"
	DMOVEM	T1,NODBLK+.LAACT;Stash for LATOP.
	MOVEI	T1,LTMAX	;Length of aux buffer
	MOVEI	T2,LTLINK	;Address of aux buffer
	DMOVEM	T1,NODBLK+.LABCT;Set pointer for returned info
	MOVEI	T1,NODBLK	;LATOP. arg pointer
	LATOP.	T1,		;Read list of terminal connections
	  JRST	LATOPE		;LATOP. UUO error
	HLRZ	T1,NODBLK+.LABCT;Get count of words returned
	IDIVI	T1,6		;Convert to count of connections
	MOVEM	T1,LTLCNT	;Save for later checking
	SKIPE	T2,SORTWD	;Get type of sorting requested
	CAIN	T2,SRT.NO	;If /NOSORT, don't bother
	POPJ	P,		;Otherwise sort connections by TTY number
LATLS1:	LSH	T1,-1		;T1/=2
	JUMPE	T1,CPOPJ	;IF T1 .EQ. 0 THEN RETURN
	MOVEI	T2,1		;T2=1
LATLS2:	HRRZ	T3,T2		;T3=T2
LATLS3:	HRRZ	T4,T3
	ADDI	T4,(T1)		;T4=T3+T1
	IMULI	T4,6		;Account for length of entries
	IMULI	T3,6		; ...
	MOVE	T5,LTLINK-6(T4)
	CAML	T5,LTLINK-6(T3)	;IF tty[T3] .LE. tty[T3+T1]
	JRST	LATLS6		;THEN GOTO SORT6
	MOVSI	T5,-6		;Start of AOBJN to entry
	HRRI	T5,(T3)		;Pointer to source
LATLS4:	MOVE	T6,LTLINK-6(T5)	;Get source word
	EXCH	T6,LTLINK-6(T4)	;Exchange with destination
	MOVEM	T6,LTLINK-6(T5)	;Finish exchange with source
	AOBJP	T5,LATLS5	;Test for end
	AOJA	T4,LATLS4	;Advance both pointers and loop over entries
LATLS5:	IDIVI	T3,6		;Convert back from offset to index
	SUBI	T3,(T1)		;T3-=T1
	JUMPG	T3,LATLS3	;IF T3 .GT. 0 THEN GOTO SORT3
LATLS6:	HRRZ	T5,LTLCNT	;Delayed T2++
	SUBI	T5,1(T1)	;then comparison
	CAILE	T2,(T5)		;IF T2 .GT. N-1
	  AOJA	T2,LATLS1	;THEN GOTO SORT1
	AOJA	T2,LATLS2	;ELSE GOTO SORT2

;Here to compare LAT server name strings

LATCMP:	PUSHJ	P,.SAVE2##	;EXTEND uses 6 ACs
	PUSHJ	P,.PSH4T##	;Preserve all ACs used
	MOVEI	T2,DNLST-6(T3)	;Address of node[T3]
	MOVEI	P1,DNLST-6(T4)	;Address of node[T3+T1]
	HRRZ	T1,DNLST-7(T3)	;Length of nodename[T3]
	HRRZ	T4,DNLST-7(T4)	;Length of nodename[T3+T1]
	SETZB	T3,P2		;Don't confuse the KL
	HRLI	T2,(POINT 7)	;Set up proper byte pointers
	HRLI	P1,(POINT 7)	; ...
	EXTEND	T1,[EXP CMPSLE,0,0] ;Compare with zero-fill
	  AOS	-4(P)		;Routine acts as a CMPSG
	PUSHJ	P,.POP4T##	;Restore the temps
	POPJ	P,		;Return with appropriate skipness

;Here to swap two short blocks

LATSWP:	MOVSI	T5,-7		;Set up length of transfer
	HRRI	T5,(T3)		;Point to source block
LATSW1:	MOVE	T6,DNLST-7(T5)	;Get a word from the source
	EXCH	T6,DNLST-7(T4)	;Exchange with destination
	MOVEM	T6,DNLST-7(T5)	;Finish exchange with source
	AOBJP	T5,CPOPJ	;Return if finished
	AOJA	T4,LATSW1	;Else, advance both pointers and do it again
;Wildcard selection of LAT servers
;
;Note that only the first six characters are checked!

LATWLD:	SKIPG	T4,SPCCNT	;Did user type any specs?
	JRST	.POPJ1##	;No, then match everything
	HRRZ	T1,DNINF+6	;Length of LAT server name string
	MOVSI	T2,(POINT 7,)	;Prototype byte pointer
	HRRI	T2,DNINF+10	;Address of LAT server name string
	PUSHJ	P,LATSIX	;Get SIXBIT name in T1
	  POPJ	P,		;Failed?
	MOVN	T4,SPCCNT	;Count of specs to check
	HRLZ	T4,T4		;AOBJN pointer to SPCLST/WLDLST

;Loop checking wildcarded node specs

LATWL2:	MOVE	T3,SPCLST(T4)	;Next user-typed name
	XOR	T3,T1		;Contrast with proposed server name
	ANDCM	T3,WLDLST(T4)	;(ignoring any junk that should be ignored)
	JUMPN	T3,LATWL5	;This spec loses!
	JRST	.POPJ1##	;No other constraints, this spec wins

LATWL5:	AOBJN	T4,LATWL2	;Loop back and check the rest of the specs
	POPJ	P,		;Reject this LAT server


;Make SIXBIT name out of ASCIZ string
;
;Call with T1/count and T2/pointer

LATSIX:	PUSH	P,[0]		;The prototype name
	MOVSI	T3,(POINT 6,0(P))  ;SIXBIT name builder
	JRST	LATSI4		;Enter loop

LATSI2:	ILDB	T4,T2		;Next name string character
	CAIL	T4,"a"		;If not lower case,
	CAILE	T4,"z"		; ...
	SUBI	T4,"0"-'0'	;SIXBITIFY the character
	JUMPLE	T4,LATSI5	;Quit on space, null, or control characters
	TLNE	T3,770000	;Filled up one word yet?
	IDPB	T4,T3		;Nope, accumulate this character
LATSI4:	SOJGE	T1,LATSI2	;Decrement the count
LATSI5:	POP	P,T1		;Position name
	JRST	.POPJ1##	;Successful return
;Here to type information about one specific server

LATSHO:	TXON	F,F.HED		;[042] Header typed yet?
	PUSHJ	P,LATHEA	;[042] No, do it now
	SKIPLE	FASWD		;Did we see /FAST?
	JRST	LATFST		;Yes, format is a bit different
	MOVEI	T1,1(P3)	;No, point to name
	PUSHJ	P,KILBLK	;Make sure it's pretty
	PUSHJ	P,TCARE		;Display it
	MOVE	P2,HPOS		;Fetch column back into our register
	CAIG	P2,7		;If not at least one tab stop,
	PUSHJ	P,.TTABC##	;Fix that
	CAIG	P2,17		;Unless the full 16 chars,
	PUSHJ	P,.TTABC##	;Space over
	MOVEI	P2,22		;Account for the extra punctuation
	HLRZ	T1,(P3)		;Get the server number
	PUSHJ	P,FLATSD	;Make sure it will fit
	CAMLE	P2,CARWID	;Will it?
	PUSHJ	P,CRLFH		;No, wrap around
	MOVEI	T1,"("		;Parenthesize its number
	PUSHJ	P,.TCHAR##	;Just because it looks better
	HLRZ	T1,(P3)		;Get the number
	PUSHJ	P,.TDECW##	;Display it
	MOVEI	T1,")"		;Close parenthesis
	PUSHJ	P,.TCHAR##	;Match them up
	PUSHJ	P,.TTABC##	;Space over for location string
	MOVE	P2,HPOS		;Get last guessed position
	ADDI	P2,8		;Tab stops are 8 chars wide
	TRZ	P2,7		;And aligned
	MOVEM	P2,HPOS		;Save where TCARE looks
	HLRZ	T1,DNINF+7	;Get length of location string
	ADJBP	T1,[POINT 7,DNINF+14] ;Point to its last character
	SETZ	T2,		;Get a null terminator
	IDPB	T2,T1		;Make sure it's ASCIZ
	MOVEI	T1,DNINF+14	;Address of the location string
	PUSHJ	P,KILBLK	;Pretty it up
	PUSHJ	P,TCARE		;Type the string
	PUSHJ	P,CRLFH		;End the line
	SETZ	P2,		;Remember the CRLF
	SKIPLE	BRIEWD		;Supposed to be brief?
	JRST	LATLNK		;Yes, check if supposed to show links

LATCNF:	SKIPG	FASWD		;Doing a fast listing?
	PUSHJ	P,.TTABC##	;No, indent for configuration info
	MOVEI	T1,DNINF	;Point to Ethernet address
	PUSHJ	P,LATADR	;Display it
	PUSHJ	P,.TSPAC##	;Make some room
	PUSHJ	P,.TSPAC##	;For readability
	PUSHJ	P,.TSPAC##	;This should be enough
	ADDI	P2,^D<8+17+3>	;How many bytes we have added
	SKIPLE	FASWD		;Unless a fast listing,
	SUBI	P2,8		;Then we didn't type the tab
	MOVEM	P2,HPOS		;Put it where TCARE looks
	HLRZ	T1,DNINF+5	;Get server type info
	ANDI	T1,377		;Keep only the part we know about
	CAIL	T1,LATPTL	;Do know about this product type?
	SETZ	T1,		;No, force it to be unknown
	MOVE	T1,LATPTC(T1)	;Get its type name
	PUSHJ	P,TCARE		;Display it
	PUSHJ	P,CRLFH		;End the line
	SETZ	P2,		;Remember the CRLF

LATLNK:	SKIPG	LINKWD		;Unless /LINKS was typed,
	POPJ	P,		;Don't display the connections
	MOVN	L1,LTLCNT	;Get negative count of links
	HRLZ	L1,L1		;Into LH for AOBJNing
LATLN1:	PUSHJ	P,LATACT	;Is this known link a match?
	  JRST	LATLN2		;No, don't show this link
	MOVE	T1,LTLINK(L1)	;Yes, get its TTY number
	PUSHJ	P,LATTRM	;Display the TTY info
LATLN2:	ADDI	L1,5		;Account for 6-word entries
	AOBJN	L1,LATLN1	;Loop over all known connections
	POPJ	P,		;Now we're done

;Here to check for matching server names for active connections

LATACT:	PUSHJ	P,.SAVE2##	;EXTEND wants 6 ACs
	PUSHJ	P,.PSH4T##	;Preserve all ACs used
	MOVEI	T2,LTLINK+2(L1)	;Point to link server's name
	MOVE	T1,LTLINK+1(L1)	;[041] Get its length word
	TLNE	T1,-1		;[041] Is the length where it belongs?
	HLRZ	T1,T1		;[041] Yes, put it where we want it
	HRRZ	T4,(P3)		;Get current server's name length
	MOVEI	P1,1(P3)	;And address
	SETZB	T3,P2		;Don't confuse the KL
	HRLI	T2,(POINT 7)	;Set up proper byte pointers
	HRLI	P1,(POINT 7)	; ...
	EXTEND	T1,[EXP CMPSN,0,0] ;Compare with zero-fill
	  AOS	-4(P)		;Routine emulates a CMPSE
	PUSHJ	P,.POP4T##	;Restore the temps
	POPJ	P,		;Return appropriate skipness to caller

;Here to display the info for one LAT connection

LATTRM:	TRO	T1,.UXTRM	;Make sure it's a TTY UDX
	MOVEM	T1,NOPBLK+.NODEV;Set in arg block
	MOVE	T1,[.NOPNM+1,,.NOGDI] ;Length,,function
	MOVEM	T1,NOPBLK+.NOFCN;Set in arg block
	XMOVEI	T1,LATPNM	;Location of port name string
	MOVEM	T1,NOPBLK+.NOPNM;Stuff for UUO
	MOVEI	T1,20		;Maximum size to return
	MOVEM	T1,LATPNM	;Set for UUO
	XMOVEI	T1,NOPBLK	;Point to arg block
	NETOP.	T1,		;Get the information
	  POPJ	P,		;Terminal must have disconnected
	MOVE	T1,NOPBLK+.NOFLG;Get type of connection
	TXNN	T1,NO.LAT	;Make sure it's still a LAT terminal
	POPJ	P,		;Skip it if not
	MOVE	T1,NOPBLK+.NODEV;Get UDX again
	DEVNAM	T1,UU.PHY	;Get the TTY's name
	  POPJ	P,		;Give up
	MOVEM	T1,LATTNM	;Save
	LDB	T1,[POINTR NOPBLK+.NODTY,TY.JOB] ;Get owning job number
	JUMPE	T1,LATTR1	;Skip some stuff if not logged-in
	MOVX	T2,DV.TTA	;Attached terminal bit
	TDNN	T2,NOPBLK+.NODCH;Make sure it isn't just assigned
	JRST	LATTR1		;It is, give up on it
	MOVSI	T2,(T1)		;Attached, get job number in LH
	HRRI	T2,.GTPRG	;So can read the program name
	GETTAB	T2,		;Ask the monitor
	  JRST	LATTR1		;Assume the job went away
	MOVEM	T2,LATPRG	;Save for later
	MOVSI	T2,(T1)		;Get job number as index again
	HRRI	T2,.GTPPN	;So can read the job's PPN
	GETTAB	T2,		;Ask the monitor
LATTR1:	  SETZB	T2,LATPRG	;Clear out program name
	MOVEM	T2,LATPPN	;Save or clear PPN
	MOVEM	T1,LATJOB	;Save job number as well
	JUMPE	T1,LATTR2	;No user name if no job
	MOVSI	T2,(T1)		;Get job in LH
	MOVSI	T1,(T1)		;Twice
	HRRI	T1,.GTNM1	;Set to read the user's name
	HRRI	T2,.GTNM2	;Both halves
	GETTAB	T1,		;Ask the monitor
	  SETZ	T1,		;Junk
	GETTAB	T2,		;For both halves
	  SETZ	T2,		;More junk
LATTR2:	DMOVEM	T1,LATUNM	;Save username for typeout
	PUSHJ	P,.TTABC##	;Indent to show this information
	MOVE	T1,LATTNM	;Get the TTY's name
	PUSHJ	P,.TSIXN##	;Display it
	PUSHJ	P,.TTABC##	;Format a little
	SKIPN	LATJOB		;TTY assigned?
	JRST	LATTR3		;No, don't type a job number
	MOVX	T1,<ASCII |Job |>;Get word to type
	PUSHJ	P,.TASCW##	;Type it
	MOVE	T1,LATJOB	;Get the job number
	PUSHJ	P,.TDECW##	;Type it
LATTR3:	PUSHJ	P,.TTABC##	;More spacing
	SKIPN	LATPPN		;Is there really a PPN?
	JRST	LATTR4		;No, just space over
	HLRZ	T1,LATPPN	;Get project halfword
	MOVEI	T3,7		;Field width
	PUSHJ	P,.TOCTJ##	;Type it right-justified
	PUSHJ	P,.TCOMA##	;And the comma to separate
	HRRZ	T1,LATPPN	;Get programmer halfword
	PUSHJ	P,.TOCTW##	;Type it left-justified
	CAIA			;Skip over excess tab
LATTR4:	PUSHJ	P,.TTABC##	;Extra spacing when no PPN
	PUSHJ	P,.TTABC##	;Another just to line up
	MOVE	T1,LATPRG	;User's program name
	PUSHJ	P,.TSIXN##	;Display it
	PUSHJ	P,.TTABC##	;Space over
	MOVE	T1,LATUNM	;First half of username
	PUSHJ	P,.TSIXS##	;Type in a 6-char field
	MOVE	T1,LATUNM+1	;Second half of username
	MOVEI	T3,8		;Give it an 8-bit field
	PUSHJ	P,.TSIXJ##	;Type left-justified SIXBIT
	HLRZ	T1,LATPNM	;How many characters in port name?
	ADJBP	T1,[POINT 8,LATPNM+1] ;Point to last
	SETZ	T2,		;Get a null to deposit
	IDPB	T2,T1		;Make sure of ASCIZ8 format
	XMOVEI	T1,LATPNM+1	;Point to port name
	PUSHJ	P,.T8STR##	;Type the 8-bit ASCIZ string
	SETZ	P2,		;About to be at BOL again
	PJRST	CRLFH		;End the line and return

;Here for fast format preamble

LATFST:	MOVEI	T1,30(P2)	;New HPOS after we're done with the field
	CAMLE	T1,CARWID	;Compare with our margin
	PUSHJ	P,CRLFH		;Wrap if necessary
	MOVE	P2,HPOS		;Make sure we're in synch
	HRRZ	T1,(P3)		;Get length of server name
	ADDI	P2,2(T1)	;Account for name and parens
	HLRZ	T1,(P3)		;Get server number
	PUSHJ	P,FLATSD	;Make sure the number will fit
	MOVEI	T1,1(P3)	;Point to server name again
	PUSHJ	P,.TSTRG##	;Type it
	MOVEI	T1,"("		;Get left paren
	PUSHJ	P,.TCHAR##	;Type it
	HLRZ	T1,(P3)		;Get server number
	PUSHJ	P,.TDECW##	;Type it
	MOVEI	T1,")"		;Get right paren
	PUSHJ	P,.TCHAR##	;Type it, too
	MOVEI	T1,(P2)		;Get current notion of HPOS
	IDIVI	T1,30		;Split into column and remainder
	AOJ	T1,		;Update for next column
	IMULI	T1,30		;Get back to HPOS
	MOVEI	P2,(T1)		;Propagate
	MOVEM	T1,HPOS		; to both places that care
	HRREI	T2,-30(T2)	;Get minus count to next boundary
	PUSHJ	P,.TSPAC##	;Type a space
	AOJL	T2,.-1		;Keep going until we line up
	SKIPE	BRIEWD		;Explicit /NOBRIEF?
	POPJ	P,		;No, just leave it here
	PJRST	LATCNF		;Yes, add configuration info

;Here to type out an Ethernet address

LATADR:	HRLI	T1,(POINT 8)	;Get B.P. to the address
	MOVEI	T3,20		;And the proper radix
	PUSH	P,T1		;Save the byte pointer
	MOVEI	T4,6		;And the number of bytes to type
	CAIA			;Skip the hyphen the first time through
LATAD1:	PUSHJ	P,.TDASH##	;Separate with hyphens
	ILDB	T1,(P)		;Get the next byte
	IDIVI	T1,20		;Split into hex digits
	PUSH	P,T2		;Save second half
	PUSHJ	P,.TRDXW##	;Type first half
	POP	P,T1		;Restore second digit
	PUSHJ	P,.TRDXW##	;Type that one as well
	SOJG	T4,LATAD1	;Loop over all six bytes
	POP	P,T1		;Balance the stack
	POPJ	P,		;Return
;This is the list of LAT server types we know about

LATPTC:	[ASCIZ	\Unknown type\]			;0
	[ASCIZ	\Ethernet Terminal Server\]	;1
	[ASCIZ	\DECserver 100\]		;2
	[ASCIZ	\VAX/VMS\]			;3
	[ASCIZ	\RSX11-M\]			;4
	[ASCIZ	\RSX11-M+\]			;5
	[ASCIZ	\TOPS-20\]			;6
	[ASCIZ	\TOPS-10\]			;7
	[ASCIZ	\ULTRIX-11\]			;8
	[ASCIZ	\LAT-11\]			;9
	[ASCIZ	\RSTS/E\]			;10
	[ASCIZ	\ULTRIX-32\]			;11
	[ASCIZ	\ELN\]				;12
	[ASCIZ	\MS/DOS\]			;13
	[ASCIZ	\P/OS\]				;14
	[ASCIZ	\PCSG-LAT\]			;15
	[ASCIZ	\DELIX\]			;16
	[ASCIZ	\DECserver 200\]		;17
	[ASCIZ	\DECserver 500\]		;18
	[ASCIZ	\Actor\]			;19

	LATPTL==.-LATPTC			;Length of table
;LAT errors

NOLAT:	PUSHJ	P,.PSH4T##	;Save the temps
	MOVE	T1,['NWKNLS']	;The prefix
	MOVE	T2,["?",,[ASCIZ	\No LAT service available
\]]
	PUSHJ	P,.ERMSG##	;Print the error message
	PUSHJ	P,.POP4T##	;Restore the temps in case of dump
	POPJ	P,		;Propagate error return


;LATOP. UUO error

LATOPE:	PUSHJ	P,.PSH4T##	;Save the "T" acs
	PUSH	P,T1		;Save the error code
	TXON	F,F.HED		;[042] If no header yet,
	PUSHJ	P,LATHEA	;[042] Type it
	MOVE	T1,['NWKLUE']	;LAT UUO Error prefix
	MOVE	T2,["?",,[ASCIZ\LATOP. UUO error (\]]
	PUSHJ	P,.ERMSG##	;Start up the error message
	MOVE	T1,0(P)		;The offending error code
	PUSHJ	P,.TOCTW##	;List the error code in octal
	POP	P,T2		;Retrieve the error code
	CAIG	T2,LATERL	;Is the	error code in range?
	CAIGE	T2,0		;...?
	  SETO	T2,		;No? make it zero!
	MOVE	T1,LATERT(T2)	;Get the error string
	PUSHJ	P,.TSTRG##	;and type it
	PUSHJ	P,.TCRLF##	;Cap off the error text
	PUSHJ	P,.POP4T##	;Restore the temps in case of dump
	POPJ	P,		;Propagate error


DEFINE	X(TXT),<[ASCIZ\) TXT\]>

	X	Unknown LATOP UUO error
LATERT:	X	Insufficient buffer size
	X	Invalid parameter value
	X	LAT is not operational
	X	Invalid/Unknown LAT server name
	X	Invalid LAT parameter
	X	Invalid LAT parameter value
	X	Invalid/Unknown LAT service name
	X	Insufficient resources
	X	LAT host name already set
	X	Invalid LATOP. function
	X	Argument list too small
	X	Address check
	X	Insufficient privileges

	LATERL==.-LATERT
	SUBTTL	Routines to interface to Scan

;** Routine to finish I/O and exit
;

FINISH:	PUSHJ	P,FLUSH			;Finish	output
	JRST	.MONRT##		;And exit gracefully

;** Routine to flush output and	go into	character mode
;Clobbers T1

FLUSH:	MOVSI	T1,MO.CHR		;Get the output	control	bit
	ANDCAM	T1,OUTCON		;And clear it
	SETZ	T1,			;Send a	null character to output the
	PJRST	OUTC			;current buffer	and return

;** Routine to buffer tty output
;   Called by SCAN and placed in character mode	for prompt
;   The	character is in	T1

OUTC:	IDPB	T1,BUFFP		;Deposit character in the buffer
	SKIPL	OUTCON			;If bit	0 is set then line mode
	  JRST	OUTLST			;If char mode output the buffer
	SOSGE	NCHAR			;Decrement the character count
	  JRST	OUTLST			;Output	it to the TTY
	POPJ	P,			;Return

OUTLST:	PUSH	P,T1			;[44] Preserve T1
	SETZ	T1,			;Zero next character
	IDPB	T1,BUFFP		;To make the string ASCIZ
	OUTSTR	BUFFER			;Output	the buffer
	MOVE	T1,[POINT 7,BUFFER]	;Reset the buffer pointer
	MOVEM	T1,BUFFP		;...
	MOVEI	T1,BUFSIZ		;Reset the character count
	MOVEM	T1,NCHAR		;...
	POP	P,T1			;[44] Restore T1
	POPJ	P,			;Return	to SCAN
;** Here from Scan to allocate space for Scan blocks as	node or	file specs
;   IALLO increments number of specs on	the input side of the "="
;   OALLO increments the number	of specs on the	output side of the "="
;
;   Scan will try to BLT the info into the right spot

IALLO:	AOSA	INFIL			;Add one to the	number of input	specs
OALLO:	AOS	OUTFIL			;Add one to the	number of output specs
	MOVE	T1,NUMBLK		;Number	of blocks allocated so far
	CAILE	T1,MAXSPC		;More than we allow?
	  JRST	ALOCE1			;Tell user we have an allocation error
	IMULI	T1,BLKSIZ		;Get the amount	of core	this takes
	ADDI	T1,BLKSIZ+SBLKS		;And add one more block	& address
	CAMG	T1,.JBREL		;Do we already have enough core?
	  JRST	OALLO1			;Yes, We already have enough
	PUSH	P,T1			;No, Save T1 around CORE UUO
	CAILE	T1,MAXCOR		;Are we	still smaller than max allowed
	  JRST	ALOCER			;No, tell user
	ADDI	T1,BLKSIZ		;Add block size
	ANDI	T1,777000		;Mask to pages
	ADDI	T1,1000			;And add one
	CORE	T1,			;...
	  JRST	ALOCER			;Allocation error, tell	user
	PUSHJ	P,.TCRLF##		;Do a <CR><LF>
	MOVEI	T1,"["			;Type a	<left bracket>
	PUSHJ	P,.TCHAR##		;...
	MOVE	T1,.JBREL		;Get how much we got now
	ANDI	T1,777000		;Mask to pages
	ADDI	T1,2000			;And add one
	PUSHJ	P,.TCORW##		;Type how much core we are using
	MOVEI	T1,[ASCIZ \ core]\]	;Tell him it's core
	PUSHJ	P,.TSTRG##		;...
	POP	P,T1			;Ok, Restore T1
OALLO1:	MOVEI	T2,BLKSIZ		;a pointer and a block size
	SUB	T1,T2			;Backup	one block length
	AOS	NUMBLK			;add one to the	count of
					;Scan blocks allocated
	POPJ	P,			;Return	to Scan
;** Here to initalize Scan with	.ISCAN
;   called from	the startup code

ISCN:	MOVE	T2,[ISLEN,,ISBLK]	;.ISCAN	argument block if logged in
	PUSHJ	P,.ISLGI##		;Are we	logged in?
	  MOVE	T2,[ISLEN,,ISBLO]	;.ISCAN	argument block if logged out
	MOVE	T1,T2			;Put the argument into T2
	PJRST	.ISCAN##		;Call .ISCAN

;** Here to do the Traditional Scanner .TSCAN
;   called from	the startup code

TSCN:	MOVE	T1,[TSLEN,,TSBLK]	;.TSCAN	arg block for DECnet and ANF10
	PUSHJ	P,.TSCAN##		;Scan a	line of	input
	MOVE	T1,[OSLEN,,OSBLK]	;.OSCAN	argument block
	PUSHJ	P,.OSCAN##		;Check SWITCH.INI[,]
	MOVSI	T1,MO.CHR		;Get the output	control	bit
	IORM	T1,OUTCON		;Set it	for buffered mode
	SKIPL	T1,WIDWD		;Did the user type /WIDTH?
	  MOVEM	T1,CARWID		;Yes, save his value for it
	POPJ	P,			;Return
	SUBTTL	Dissect	the Scan blocks

;** Routine to get a node-spec out of a	Scan block
;
;   If the spec	is "wild" do a search of node names for	winners
;   If not "wild" use the NODE.	UUO to figure out who we want
;   Then (in either case) insert the proper entries into the
;   selection table
;   Finally jump to the	main loop to tell the user about what we already know

DISECT:	SETZB	T4,SPCCNT		;Zero both counts
	SKIPN	T3,NUMBLK		;Any spec's typed?
	  JRST	DISEC3			;No, just return
	MOVN	T3,NUMBLK		;Number	of Scan	Blocks
	HRL	T3,T3			;Make an AOBJN pointer
	HRRI	T3,SBLKS		;Point to the first Scan block
DISEC1:	PUSH	P,[DISEC2]		;Return	address	for error routines
	MOVE	T1,.FXMOD(T3)		;Get the modifier word
	TXNN	T1,FX.NDV		;Did he	type a device?
	 JRST	SPECER			;Yes, tell him
	TXNN	T1,FX.NUL		;Did he	type an	extension?
	 JRST	SPECER			;Yes, tell him
	TXNE	T1,FX.DIR		;Did he	type a P,PN?
	 JRST	SPECER			;Yes, tell him
	MOVE	T2,.FXNAM(T3)		;Is there a name?
	MOVEM	T2,SPCLST(T4)		;Save the node spec
	SETCM	T1,.FXNMM(T3)		;And out the mask
	MOVEM	T1,WLDLST(T4)		;Save the wild card mask
	AOS	T4			;Increment the count of	node specs
	POP	P,(P)			;Don't do the error return
DISEC2:	ADDI	T3,BLKSIZ-1		;Add size of the block to the pointer
	AOBJN	T3,DISEC1		;Loop until all	the blocks are checked
	MOVEM	T4,SPCCNT		;Save the count	of spec's
	SKIPE	SPCLST			;If there are any spec's  then
	  POPJ	P,			;Just return
DISEC3:	MOVEI	T1,1			;Our default (/BRIEF)
	SKIPGE	BRIEWD			;Did he	specify	/BRIEF or /NOBRIEF?
	  MOVEM	T1,BRIEWD		;No, assume /BRIEF on default
	POPJ	P,			;Return	when all blocks	are checked
	SUBTTL	Error message handling routines

;** Here when we run out of Scan block storage.
;   tell the user once and continue, ignoring any more specs

ALOCER:	SKIPE	SBMCNT			;Sure to only tell him once!
	  JRST	ALOCE2			;Don't count errors unless we print them
	MOVE	T1,NFECNT		;How many non-fatal errors did we have?
	CAILE	T1,MAXNFE		;Did we	have too many?
	  JRST	NFEERR			;Yes, tell the user and	die
	AOS	NFECNT			;No, count the error
	POP	P,T1			;Restore T1
ALOCE1:	PUSHJ	P,.PSH4T##		;Save the temps
	MOVE	T1,['NWKSBE']		;Yes, tell the user
	MOVE	T2,["%",,[ASCIZ	\Scan Blocks used up. Node spec	ignored
\]]
	PUSHJ	P,.ERMSG##		;Yes, print the	error
	PUSHJ	P,.POP4T##		;Restore the temps
ALOCE2:	MOVEI	T2,1			;Dummy up a scan block
	MOVE	T1,NUMBLK		;Number	of blocks allocated so far
	IMULI	T1,BLKSIZ		;Get the amount	of core	this takes
	ADDI	T1,BLKSIZ+SBLKS		;And add one more block	& address
	AOS	SBMCNT			;Keep track of how many	times here
	POPJ	P,			;Return
;Copy of the interrupt control block to	be BLTed on initalization

INT:	XWD	4,CONC		;4 words long,,interrupt handler
	XWD	0,2		;No message control,, 2	^C
	BLOCK	1		;User PC stored	here when interrupted
	BLOCK	1		;Iinterrupt type in LH

	IBLKLN==.-INT		;Length	of interrupt block



;** Pointers to	asciz strings used by the PCONF	routine	to
;   print the device names in the configuration	of a node. They	must
;   be in this order since they	are indexed by their NCL device	types.

CTAB:	POINT 7,[ASCIZ \MCR[\]
	POINT 7,[ASCIZ \TTY[\]
	POINT 7,[ASCIZ \CDR[\]
	POINT 7,[ASCIZ \LPT[\]
	POINT 7,[ASCIZ \PTR[\]
	POINT 7,[ASCIZ \PTP[\]
	POINT 7,[ASCIZ \PLT[\]
	POINT 7,[ASCIZ \MTA[\]
	POINT 7,[ASCIZ \DTA[\]
	POINT 7,[ASCIZ \TSK[\]
	POINT 7,[ASCIZ \RDA[\]
	POINT 7,[ASCIZ \CDP[\]
	POINT 7,[ASCIZ \DDP[\]
	SUBTTL	Scan macro calls and definitions

;** Switch definitions

DEFINE SWTCHS<
	SN	*ANF10,ANF10W,FS.NFS	;Control ANF10 portion of program
	SN	BRIEF,BRIEWD,FS.NFS	;Control listing of devices
	SN	CDP,CDPWD,FS.NFS	;Only nodes with CDP's
	SN	CDR,CDRWD,FS.NFS	;Only nodes with CDR's
	SN	COST,COSTWD,FS.NFS	;List the link cost with /TOPOLOGY
	SN	DDP,DDPWD,FS.NFS	;Only nodes with DDP's
	SN	*DECNET,DECNWD,FS.NFS	;Control DECnet	portion	of program
	SN	DTA,DTAWD,FS.NFS	;Only nodes with DTA's
	SN	ERROR,ERRWD,FS.NFS	;Control listing of errors
	SN	FAST,FASWD,FS.NFS	;For super short list of nodes
	SN	HEADER,HEADWD,FS.NFS	;Control listing of headers
	SN	HOSTES,MCRWD,FS.NFS	;Same as "MCR"
	SN	LAT,LATNWD,FS.NFS	;Control LAT portion of program
	SN	LINKS,LINKWD,FS.NFS	;Listing of DECnet nodes with links
	SN	LPT,LPTWD,FS.NFS	;Only nodes with LPT's
	SN	MCR,MCRWD,FS.NFS	;Only nodes with MCR's (can be a host)
	SN	MTA,MTAWD,FS.NFS	;Only nodes with MTA's
	SN	PLT,PLTWD,FS.NFS	;Only nodes with PLT's
	SN	PTP,PTPWD,FS.NFS	;Only nodes with PTP's
	SN	PTR,PTRWD,FS.NFS	;Only nodes with PTR's
	SN	RDA,RDAWD,FS.NFS	;Only nodes with RDA's
	SN	SILENC,SILWD,FS.NFS	;Control non-error output
	SL	*SORT,SORTWD,SRT,SRT.DF,FS.NFS!FS.NOS	;To sort the node names
	SN	*TOPOLO,TOPWD,FS.NFS	;For the TOPOLOGY listing
	SN	TSK,TSKWD,FS.NFS	;Only nodes with TSK's
	SN	TTY,TTYWD,FS.NFS	;Only nodes with TTY's
	SP	TYPE,TYPWD,.SIXSW##,-1,FS.LRG!FS.NFS!FS.VRQ  ;Node type
	SN	UNREACH,URCHWD,FS.NFS	;List all known	DECnet nodes
	SP	WIDTH,WIDWD,.DECNW##,-1,FS.NFS!FS.LRG	;Output	width
>	;END OF	THE SWTCHS MACRO

	DOSCAN	(TOGLS)		;The DOSCAN macro generates the	tables
				;defined by the	SWTCHS macro

	KEYS	SRT,<NAME,NONE,NUMBER>
	SRT.DF==SRT.L+1
	SRT.NA==SRTNAM
	SRT.NO==SRTNON
	SRT.NU==SRTNUM
	SUBTTL	Scan argument blocks

;** .ISCAN initalization block if logged out

ISBLO:	IOWD	1,ISCANI	;Acceptable CCL	commands table
	XWD	OFFSET,'NWK'	;Starting offset,,Tmp core name
	XWD	0,OUTC		;Default I/O
	XWD	0,0		;Indirect file name (unknown)
	XWD	0,0		;Monitor return,, prompt routine
	EXP	FS.IFI!FS.INC	;Indirect files	illegal	if logged out

;** .ISCAN initalization block if logged in

ISBLK:	IOWD	1,ISCANI	;Acceptable CCL	commands table
	XWD	OFFSET,'NWK'	;Starting offset,,Tmp core name
	XWD	0,OUTC		;Default I/O
	XWD	0,0		;Indirect file name (unknown)
	XWD	0,0		;Monitor return,, prompt routine
	EXP	FS.INC		;Don't allow CORE UUOs from SCAN
ISLEN==.-ISBLK			;.ISCAN	block length

;** Table of CCL names for SCAN

ISCANI:	SIXBIT/NETWOR/		;Default CCL name

;** .OSCAN argument block
;   The	options	file scanner (SWITCH.INI[,])

OSBLK:	IOWD	TOGLSL,TOGLSN	;SWTCHS' table length,,name table
	XWD	TOGLSD,TOGLSM	;Table of defaults,,processor address
	XWD	0,TOGLSP	;Pointers for storing values
	EXP	-1		;Help word, -1 for "HLP:NETWOR.HLP"
	SIXBIT	/NETWOR/	;Options word...our name
OSLEN==.-OSBLK			;Length	of .OSCAN block

TSBLK:	IOWD	TOGLSL,TOGLSN	;SWTCHS' table length,,name table
	XWD	TOGLSD,TOGLSM	;Table of defaults,,processor address
	XWD	0,TOGLSP	;Pointers for storing values
	EXP	-1		;Use our name for help
	XWD	0,0		;Default to clear answers and file specs
	XWD	IALLO,OALLO	;Scan block allocation routines
	XWD	0,0		;Default for sticky defaults
	EXP	FS.MOT!FS.MIO	;Scan control flags
				;1B18=More than	1 input	spec OK
				;1B19=Global switches can be anywhere
	XWD	0,0		;Let Scan store	the values
TSLEN==.-TSBLK			;.TSCAN	block length
;Here on a GETTAB error

GTABER:	PUSHJ	P,.PSH4T##		;Save the temps
	MOVE	T1,['NWKGUE']		;The prefix
	MOVE	T2,["?",,[ASCIZ	\GETTAB	UUO error at PC	\]]
	PUSHJ	P,.ERMSG##		;Print the error message
	HRRZ	T1,-4(P)		;Get the PC
	SUBI	T1,2			;Backup	to the UUO
	PUSHJ	P,.TOCTW##		;Type the address of the error
	PUSHJ	P,.POP4T##		;Restore the temps in case of dump
	JRST	FINISH			;and die


;Here with no network software loaded

NNSERR:	PUSHJ	P,.PSH4T##		;Save the temps
	MOVE	T1,['NWKNNS']		;The prefix
	MOVE	T2,["?",,[ASCIZ	\No networks are available
\]]
	PUSHJ	P,.ERMSG##		;Print the error message
	PUSHJ	P,.POP4T##		;Restore the temps in case of dump
	JRST	FINISH			;and die


NOANF:	MOVE	T1,['NWKNA1']		;The prefix
	MOVE	T2,["?",,[ASCIZ	\No ANF10 software installed\]]
	PUSHJ	P,.ERMSG##		;Print the error message
	PUSHJ	P,.POP4T##		;Restore in case of dump
	JRST	FINISH			;and die


OLDMON:	MOVE	T1,['NWKMTO']		;The prefix
	MOVE	T2,["?",,[ASCIZ	\Monitor too old. Must be 7.00 or later\]]
	PUSHJ	P,.ERMSG##		;Print the error message
	PUSHJ	P,.POP4T##		;Restore in case of dump
	JRST	FINISH			;and die
;Here on a DNET. UUO error
;DNET. errors:

DNERMS:	[ASCIZ	\DNUNE%	Unknown	DNET error\]
	[ASCIZ	\DNADE%	Address	error\]
	[ASCIZ	\DNWNA%	Wrong number of	arguments\]
	[ASCIZ	\DNIDN%	Illegal	job number\]
	[ASCIZ	\DNFNE%	Illegal	function number\]
	[ASCIZ	\DNILF%	Illegal	flag combination\]
	[ASCIZ	\DNNSN%	No such	node name\]
	[ASCIZ	\DNNSC%	No such	channel\]
DNERML=.-DNERMS				;Size of error message table

DNETER:	PUSHJ	P,.PSH4T##		;Save the temps
	MOVE	T1,['NWKDUE']		;The prefix
	MOVE	T2,["?",,[ASCIZ	\DNET. UUO error \]]
	PUSHJ	P,.ERMSG##		;Print the error message
	PUSH	P,T5			;Save the error	code
	CAIG	T5,DNERML		;Is the	error code in range?
	CAIGE	T5,0			;...?
	  SETZ	T5,			;No? make it zero!
	MOVE	T1,DNERMS(T5)		;Get the error string
	PUSHJ	P,.TSTRG##		;and type it
	POP	P,T5			;Restore the error code
	MOVEI	T1,[ASCIZ \ at PC \]	;End of	string
	PUSHJ	P,.TSTRG##		;Type it
	HRRZ	T1,-4(P)		;Get the PC
	SUBI	T1,2			;Backup	to the UUO
	PUSHJ	P,.TOCTW##		;Type the address of the error
	PUSHJ	P,.POP4T##		;Restore the temps in case of dump
	JRST	FINISH			;and die
;Here on a NODE. UUO error
;Error codes

NODERM:	[ASCIZ	\NDUKE%	Undefined error\]
	[ASCIZ	\NDIAL%	Illegal	argument list\]
	[ASCIZ	\NDINN%	Illegal	node name/number\]
	[ASCIZ	\NDPRV%	Caller not privileged\]
	[ASCIZ	\NDNNA%	Node not available\]
	[ASCIZ	\NDNLC%	Job not	locked in core\]
	[ASCIZ	\NDTOE%	Time out error\]
	[ASCIZ	\NDRNZ%	Reserved word non-zero\]
	[ASCIZ	\NDNND%	I/O channel not	open to	or not network device\]
	[ASCIZ	\NDIOE%	I/O Error occurred, LH is getsts info\]
	[ASCIZ	\NDNFC%	No free	core\]
	[ASCIZ	\NDIAJ%	In use by another job\]
	[ASCIZ	\NDNMA%	No message available\]
	[ASCIZ	\NDTNA%	Terminal not available\]
	[ASCIZ	\NDNLT%	Not a legal terminal\]
	[ASCIZ	\NDISF%	Illegal	sub function\]
	[ASCIZ	\NDRBS%	Receive	buffer too small\]
	[ASCIZ	\NDNUG%	No ungreeted nodes\]
NODERL=.-NODERM

NODERR:	PUSHJ	P,.PSH4T##		;Save the temps
	MOVE	T4,[%FTPER]		;Get the feature test word
	GETTAB	T4,			;...
	  PUSHJ	P,GTABER		;GETTAB	error? tell user and die
	TRNN	T4,F%NET&777777		;Do we have network software?
	  JRST	NOANF			;No, tell the user
	MOVE	T4,[%CNVER]		;Is the	monitor	7.00 or	later?
	GETTAB	T4,			;...
	  PUSHJ	P,GTABER		;GETTAB	error? tell user and die
	LSH	T4,-6			;Right justify monitor version
	ANDI	T4,777			;and mask out other stuff
	CAIGE	T4,700			;7.00 or later?
	  JRST OLDMON			;No, tell user and die
	PUSH	P,T1			;Save the error	code
	MOVE	T1,['NWKNUE']		;Yes, the prefix
	MOVE	T2,["?",,[ASCIZ	\NODE UUO error	\]]
	PUSHJ	P,.ERMSG##		;Print the error message
	POP	P,T1			;Restore the error code
	CAIG	T1,NODERL		;Is the	error code in range?
	CAIGE	T1,0			;...?
	  SETZ	T1,			;No? make it zero!
	MOVE	T1,NODERM(T1)		;Get the error string
	PUSHJ	P,.TSTRG##		;and type it
	MOVEI	T1,[ASCIZ \ at PC \]	;End of	string
	PUSHJ	P,.TSTRG##		;Type it
	HRRZ	T1,-4(P)		;Get the PC
	SUBI	T1,2			;Backup	to the UUO
	PUSHJ	P,.TOCTW##		;Type the address of the error
	PUSHJ	P,.POP4T##		;Restore the temps in case of dump
	JRST	FINISH			;and die
;Loop through all the specs looking for	error bits
;in the	SPCFLG vector

ERRSCN:	MOVE	T1,NFECNT		;How many non-fatal errors did we have?
	CAILE	T1,MAXNFE		;Did we	have too many?
	  JRST	NFEERR			;Yes, tell the user and	die
	AOS	NFECNT			;No, count the error
	MOVE	T1,ANF10W		;Get /ANF
	IOR	T1,DECNWD		;And /DECNET
	IOR	T1,LATNWD		;And /LAT
	JUMPE	T1,NONET		;If /NO<everything> then complain
	SKIPN	L1,SPCCNT		;Any Spec's?
	  POPJ	P,			;No, just return
	MOVNS	L1			;Get the count of specs
	HRLZS	L1			;Make a	AOBJN pointer
	SETZ	T4,			;Clear our accumulator
ERRSC1:	MOVE	T1,SPCFLG(L1)		;Get the error mask
	TLNN	T1,SP.DEC!SP.ANF!SP.LAT	;Did we	find this node?
	  JRST	[PUSHJ	P,NONOD			;No, check it out
		 AOS	T4			;Count losers
		 JRST	ERRSC2	]		;Carry on...
	TLNE	T1,SP.DEC		;DECnet	node?
	  AOS	MATCH			;Yes, count the	match
ERRSC2:	AOBJN	L1,ERRSC1		;Loop over all specs
	SKIPE	MATCH			;Any WINNERS?
	  POPJ	P,			;Yes, See if we	printed	it
	SKIPN	T4			;No, Any LOSERS?
	  PUSHJ	P,NOMAT			;Yes, Tell user
	POPJ	P,			;Done, return to the main loop

;** Here when no node can meet the constraints set by the device
;   switches set by the	user
;   Only prints	if no other message has	been typed
;  uses	T1-T4

NOMAT:	MOVE	T1,['NWKNNM']		;The prefix
	MOVE	T2,["%",,[ASCIZ	\No Nodes meet constraints
\]]
	SETZB	T3,T4			;Zero these for	Scan
	PJRST	.ERMSG##		;Print the error message
					;and return
;** Here when the user has both	/NOANF and /NODECNET selected

NONET:	SKIPN	ERRWD			;Do we want to print no-node errors?
	 POPJ	P,			;No, just return
	MOVE	T1,['NWKNNS']		;Get the prefix	characters
	PUSHJ	P,ERMSP			;Go to our error message processor
	  POPJ	P,			;Prefix	only...
	MOVEI	T1,[ASCIZ \No network type selected.\]
	PUSHJ	P,.TSTRG##		;rest of the message
;	MOVEI	T1,[ASCIZ\ ANF10\]	;ANF10 string
;	SKIPE	FTANF			;If we have ANF10
;	  PUSHJ	P,.TSTRG##		;Tell the user
;	MOVEI	T1,[ASCIZ\ and\]	;If we have both ANF10 and DECnet
;	SKIPE	FTANF			;...
;	SKIPN	FTDEC			;...
;	 CAIA				;Wrong sense
;	  PUSHJ	P,.TSTRG##		;Tell the user
;	MOVEI	T1,[ASCIZ\ DECnet\]	;DECnet	string
;	SKIPE	FTDEC			;If we have DECnet
;	  PUSHJ	P,.TSTRG##		;Tell the user
;	MOVEI	T1,"."			;PUNCUATE my mother always told	me!
;	PUSHJ	P,.TCHAR##		;so I did.
	PJRST	.TCRLF			;Finish out line


;** Here when we have to tell the user about a no-match	situation.

NONOD:	SKIPN	ERRWD			;Do we want to print no-node errors?
	 POPJ	P,			;No, just return
	AOS	MATCH			;Printed an error, increment match count
	MOVE	T1,['NWKNNN']		;Get the prefix	characters
	PUSHJ	P,ERMSP			;Go to our error message processor
	  POPJ	P,			;Prefix	only...
	MOVEI	T1,[ASCIZ \Node \]	;If here, print	the
	PUSHJ	P,.TSTRG##		;rest of the message
	MOVE	T1,SPCLST(L1)		;Put the node name into	T1 for Scan
	PUSHJ	P,.TSIXN##		;and print it
	MOVEI	T1,[ASCIZ \ not in Network
\]
	PJRST	.TSTRG##		;and the rest of the message
;** Here to handle too many non-fatal errors
;   this is determined by MAXNFE in NDATA

NFEERR:	MOVE	T1,['NWKTME']		;Too many non-fatal errors
	MOVE	T2,["?",,[ASCIZ	\Too many errors
\]]
	SETZB	T3,T4			;Clear for Scan
	PUSHJ	P,.ERMSG##		;Tell the user the bad news
	JRST	FINISH			;and then just die

;** Here to print standard error message prefixes
;   Modified version of	Scan's .ERMSG routine to allow us to put
;   extra things in the	line like a node spec or illegal parts of a
;   node spec...
;
;   T1	=  The message prefix
;   -1(P) = The	address	of the extra print routine
;   uses T2-4

ERMSP:	PUSH	P,T1		;Save the prefix
	MOVE	T1,NFECNT	;How many non-fatal errors did we have?
	CAILE	T1,MAXNFE	;Did we	have too many?
	  JRST	NFEERR		;Yes, tell the user and	die
	AOS	NFECNT		;No, count the error
	SKIPE	HPOS		;If in middle of a line
	PUSHJ	P,CRLFH		;Then position to start of new line
	MOVEI	T1,"%"		;Get the lead character	(never called if fatal)
	PUSHJ	P,.TCHAR##	;Issue the lead	character
	PUSHJ	P,.VERBO##	;Get /MESSAGE setting
	MOVE	T4,T1		;and copy it to	a safer	place
	POP	P,T1		;Get the prefix	back
	TXNE	T4,JWW.PR	;See if	/VERBOS:PREFIX
	PUSHJ	P,.TSIXN##	;Yes, issue the	prefix
	PUSHJ	P,.TSPAC##	;Space to the text area
	TXNE	T4,JWW.FL	;See if	/MESSAGE:FIRST
	  AOS	(P)		;Yes, Skip return to print the rest
	POPJ	P,		;and return to there
;** Here to tell the user he has entered a bad node spec.
;   This happens when we get a PPN, device, or extension in a node spec
;   We will tell him and then prompt him with a	* as we	change into
;   run	mode by	poking our OFFSET word

SPECER:	PUSHJ	P,.PSH4T##		;Save the temps
	MOVE	T1,['NWKBNS']		;The prefix
	PUSHJ	P,ERMSP			;Process the message
	  JRST	SPECE1			;and exit if prefix only
	MOVEI	T1,[ASCIZ \Bad NODE spec \]
	PUSHJ	P,.TSTRG##		;Type the generic message
	MOVEI	T1,(T3)			;Point to the scan block
	PUSHJ	P,.TFBLK##		;Dump it
SPECE1:	PUSHJ	P,.TCRLF##		;Finish	the error message with a <CRLF>
	PUSHJ	P,.POP4T##		;Restore the temps
	MOVSI	T1,SP.DEC!SP.ANF	;Get spec found	flags
	MOVEM	T1,SPCFLG(T4)		;Say that we found the nodes
	AOS	T4			;Fake out the count
	POPJ	P,			;and fake a return to WILDS
;** Here when a	node has gone offline when we are processing it

OFLINE:	SKIPN	ERRWD			;Print "No Node" errors
	  POPJ	P,			;No, fake loop
	AOS	MATCH			;So we don't get the
					;"No nodes meet	constraints"
	MOVE	T1,['NWKNWD']		;No, The prefix
	PUSHJ	P,ERMSP			;Error message routine
	  JRST	OFLIN3			;and exit to the main loop
OFLIN2:	MOVEI	T1,[ASCIZ \Node	(\]	;text
	PUSHJ	P,.TSTRG##		;Type the string
	MOVE	T1,CN			;Get the node number
	PUSHJ	P,.TOCTW##		;Type it
	MOVEI	T1,")"			;Get a <right paren>
	PUSHJ	P,.TCHAR##		;Type it
	MOVEI	T1,[ASCIZ \ is going on or offline\]	;Strange state msg
	PUSHJ	P,.TSTRG##		;Type the rest of the message
OFLIN3:	PJRST	CRLFH			;fake the end of the main loop
	SUBTTL	Control/C and other interrupt handling!

;Here on a ^C or other interrupt

CONC:	PUSHJ	P,.PSH4T##		;Save the temps
	HLRZ	T1,INTBLK+.ERCCL	;Get the interrupt type
	TRNN	T1,ER.ICC		;Was it	a ^C interrupt?
	  JRST	CONC1			;No, check the next type
	PUSHJ	P,.ISLGI##		;Are we	logged in?
	  JRST	FINISH			;No, exit!
	PUSHJ	P,.POP4T##		;Yes, restore the temps	and make it
	MONRT.				;look like a plain ^C

;Here if the user types a CONTINUE command

	PUSH	P,INTBLK+.EROPC		;Put the return	address	on the stack
	SETZM	INTBLK+.EROPC		;and clear it in the interrupt block
	POPJ	P,			;Finally, return to what we were doing

CONC1:	CAIE	T1,ER.FUL		;is the	disk full
	  JRST	CONC2			;No, check the next possibility
	PUSHJ	P,.PSH4T##		;Save the temps
	MOVE	T1,['NWKNMR']
	MOVE	T2,["?",,[ASCIZ	\No more room on file structure\]]
	SETZB	T3,T4			;Clear T3 and T4
	PUSHJ	P,.ERMSG##		;Print the Message
	PUSHJ	P,.POP4T##		;Restore the temps
	JRST	FINISH			;Exit...(Die)

CONC2:	CAIE	T1,ER.QEX		;Did he	exceed his disk	quota?
	  JRST	CONC3			;No, check the next possibility
	MOVE	T1,['NWKDQE']
	MOVE	T2,["?",,[ASCIZ	\Disk Quota exceeded\]]
	SETZB	T3,T4			;clear T3 and T4
	PUSHJ	P,.ERMSG##		;Print the message
	PUSHJ	P,.POP4T##		;Restore the temps
	JRST	FINISH			;Exit...(die)
CONC3:	CAIE	T1,ER.TLX		;Did he	exceed his time	limit?
	  JRST	CONC4			;No, check the last possibility
	MOVE	T1,['NWKTLE']
	MOVE	T2,["?",,[ASCIZ	\Time Limit exceeded\]]
	SETZB	T3,T4			;Clear T3 and T4
	PUSHJ	P,.ERMSG##		;Print the message
	PUSHJ	P,.POP4T##		;Restore the temps
	MONRT.				;Do a continuable exit

;Here if the	user types a CONTINUE command

	PUSH	P,LASTPC		;Put the return	address	on the stack
	SETZM	LASTPC			;and clear it in the interrupt block
	POPJ	P,			;Finally, return to what we were doing

CONC4:	CAIE	T1,ER.EIJ		;Did he	encounter a fatal error
					;of the	fourth kind?
	  JRST	CONC5			;No, let the user have it
	MOVE	T1,['NWKFER']
	MOVE	T2,["?",,[ASCIZ	\Fatal Error at	PC \]]
	SETZB	T3,T4			;Clear T3 and T4
	PUSHJ	P,.ERMSG##		;Print the message
	HRRZ	T1,LASTPC		;Get the last PC
	SUBI	T1,1			;Backup	to the error PC
	PUSHJ	P,.TOCTW##		;and type the PC
	PUSHJ	P,.POP4T##		;restore the temps
	JRST	FINISH			;Exit to the monitor

CONC5:	PUSHJ	P,.POP4T##		;Restore the temps
	PUSH	P,LASTPC		;Put the last PC on the	stack
	SETZM	LASTPC			;Clear it in the interrupt block
	POPJ	P,			;Return	to the user program
	XLIST				;For a neater listing
	LIT				;Force literals	to be in high segment
	LIST				;

	END	START