perm filename HOSTS1.MID[HST,NET] blob sn#696034 filedate 1983-01-14 generic text, type T, neo UTF8
;-*-MIDAS-*-
TITLE HOSTS1

IFNDEF SAILSW,SAILSW==IFE <.OSMIDAS-SIXBIT/SAIL/>,[-1] .ELSE 0

;This program .INSRTs the file SYSENG;HOSTS > describing all the network hosts
;and produces a compiled file SYSBIN;HOSTS1 > which network programs read in.
;At SAIL the files are HOSTS.TXT[S,NET] and HOSTS1.BIN[S,NET].

;The format of the compiled HOSTS1 file is:
HSTSID==0	; wd 0	SIXBIT /HOSTS1/
HSTFN1==1	; wd 1	SIXBIT /HOSTS/
HSTVRS==2	; wd 2	FN2 of HOSTS file which this was compiled from.
		;	SIXBIT /SAIL/ if generated at SAIL
HSTWHO==3	; wd 3	UNAME of person who compiled this
HSTDAT==4	; wd 4	Date of compilation as sixbit YYMMDD
HSTTIM==5	; wd 5	Time of compilation as sixbit HHMMSS
NAMPTR==6	; wd 6	Address in file of NAME table.
NUMPTR==7	; wd 7	Address in file of NUMBER table.
		;....

;NUMBERS table:
; wd 0	Number of entries in this table.
; wd 1	Number of words per entry (currently 3).
; followed by entries, in order by host number.
; Each entry looks like this:
NUMNUM==0	;   entry wd 0	host number
NUMSYS==1	;   entry wd 1	lh  ptr to system name (ITS, TIP, TENEX, etc.)
		;			May be 0 => not known.
NUMNAM==1	;   entry wd 1  rh  ptr to official name of host.
NUMBTS==2	;   entry wd 2  lh  flags:
NUMSRV==400000	;	4.9 1 => server site.
NUMMCH==2	;   entry wd 2  rh  ptr to machine name (PDP10, etc).
		;			May be 0 => not known.
NUMLEN==3
;....

;NAMES table:
; wd 0	Number of entries
; followed by one word entries, sorted by the host name treated as a vector of
; signed integers, looking like:
		; lh		address in file of NUMBERS table entry for this host.
NAMNAM==0	; rh		ptr to host name
NAMLEN==1	;length of entry.

; Host, system and machine names are ASCIZ strings, all letters upper case.
; The strings are stored before, after and between the NAME and NUMBER tables.
;HSTNAM HSTNUM HSTSRV HSTSYS HSTMCH HSTNIC HSTLEN F A B C D E G H I J K M N R S P TYOC CALL RET SAVE REST

;The source file of the table is SYSENG;HOSTS > (at SAIL, HOSTS.TXT[S,NET]).
;Each host is described by a line which looks like
; HOST	<official name>,<addresses>,<status>,<system>,<machine>,[<nickname list>]
;<addresses> can be a single <address> or a bracketed list of <address>s
;separated by commas.  An <address> can be an octal number, or the name of
;a network (CHAOS, ARPA) followed by a space and a number.  Arpanet addresses
;can also be written as host slash imp, which of course is backwards but
;seems to be what BBN is foolishly standardizing on.  This program ignores
;addresses for other than the Arpanet.

;We assemble that into a string of entries, of this form:

HSTNAM==0	; wd 0	-> asciz host name
HSTNUM==1	; wd 1	host number
HSTSRV==2	; wd 2  nonzero iff server host
HSTSYS==3	; wd 3	-> asciz system name ("TIP" is a system name).
		;	    (may be 0).
HSTMCH==4	; wd 4  -> asciz machine name (may be 0).
HSTNIC==5	; wd 5	-> nickname list, LISP-style.  LH of each word, starting
		;	   with this one itself, -> ASCIZ, RH is next.  All zero
		;	   word rather than zero RH terminates list
HSTLEN==6	;6 words per host entry.

;AC Defs

F==0
A=1
B=2
C=3
D=4
E=5
G=6
H=7
I=10
J=11
K=12
M=13
N=14
R=15
S=16
P=17

TYOC==17  ;in case error messages

CALL=PUSHJ P,
RET=POPJ P,
SAVE=PUSH P,
REST=POP P,
;INCH OUTUUO LPDL PDL PATCH

IFE SAILSW,[
LOC 100		;absolute assembly

;To make a new version of the HOSTS1 table, :XFILE AI:SYSENG;HOSTS1 XFILE
;which will run this program with latest host table and
;dump out a new version of the HOSTS1 file.

	;1st arg name of system call,
	;2nd like a literal has args to call.
DEFINE SYSCAL A,B
	.CALL [SETZ ? SIXBIT/A/ ? B ((SETZ))]
TERMIN

INCH==1	;Input channel

];IFE SAILSW

IFN SAILSW,[

;To make a new version of the HOSTS1 table, BATCH/NOW @HOSTS1
;which will run this program with latest host table and
;dump out a new version of the HOSTS1 file.

DEFINE .VALUE
 JRST 4,.-1
TERMIN

IF1,[		;name conflict with WAITS
OUTUUO=OUT
EXPUNGE OUT
];IF1

];IFN SAILSW

LPDL==40
PDL:	BLOCK LPDL+10
PATCH: PAT: BLOCK 40
;DUMP

;Write out the compiled file.

DUMP:	MOVE P,[-LPDL,,PDL-1]
IFE SAILSW,[
	.OPEN TYOC,[.UAO,,'TTY]
	 .LOSE %LSFIL
	.CORE <CORTOP+1777>/2000
	 .LOSE
	.SUSET [.RUNAME,,UNAME]
	.RDATE A,		;Init the auditing info at the front
	MOVEM A,$DATE		;Name conflict with WAITS
	.RTIME A,
	MOVEM A,TIME
];IFE SAILSW
IFN SAILSW,[
	MOVEI A,CORTOP
	MOVEM A,JOBFF
	CORE A,
	 .VALUE
	SETZM OUTEND
	MOVE A,[OUTEND,,OUTEND+1]
	BLT A,CORTOP-1
	GETPPN A,
	 CAI			;Fastest no-op in the West!
	HRLZM A,UNAME
	DATE B,
	IDIVI B,12.*31.
	ADDI B,64.
	IDIVI C,31.
	ADDI C,1
	ADDI D,1
	PUSH P,C
	IDIVI B,10.
	MOVEI A,'0(B)
	LSH A,6
	ADDI A,'0(C)
	POP P,B
	IDIVI B,10.
	LSH A,6
	ADDI A,'0(B)
	LSH A,6
	ADDI A,'0(C)
	IDIVI D,10.
	LSH A,6
	ADDI A,'0(D)
	LSH A,6
	ADDI A,'0(E)
	MOVEM A,$DATE
	MSTIME B,
	IDIVI B,1000.
	IDIVI B,60.*60.
	IDIVI C,60.
	PUSH P,C
	IDIVI B,10.
	MOVEI A,'0(B)
	LSH A,6
	ADDI A,'0(C)
	POP P,B
	IDIVI B,10.
	LSH A,6
	ADDI A,'0(B)
	LSH A,6
	ADDI A,'0(C)
	IDIVI D,10.
	LSH A,6
	ADDI A,'0(D)
	LSH A,6
	ADDI A,'0(E)
	MOVEM A,TIME
];IFN SAILSW
	CALL RHOSTF	;Read in the HOSTS file
;	JRST UPPER	;Drops through to next page
;UPPER UPPER1 UPPER2 UPPER3 UPPERS UPPER4

;Now convert all system, machine and host names to upper case.
;This is so that user programs can search and compare more easily.
;Also, it makes sure that CANON really maps all instances of a system
;or machine name into the same name.

UPPER:	MOVEI A,HSTTAB
UPPER1:	MOVE B,HSTSYS(A)
	CALL UPPERS
	MOVE B,HSTMCH(A)
	CALL UPPERS
	MOVE B,HSTNAM(A)
	CALL UPPERS
	MOVE C,HSTNIC(A)	;Get nickname list
	JUMPE C,UPPER3		;empty
UPPER2:	HLRZ B,C		;CAR
	CALL UPPERS		;and convert each nickname in it.
	SKIPE C,(C)		;CDR
	 JRST UPPER2
UPPER3:	ADDI A,HSTLEN		;Advance to next host.
	CAME A,HSTTBE
	 JRST UPPER1
	JRST CANON

;Convert the the ASCIZ string that B points to to upper case,
;modifying it in place.  Clobbers B and E.

UPPERS:	HRLI B,440700
UPPER4:	ILDB E,B
	JUMPE E,CPOPJ
	CAIL E,"a
	 CAILE E,"z
	  JRST UPPER4
	SUBI E,"a-"A
	DPB E,B
	JRST UPPER4
;CANON CNTLP CNTLP1 CNTLP2

;Now store the System name strings into the file, storing each
;distinct name only once.  We replace each System name pointer
;with a pointer (in our address space) to the string stored
;into the file (the "interned" string) so we don't have to search
;the file when we write the NAMES table.
;Also, G counts how many words of space will be needed for all
;the host names and nicknames.

CANON:	MOVEI A,SYSNMS		;A is storing pointer for new system names.
	MOVEI B,HSTTAB		;B points at data of next host to hack.
	SETZB G,H
CNTLP:	SKIPE C,HSTSYS(B)	;Store the system name if necessary.
	 CALL CONSNM
	SKIPE HSTSYS(B)
	 MOVEM J,HSTSYS(B)	;replace system name string with interned one.
	SKIPE C,HSTMCH(B)
	 CALL CONSNM		;Do the same thing with the machine name.
	SKIPE HSTMCH(B)
	 MOVEM J,HSTMCH(B)
	MOVE C,HSTNAM(B)
	CALL COUNT		;Count space official name will take,
	MOVE D,HSTNIC(B)	;and space the nicknames will take.
	AOS H			;H counts number of names and nicknames.
	JUMPE D,CNTLP2
CNTLP1:	HLRZ C,D		;CAR
	CALL COUNT
	AOS H			;H counts number of names and nicknames.
	SKIPE D,(D)		;CDR
	 JRST CNTLP1
CNTLP2:	ADDI B,HSTLEN
	CAMGE B,HSTTBE
	 JRST CNTLP
	ADD G,OUTPT		;Leave space after system names for them
	MOVEM G,NUMP		;to find where NUMBERS table should start.
	MOVE M,NHOSTS
	MOVEM M,(G)		;Store number of entries in NUMBERS table.
	MOVEI A,NUMLEN
	MOVEM A,1(G)		;Store number of words per entry.
	IMUL M,A		;Compute total length
	ADDI M,2(G)		;and thus the position of NAMES table.
	MOVEM M,NAMEP
	MOVEM M,NAMP
	MOVEM H,@NAMEP		;Store size of NAMES table (= # of hosts + nicknames)
	AOS NAMEP		;in its 1st word, and advance storing pointer.
	SUBI G,OUT
	MOVEM G,NUMPR
	SUBI M,OUT
	MOVEM M,NAMPR
	JRST MACH		;Go figure out machine names if possible.
;COUNT CONSNM CONSLP CONSCM CONSNX CONSLS

;C -> an ASCIZ string.  Add to G the number of words it occupies.
;Clobbers E.

COUNT:	MOVE E,(C)
	AOS G
	TRNN E,376
	 RET
	AOJA C,COUNT

;C -> an ASCIZ string;  intern it in the system names table.
;If the table has no string EQUAL to the arg, make a new one at the end.
;In either case, return in J the address of the interned string.
;A -> the beginning of the system names table, and OUTPT -> the end.
;Clobbers D, E, and K.

CONSNM:	MOVE E,A		;E looks at all strings in table, 1 by 1.
CONSLP:	MOVE J,E
	CAMN E,OUTPT		;Reached start of next string in table
	 JRST CONSLS		; but maybe it's the end of table.
	MOVE K,C
CONSCM:	MOVE D,(K)
	CAME D,(E)		;Compare table string agains our arg word
	 JRST CONSNX		;by word.  No match => skip to next string
	TRNN D,376		;in table.  Match until end of ASCIZ =>
	 RET			;we found the arg in the table.
	AOS E			;else compare next words of the two strings.
	AOJA K,CONSCM
	
CONSNX:	MOVE K,(E)		;Advance to start of next ASCIZ string in table
	TRNN K,376
	 AOJA E,CONSLP		;then compare it against our arg.
	AOJA E,CONSNX

CONSLS:	MOVE D,(C)		;String not found in table, so copy it
	MOVEM D,@OUTPT		;to the end of the table.
	AOS OUTPT
	TRNE D,376
	 AOJA C,CONSLS
	RET
;MACH MACHL MACHNX

;Now figure out the type of machine from the system name, if possible,
;in case HOSTS currently has no info on machine type.

MACH:	MOVEI A,HSTTAB
MACHL:	MOVE B,HSTSYS(A)
	SKIPE C,HSTMCH(A)	;If machine type not already known,
	 JRST MACHNX		;try to determine it from system name.
	CAIE B,ITS
	 CAIN B,TENEX
	  MOVEI C,PDP10
	CAIE B,TOPS10
	 CAIN B,TOPS20
	  MOVEI C,PDP10
	CAIE B,SAIL
	 CAIN B,TEN50
	  MOVEI C,PDP10
	CAIE B,BOTS10
	 CAIN B,TWENEX
	  MOVEI C,PDP10
	CAIN B,TIP
	 MOVEI C,TIP
	CAIN B,MULTIC
	 MOVEI C,MULTIC
	CAIE B,HYDRA
	 CAIN B,RSX11
	  MOVEI C,PDP11
	CAIE B,ELF
	 CAIN B,UNIX
	  MOVEI C,PDP11
	MOVEM C,HSTMCH(A)
MACHNX:	ADDI A,HSTLEN
	CAME A,HSTTBE
	 JRST MACHL
;	JRST MT			;After this, build the NAMES table.
;MT MTLP NAMCPY MTE1

;Now build the contents of the NUMBERS table, exact but not sorted.

MT:	MOVEI B,HSTTAB		;B points at data of next host to hack.
	MOVE A,NUMP
	ADDI A,2		;A is pointer for storing NUMBERS table entries.
MTLP:	MOVE C,HSTNAM(B)
	MOVE E,HSTNUM(B)
	MOVEM E,NUMNUM(A)	;Store the host number.
	SKIPE E,HSTSYS(B)
	 SUBI E,OUT		;Store ptr to system name (in file addr space).
	HRLZM E,NUMSYS(A)
	SKIPE E,HSTMCH(B)
	 SUBI E,OUT
	MOVEM E,NUMMCH(A)	;and the machine name.
	MOVSI E,NUMSRV
	SKIPE HSTSRV(B)		;If a server host, set the flag for that.
	 IORM E,NUMBTS(A)
	CALL NAMCPY		;Copy the host name to where OUTPT points,
	HRRM E,NUMNAM(A)	;and store a pointer to the copy.
	ADDI A,NUMLEN		;Advance A to store next entry next time.
	ADDI B,HSTLEN
	CAMGE B,HSTTBE
	 JRST MTLP
	CAME A,NAMP		;Check that NUMBERS occupies expected
	 .VALUE			;amount of space.
	SUB A,NUMP
	SUBI A,2
	MOVE B,@NUMP		;Check that right number of NUMBERS
	IMULI B,NUMLEN		;entries were made.
	CAME A,B
	 .VALUE
	JRST SNT

;Copy ASCIZ string <- C to where OUTPT points, advancing OUTPT.
;Return in E the address of the copy, in file address space.

NAMCPY:	MOVE E,OUTPT
	SUBI E,OUT
	SAVE E
MTE1:	MOVE E,(C)
	MOVEM E,@OUTPT
	AOS OUTPT
	TRNE E,376
	 AOJA C,MTE1
	REST E
	RET
;SNT SNTL SNTWN

;Now sort the NUMBERS table by numbers.

SNT:	SETZ B,			;Another pass, no exchanges yet.
	MOVE A,NUMP
	ADDI A,2
SNTL:	MOVE C,NUMNUM(A)
	CAMN C,NUMNUM+NUMLEN(A)	;Check for duplicate host number
	 JRST [	MOVEI A,[ASCIZ/Duplicate host number: /]
		PUSHJ P,ASZOUT
		MOVE A,C
		PUSHJ P,DECOUT
		MOVEI A,[ASCIZ/ (decimal)/]
		PUSHJ P,ASZOUT
		.VALUE ]
	CAMG C,NUMNUM+NUMLEN(A)	;Skip if this entry and next are mis-ordered.
	 JRST SNTWN		;No skip => this one's is less.
	SETO B,			;Wrong order => interchange.
REPEAT 3,[
	MOVE C,.RPCNT(A)
	EXCH C,.RPCNT+NUMLEN(A)
	MOVEM C,.RPCNT(A)
]
SNTWN:	ADDI A,NUMLEN		;Keep exchanging if nec thru all of NUMBERS.
	MOVEI C,NUMLEN(A)
	CAME C,NAMP
	 JRST SNTL
	JUMPN B,SNT		;If not finished exchanging, need another pass.
	JRST MNAM		;Now NUMBERS is finished, so make NAMES.
;MNAM MNAML MNAML1 MNAMF MNAMN MNAMX

;Now that the NUMBERS table is finished, we can make the NAMES
;table, which has pointers into the NUMBERS table.

MNAM:	MOVE A,NUMP		;A scans through the NUMBERS table.
	ADDI A,2
	MOVE B,@NUMP
MNAML:	MOVEI C,HSTTAB		;Make the NAMES table entries for the next host.
	MOVE D,NUMNUM(A)
MNAML1:	CAMN D,HSTNUM(C)	;Find the HSTTAB entry for this host, since it
	 JRST MNAMF		;has the nicknames in it.
	ADDI C,HSTLEN
	CAME C,HSTTBE
	 JRST MNAML1
	.VALUE			;It's in NUMBERS table but not in original input

MNAMF:
IFE SAILSW,HRLZI E,-OUT(A)	;Make the official name's entry.  Get NUMBERS entry addr in lh.
IFN SAILSW,[
	MOVEI D,(A)		;This allows reloation so can debug with RAID
	SUBI D,OUT
	HRLZI E,(D)
];IFN SAILSW
	HRR E,NUMNAM(A)		;Put ptr to host name in rh (copy from NUMBERS entry).
	MOVEM E,@NAMEP
	AOS NAMEP
	MOVE D,HSTNIC(C)	;D points to list of nickname pointers.
	JUMPE D,MNAMX
MNAMN:	HLRZ C,D		;C gets the next nickname. (CAR)
	CALL NAMCPY		;Copy the nickname into file, E gets addr of copy.
IFE SAILSW,[
	HRLI E,-OUT(A)		; Get NUMBERS entry addr in lh.
];IFE SAILSW
	MOVEM E,@NAMEP
IFN SAILSW,[
	MOVEI E,(A)		;This allows relocation so can debug with RAID
	SUBI E,OUT
	HRLM E,@NAMEP
];IFN SAILSW
	AOS NAMEP
	SKIPE D,(D)		;CDR
	 JRST MNAMN
MNAMX:	ADDI A,NUMLEN		;Finished making NAMES entry for this host.  Hack the next.
	SOJG B,MNAML
	MOVE B,NAMEP		;Check that expected number of NAMES
	SUB B,NAMP		;entries were made.
	SUBI B,1
	CAME B,@NAMP
	 .VALUE
	MOVE B,OUTPT		;Check that host names exactly filled
	CAME B,NUMP		;the space allotted.
	 .VALUE
	JRST SNAM		;Now go sort this table.
;SNAM SNAML SNAMWN COMPAR CMPRLP CMPRBF ASZOUT ASZOU1 POPJ1 CPOPJ

;Sort the NAMES table.

SNAM:	SETZ B,			;No exchanges yet this pass.
	MOVE A,NAMP		;A is pointer for scanning through.
	ADDI A,1
	MOVE G,NAMEP		;G -> next to the last NAMES entry.
	SUBI G,2
SNAML:	HRRZ C,NAMNAM(A)	;Get this entry's name and next entry's.
	HRRZ D,NAMNAM+NAMLEN(A)
	ADDI C,OUT		;Convert file's address space to ours.
	ADDI D,OUT
	CALL COMPAR		;Skip if these two entries mis-ordered.
	 JRST SNAMWN
	SETO B,
	MOVE E,(A)
	EXCH E,NAMLEN(A)
	MOVEM E,(A)
SNAMWN:	CAME A,G		;Each pass scan whole table.
	 AOJA A,SNAML		;If we exchanged, we need another pass.
	JUMPN B,SNAM
	JRST WRITE

;Compare two ASCIZ strings alphabetically.
;C -> first string, D -> second.  Skip if first is greater.
;If the strings are EQUAL, we barf.

COMPAR:	MOVEM C,COMPR1'
	MOVEM D,COMPR2'
CMPRLP:	MOVE E,(D)		;Better make this comparison unsigned...
	LSH E,-1
	MOVEM E,COMPR3'
	MOVE E,(C)	  
	LSH E,-1
	CAMGE E,COMPR3
	 RET
	CAMLE E,COMPR3
	 JRST POPJ1
	TRNN E,177		;Two host names are EQUAL???
	 JRST CMPRBF
	AOS C
	AOJA D,CMPRLP

CMPRBF:	MOVEI A,[ASCIZ/Two equal host names? /]
	PUSHJ P,ASZOUT
	MOVE A,COMPR1
	PUSHJ P,ASZOUT
	MOVEI A,[ASCIZ/ and /]
	PUSHJ P,ASZOUT
	MOVE A,COMPR2
	PUSHJ P,ASZOUT
	MOVEI A,[ASCIZ/
/]
	PUSHJ P,ASZOUT
	.VALUE

ASZOUT:
IFN SAILSW,[
	OUTSTR (A)
	POPJ P,
];SAILSW
IFE SAILSW,[
	HRLI A,440700
ASZOU1:	ILDB B,A
	JUMPE B,CPOPJ
	.IOT TYOC,B
	JRST ASZOU1
];SAILSW

POPJ1:	AOS (P)
CPOPJ:	RET
;WRITE DMPDEV DMPFN1 DMPFN2 DMPSNM WRITE DMPFN1 DMPFN2 DMPSNM

;Now write out the compiled hosts file.

IFE SAILSW,[
WRITE:	SYSCAL OPEN,[[.UIO,,] ? DMPDEV ? DMPFN1 ? DMPFN2 ? DMPSNM]
	 .LOSE %LSFIL
	MOVE A,[444400,,OUT]	;get BP to data in core,
	MOVE B,NAMEP
	SUBI B,OUT		;and size of file.
	SYSCAL SIOT,[1000,, ? A ? B]
	 .LOSE %LSSYS
	.CLOSE			;write and close, and we're done.
	.LOGOUT 1,

;These are the filenames to write.
DMPDEV:	SIXBIT /DSK/
DMPFN1:	SIXBIT /HOSTS1/
DMPFN2:	SIXBIT />/
DMPSNM:	SIXBIT /SYSBIN/

];IFE SAILSW

IFN SAILSW,[

WRITE:	OPEN [17 ? 'DSK,, ? 0]
	 .VALUE
	ENTER DMPFN1
	 .VALUE
	MOVE B,NAMEP
	SUBI B,OUT+1		;and size of file.
	HRLO A,B
	EQVI A,OUT-1
	SETZ B,
	OUTUUO A
	 CAIA
	  .VALUE
	CLOSE			;write and close
	EXIT

;These are the filenames to write.

DMPFN1:	SIXBIT /HOSTS1/
DMPFN2:	SIXBIT /BIN/
	0
DMPSNM:	SIXBIT /HSTNET/

];IFN SAILSW
;RCH RCH2 RCH1 RTOKEN RTOK1 RTOK2 RTOKCM RCOMLF RCOMMA BARF DECOUT

;Midas doesn't really make it for parsing this hosts table.
;Here's the new frob.

;Get character in A
RCH:
IFE SAILSW,[
	SKIPGE A,UNRCHF'
	 .IOT INCH,A
	JUMPE A,.-1		;SAIL might put nulls in the file?
	HRRZS A			;Flush -1 in LH of EOF ↑C
];IFE SAILSW
IFN SAILSW,[
	SKIPL A,UNRCHF'
	 JRST RCH1
RCH2:	SOSG IBUFH+2
	 IN
	  CAIA
	   SKIPA A,[↑C]
	    ILDB A,IBUFH+1
RCH1:	JUMPE A,RCH2
];IFN SAILSW
	CAIN A,↑J		;Count lines
	 SKIPL UNRCHF
	  CAIA
	   AOS LINENO'
	SETOM UNRCHF
	RET

;Returns in A positive character (SCO), ↑C at eof, or negative BP to ASCIZ string
;Bash B
RTOKEN:	CALL RCH		;First, skip white space and comments
	CAIN A,↑C
	 RET			;EOF
	CAIN A,";
	 JRST RTOKCM
	CAIN A,↑J		;LF is an SCO
	 RET
	CAIG A,40
	 JRST RTOKEN		;White space
	CAIN A,",		;Comma is an SCO
	 RET
	CAIE A,"[		;Brackets are SCO
	 CAIN A,"]
	  RET
	;; OK, this is going to be a long symbol
	MOVE B,TOKBP		;Start of this symbol
RTOK1:	IDPB A,TOKBP
	CALL RCH
	CAILE A,40		;Check for termination
	 CAIN A,";
	  JRST RTOK2
	CAIN A,",
	 JRST RTOK2
	CAIE A,"[
	 CAIN A,"]
	  JRST RTOK2
	JRST RTOK1

RTOK2:	MOVEM A,UNRCHF
	MOVEI A,0
	IDPB A,TOKBP
	MOVE A,B		;Return value is negative BP to ASCIZ
	AOS B,TOKBP		;Advance BP to next word
	HRLI B,440700
	MOVEM B,TOKBP
	RET

RTOKCM:	CALL RCH		;Skip comment
	CAIE A,↑J		;Which turns into CRLF
	 CAIN A,↑C		;EOF Shouldn't happen
	  RET
	JRST RTOKCM

;Require a comma here, or a CRLF.  Skip if comma
RCOMLF:	CALL RTOKEN
	CAIN A,↑J
	 RET
	CAIN A,",
	 JRST POPJ1
	MOVEI A,[ASCIZ/Missing comma or CRLF/]
	JRST BARF

;Require a comma here
RCOMMA:	CALL RTOKEN
	CAIN A,",
	 RET
	MOVEI A,[ASCIZ/Missing comma/]
	JRST BARF

BARF:	PUSHJ P,ASZOUT
	MOVEI A,[ASCIZ/
Error near line #/]
	PUSHJ P,ASZOUT
	MOVE A,LINENO
	PUSHJ P,DECOUT
	.VALUE

DECOUT:	IDIVI A,10.
	HRLM B,(P)
	SKIPE A
	 PUSHJ P,DECOUT
	HLRZ B,(P)
	ADDI B,"0
IFE SAILSW, .IOT TYOC,B
IFN SAILSW, OUTCHR B
	POPJ P,
;GHOST GHOSTE GNET GHOST1 GHOST2 GHOST3 GHOST4 GHOST5 GHOST6

;; This guy is called to read HOST lines.  Store indirect through D.
GHOST:	CALL RTOKEN		;Should be HOST
	JUMPL A,GHOST1		;If SCO, hopefully EOF or blank line
	CAIN A,↑J
	 JRST GHOST
	CAIN A,↑C
	 RET
GHOSTE:	MOVEI A,[ASCIZ/Randomness when expecting HOST/]
	JRST BARF

GNET:	CALL RCH		;Ignore network entries
	CAIE A,↑J		;By flushing until end of line
	 JRST GNET
	JRST GHOST

GHOST1:	MOVE B,(A)
	CAMN B,[ASCIZ/NET/]
	 JRST GNET
	CAME B,[ASCIZ/HOST/]
	 JRST GHOSTE
	CALL RTOKEN		;Next should be host name
	JUMPGE A,[	MOVEI A,[ASCIZ/Random character when expecting host name/]
			JRST BARF ]
	MOVEM A,HSTNAM(D)
	CALL RCOMMA		;Next should be comma
	SETO C,			;Host number not got yet
	CALL RTOKEN		;Should be either a host# or a bracketed list of such
	CAIE A,"[		;]
	 JRST [	CALL GHOSTN
		JRST GHOST3 ]
GHOST2:	CALL RTOKEN
	CALL GHOSTN		;
	CALL RTOKEN
	CAIN A,",
	 JRST GHOST2		;[
	CAIE A,"]
	 JRST [	MOVEI A,[ASCIZ/Missing close bracket/]
		JRST BARF ]
GHOST3:	CALL RCOMMA		;Next a comma
	JUMPL C,[ PUSHJ P,RTOKCM	;This host not to be included, treat as comment
		  JRST GHOST ]
	MOVEM C,HSTNUM(D)
	CALL RTOKEN		;Status	
	MOVE B,(A)
	SETZM HSTSRV(D)
	CAMN B,[ASCII/SERVE/]
	 SETOM HSTSRV(D)
	CALL RCOMLF
	 JRST GHOST6		;CRLF
	CALL RTOKEN		;Optional system name
	JUMPGE A,[ SETZM HSTSYS(D)
		   MOVEM A,UNRCHF
		   JRST .+2 ]
	 MOVEM A,HSTSYS(D)
	CALL RCOMLF
	 JRST GHOST6		;CRLF
	CALL RTOKEN		;Optional machine name
	JUMPGE A,[ SETZM HSTMCH(D)
		   JRST .+3 ]
	 MOVEM A,HSTMCH(D)
	 CALL RTOKEN
	;Here A is comma before nicknames, or CRLF
	SETZM HSTNIC(D)
	CAIE A,",
	 JRST GHOST6
	CALL RTOKEN		;Single nickname or bracket that begins list
	CAIE A,"[		;]
	 JRST [	CALL GNICKN
		JRST GHOST5 ]
GHOST4:	CALL RTOKEN
	CALL GNICKN
	CALL RTOKEN
	CAIN A,",
	 JRST GHOST4		;[
	CAIE A,"]
	 JRST [	MOVEI A,[ASCIZ/Missing close bracket/]
		JRST BARF ]
GHOST5:	CALL RTOKEN
GHOST6:	CAIE A,↑J		;Should be end of line
	 JRST [	MOVEI A,[ASCIZ/Garbage where end of line expected/]
		JRST BARF ]
	ADDI D,HSTLEN
	AOS NHOSTS
	JRST GHOST
;GHOSTN GHSTN1 GHSTN2 GHSTN3 GHSTN5 GHSTN9 GNICKN

;;; This parses up a host number and puts it in C if it likes it
;;; First token is in A
GHOSTN:	JUMPGE A,GHSTN9		;SCO?
	ILDB B,A		;First char tells whether it's a number
	CAIL B,"0
	 CAILE B,"9
	  JRST GHSTN5
	MOVEM A,GHSNBP'		;Save ptr to this number
	MOVEI C,0		;It's a number, read in as octal in C
GHSTN1:	LSH C,3
	ADDI C,-"0(B)
	ILDB B,A
	JUMPE B,CPOPJ		;Clearly an Arpanet guy
	CAIE B,"/		;Slash allowed in numbers for host slash imp frob
	 JRST GHSTN1
	MOVE A,GHSNBP		;Oh dear.  Rescan the number in decimal
	LDB B,A
	MOVEI C,0
GHSTN2:	IMULI C,10.
	ADDI C,-"0(B)
	ILDB B,A
	CAIE B,"/
	 JRST GHSTN2
	PUSH P,C		;Save host number
	MOVEI C,0		;It's a number, read in as decimal in C
	ILDB B,A
	CAIL B,"0
	 CAILE B,"9
	  JRST [MOVEI A,[ASCIZ/Random character in number/]
		JRST BARF ]
GHSTN3:	IMULI C,10.
	ADDI C,-"0(B)
	ILDB B,A
	JUMPN B,GHSTN3
	POP P,B			;B host, C imp.  See if fits in old format
;New format result to C
	LSH C,9			
	ADDI C,(B)
	RET

GHSTN5:	MOVE B,(A)		;Must be a network name
	CAMN B,[ASCIZ/ARPA/]
	 JRST [	CALL RTOKEN	;Arpanet is OK
		JRST GHOSTN ]
	CALL RTOKEN		;Give up on this guy (skip his number)
	RET

GHSTN9:	.VALUE			;Shouldn't see SCO's here.

;Get a nickname.  Make HSTNIC be pointer to vector of addresses of ASCIZ, end by zero.
;Nick name is already in A, just needs to be CONSed onto list.
GNICKN:	MOVSS A			;CAR is in LH
	HRR A,TOKBP		;CDR is next free loc
	EXCH A,HSTNIC(D)	;Store first CONS, get set to store previous
	MOVEM A,@TOKBP		;Store previous
	AOS TOKBP		;Bump free ptr
	RET
;UPSIZE RHOSTF HSTTAB RHOSTF HSTTAB

;; Here to read in and parse the hosts file, making HSTTAB and various ASCIZ strings

UPSIZE==12			;Number of K for upper

IFE SAILSW,[
RHOSTF:	MOVE A,[-UPSIZE,,HSTTAB/2000]	;5K should be enough core
	SYSCAL CORBLK,[MOVEI %CBNDW ? MOVEI %JSELF ? A ? MOVEI %JSNEW ]
	 .LOSE %LSSYS
	SETZM HSTTAB		;Always a good idea
	MOVE A,[HSTTAB,,HSTTAB+1]
	BLT A,<HSTTAB+UPSIZE*2000>-1
	MOVE A,[440700,,HSTTAB+4000]	;2K of host table, rest is ASCIZ strings
	MOVEM A,TOKBP'
	SETZM NHOSTS'
	SYSCAL OPEN,[[.UAI,,INCH] ? [SIXBIT/DSK/]
		[SIXBIT/HOSTS/] ? [SIXBIT/>/] ? [SIXBIT/SYSENG/]]
	 .LOSE %LSFIL
	MOVEI D,HSTTAB		;Store indirect through D
	CALL GHOST
	MOVEM D,HSTTBE'
	SYSCAL RFNAME,[MOVEI INCH ? MOVEM A ? MOVEM FFN1 ? MOVEM FFN2 ]
	 .LOSE %LSSYS
	.CLOSE INCH,
	RET

HSTTAB=600000
];IFE SAILSW

IFN SAILSW,[
RHOSTF:	MOVEI A,<HSTTAB+UPSIZE*2000>-1	;Moon sez: 5K should be enough core
	CORE2 A,		;Make us an upper (NOTE: If this program is
	 .VALUE			;brought up on a Tops-10 this will have to change)
	SETZM HSTTAB		;And at SAIL you ain't got no choice!
	MOVE A,[HSTTAB,,HSTTAB+1]
	BLT A,<HSTTAB+UPSIZE*2000>-1
	MOVE A,[440700,,HSTTAB+4000]	;2K of host table, rest is ASCIZ strings
	MOVEM A,TOKBP'
	SETZM NHOSTS'
	OPEN [0 ? 'DSK,, ? IBUFH]
	 .VALUE
	DMOVE A,[SIXBIT/HOSTS/ ? 'TXT,,]
	MOVE D,[SIXBIT/HSTNET/]
	LOOKUP A
	 .VALUE
	MOVEI D,HSTTAB		;Store indirect through D
	CALL GHOST
	MOVEM D,HSTTBE'
	CLOSE
	RELEASE
	RET

HSTTAB=400000			;This must *NOT* change
];IFE SAILSW
;OUTPT NAMP NAMEP NUMP IBUFH OUT FFN1 FFN2 UNAME $DATE TIME NAMPR NUMPR SYSNMS TIP PDP10 ITS TENEX TOPS10 TOPS20 TEN50 TWENEX BOTS10 SAIL PDP11 ELF UNIX RSX11 HYDRA MULTIC OUTEND CORTOP FOO

;Here is the beginning of the hosts table file.

OUTPT:	OUTEND			;Pointer to where to put next word we add.
NAMP:	0			;Addr of place to put NAME table
				;(in our address space).
NAMEP:	0			;Ptr for storing into NUMBERS table.

NUMP:	0			;Addr of place to put NUMBER table.

IFN SAILSW,[
IBUFH:	BLOCK 3			;Input buffer header
];IFN SAILSW

CONSTANTS
VARIABLES

;The data actually written into the file starts here.

OUT:	SIXBIT /HOSTS1/
FFN1:				;Include filenames of HOSTS file.
IFE SAILSW,0
 .ELSE	SIXBIT/HOSTS/
FFN2:
IFE SAILSW,0
 .ELSE	SIXBIT/SAIL/
UNAME:	0			;UNAME of person who compiles the file.
$DATE:	0			;Date and time of compilation.
TIME:	0
NAMPR:	0			;Pointer to NAME table, rel to OUT.
NUMPR:	0			;Pointer to NUMBER tables, rel to OUT.
SYSNMS:				;The table of interned system and machine
				;names starts here.
TIP:	ASCIZ /TIP/		;These are pre-interned so they go in known
PDP10:	ASCIZ /PDP10/		;places and are easy to test for in MACH.
ITS:	ASCIZ /ITS/		;Note: PDP10, not PDP-10, so fits in 1 word.
TENEX:	ASCIZ /TENEX/
TOPS10:	ASCIZ /TOPS-10/
TOPS20:	ASCIZ /TOPS-20/
TEN50:	ASCIZ /10-50/
TWENEX:	ASCIZ /TWENEX/
BOTS10:	ASCIZ /BOTTOMS-10/
SAIL:	ASCIZ /WAITS/
PDP11:	ASCIZ /PDP11/
ELF:	ASCIZ /ELF/
UNIX:	ASCIZ /UNIX/
RSX11:	ASCIZ /RSX-11/
HYDRA:	ASCIZ /HYDRA/
MULTIC:	ASCIZ /MULTICS/

OUTEND=.
CORTOP=OUTEND+20*2000
FOO==.
CONSTANTS
VARIABLES
IFN .-FOO,Constants or variables in skeleton output file

END DUMP