Google
 

Trailing-Edge - PDP-10 Archives - BB-KL11L-BM_1990 - t20src/mshost.mac
There are 16 other files named mshost.mac in the archive. Click here to see a list.
;This software is furnished under a license and may only be used
;  or copied in accordance with the terms of such license.
;
;Copyright (C) 1979,1980,1981,1982 by Digital Equipment Corporation
;	       1983,1984,1985,1986    Maynard, Massachusetts, USA


	TITLE MSHOST - Host table module for MS and friends

	SEARCH GLXMAC,MSUNV,MACSYM
	PROLOG (MSHOST)

	CPYRYT
	MSINIT

	GLOBS
	GLOBRS

;Routines defined herein

	INTERNAL HSTINI, NAMINI, VALID8

;Routines defined elsewhere

;MSUTL.MAC
	EXTERNAL ALCSB, COMPAC, COUNTS, MOVST0, MOVST2, RELSB, TBADDS
	EXTERNAL ALCFOB

;Global data items defined herein

	INTERNAL HOSTAB

;Global data items defined elsewhere
;MS.MAC
	EXTERNAL  MYHSPT, MYHDPT

;Local storage

	IMPUR0

      TOPS10<
MYHOST:	BLOCK 1			; Sixbit name of our host
NODNAM:	BLOCK 2			; ASCIZ name of node fetched from HOSTS.TXT
      >;end TOPS10
LHOSTN:	BLOCK 1			; Local host number
CFSINI:	BLOCK 1			; CFS table initialization flag
PMRINI:	BLOCK 1			; PMR table initialization flag
HOSTAB:	BLOCK 1			; Address of the host table
SMLBUF==40			; 199. characters ought to do it.
ATMBF2:	BLOCK SMLBUF		; For parsing DNHOST.TXT

	PURE

;Switches for UPS:DNHOST.TXT

SWTTAB:	SWTTB0,,SWTTB0
	CMD (NOMAIL20,NT%KWL)
SWTTB0==.-SWTTAB-1
 SUBTTL Routines to parse host tables, determine what nets are present, etc.

;Figure out if we're on a network, and what our local host name is
; If we're both a DECNET and an ARPANET host, the ARPANET host name is used
; Also, note whether XMAILR exists

NAMINI:	$SAVE <E>		; [3105]Save an AC
	STKVAR <NODARG,<CFIGBL,10>> ; [3105]Add arg block for CNFIG%
	TXZ F,F%ARPA!F%DECN!F%ANFX ; Assume no XMAILR or nets
TOPS20<	MOVEI A,10		; [3105]Length is 10
	MOVEM A,CFIGBL		; [3105]Initialize the argument block
	MOVX A,.CFINF		; [3105]Get Info
	MOVEI B,CFIGBL		; [3105] from the CNFIG% jsys
	CNFIG%			; [3105]  into CFIGBL
	 ERJMP [JRETER <Can't find network info with CNFIG>
		RET]		; [3105]Assume no network
	MOVE A,.CFISO(B)	; [3105]Get the network bits
	MOVE E,A		; [3105]Store them here
	TXNN E,CF%ARP		; [3105]Do we have arpanet?
	JRST NAMIN2		; [3105]No...
	MOVX A,.GTHSZ		; Try new style JSYS
	GTHST			;  for local host number
	 ERJMP NAMIN2		; No ARPANET, try DECNET
	MOVEM D,LHOSTN		; OK, save local host number
	MOVE C,D		; Find our name
	MOVE B,MYHSPT
	MOVX A,.GTHNS
	GTHST
	 ERJMP [JRETER <Can't find local host name with GTHST>
		JRST NAMIN2]		; Eh?  maybe try old stuff
	TXO F,F%ARPA		; Remember net exists
NAMIN2:	TXNN E,CF%DCN		; [3105]Do we have DECnet?
	RET			; [3105]No, so we're done
	MOVEI A,.NDGLN		; Get DECnet host name
	MOVE B,MYHDPT
	MOVEM B,NODARG		; Setup arg block for NODE jsys
	MOVEI B,NODARG		; Point to it
	NODE			; Get our name
	 ERJMP R		; Return - no network
	TXO F,F%DECN!F%DNNM	; Set flag - we have DECnet, Default node names

; Edit 2370...
; Earlier code stuffed DECnet host name in ARPAnet node name string
; if there's no ARPAnet.  This tends to break things, such as the
; default host name used for local user addresses, so MYHDEC is now
; the default host name always, and ARPAnet mail is the exception.
; This means there's no need to stuff the DECnet host name in MYHNAM
; so...

	RET			;  and return
   >;End TOPS20
   TOPS10<
	MOVEI	A,.GTLOC	; Get location of job 0 (crock)
	GETTAB	A,		;  ..
	  JRST	NOANF		; Failure, assume no net
	SKIPN 	A		;  ..
	  JRST	NOANF		;  ..
	MOVEM A,LHOSTN		; Save local host number
	MOVE C,A		; Copy to good place
	MOVE A,[.NDRNN,,B]	; Function to return node name
	MOVEI B,2		; Length of arg block
	NODE. A,		; Get our node name
	  JRST  NOANF		; Ratz...  assume no net
	MOVEM A,MYHOST		; Save sixbit name for later checking
	MOVE B,A		; Get SIXBIT into better AC
	MOVE C,MYHSPT		; Where to put ASCII name
NAMIN2:	SETZ A,
	LSHC A,6		; Get SIXBIT character in A
	ADDI A,40		; Make ASCII
	IDPB A,C		; Stuff into name
	JUMPN B,NAMIN2		; Do all chars
	IDPB B,C		; Insure ASCIZ
	TXO F,F%ANFX		; Remember presence of ANF10 net
; Now see if there is a DECNET network
	MOVEI	A,B		; point to the DNET. table
	MOVE	B,[DN.FLE+<.DNLNN,,3>]
	DNET.	A,
	  RET			; there must be non DECNET network
	MOVE	B,D		; Get SIXBIT into better AC
	MOVE	C,MYHDPT	; Where to put ASCII name
NAMIN3:	SETZ	A,
	LSHC	A,6		; Get SIXBIT character in C
	ADDI	A,40		; Make ASCII
	IDPB	A,C		; Stuff into name
	JUMPN	B,NAMIN3	; Do all chars
	IDPB	B,C		; Insure ASCIZ
	TXOA	F,F%DECN	; Remember presence of DECNET net
NOANF:	SETZM	MYHNAM		; No networks what-so-ever
	RET			; Home, James
   >;End TOPS10
 SUBTTL HSTINI - init hostname tables
; HSTINI - Initialize host table control variables
;
HSTINI::SETZM HOSTAB		; no host table yet
	SETZM PMRINI		; PMR hasn't been read
	SETZM CFSINI		; We don't know about CFS either
	RET			; All done

;
; VALID8 - Validate the existance of a host name
;
;	- This routine uses HOSTAB as a cache of validated host names
;	  rather than the definitive source of legal hosts.  It first
;	  checks this table to see if the requested host has already been
;	  validated.
;	- Failing this, we ask the O/S for validation, first via DECnet, then
;	  ARPAnet (if TOPS20), then via ANF10 (if TOPS10)
;	- If the host is still unknown, and the PMR table has not been parsed
;	  yet, then it is parsed, and the new hosts added to HOSTAB.  HOSTAB
;	  is checked once more for the requested host name, and if not found
;	  VALID8 returns a failure (+1).
;
;	A/ Pointer to ASCIZ host name string
;
;	Returns:
;		+1 - No such host
;		+2 - Valid host
;
; This table contains the host name validation routines, in the order they
; are tried.  If we haven't already validated this host, VALID8 uses these
; routines to figure out who this host is...
;
V8TABL:
TOPS20<	CALL VALCFS>		; CFS, for TOPS-20 systems only
	CALL VALDNA		; DECnet
TOPS20<	CALL VALARP>		; ARPAnet
TOPS10<;CALL VALANF>		; ANF-10
V8NUM==.-V8TABL  		; This is the table size
;
;
VALID8:	STKVAR	<SVPTR>		;Place to save the host name pointer
	TLC A,-1		; Did we get a -1,,addr?
	TLCN A,-1		; If so, it was a 0, so don't skip
	 HRLI A,(POINT 7,)	; Otherwise make it a pointer
	MOVEM A,SVPTR		; Save pointer to host name
	SKIPE	B,HOSTAB	; Any host table?
	IFNSK.			; No skip => table exists
	 EXCH	A,B		; Put arguments where they're expected
	 $CALL S%TBLK		; Look up the host
	 EXCH A,B		; Put things back where they're expected
	 TXNE A,TL%EXM		; Has this host already been checked?
	  RETSKP		; Yes, this is a valid host
	 MOVE A,SVPTR		; Put the pointer back in A
	ENDIF.			; Here when we have to take the longer route
	MOVSI C,-V8NUM		; Make an AOBJN pointer
VALID9:	XCT V8TABL(C)		; Check out the host
	IFSKP.			; Skip return means this is a valid host
	 CALL NEWHST		; Add this host to HOSTAB
	  RET			; No room for host entry
	 RETSKP			; And return good
	ENDIF.			; Otherwise...
	AOBJN C,VALID9		; Loop through the validation table
	CALL VALPMR		; Check to see if we already loaded PMR table
	 RET			; Yes we did, so the host isn't valid
	RETSKP			; It was a PMR host
SUBTTL Network Host name validation routines
;
; VALANF - TOPS-10 only routine to ask the system if the host name supplied
;		is a valid ANF-10 host
;
;	Called with	A/ Pointer to ASCIZ host name
;
;	Returns
;		+1 - Not an ANF-10 host
;		+2 - Valid host, B/ HOSTAB-style node block
;
TOPS10<
;VALANF:RET>			; For now
;
; VALARP - TOPS-20 only routine to ask the system if the host name supplied
;		is valid
;
;	Called with	A/ Pointer to ASCIZ host name
;
;	Returns
;		+1 - Not an ARPAnet host
;		+2 - Valid host, B/ HOSTAB-style node block
;
TOPS20<
VALARP:	$SAVE <A,C,D>		; Save caller's ac's
	STKVAR <HOSTN,HSTR,HBLK>	; Node number, host string block address
	MOVEM A,HSTR		; save the pointer to the host name here
	MOVE B,A		; Put the pointer in B
	MOVX A,.GTHSN		; Convert name to host number function
	GTHST%			; Ask the ARPAnet
	 ERJMP CHDNS		;[3112] Not a valid name, check DNS
	TXNE D,HS%SRV		;[3112] Is this a server host?
	JRST VALOK		;[3112] Yes.  Life is good
CHDNS:  MOVEI A,.GTHVN		;[3112] No.  Check for DNS MX RR.
	MOVE B,HSTR		;[3112] Get back the pointer
	MOVEI C,.GTHTM		;[3112] MX RR
	MOVEI D,.NULIO		;[3112] Don't need no stinking canonical name
	GTHST%			;[3112] Get the information
	 ERJMP R		;[3112] Not a DNS MX RR either
VALOK:	MOVEM C,HOSTN		;[3112] Save host number for a bit
	CALL ALCNB		; get a node block
	IFNSK.			; No skip means memory exhausted,
	 MOVE A,HSTR		; So release the string block,
	 $TEXT(KBFTOR,<%Memory space exhausted.>)
	 $TEXT(KBFTOR,<%Cannot add ARPAnet host ^T/A/.>)
	 CALL RELSB		; because we can't build a HOSTAB entry
	 RET			; Bad return.
	ENDIF.
	MOVEM A,HBLK		; save the address of the block
	MOVE A,HSTR		; get the string pointer back
	CALL COUNTS		; find out how long it is
	CALL ALCSB		; and get a string block that long
	IFNSK.			; No skip means no memory left
	 $TEXT(KBFTOR,<%Memory space exhausted.>)
	 $TEXT(KBFTOR,<%Cannot add ARPAnet host ^T/A/.>)
	 RET			; No memory, no deal
	ENDIF.			;
	MOVE A,HBLK		; get the node block address
	MOVEM B,N.NAME(A)	; save the address of the string block in it
	MOVE A,B		; put the string block in A
	HRLI A,(POINT 7,)	; make the string block address a pointer
	MOVE B,HSTR		; get the pointer to the actual node name
	CALL MOVST2		; and move the host name into the string block
	MOVX B,NT%ARP		; ARPANET host flag to RH
	CAMN C,LHOSTN		; Is this us?
	TXO B,NT%LCL		; Yes, light local host flag
	MOVE A,HBLK		; get the node block address back
	MOVEM B,N.FLGS(A)	; Set flags in node block
	HRLZ B,N.NAME(A)	; get the address of the name string
	HRR B,A			; Node block address to RH
	RETSKP			; Here means it's a valid name
>				; End TOPS20 conditional
; VALCFS - TOPS-20 only routine to validate the host name supplied with the
;		list of known CFS hosts that are sharing POBOX:.  This routine
;		is called AFTER VALID8 has looked in HOSTAB, so the only thing
;		to do is to check if HOSTAB includes the CFS hosts.  If it does,
;		then obviously the host name isn't a CFS host.  If it doesn't,
;		then we load the CFS host names from SYSTEM:CFS-HOSTS.TXT and
;		look again.
;
TOPS20<
VALCFS:	$SAVE <A,C>			; Save the caller's ac's
	STKVAR	CFSSAV			; place to keep the pointer
	SKIPN CFSINI			; Is CFS table initialized?
	 RET				; Yes, so we already checked it
	MOVEM A,CFSSAV			; Save the host name pointer
	CALL CFSOPN			; No, so open the file
	 RET				; No file, no CFS hosts
	CALL CFSPRS			; Parse the CFS hosts into HOSTAB
	CALL CFSCLS			; Close the CFS file
	MOVE B,CFSSAV			; Put the string pointer in B
	MOVEI A,HOSTAB			; Get the host table address
	CALL S%TBLK			; Look it up
	TXNN B,TL%EXM			; Did we find a match?
	 RET				; nope, not a CFS host
	RETSKP				; yes, it's good

; CFSOPN - Open the CFS host name file (SYSTEM:CFS-HOSTS.TXT)
;
;	Returns:
;
;		+1 - file not found or open error
;		+2 - succeeded, JFN in A
;
CFSOPN:
	RET				; Do this later
; CFSPRS - Parse the CFS host name file
;
;	Returns +1 always
;
CFSPRS:
	RET
; CFSCLS - Close the CFS host name file
;
;	Returns +1 always
;
CFSCLS:
	RET
>					; End of TOPS20 conditional
;
; VALDNA - DECnet routine to validate the supplied host name
;
;	Called with	A/ Pointer to ASCIZ host name
;
;	Returns
;		+1 - Not a DECnet host name
;		+2 - Valid DECnet host name
;			with B/ TBLUK-style node block
;
VALDNA:	$SAVE	<A,C>		; Save the caller's ac's
	STKVAR <VNBLK,VHPTR>	; local storage
	MOVEM A,VHPTR		; Save the pointer to the node name
	CALL NODVFY		; Call O/S-specific DECnet routine
	 RET			; Not a valid node
	CALL ALCNB		; Allocate a node block
	IFNSK.			; If there's no more memory,
	 $TEXT(KBFTOR,<%Memory space exhausted.>)
	 $TEXT(KBFTOR,<%Cannot add DECnet host ^T/A/.>)
	 RET			; And return bad
	ENDIF.			;
	MOVEM A,VNBLK		; Save N-block address
	MOVE A,VHPTR		; Get the pointer to the node name
	CALL COUNTS		; Count the bytes in it
	CALL ALCSB		; Get a string block for it
	IFNSK.			; If we're out of memory now...
	 MOVE A,VNBLK		; Get the N-block address
	 CALL RELNB		; And release it
	 $TEXT(KBFTOR,<%Memory space exhausted.>)
	 $TEXT(KBFTOR,<%Cannot add DECnet host ^T/A/.>)
	 RET			; and return bad
	ENDIF.			;
	MOVE A,VNBLK		; Get the node block address
	MOVEM B,N.NAME(A)	; Stuff string address into N-block
	MOVE A,B		; Set up for MOVST0
	HRLI A,(POINT 7,)	; Byte pointer
	MOVE B,VHPTR		; Get the pointer to the node name
	CALL MOVST2		; Copy to new block
	MOVE B,VNBLK		; Point to N-block
	MOVE A,N.NAME(B)	; Point to name string
	HRLI A,(POINT 7,)	;  ..
	MOVE B,MYHDPT
TOPS20<	STCMP >			; See if this name matches local node name
TOPS10<	$CALL	S%SCMP>		; Ditto
	MOVX B,NT%DCN!NT%NM0	; DECNET node, name in heap space
	SKIPN A			; A = 0 if name matched
	TXO B,NT%LCL		; Match, this is the local node
	MOVE A,VNBLK		; Point to node block again
	MOVEM B,N.FLGS(A)	; Stuff flags into N-block
	HRR B,A			; Set up for TBADDS
	HRL B,N.NAME(B)		; Ptr to name string in LH
	RETSKP			; Return the HOSTAB-style node block address
; NODVFY - Operating System-specific DECnet Node name verification routine
;
;	Called with	A/ Pointer to ASCIZ node name string
;
;	Returns:
;		+1 - Not a valid name
;		+2 - Valid
;
NODVFY:	STKVAR	<<NODBLK,2>>		; Temporary storage
TOPS20<	MOVEI B,NODBLK			; Point to argument block
	MOVEM A,.NDNOD(B)		; Save the pointer to the host name
	MOVX A,.NDVFY			; NODE% JSYS Verify function
	NODE%				; Call TOPS-20
	 ERJMP R			; Shouldn't happen, but just in case
	MOVE B,.NDFLG(B)		; Get the flags returned by NODE%
	TXNN B,ND%EXM			; Was it an exact match?
	 RET				; Nope, no good.
	RETSKP				; Node name is ok.
>; End of TOPS20 conditional
TOPS10<	CALL	ASCSIX			; Turn the node name into SIXBIT
	MOVEM	B,.DNNAM+NODBLK		; And save it for DNET.
	MOVE	A,[DN.FLK+<.DNNDI,,2>]	; Args to ask DNET if this node valid
	MOVEM	A,NODBLK		; Save it away
	MOVEI	A,NODBLK		; Point to block
	DNET.	A,			; Is this a valid DECNET node name?
	  CAIE	A,DNNSN%		; No such node.
	RETSKP				; Node name is ok.
	RET				; Node name is not legit.

;Convert ASCIZ string pointed to by A into SIXBIT in B

ASCSIX:	SETZ B,
	MOVE D,[POINT 6,B]
ASCSX1:	ILDB C,A		; Next byte
	JUMPE C,R		; Stop on null
	CAIGE C,40		; Insure no random ctrl chars
	JRST ASCSX1		; just ignore 'em if present
	CAIL C,140		; Uppercasify
	TRZ C,40		;  ..
	SUBI C,40		; SIXBIT-ify
	IDPB C,D		; Stuff
	TRNN B,77		; Stop at six chars
	JRST ASCSX1		;  ..
R:	RET

>; End of TOPS10 conditional
;
; NEWHST - Add the specified host name to HOSTAB
;
;	Called with	B/ TBLUK-style entry (string-addr,,block-addr)
;
;	Returns +1 always
;		with B/ Address of new HOSTAB slot
;
;	Note: if HOSTAB is full, then the host just doesn't get into the table.
;
NEWHST:	MOVEI A,HOSTAB		; Get the TBLUK header
	CALL TBADDS		; Add it to the table.
	 RET			; No more room
	MOVE B,A		; Put the entry where callers expect it.
	RETSKP			; All set
; VALPMR - Check to see if the PMR tables have been loaded, if not
;		do so and look for the specified host name again.  Otherwise
;		just return +1
;
;	Called with	A/ pointer to ASCIZ host name
;
;	Returns:
;		+1 - invalid host name
;		+2 - Valid host, B/ Pointer into HOSTAB entry
;
VALPMR:	SKIPE PMRINI		; Have we been here already?
	 RET			; Yes, so the host name is invalid
	SETOM PMRINI		; Set the PMR flag
	CALL HSTIND		; Initialize the table
	MOVE B,A		; Put the host name here
	MOVE A,HOSTAB		; and the address of the table
	$CALL S%TBLK		; Look it up
	EXCH A,B		; Put argument where it's expected
	TXNN A,TL%EXM		; Match?
	 RET			; Nope
	RETSKP			; Yes, return good.

;See if DECNET host name table exists, and add hosts to table if so.

TOPS20<
HSTIND:	$SAVE <A,B,C>		; Just in case, save work registers
	TRVAR <FBITS,HSTJFN,HFPGS,HFPGN,HFPTR,HFCNT,HSTR,HDST,SSTR,PATH,PTHFLG>
	MOVX A,GJ%OLD!GJ%SHT	; Look for existing file
	HRROI B,[ASCIZ /UPS:DNHOST.TXT/]
	GTJFN
	 ERJMP R		; No table, just quit
	MOVX B,OF%RD
	OPENF			; open for read
	 JFATAL <Cannot open DECnet host name table>
	MOVEM A,HSTJFN		; Save JFN
	SIZEF			; Get file size
	 JFCL			; Unlikely
	MOVEM C,HFPGS		; Save page count
	MOVE A,C		; Acquire space to map file
	$CALL M%AQNP		;  ..
	MOVEM A,HFPGN		; Save page no. of 1st page
	LSH A,^D9		; Form word address
	HRLI A,(POINT 7,)	; Form byte pointer
	MOVEM A,HFPTR		; save
	HRLZ A,HSTJFN		; Map from file page zero
	HRLI B,.FHSLF		;  to fork page
	HRR B,HFPGN		;  here
	MOVE C,HFPGS		; Page count
	TXO C,PM%RD!PM%PLD!PM%CNT
	PMAP
	MOVE A,HSTJFN		; Get JFN back
	MOVE B,[1,,.FBSIZ]	; Get byte count for file
	MOVEI C,C		; Into C
	GTFDB
	MOVEM C,HFCNT		; Save
	SETZM PATH		; No path block yet
;	JRST HSTID1		; Enter host parse loop
HSTID1:	MOVE A,[POINT 7,ATMBF2]	; Where to build host name string
	MOVEM A,HDST		; Init destination pointer
	SETZM FBITS		; No flag bits known yet
	SETZM SSTR		; No synonyms yet
	SETZM PTHFLG		; Clear the path flag (set when parsing a path)
	SETZM PATH		; Init path-seen flag
HSTID2:	CALL BYTIN		; Get a byte
	 JRST HSTIDE		; Error or EOF - quit
	CAIN B,"/"		; Check for switches
	CALL HSTIDK		; Go handle
	CAIN B,","		; Comma?  (routing info follows)
	JRST [	SETZ B,			; Insure ASCIZ for name string
		IDPB B,HDST		;  ..
		CALL CPYAT2		; Allocate a string block
		 JRST HSTIDM		; Insufficient memory
		MOVEM A,PATH		; Save addr of temp block
		MOVE A,[POINT 7,ATMBF2]	; Reinit atom buffer pointer
		MOVEM A,HDST		;  for collection of path string
		SETOM PTHFLG		; We are now parsing a path
		JRST HSTID2]		; Go eat path string
	CAIE B,";"		; Start of comment?
	CAIN B,"!"		;  ..
	JRST HSTID3		; Yes, go gobble it up

;Here with a valid character which is an element of a hostname
	CAIN B,.CHLFD		; EOL? (Line Feed)
	JRST HSTID5		; Yes, quit this line
	CAIN B,"="		; Start of synonym?
	JRST HSTIDS		; Yes, go handle synonym
	IDPB B,HDST		; Save character
	JRST HSTID2		; Get next

;Here for comment, gobble it up to EOL
HSTID3:	CALL BYTIN		; Eat chars until EOL
	 JRST HSTIDE
	CAIN B,.CHLFD		; EOL?
	JRST HSTID5		; Yes, start interpreting chars again
	JRST HSTID3		; No, eat more comment

;Here on EOL to process this line

HSTID5:	MOVE A,[POINT 7,ATMBF2]	; Get a virgin pointer
	CAME A,HDST		; Was the pointer touched?
	SKIPN PTHFLG		; Were we parsing a path?
	IFNSK.			; No?
	 SKIPE A,PATH		; No, release path block if need be
	 CALL RELSB		;  ..
	 JRST HSTID1		; Don't put null name in table
	ENDIF.
	MOVEI B,0		; Yes, add terminating null
	IDPB B,HDST		;  ..
	SKIPE PATH		; Was a path string seen?
	IFNSK.			; No?
	 CALL CPYAT2		; Yes, copy to a string block
	  JRST HSTIDM		; Memory allocation error
	 MOVE D,PATH		; Get addr of hostname string
	 MOVEM A,PATH		; Save addr of path string
	 MOVE A,[POINT 7,ATMBF2]	; Copy host name string to atom buffer
	 MOVE B,D		; Set up for MOVST0
	 CALL MOVST0		; Do the copy
	 MOVEM A,HDST		; Set up HDST so ASCIZing doesn't lose
	 MOVE A,D		; Get string block address back
	 CALL RELSB		; Release it
	ENDIF.			; Rejoin mail line.
	MOVE A,MYHDPT		; Local host name
	HRROI B,ATMBF2		; This host name
	STCMP			; See if the same
	SKIPN A			; A=0 if name matched
	SKIPA B,[NT%LCL!NT%DCN]	; Local, set flag
	MOVX B,NT%DCN		; Set DECnet flag
	IORB B,FBITS		; Add in any switch-induced bits
	TXNE B,NT%KWL		; Can this host receive 20-style mail?
	JRST HSTID1		; No, just reuse string block
HSTID7:	MOVE A,[POINT 7,ATMBF2]	; Point to this name
	CALL COUNTS		; Count the characters
	ADDI A,5		; Allow space for flag bits
	CALL ALCSB		; Allocate a string block
	 JRST HSTIDM		; Insufficient memory
	MOVEM B,HSTR		; Save address of string block
	MOVX A,CM%FW		; Light bit that says "dere's flags here!"
	IORM A,(B)		;  ..
	MOVEI A,1(B)		; Skip flags word, set up for MOVST0
	HRLI A,(POINT 7,)	;  ..
	MOVEI B,ATMBF2		; Address of name string
	CALL MOVST0		; Copy name string to string block
	CALL ALCNB		; Allocate node block
	 JRST HSTIDM		; Insufficient memory
	MOVE B,FBITS		; Flag bits
	MOVEM B,N.FLGS(A)	;  to node block
	MOVE B,PATH		; Path string
	MOVEM B,N.PATH(A)	;  to node block
	MOVE B,SSTR		; Addr of node block for real name
	MOVEM B,N.REAL(A)	;  to node block
	MOVE B,HSTR		; String address
	MOVEM B,N.NAME(A)	;  to node block
	HRLZS B,B		;  and to LH for TBADD
	HRR B,A			; Node block address to RH
	MOVE D,B		; Preserve over this stuff
	HLR B,B			; Get string address to RH
	MOVE A,(B)		; Get possible flags word
	TLNN A,(177B6)		; Is this a flags word?
	TXNN A,CM%FW		;  ..
	SKIPA
	ADDI B,1		; Yes, skip the flags and point to string
	HRLI B,(POINT 7,)	; Form kosher byte pointer
	SKIPN A,HOSTAB		; See if already have an entry
	JRST HSTID4		; No table, so add the entry
	$CALL S%TBLK		;  ..
	TXNE B,TL%EXM		; Do we have an entry?
	JRST HSTID6		; Yes, go link this to it
HSTID4:	MOVE B,D		; No, restore HOSTAB entry
	MOVEI A,HOSTAB		; Host name table
	CALL TBADDS		; Add to table, maybe expanding table
	 JRST [ $TEXT(KBFTOR,<%Can't add DECnet node ^T/ATMBF2/ to host table>)
		$TEXT(KBFTOR,<%Because: ^E/A/>)
		CAIN A,ERTBF$	; Is host table full?
		 JRST [WARN<Insufficient Memory>
			RET]
		JRST HSTID1]	; Get next node
	JRST HSTID1		; Get next

;Here if we've found an entry for a host already in the table.  Link
; the node block for this entry to the end of the chain of node blocks
; for this name.

HSTID6:	HRRZ C,(A)		; Get pointer to 1st node block
HSTD6A:	SKIPE A,N.NEXT(C)	; Is this the last block in the chain?
	JRST [	MOVE C,A		; No, keep looking
		JRST HSTD6A]		;  ..
	HRRZM D,N.NEXT(C)	; Yes, append this block to the chain
	JRST HSTID1		; Keep parsing
;Parse switch
;Call:	A/ JFN of input file
;Return	+1: always, B/ terminating character, A preserved, C trashed

HSTIDK:	STKVAR <TERM,IJFN,<TSTR,10>>	; Terminating character, JFN, string
	MOVEM A,IJFN		; Save JFN
	MOVEI C,TSTR		; Point to place to stuff switch
	HRLI C,(POINT 7,)
HSTDK0:	CALL BYTIN		; Get a byte
	 JRST HSTDK1		; Let someone else bite it on this one
	CAIG B,172
	CAIGE B,101		; If not alphabetic,
	JRST [	CAIG B,71		; And also not numeric
		CAIGE B,60		;  ..
		JRST HSTDK1		; It terminates this field
		JRST .+2]		; Don't TRZ numbers
	TRZ B,40		; Uppercase
	IDPB B,C		; Stuff into switch
	JRST HSTDK0		; Loop thru all chars
HSTDK1:	MOVEM B,TERM		; Save terminator
	SETZ B,			; Insure ASCIZ
	IDPB B,C
	MOVEI B,TSTR		; Point to switch name
	MOVEI A,SWTTAB		; Switch table
	$CALL S%TBLK		; Get the sucker
	JUMPF [	WARN <Internal error at HSTDK1>
		RET]
	TXNN B,TL%EXM!TL%ABR	; Found this switch?
	RET			; Just ignore unknown switches
	HRRZ A,(A)		; Get bits associated with switch
	IORM A,FBITS		; Save for posterity
	MOVE A,IJFN		; Restore A
	MOVE B,TERM		; Return terminator
	RET			; Return

;Still in TOPS20
;Still in TOPS20

;Here to handle synonym -- insure that what it is a synonym for is in the
; table, add it to table, and point its entry to real thing

HSTIDS:	MOVEI B,0		; Tie off this string
	IDPB B,HDST		;  ..
	CALL CPYAT2		; Copy synonym name to string block
	 JRST HSTIDM		; Insufficient memory
	MOVEM A,SSTR		; Address of synonym string
	MOVE C,[POINT 7,ATMBF2]	; Where to accumulate "real" name

HSTIS0:	CALL BYTIN		; Next byte of real name
	 JRST HSTIDE
	CAIN B,12		; EOL?
	JRST HSTIS1		; Yes...
	IDPB B,C		; No, stuff this char
	JRST HSTIS0		; Keep going
HSTIS1:	MOVEI B,0		; Terminate string
	IDPB B,C		;  ..
	MOVE A,[POINT 7,ATMBF2]	; Point to the real name again
	CALL VALID8		; Call the host validation routine
	IFNSK.			; No such host
	 HRROI A,ATMBF2		;  for error message
	 HRRO B,SSTR
	 WARN (UPS:DNHOST.TXT has bad format)
	 WARN < %2S=%1S, but %1S is not defined>
	 MOVE A,SSTR		; Release synonym string block
	 CALL RELSB
	 CALLRET HSTIDE		; Just quit now
	ENDIF.			;
	HRRZ A,(B)		; Get real N-block address
	EXCH A,SSTR		; Get addr of synonym name, save real N-blk adr
	MOVE D,A		; Safer AC
	MOVE A,[POINT 7,ATMBF2]	; Copy synonym name to string space
	MOVE B,D		; Set up for MOVST0
	CALL MOVST0		; Do the copy
	MOVE A,D		; Release SSTR block
	CALL RELSB		;  ..
	MOVE A,SSTR		; Get addr of real N-block
	MOVE B,N.FLGS(A)	; Get flag bits for real name
	TXZ B,NT%NXL		; Don't propagate no-translate bit
	TXO B,NT%SYN		; Light synonym bit
	IORM B,FBITS
	HRROI A,[ASCIZ /Interoffice-mail/]
	HRROI B,ATMBF2		; Point to current synonym
	STCMP			; Does synonym CONTAIN "Interoffice-mail"?
	TXNE A,SC%SUB		; If so, it should never be translated
	JRST [	MOVX A,NT%NXL		; Yes, light no-translate bit
		IORM A,FBITS		;  ..
		MOVX A,NT%LCL		; Don't propagate "local" bit
		ANDCAM A,FBITS		;  ..
		JRST .+1]
	JRST HSTID7		; Add to host table
;Memory allocation errors all come here

HSTIDM:	WARN <Can't build host table because:  insufficient memory>
;	JRST HSTIDE

;Here on OK finish

HSTIDE:	SETO A,			; Unmap file pages
	HRLI B,.FHSLF		;  from fork
	HRR B,HFPGN		; Starting page
	MOVE C,HFPGS		; page count
	TXO C,PM%CNT
	PMAP
	MOVE A,HFPGS		; Release storage too
	MOVE B,HFPGN
	$CALL M%RLNP
	MOVE A,HSTJFN
	CLOSF			; EOF - close file
	 JFCL
	RET			; Return

;Utility routine to read bytes, ignoring null, LWSP, and CR
;Return	+1: EOF or error, msg already typed if error
;	+2: OK, byte in B, A preserved

BYTIN:	SOSGE HFCNT		; Any bytes left?
	RET			; No, nonskip return
	ILDB B,HFPTR		; Yes, fetch next
	JUMPE B,BYTIN		; Ignore nulls
	CAIE B," "		;  spaces
	CAIN B,.CHCRT		;  and CR
	JRST BYTIN
	CAIE B,.CHFFD		;  and Form feeds
	CAIN B,.CHTAB		;  and tabs
	JRST BYTIN
	RETSKP
>				; End TOPS20 conditional
;CPYAT2 - Count the bytes in the string in the atom buffer, allocate
;	  a chunk for it, and copy the string into the chunk.
;Call:	no arguments
;Return	+1: failure, no room
;	+2: OK, A has address of first word of string in chunk

CPYAT2:	STKVAR <STRAD>
	MOVE A,[POINT 7,ATMBF2]	; Count the bytes
	CALL COUNTS		;  ..
	CALL ALCSB		; Get a chunk
	 RET			; Propagate failure
	MOVEM B,STRAD		; Save string address
	MOVE A,B		; Copy address of string space
	HRLI A,(POINT 7,)	; Form byte pointer
	MOVEI B,ATMBF2		; Copy from atom buffer to chunk
	CALL MOVST0		; With the null
	MOVE A,STRAD		; Return string address to caller
	RETSKP			; Success!
;HSTIND - Here from HSTINI for TOPS10
; to get list of all possible hosts

TOPS10<
HSTIND:

;See if host name table exists, and add hosts to table if so.

	TRVAR <FBITS,HSTJFN,HFPTR,HFCNT,HSTR,HDST,SSTR,PATH,REDIFN>
	MOVEI	A,FDXSIZ	; Size of file descriptor
	$CALL	M%GMEM		; Try to allocate space
	 JUMPF	HSTERR		; No space??
	HRLZM	A,.FDLEN(B)	;
	MOVSI	A,(SIXBIT /INI/) ; Structure name
	MOVEM	A,.FDSTR(B)
	MOVE	A,[SIXBIT /DNHOST/]
	MOVEM	A,.FDNAM(B)
	MOVSI	A,(SIXBIT /TXT/) ; Extension
	MOVEM	A,.FDEXT(B)
	MOVE	A,[XWD 5,34]
	MOVEM	A,.FDPPN(B)
	MOVE	A,B
	CALL	ALCFOB
	 JRST	HSTERR
	MOVX	A,FB.LSN	; Don't try to remove sequence numbers
	ANDCAM	A,FOB.CW(B)	; ALCFOB set this
	SETZM	REDIFN		; No read IFN
	MOVX	A,FOB.MZ	; Fake smaller FOB to bypass protection checks
	$CALL	F%IOPN		; Open
	 JUMPF	HSTERR
	MOVEM	A,REDIFN	; Remember IFN for reading and releasing
	SETZM	HFCNT		; Byte count in file buffer
	SETZM	HFPTR		; Byte pointer
	SETZM	PATH		; No path block yet
;	JRST	HSTID1		; Enter host parse loop
HSTID1:	MOVE A,[POINT 7,ATMBF2]	; Where to build host name string
	MOVEM A,HDST		; Init destination pointer
	SETZM FBITS		; No flag bits known yet
	SETZM SSTR		; No synonyms yet
	SETZM PATH		; Init path-seen flag
HSTID2:	CALL BYTIN		; Get a byte
	 JRST HSTIDE		; Error or EOF - quit
	CAIN B,"/"		; Check for switches
	CALL HSTIDK		; Go handle
	CAIN B,","		; Comma?  (routing info follows)
	JRST [	SETZ B,			; Insure ASCIZ for name string
		IDPB B,HDST		;  ..
		CALL CPYAT2		; Allocate a string block
		 JRST HSTIDM		; Insufficient memory
		MOVEM A,PATH		; Save addr of temp block
		MOVE A,[POINT 7,ATMBF2]	; Reinit atom buffer pointer
		MOVEM A,HDST		;  for collection of path string
		JRST HSTID2]		; Go eat path string
	CAIE B,";"		; Start of comment?
	CAIN B,"!"		;  ..
	JRST HSTID3		; Yes, go gobble it up

;Here with a valid character which is an element of a hostname
	CAIN B,12		; EOL?
	JRST HSTID5		; Yes, quit this line
	CAIN B,"="		; Start of synonym?
	JRST HSTIDS		; Yes, go handle synonym
	IDPB B,HDST		; Save character
	JRST HSTID2		; Get next

;Here for comment, gobble it up to EOL
HSTID3:	CALL BYTIN		; Eat chars until EOL
	 JRST HSTIDE
	CAIN B,12		; EOL?
	JRST HSTID5		; Yes, start interpreting chars again
	JRST HSTID3		; No, eat more comment

;Here on EOL to process this line

HSTID5:	MOVE A,[POINT 7,ATMBF2]	; Get a virgin pointer
	CAMN A,HDST		; Has this pointer been touched?
	JRST [	SKIPE A,PATH		; No, release path block if need be
		CALL RELSB		;  ..
		JRST HSTID2]		; Don't put null name in table
	MOVEI B,0			; Yes, add terminating null
	IDPB B,HDST			;  ..
	SKIPE PATH			; Was a path string seen?
	JRST [	CALL CPYAT2		; Yes, copy to a string block
		 JRST HSTIDM		; Memory allocation error
		MOVE D,PATH		; Get addr of hostname string
		MOVEM A,PATH		; Save addr of path string
		MOVE A,[POINT 7,ATMBF2]	; Copy host name string to atom buffer
		MOVE B,D		; Set up for MOVST0
		CALL MOVST0		; Do the copy
		MOVEM A,HDST		; Set up HDST so ASCIZing doesn't lose
		MOVE A,D		; Get string block address back
		CALL RELSB		; Release it
		JRST .+1]		; Rejoin main flow
	MOVE A,MYHDPT		; Local host name
	HRROI B,ATMBF2		; This host name
	$CALL	S%SCMP		; See if the same
	SKIPN A			; A=0 if name matched
	SKIPA B,[NT%LCL!NT%DCN]	; Local, set flag
	MOVX B,NT%DCN		; Set DECnet flag
	IORB B,FBITS		; Add in any switch-induced bits
	TXNE B,NT%KWL		; Can this host receive 20-style mail?
	JRST HSTID1		; No, just reuse string block
HSTID7:	MOVE A,[POINT 7,ATMBF2]	; Point to this name
	CALL COUNTS		; Count the characters
	ADDI A,5		; Allow space for flag bits
	CALL ALCSB		; Allocate a string block
	 JRST HSTIDM		; Insufficient memory
	MOVEM B,HSTR		; Save address of string block
	MOVX A,CM%FW		; Light bit that says "dere's flags here!"
	IORM A,(B)		;  ..
	MOVEI A,1(B)		; Skip flags word, set up for MOVST0
	HRLI A,(POINT 7,)	;  ..
	MOVEI B,ATMBF2		; Address of name string
	CALL MOVST0		; Copy name string to string block
	CALL ALCNB		; Allocate node block
	 JRST HSTIDM		; Insufficient memory
	MOVE B,FBITS		; Flag bits
	MOVEM B,N.FLGS(A)	;  to node block
	MOVE B,PATH		; Path string
	MOVEM B,N.PATH(A)	;  to node block
	MOVE B,SSTR		; Addr of node block for real name
	MOVEM B,N.REAL(A)	;  to node block
	MOVE B,HSTR		; String address
	MOVEM B,N.NAME(A)	;  to node block
	HRLZS B,B		;  and to LH for TBADD
	HRR B,A			; Node block address to RH
	MOVE D,B		; Preserve over this stuff
	HLR B,B			; Get string address to RH
	MOVE A,(B)		; Get possible flags word
	TLNN A,(177B6)		; Is this a flags word?
	TXNN A,CM%FW		;  ..
	SKIPA
	ADDI B,1		; Yes, skip the flags and point to string
	HRLI B,(POINT 7,)	; Form kosher byte pointer
	SKIPN A,HOSTAB		; See if already have an entry
	JRST HSTID4		; No table, so add the entry
	$CALL S%TBLK		;  ..
	TXNE B,TL%EXM		; Do we have an entry?
	JRST HSTID6		; Yes, go link this to it
HSTID4:	MOVE B,D		; No, restore HOSTAB entry
	MOVEI A,HOSTAB		; Host name table
	CALL TBADDS		; Add to table, maybe expanding table
	 JRST [ $TEXT(KBFTOR,<%Can't add DECnet node ^T/ATMBF2/ to host table>)
		CAIN A,ERTBF$	; Is host table full?
		 JRST [WARN<Insufficient Memory>
			RET]
		JRST HSTID1]	; Get next node
	JRST HSTID1		; Get next

;Here if we've found an entry for a host already in the table.  Link
; the node block for this entry to the end of the chain of node blocks
; for this name.

HSTID6:	HRRZ C,(A)		; Get pointer to 1st node block
HSTD6A:	SKIPE A,N.NEXT(C)	; Is this the last block in the chain?
	JRST [	MOVE C,A		; No, keep looking
		JRST HSTD6A]		;  ..
	HRRZM D,N.NEXT(C)	; Yes, append this block to the chain
	JRST HSTID1		; Keep parsing
;Parse switch
;Call:	A/ JFN of input file
;Return	+1: always, B/ terminating character, A preserved, C trashed

HSTIDK:	STKVAR <TERM,IJFN,<TSTR,10>>	; Terminating character, JFN, string
	MOVEM A,IJFN		; Save JFN
	MOVEI C,TSTR		; Point to place to stuff switch
	HRLI C,(POINT 7,)
HSTDK0:	CALL BYTIN		; Get a byte
	 JRST HSTDK1		; Let someone else bite it on this one
	CAIG B,172
	CAIGE B,101		; If not alphabetic,
	JRST [	CAIG B,71		; And also not numeric
		CAIGE B,60		;  ..
		JRST HSTDK1		; It terminates this field
		JRST .+2]		; Don't TRZ numbers
	TRZ B,40		; Uppercase
	IDPB B,C		; Stuff into switch
	JRST HSTDK0		; Loop thru all chars
HSTDK1:	MOVEM B,TERM		; Save terminator
	SETZ B,			; Insure ASCIZ
	IDPB B,C
	MOVEI B,TSTR		; Point to switch name
	MOVEI A,SWTTAB		; Switch table
	$CALL S%TBLK		; Get the sucker
	JUMPF [	WARN <Internal error at HSTDK1>
		RET]
	TXNN B,TL%EXM!TL%ABR	; Found this switch?
	RET			; Just ignore unknown switches
	HRRZ A,(A)		; Get bits associated with switch
	IORM A,FBITS		; Save for posterity
	MOVE A,IJFN		; Restore A
	MOVE B,TERM		; Return terminator
	RET			; Return

;Still in TOPS10
;Still in TOPS10

;Here to handle synonym -- insure that what it is a synonym for is in the
; table, add it to table, and point its entry to real thing

HSTIDS:	MOVEI B,0		; Tie off this string
	IDPB B,HDST		;  ..
	CALL CPYAT2		; Copy synonym name to string block
	 JRST HSTIDM		; Insufficient memory
	MOVEM A,SSTR		; Address of synonym string
	MOVE C,[POINT 7,ATMBF2]	; Where to accumulate "real" name

HSTIS0:	CALL BYTIN		; Next byte of real name
	 JRST HSTIDE
	CAIN B,12		; EOL?
	JRST HSTIS1		; Yes...
	IDPB B,C		; No, stuff this char
	JRST HSTIS0		; Keep going
HSTIS1:	MOVEI B,0		; Terminate string
	IDPB B,C		;  ..
	MOVE A,HOSTAB		; Point to host name table
	MOVE B,[POINT 7,ATMBF2]	; Look up this entry
	$CALL	S%TBLK		; Better exist
	TXNN B,TL%EXM		; Does it?
	JRST [	HRROI A,ATMBF2		;  for error message
		HRRO B,SSTR
		WARN (SYS:HOSTS.TXT has bad format)
		WARN < %2S=%1S, but %1S is not defined>
		MOVE A,SSTR		; Release synonym string block
		CALL RELSB
		CALLRET HSTIDE]		; Just quit now
	HRRZ A,(A)		; Get real N-block address
	EXCH A,SSTR		; Get addr of synonym name, save real N-blk adr
	MOVE D,A		; Safer AC
	MOVE A,[POINT 7,ATMBF2]	; Copy synonym name to string space
	MOVE B,D		; Set up for MOVST0
	CALL MOVST0		; Do the copy
	MOVE A,D		; Release SSTR block
	CALL RELSB		;  ..
	MOVE A,SSTR		; Get addr of real N-block
	MOVE B,N.FLGS(A)	; Get flag bits for real name
	TXZ B,NT%NXL		; Don't propagate no-translate bit
	TXO B,NT%SYN		; Light synonym bit
	IORM B,FBITS
;	HRROI A,[ASCIZ /Interoffice-mail/]
;	HRROI B,ATMBF2		; Point to current synonym
;	STCMP			; Does synonym CONTAIN "Interoffice-mail"?
;	TXNE A,SC%SUB		; If so, it should never be translated
;	JRST [	MOVX A,NT%NXL		; Yes, light no-translate bit
;		IORM A,FBITS		;  ..
;		MOVX A,NT%LCL		; Don't propagate "local" bit
;		ANDCAM A,FBITS		;  ..
;		JRST .+1]
	JRST HSTID7		; Add to host table
;Memory allocation errors all come here

HSTIDM:	WARN <Can't build host table because:  insufficient memory>
;	JRST HSTIDE

;Here on OK finish

HSTIDE:	MOVE	A,REDIFN	; Get file IFN
	$CALL	F%REL		; Done, close file
	 JFCL
	SETZM	REDIFN
HSTERR:	RET			; Return

;Utility routine to read bytes, ignoring null, LWSP, and CR
;Return	+1: EOF or error, msg already typed if error
;	+2: OK, byte in B, A preserved

BYTIN:	SOSGE HFCNT		; Any bytes left?
	 JRST	RDBUF		; Try for more
	ILDB B,HFPTR		; Yes, fetch next
	JUMPE B,BYTIN		; Ignore nulls
	CAIE B," "		;  spaces
	CAIN B,15		;  and CR
	JRST BYTIN
	CAIN B,11		; Ignore tabs
	JRST BYTIN
	RETSKP

RDBUF:	MOVE	A,REDIFN	; Get the IFN for this file
	$CALL	F%IBUF		; Try to get a buffer
	 JUMPF	RDONE
	MOVEM	A,HFCNT		; Save byte count
	MOVEM	B,HFPTR		;  and pointer
	JRST	BYTIN
RDONE:	RET
 repeat 0,<
NODUUO:	STKVAR <NBLK,SBLK,NPAG>	; Node block addr, Node name string block
				; And NODE. UUO block address
	$CALL	M%GPAG		; Get a free page
	MOVEM	A,NPAG		; Save address for later
	MOVE	E,A		; Copy block address
	HRLI	E,.NDLND	; Insert NODE. function to list nodes
	MOVEI	B,1000		; Length of block
	MOVEM	B,(A)		; Set for UUO
	NODE.	E,		; Return list of reachable nodes
	 JRST	NODUUX		; There are no ANF-10 nodes
	MOVNS	E		; Get negative node count
	MOVSS	E		; Form into left half for AOBJN
	HRRI	E,1(A)		; Point to first node in list
NODUU0:	MOVE	C,(E)		; Get next node number to convert
	MOVEI	B,2		; Number of words in block
	MOVE	A,[.NDRNN,,B]	; Set up for node uuo
	NODE.	A,		; Convert node number to name
	 JRST	NODUU3		; Node went off-line
	MOVE	B,A		; Get SIXBIT into better AC
	MOVE	C,[POINT 7,NODNAM]; Where to put ASCII name
NODUU1:	SETZ A,
	LSHC A,6		; Get SIXBIT character in A
	ADDI A,40		; Make ASCII
	IDPB A,C		; Stuff into name
	JUMPN B,NODUU1		; Do all chars
	IDPB B,C		; Insure ASCIZ
	MOVE	A,[POINT 7,NODNAM]
	CALL	COUNTS		; Count the bytes in it
	ADDI	A,5		; Account for flag word
	CALL	ALCSB		; Get a string block for it
	 JRST [	WARN <Can't get string block for local node names>
		JRST NODUUM]
	MOVEM	B,SBLK		; Save address of string block
	MOVX	A,CM%FW		; There are flags in first word of block
	IORM	A,(B)		;
	MOVEI	A,1(B)		; Set up for MOVST2
	HRLI	A,(POINT 7,)	; Byte pointer
	MOVE	B,[POINT 7,NODNAM] ; Pointer to name
	CALL	MOVST2		; Copy to new block
	CALL	ALCNB
	 JRST	[ WARN <Can't get node block for local nodes>
		  JRST NODUUM]
	MOVEM	A,NBLK		; Save address of node block
	MOVE	A,[POINT 7,NODNAM] ; Name of node we are processing
	MOVE	B,MYHSPT	; Name of our host
	$CALL	S%SCMP		; See if this name matches local node name
	MOVX B,NT%DCN!NT%NM0	; DECNET node, name in heap space
	SKIPN A			; A = 0 if name matched
	TXO B,NT%LCL		; Match, this is the local node
	MOVE A,NBLK		; Point to node block
	MOVEM	B,N.FLGS(A)	; Stuff flags into N-block
	MOVE	B,SBLK		; Get string block address
	MOVEM	B,N.NAME(A)	;  and save pointer in node block
	HRLZS	B,B		; Set up for TBADDS with LH=string pointer
	HRR	B,A		;  and right half in node block pointer
	MOVEI A,HOSTAB		; Addr of ptr to host table
	CALL TBADDS		; Load 'em on up!
	 JRST [$TEXT(KBFTOR,<%Can't add ANF node ^T/NODNAM/ to host table.>)
		CAIN A,EREIT$	; Is node already in table?
		JRST NODUU3	; Try the next node
		JRST NODUUM]	; No more room
NODUU3:	AOBJN E,NODUU0		; Loop through all blocks we got
	JRST	NODUUX		; Finish up

NODUUM:	WARN <Insufficient memory>
NODUUX:	MOVE	A,NPAG		; Get node block address back again
	$CALL	M%RPAG		; Return the page to the free pool
	RET

   >;End TOPS10
>; end repeat 0

;ALCNB - Allocate a node block
;Call:	no arguments
;Return	+1: failure, no memory
;	+2: success, A/ address of Node Block (N.SIZE inited)

ALCNB:	MOVEI A,N.LEN		; Length of a node block
	$CALL M%GMEM		; Get a chunk
	JUMPF R			; Error, nonskip return
	MOVEM A,N.SIZE(B)	;
	MOVE A,B		; Return addr of block in A for caller
	RETSKP			; Good return

;RELNB - Release a node block
;Call:	A/ address of node block
;Return	+1: always

RELNB:	MOVE B,A		; Set up for M%RMEM
	MOVEI A,N.LEN		; Length of a node block
	$CALL M%RMEM
	RET

	END

; Edit 2462 to MSHOST.MAC by PRATT on 1-Nov-85
; Merge many changes in -10, -20, and common code.
; *** Edit 2479 to MSHOST.MAC by PRATT on 20-Nov-85
; Fix off by one bug in VALID8 that kept Arpa mail from working


; *** Edit 2484 to MSHOST.MAC by SANTEE on 21-Nov-85
; Clean up the various edit histories.
; *** Edit 2485 to MSHOST.MAC by MAYO on 21-Nov-85
;
; *** Edit 2486 to MSHOST.MAC by PRATT on 22-Nov-85
; Copyright statements

; *** Edit 2651 to MSHOST.MAC by SANTEE on 2-Feb-86
; Eliminate the need for MSUTAB at all. Move the few useful lines elsewhere. 
; *** Edit 2700 to MSHOST.MAC by RASPUZZI on 20-May-86
; Change MS to look for UPS:DNHOST.TXT instead of SYSTEM:DECNET-HOSTS.TXT 
; Edit= 3105 to MSHOST.MAC on 17-May-88 by WADDINGTON, for SPR #21402
;Use the CNFIG% JSYS instead of relying on the NODE% jsys failure to determine
;if DECnet exists.
; Edit= 3112 to MSHOST.MAC on 9-Mar-90 by WADDINGTON
;Add support for new .GTHVN GTHST% function.