!
!THIS PROGRAM IS USED TO BOOT THE NAME TABLE FOR THE RING NAME SERVER
!IT HAS THE SAME INTERFACE AS THE CAMBRIDGE FILE SERVER (ENOUGH TO
!ACCOMPLISH THIS TASK). ALL REQUESTS TO IT TO READ A FILE CAUSE STREAM
!1 TO BE SELECTED AND READ, THIS SHOULD BE THE SOURCE FORM OF THE NAME 
!SERVER TABLE I.E. A SERIES OF LINES OF THE FORM:-
!
!     name  address  port  type   function
!
!    name should be enclosed in quotes (' or ") if it contains 
!    non-alphanumerics or starts with a digit.
!
!    type and function are optional, if present type should be
!    one of the strings - SSP, BSP, DEV, SLOW-SSP or SLOW-BSP
!
!    Comments may be enclosed in [ to ] or | to end-of-line.
!
!    Numbers should be decimal or #Xhex-number
!
!    The list of names should be terminated with the name END
!



SYSTEMROUTINESPEC  ALARM(INTEGER  TICKS)
BEGIN 
!DATA FOR OUTPUT TO RING SIDE
!****************************

RECORDFORMAT  DF(BYTEINTEGERARRAY  A(0:200))

RECORDFORMAT  MEF(RECORD  (MEF) NAME  LINK,       C 
   BYTEINTEGER  LEN,TYPE, INTEGER  ADDRESS,       C 
   PORT, RECORD  (DF) DATA)

RECORDFORMAT  FSREQUEST(INTEGER  SSPCOM,REPLY PORT,C 
   FSCOMMAND,TAG,   INTEGERARRAY  UID(1:4),        C 
   INTEGER  START1,START2,NUM1,NUM2,READ PORT)

RECORDFORMAT  FSREPLY(INTEGER  SSPREP,DUMMY,RETURN CODE, C 
   TAG,NUM1,NUM2)

OWNRECORD  (MEF) NAME  BUF

RECORDFORMAT  PEF(BYTEINTEGER  SER,REPLY,FN,PORT,    C 
   RECORD  (MEF) NAME  MES, BYTEINTEGER  X,Y)
RECORDFORMAT  PE2(BYTEINTEGER  SER,REPLY,FN,PORT,    C 
   INTEGER  LPORT,HPORT)

RECORD  (PE2) NAME  PP


OWNRECORD  (PEF) P


CONSTINTEGER  BMAX=240

OWNINTEGER  BUFLEN,TOTAL,XERROR,ADDRESS,X

CONSTINTEGERNAME  INT=K'160060'
CONSTINTEGERNAME  OWN ID=K'160030'
CONSTINTEGER  RINGSER=10
CONSTINTEGER  BUFFERMANAGER=17
CONSTINTEGER  REQUESTBUFFER=0
CONSTINTEGER  RELEASEBUFFER=1

CONSTINTEGER  INPUT DONE=2
CONSTINTEGER  DO OUTPUT=X'C1';          !NOTIFY WHEN GONE AND RELEASE BUFFER
CONSTINTEGER  SET PORTS=0
CONSTINTEGER  OUTPUT ERROR=1

OWNRECORD (FSREQUEST) FSREQ


RECORDFORMAT  IBF(INTEGER  D1,D2,D3, STRING  (64) NAME)

OWNRECORD  (IBF) NAME  IB

RECORDFORMAT  IBA(BYTEINTEGERARRAY  A(1:72))

OWNRECORD  (IBA) IBLOCK

CONSTINTEGER  LINEMAX=80
OWNBYTEINTEGERARRAY  LINE(1:LINEMAX)
OWNINTEGER  LINEPNT,EOF,NUMBER

CONSTINTEGER  MAXPNT=64;           !MAX NAME BUFLEN
STRING  (MAXPNT) NAME


OWNINTEGER  LINENO,NULL COUNT, BYTE COUNT
OWNINTEGER  I,CH,N;                  !OF BYTES OUTPUT

CONSTINTEGER  SYNAME=0
CONSTINTEGER  SYNUMBER=1
CONSTINTEGER  SYEND=2
CONSTINTEGER  SYERROR=3

OWNINTEGER  IPNT,IMAX


CONSTSTRING  (8) ARRAY  FLAGNAME(1:5)= "SSP",  C 
         "BSP","DEV","SLOW-SSP","SLOW-BSP"

CONSTINTEGERARRAY  FLAGVAL(1:5)=10,9,11,26,25

OWNINTEGER  CLOCK=0

CONSTINTEGER  ON=1
CONSTINTEGER  OFF=0

ROUTINESPEC  FREE BUFFER

ROUTINE  ERROR(INTEGER  N)
   SWITCH  ERR(1:5)

   PRINTSTRING("*******  ERROR ")
   IF  N>5 THEN  ->END
   ->ERR(N)
ERR(1):PRINTSTRING("MISSING NAME");   ->END
ERR(2):PRINTSTRING("MISSING DEVICE NUMBER");   ->END
ERR(3):PRINTSTRING("MISSING PORT NUMBER");   ->END
ERR(4):PRINTSTRING("INVALID FLAGS MNEMONIC");   ->END
ERR(5):PRINTSTRING("EXTRA ON END OF LINE");  ->END
END:
   PRINTSTRING(" IN LINE-");   WRITE(LINENO, 3)
   NEWLINE

END 

ROUTINE  READCH(INTEGERNAME  CH)

   CH=LINE(LINEPNT)
   LINEPNT=LINEPNT+1

END 


ROUTINE  GETSIGCHAR(INTEGERNAME  CH)

   UNTIL  CH#' ' AND  CH # ',' AND  CH#9 CYCLE 
      READCH(CH)
   REPEAT 

END 


ROUTINE  GETLINE
INTEGER  CH

   LINEPNT=0
   UNTIL  CH=NL OR  CH=4 CYCLE 
     READSYMBOL(CH)
      IF  LINEPNT<LINEMAX-1 AND  CH#4 START 
         LINEPNT=LINEPNT+1
         LINE(LINEPNT)=CH
      FINISH 
   REPEAT 
   IF  CH=4 START 
      LINEPNT=LINEPNT+1
      LINE(LINEPNT)=NL
   FINISH 
   IF  LINEPNT=1 AND  CH=4 THEN  EOF=1
   LINEPNT=1
   LINENO=LINENO+1
END 

ROUTINE  STORENAME
   IB_NAME=NAME
   IMAX=LENGTH(NAME)+7
END 


INTEGERFN  HEX(INTEGER  CH)

   IF  '0'<=CH<='9' THEN  RESULT =CH-'0'
   IF  'A'<=CH<='F' THEN  RESULT =CH-'A'+10
   RESULT =-1

END 


INTEGERFN  GETSYMB
INTEGER  CH,QUOTE,PNT

   GETSIGCHAR(CH)
   IF  CH='|' START 
      UNTIL  CH=NL CYCLE 
         READCH(CH)
      REPEAT 
   FINISH 
   
   IF  CH=NL THEN  RESULT = (SYEND)

   IF  CH='[' START 
      WHILE  CH#']' CYCLE 
         READCH(CH)
         IF  CH=NL THEN  RESULT =(SYEND)
      REPEAT 
   FINISH 

   IF  CH='#' START 
      READCH(CH)
      IF  CH#'X' THEN  RESULT =SYERROR
      NUMBER=0;  READCH(CH)
      WHILE  HEX(CH)>=0 CYCLE 
         NUMBER=NUMBER<<4+HEX(CH)
         READCH(CH)
      REPEAT 
      LINEPNT=LINEPNT-1
      RESULT =SYNUMBER

    FINISH 
   IF  '0'<=CH<='9' START 
      NUMBER=0
      WHILE  '0'<=CH<='9' CYCLE 
         NUMBER=NUMBER*10+CH-'0'
         READCH(CH)
      REPEAT 
      LINEPNT=LINEPNT-1
     RESULT =(SYNUMBER)
   FINISH 
   QUOTE=' '
   IF  CH='''' OR  CH='"' THEN  QUOTE=CH AND  READCH(CH)
   PNT=0
   CYCLE 
      IF  CH=QUOTE THEN  EXIT 
      IF  CH=' ' OR  CH=',' OR  CH=9 OR  CH=NL START 
         LINEPNT=LINEPNT-1
         EXIT 
      FINISH 
      IF  PNT<MAXPNT START 
         PNT=PNT+1
         CHARNO(NAME,PNT)=CH
      FINISH 
      READCH(CH)
   REPEAT 
   LENGTH(NAME)=PNT
  RESULT =(SYNAME)
END 


ROUTINE  GETIBLOCK
INTEGER  I,SY,FUNCTION,FLAGS

   IPNT=0
LOOP:
   GETLINE
   FUNCTION=0
   FLAGS=8;          !FUNCTION NOT SET
   IF  EOF=1 THEN  RETURN 

!DECODE LINE
  SY=GETSYMB 
   IF  SY=SYEND THEN  ->LOOP;          !IGNORE EMPTY LINES
   IF  SY#SYNAME THEN  ERROR(1) AND  ->LOOP
   IF  NAME="END" THEN  EOF=1 AND  RETURN 
  STORENAME
   SY=GETSYMB
   IF  SY#SYNUMBER THEN  ERROR(2) AND  ->LOOP
   IBLOCK_A(1)=NUMBER
   SY=GETSYMB
   IF  SY#SYNUMBER THEN  ERROR(3) AND  ->LOOP
   IBLOCK_A(3)=NUMBER>>8
   IBLOCK_A(4)=NUMBER & 255
   SY=GETSYMB
   IF  SY=SYNAME START 
      CYCLE  I=1,1,5
         IF  NAME=FLAGNAME(I) THEN  FLAGS=FLAGVAL(I)
      REPEAT 
      IF  FLAGS=8 THEN  ERROR(4) AND  ->LOOP
      SY=GETSYMB
   FINISH 
   IF  SY=SYNUMBER START 
      FUNCTION=NUMBER
      SY=GETSYMB
      FLAGS=FLAGS - (FLAGS & 8)
   FINISH 
   IBLOCK_A(5)=FUNCTION>>8
   IBLOCK_A(6)=FUNCTION & 255
   IF  SY#SYEND THEN  ERROR(5) AND  ->LOOP
   IBLOCK_A(2)=FLAGS
END 

ROUTINE  GETCH

   IF  IPNT=IMAX START 
      GETIBLOCK; 
   FINISH 
   IF  EOF=1 START 
      CH=0
      NULL COUNT=NULL COUNT+1
      RETURN 
   FINISH 
   BYTE COUNT=BYTE COUNT+1
   IPNT=IPNT+1
   CH=IBLOCK_A(IPNT)

END 

ROUTINE  POFFWAIT(INTEGER  SERVICE)

   CYCLE 
      P_SER=0;   POFF(P)
      IF  SERVICE=0 OR  P_REPLY=SERVICE THEN  RETURN 
      IF  P_REPLY=RING SER AND  P_FN=INPUT DONE THEN  FREE BUFFER ELSEC 
         START  
              IF  P_REPLY=0 THEN  CLOCK=OFF
         FINISH 
   REPEAT 

END 

ROUTINE  REQ BUFFER
   P_SER=BUFFER MANAGER;   P_REPLY=OWN ID
   P_FN=REQUEST BUFFER;   P_X=0
   PON(P)

END 


ROUTINE  GETBUFFER

   REQ BUFFER
   POFFWAIT(BUFFER MANAGER)

END 

ROUTINE  FREE BUFFER

   P_SER=BUFFER MANAGER;  P_REPLY=OWN ID
   P_FN=RELEASE BUFFER
   PON(P)

END 

ROUTINE  TO RING

   P_SER=RING SER;  P_REPLY=OWN ID
   P_FN=DO OUTPUT
   PON(P)

END 


ROUTINE  SEND BUFFER
   
   P_MES_ADDRESS=ADDRESS
   TO RING
   CYCLE 
      POFF WAIT(RING SER)
      IF  P_FN=INPUT DONE THEN  FREE BUFFER AND  CONTINUE 
      EXIT 
   REPEAT 
   IF  P_FN=OUTPUT ERROR THEN  XERROR=1

END 


ROUTINE  SEND REPLY

RECORD  (FSREPLY) NAME  REPLY

   REPLY==P_MES_DATA
   REPLY_SSPREP=X'6500'
   REPLY_DUMMY=0
   REPLY_RETURN CODE=0
   REPLY_TAG=FSREQ_TAG
   REPLY_NUM1=0
   REPLY_NUM2=TOTAL
   P_MES_LEN=5
   P_MES_PORT=FSREQ_REPLY PORT
   P_MES_ADDRESS=ADDRESS
   SEND BUFFER

END 

ROUTINE  PUTCH(INTEGER  CH)

   IF  XERROR=1 THEN  RETURN 

   IF  BUFLEN=BMAX START 
      P_MES==BUF
      P_MES_LEN=(BUFLEN+1)>>1-1
      P_MES_PORT=FSREQ_READ PORT
      SEND BUFFER
      IF  XERROR=1 THEN  RETURN 
      GETBUFFER
      BUFLEN=0;    X=1
      BUF==P_MES
   FINISH 
   BUF_DATA_A(BUFLEN+X)=CH
   X=-X
   BUFLEN=BUFLEN+1
   IF  X>0 THEN  TOTAL=TOTAL+1;     !16 BIT WORDS

END 




   

   IB==IBLOCK;        !SO CAN ACCESS IBLOCK USING FORMAT AS PART STRING
   MAP VIRT(BUFFER MANAGER,5, 4)
   MAP VIRT(BUFFER MANAGER,6, 5)
   CLOCK=OFF
   PP==P
   P_SER=RING SER;   P_REPLY=OWN ID
   P_FN=SET PORTS
   PP_LPORT=64;   PP_HPORT=64
   PON(P)
   CYCLE 
      IF  CLOCK=OFF THEN  ALARM(100) AND  CLOCK=ON
      POFFWAIT(0)
      IF  P_REPLY=0 START 
         IF  INT='A' THEN  STOP 
         CLOCK=OFF
         CONTINUE 
      FINISH 
      IF  P_REPLY=RING SER AND  P_FN=INPUT DONE START 
         FSREQ=P_MES_DATA;
          ADDRESS=P_MES_ADDRESS
         FREEBUFFER
         LINENO=0;    IPNT=0;   IMAX=0
         TOTAL=0
         IF  FSREQ_FSCOMMAND = 7 START 
            SELECTINPUT(1)
            EOF=0;   XERROR=0;
            GETBUFFER;   BUFLEN=0;   X=1
            BUF==P_MES
            CYCLE  I=1,1,24;  PUTCH(0);  REPEAT 
            NULL COUNT=0
            BYTE COUNT=24
            UNTIL  XERROR=1 OR  TOTAL=FSREQ_NUM2 CYCLE 
               GETCH;   PUTCH(CH)
            REPEAT 
            CLOSEINPUT
            IF  XERROR#1 START 
               P_MES==BUF
               P_MES_LEN=(BUFLEN+1)>>1-1
               P_MES_PORT=FSREQ_READ PORT
               SEND BUFFER
               GETBUFFER
               SEND REPLY
            FINISH 
            PRINTSTRING("Name table loaded to"); WRITE(ADDRESS, 3)
            IF  XERROR#1 THEN  PRINTSTRING("** FAILED ")
            PRINTSTRING(" size="); WRITE(BYTE COUNT, 3)
            PRINTSTRING(" free="); WRITE(NULL COUNT, 3)
            NEWLINE
         FINISH 
      FINISH 
   REPEAT 

ENDOFPROGRAM