*DECK GNDT                         23JUL81
USETEXT COMCBEG 
USETEXT COMCAPR 
USETEXT COMCCAE 
USETEXT COMQDEF 
USETEXT COMQFIL 
USETEXT COMQKDS 
USETEXT COMQNET 
USETEXT COMQPID 
    PROC GNDT;
      BEGIN    # GNDT # 
# 
**    GNDT       GET NETWORK DESCRIPTION TABLE. 
* 
*     GNDT OBTAINS A COPY OF THE SYSTEM NETWORK DESCRIPTION TABLE 
*     AND CREATES OR UPDATES THE LOCAL PID/LID TABLE.  THE PID AND
*     LID INFORMATION IS USED TO REGULATE CALLS TO QAC/QAF TO 
*     ACQUIRE QUEUE FILES.
* 
*     FOR NOS, THE NDT INFORMATION IS OBTAINED FROM THE CMR LID TABLE 
*     (LDT) VIA THE *GETLIDT* SFM FUNCTION. 
* 
*     FOR NOS/BE, A COPY OF THE RHF SUBSYSTEM NDT IS OBTAINED WITH
*     THE *CTRL/INFO/R* SUPERVISORY MESSAGE.
* 
*     IN EITHER CASE, PID-RELATED INFORMATION STORED IN THE LOCAL 
*     PID/LID TABLE IS PRESERVED ACROSS UPDATES.
* 
*     PROC GNDT 
* 
*     ENTRY      NONE.
* 
*     EXIT       PLT UPDATED (INITIALIZED IF 1ST CALL). 
*                PIDLPID = INITIALIZED RANDOMLY IF 1ST CALL.
*                PIDNPID = NUMBER OF PIDS DEFINED.
*                PIDLLDT = LENGTH OF SYSTEM NDT.
* 
*     PROCESS    GET MEMORY FOR WORK SPACE. 
*                IF NOS:  
*                  CALL GETLIDT TO OBTAIN SYSTEM LID TABLE. 
*                IF NOS/BE: 
*                  CALL NETPUT (CTRL/INFO) TO OBTAIN RHF NDT. 
*                SAVE CURRENT PIDS AND PID FLAGS IN WORK SPACE. 
*                FOR EACH PID IN LDT/NDT: 
*                  SEARCH OLDPIDS LIST FOR PID FLAGS
*                  IF (PID ENABLED
*                      AND NETWORK PATH IN SERVICE):  
*                    SET PLTNUMLID TO ZERO
*                    FOR EACH LID WORD IN PID ENTRY:  
*                      IF LID ENABLED 
*                          AND (PID NOT DISABLED) 
*                          AND (LOOPBACK OR NOT THIS HOST): 
*                        STORE LID IF ROOM IN PLT.
*                    LINK PREVIOUS PLT PID TO THIS PID
*                    INCREMENT PID COUNT. 
*                  IF NO ROOM FOR ADDITIONAL PIDS:  
*                    TERMINATE LOOP.
*                LINK LAST SAVED PID TO FIRST PID ENTRY 
*                COMPUTE MAXIMUM PAGES FOR STATUS,PID DISPLAY 
*                RESET CURRENT PAGE IF OUT-OF-RANGE 
*                RELEASE WORK SPACE.
# 
  
# 
****  XREF
# 
      XREF
        BEGIN 
        PROC ABORTQ;
        PROC CMMALF;
        FUNC FREECMM    U;
        PROC FTUPUT;
        PROC GETLIDT; 
        PROC MSGLOG;
        PROC NAME;                 # DEBUG CODE # 
        PROC NSTORE;
        PROC SETPLTA;              # LOCATE PID # 
        END 
# 
****  XREF END
# 
  
  
      DEF LLDTFET    #06#;         # FET LENGTH FOR NOS *GETLIDT* # 
  
    CONTROL IFEQ OS$NOS;
      DEF LPIDHDR    #03#;         # LENGTH OF LDT PID ENTRY #
  
      DEF PIDNWS$NA  #00#;         # NO NETWORK PATH DEFINED #
      DEF PIDNWS$IN  #01#;         # NETWORK PATH IN SERVICE #
      DEF PIDNWS$OT  #02#;         # ALL PATHS OUT OF SERVICE # 
  
      BASED ARRAY PIDHDR     S(LPIDHDR);
        BEGIN 
        ITEM PID$PID    U(00,00,18);  # PHYSICAL ID # 
        ITEM PID$PIDH   B(00,18,01);  # HOST ATTRIBUTE #
        ITEM PID$PIDE   B(00,19,01);  # ENABLED # 
        ITEM PID$PIDV   B(00,20,01);  # VALIDATE #
        ITEM PID$PIDN   B(00,21,01);  # NO-LIST # 
        ITEM PID$NWSSSF U(00,48,04);  # SSF STATUS #
        ITEM PID$NWSRHF U(00,52,04);  # RHF STATUS #
        ITEM PID$NWSNHP U(00,56,04);  # NAM STATUS #
        ITEM PID$MFTYPE U(01,00,42);  # HOST TYPE # 
        ITEM PID$NXTPID U(01,42,18);  # NEXT PID OFFSET # 
        ITEM PID$NLIDS  U(02,48,12);  # NUMBER OF LIDS #
        END 
  
      BASED ARRAY LIDENTRY   S(1);
        BEGIN 
        ITEM LID$LID    U(00,00,18);  # LOGICAL ID #
        ITEM LID$LIDE   B(00,24,01);  # ENABLED # 
        ITEM LID$LIDS   B(00,25,01);  # STORE-FORWARD # 
        ITEM LID$LIDV   B(00,26,01);  # VALIDATE #
        ITEM LID$LIDB   B(00,27,01);  # LOOP-BACK # 
        ITEM LID$LIDN   B(00,28,01);  # NO-LIST # 
        END 
  
    CONTROL ENDIF;
  
    CONTROL IFEQ OS$NOSBE;
      DEF LPIDHDR    #03#;         # LENGTH OF NDT PID ENTRY #
  
      ITEM RIGHTLID   B = FALSE;   # PROCESSING RIGHT HALF #
      ITEM PID$PIDH   B = FALSE;   # HOST # 
      ITEM LID$LIDB   B = FALSE;   # LOOP-BACK LID #
  
      BASED ARRAY PIDHDR     S(LPIDHDR);
        BEGIN 
        ITEM PID$PID    U(00,00,18);  # PHYSICAL ID # 
        ITEM PID$PIDE   B(00,23,01);  # ENABLED # 
        ITEM PID$NXTPID U(00,42,18);  # NEXT PID OFFSET # 
        ITEM PID$MFTYPE U(01,00,42);  # HOST TYPE # 
        ITEM PID$LIDADR U(01,42,18);  # ADDR OF LIDENTRY #
        ITEM PID$NLIDS  U(02,12,12);  # NUMBER OF LIDS #
        END 
  
      BASED ARRAY LIDENTRY   S(1);
        BEGIN 
        ITEM LID$LEFT   U(00,00,30);  # LEFT LID ENTRY #
        ITEM LID$LIDE   B(00,11,01);  # ENABLED # 
        ITEM LID$LID    U(00,12,18);  # LOGICAL ID #
        ITEM LID$RIGHT  U(00,30,30);  # RIGHT LID ENTRY # 
#       ITEM LID$LID2E  B(00,41,01)     ENABLED # 
#       ITEM LID$LID2   U(00,42,18)     LOGICAL ID #
        END 
  
    CONTROL ENDIF;
  
      BASED ARRAY NDTBUF S(1);
        BEGIN 
        ITEM NDTBUFWD   U(00,00,60);  # BUFFER WORD # 
  
      CONTROL IFEQ OS$NOS;
        ITEM NDTLENGTH  U(00,00,12);  # LIDT LENGTH # 
      CONTROL ENDIF;
  
      CONTROL IFEQ OS$NOSBE;
        ITEM NDTLENGTH  U(00,24,18);  # NDT LENGTH #
      CONTROL ENDIF;
  
        ITEM NDTBIAS    U(00,42,18);  # NDT BIAS #
        END 
  
      BASED ARRAY OLDPIDS [0:999] S(1); 
        BEGIN 
        ITEM OLDPIDWD   U(00,00,60);
        ITEM OLDPID     U(00,00,18);
        END 
  
      STATUS STDLIDPOS  LEFT       # DLID POSITION SWITCH # 
                       ,MIDDLE
                       ,RIGHT 
                       ,FIRST 
                       ;
  
      ITEM D          I;           # DESTINATION (PLT) INDEX #
      ITEM DLIDPOS    S:STDLIDPOS; # PLT DLID POSITION SWITCH # 
      ITEM DONE       B;           # CONTROL FLAG # 
      ITEM FWAPIDHDR  U;           # FIRST LDT/NDT PID ENTRY #
      ITEM FWAPLTHDR  U;           # FIRST PLT PID ENTRY #
      ITEM I          I;           # MOVE LOOP INDEX #
      ITEM NEXTPIDHDR U;           # POINTER TO NEXT LDT/NDT PID #
      ITEM NUMLIDS    U;           # NUMBER OF LIDS # 
      ITEM OLDNPID    I;           # NUMBER OF ENTRIES IN OLDPIDS # 
      ITEM PREVPLTHDR U;           # PREVIOUS PLT PID ENTRY # 
      ITEM THISPLTHDR U;           # CURRENT PLT PID ENTRY #
  
  
  
      SWITCH SWDLIDPOS:STDLIDPOS
           SW$LEFT:LEFT 
          ,SW$MIDDLE:MIDDLE 
          ,SW$RIGHT:RIGHT 
          ,SW$FIRST:FIRST 
          ; 
  
  
      $BEGIN                       # DEBUG CODE # 
      NAME("GNDT"); 
      $END                         # DEBUG CODE # 
  
      KS$UPDATE[KDIS"PID"] = TRUE;
      DONE = FALSE; 
      D = PIDLLDT;                 # LAST LID TABLE LENGTH #
      IF D LE 0 
      THEN
        BEGIN 
        D = PLTLEN * 2;            # TRIAL LENGTH # 
        END 
  
      ASLONGAS NOT DONE 
      DO
        BEGIN 
        I = (LLDTFET) + (PIDNPID + LACNMAX + 1) + (D);
        CMMALF(I, 0, CMMN, P<OLDPIDS>);  # ALLOCATE WORK SPACE #
        P<FET> = P<OLDPIDS> + (PIDNPID + LACNMAX + 1);
        P<NDTBUF> = P<FET> + LLDTFET; 
        NDTBUFWD[0] = 0;           # CLEAR 1ST WORD OF BUFFER # 
  
      CONTROL IFEQ OS$NOS;
        FOR I = 0 STEP 1 UNTIL LLDTFET-1
        DO
          BEGIN 
          FETWD[I] = 0; 
          END 
  
        FETCOMP = TRUE;            # INITIALIZE FET FOR *GETLIDT* # 
        FETEP   = TRUE;            # SELECT ERROR PROCESSING #
        FETFIR  = P<NDTBUF>;
        FETIN   = FETFIR; 
        FETOUT  = FETFIR; 
        FETLIM  = FETFIR + D; 
        GETLIDT(FET, 0);           # GET SYSTEM LID TABLE # 
        IF FETEC NE 0              # IF ERROR RETURNED BY *SFM* # 
        THEN
          BEGIN 
          IF FETEC EQ 6            # IF BUFFER TOO SMALL FOR LIDT # 
          THEN
            BEGIN 
            IF FETSFMLLDT LT D     # IF LIDT LENGTH NOT RETURNED #
            THEN
              BEGIN 
              NDTLENGTH = D + PLTLEN;  # MAKE A GUESS FOR NEXT TRY #
              END 
  
            ELSE
              BEGIN 
              NDTLENGTH = FETSFMLLDT; 
              END 
  
            END 
  
          ELSE                     # UNEXPECTED *SFM* ERROR # 
            BEGIN 
            ABORTQ("GNDT/SFM"); 
            END 
  
          END 
  
        NDTBIAS = 0;
      CONTROL ENDIF;
  
      CONTROL IFEQ OS$NOSBE;
        NHA = SUPHDR+1;            # SET UP CTL/INFO MESSAGE #
        NSTORE (NTA,$PFCSFC,CTRINF);  # SET CTRL/INFO REQUEST # 
        NSTORE (NTA,$CTFNDTL,D);   # SET BUFFER LENGTH #
        NSTORE (NTA,$CTFNDTA,P<NDTBUF>);  # SET BUFFER ADDR # 
        NSTORE (NTA,$CTFC,2);      # SET FUNCTION 2 # 
        FTUPUT (NHA,NTA); 
      CONTROL ENDIF;
  
        IF NDTLENGTH[0] GE D       # IF NDT BUFFER TOO SMALL #
        THEN
          BEGIN 
          D = NDTLENGTH[0] + 1;    # RESET LENGTH # 
          P<OLDPIDS> = FREECMM(P<OLDPIDS>);  # RELEASE BUFFER # 
          END 
  
        ELSE
          BEGIN 
          DONE = TRUE;
          END 
  
        END 
  
      PIDLLDT = NDTLENGTH + 1;     # SAVE LENGTH #
      OLDNPID = PIDNPID;           # SAVE OLD PID COUNT # 
      PIDNPID = 0;                 # RESET PID COUNT #
      P<PLTHDR> = P<OLDPIDS>;      # INITIALIZE SENTINEL ENTRY #
      PLTFLAGS = 0; 
      PLTSCINUSE = 0; 
      PLTSCDISAB = 0; 
      PLTDISTIME = 0; 
      P<PLTHDR>  = LOC(PLTWD[0]); 
      FOR I = 1 STEP 1 UNTIL OLDNPID
      DO
        BEGIN 
        PLTLPIDF = (PIDLPID EQ P<PLTHDR>);  # LAST PID USED FLAG #
        OLDPIDWD[I] = PLTWD0;      # SAVE PID, FLAGS, AND TIME #
        P<PLTHDR> = PLTNXTPID;     # POINT TO NEXT PID #
        END 
  
      PIDLPID = 0;                 # CLEAR LAST PID USED POINTER #
      FWAPIDHDR = P<NDTBUF> + 1;
      IF PIDLLDT EQ 0              # IF ZERO-LENGTH LDT/NDT # 
      THEN
        BEGIN 
        NEXTPIDHDR = 0;            # TERMINATE LOOP # 
        END 
  
      ELSE
        BEGIN 
        NEXTPIDHDR = FWAPIDHDR;    # INITIAL LDT/NDT ENTRY #
        END 
  
      FWAPLTHDR = LOC(PLTWD[0]);   # INITIAL PLT ENTRY #
      PREVPLTHDR = FWAPLTHDR;      # POINTER TO PREVIOUS ENTRY #
      THISPLTHDR = FWAPLTHDR;      # CURRENT ENTRY #
      ASLONGAS NEXTPIDHDR NE 0     # FOR EACH PID IN LDT/NDT #
      DO
        BEGIN 
        P<PLTHDR> = THISPLTHDR; 
        P<PIDHDR> = NEXTPIDHDR; 
        IF PID$NXTPID EQ 0         # IF NO MORE PIDS #
        THEN
          BEGIN 
          NEXTPIDHDR = 0; 
          END 
  
        ELSE
          BEGIN 
  
        CONTROL IFEQ OS$NOS;
          NEXTPIDHDR = P<PIDHDR> + PID$NXTPID;
        CONTROL ENDIF;
  
        CONTROL IFEQ OS$NOSBE;
          NEXTPIDHDR = PID$NXTPID - NDTBIAS + FWAPIDHDR;
        CONTROL ENDIF;
  
          END 
  
        OLDPID[0] = PID$PID;       # SET PID IN SENTINEL #
        I = OLDNPID;               # NUMBER OF OLD PIDS # 
        ASLONGAS PID$PID NE OLDPID[I] 
        DO
          BEGIN 
          I = I - 1;
          END 
  
        PLTWD0 = OLDPIDWD[I];      # SAVE PID WORD #
        IF I NE 0                  # IF OLD PID FOUND # 
        THEN
          BEGIN 
          OLDPIDWD[I] = 0;         # CLEAR PID WORD # 
          END 
  
      CONTROL IFEQ OS$NOS;
        PID$PIDE = PID$PIDE 
           AND (   ( (NOT NAM) AND (PID$NWSRHF EQ PIDNWS$IN) )
                OR (    NAM    AND (PID$NWSNHP EQ PIDNWS$IN) ) ); 
      CONTROL ENDIF;
  
        IF (PID$PID NE 0)          # IF VALID PID # 
        THEN
          BEGIN 
          PLTWD1 = 0;              # INITIALIZE PLTNUMLID, ETC. # 
  
        CONTROL IFEQ OS$NOS;
          P<LIDENTRY> = P<PIDHDR> + LPIDHDR - 1;
        CONTROL ENDIF;
  
        CONTROL IFEQ OS$NOSBE;
          P<LIDENTRY> = PID$LIDADR - NDTBIAS + FWAPIDHDR - 1; 
          PID$PIDH = PID$PID EQ HD;  # HOST PID IF PID MATCHES HOST # 
          RIGHTLID = FALSE;        # START WITH LEFT-HALF OF LIDENTRY # 
        CONTROL ENDIF;
  
          P<PLTDLID> = P<PLTHDR> + PLTHDRL - 1; 
          DLIDPOS = S"FIRST"; 
          IF PID$PIDE              # IF PID IS IN-SERVICE # 
          THEN
            BEGIN 
            NUMLIDS = PID$NLIDS;   # NUMBER OF LIDS IN LDT/NDT #
            END 
  
          ELSE
            BEGIN 
            NUMLIDS = 0;           # DO NOT PROCESS LIDS #
            END 
  
          ASLONGAS NUMLIDS GT 0    # WHILE LID ENTRIES REMAIN # 
          DO
            BEGIN 
            NUMLIDS = NUMLIDS - 1; # DECREMENT LID COUNT #
  
          CONTROL IFEQ OS$NOS;
            P<LIDENTRY> = P<LIDENTRY> + 1;
          CONTROL ENDIF;
  
          CONTROL IFEQ OS$NOSBE;
            RIGHTLID = NOT RIGHTLID;  # TOGGLE LEFT/RIGHT # 
            IF NOT RIGHTLID 
            THEN
              BEGIN 
              LID$LEFT == LID$RIGHT;  # SWAP HALVES # 
              END 
  
            ELSE                   # FETCH NEXT LID ENTRY # 
              BEGIN 
              P<LIDENTRY> = P<LIDENTRY> + 1;
              END 
  
            LID$LIDB = (LID$LID NE HD)  # MUST NOT MATCH HOST PID # 
                     # AND (PID$PIDH)#; # AND HOST PID (DONT CARE) #
          CONTROL ENDIF;
  
            IF (LID$LID NE 0)      # IF LID EXISTS #
              AND (LID$LIDE)       #   AND IS ENABLED # 
              AND (LID$LIDB        #   AND EITHER LOOP-BACK # 
                   OR NOT PID$PIDH)  #     OR NOT THIS HOST # 
            THEN
              BEGIN 
              PLTNUMLID = PLTNUMLID + 1;  # INCREMENT LID COUNT # 
              GOTO SWDLIDPOS[DLIDPOS];  # SIMULATED CASE STMNT #
  
  
SW$FIRST:                          # FIRST DLID POSITION #
                PLTFLID = LID$LID;
                DLIDPOS = S"LEFT";
                GOTO SW$END;       # END OF CASE #
  
SW$LEFT:  
                IF (P<PLTDLID> - FWAPLTHDR) 
                      GE (PLTLEN - 1) 
                THEN
                  BEGIN 
                  NUMLIDS = 0;     # NO MORE ROOM FOR LIDS #
                  END 
  
                ELSE
                  BEGIN 
                  P<PLTDLID> = P<PLTDLID> + 1;
                  PLTDLIDWD = 0;   # INITIALIZE NEXT LID WORD # 
                  PLTDLID1 = LID$LID; 
                  DLIDPOS = S"MIDDLE";
                  END 
  
                GOTO SW$END;       # END OF CASE #
  
SW$MIDDLE:  
                PLTDLID2 = LID$LID; 
                DLIDPOS = S"RIGHT"; 
                GOTO SW$END;       # END OF CASE #
  
SW$RIGHT: 
                PLTDLID3 = LID$LID; 
                DLIDPOS = S"LEFT";
                GOTO SW$END;       # END OF CASE #
  
SW$END:                            # CASE END # 
              END 
  
            END 
  
          PLTDISLDT = NOT PID$PIDE;  # PID DISABLED IN LDT FLAG # 
          PLTLIDSDIS = (PLTNUMLID EQ 0);  # ALL LIDS DISABLED # 
          IF PLTLPIDF              # IF THIS WAS LAST PID USED #
          THEN
            BEGIN 
            PIDLPID = P<PLTHDR>;   # POINT TO THIS PID #
            END 
  
          P<PLTHDR> = PREVPLTHDR; 
          PLTNXTPID  = THISPLTHDR; # LINK PREVIOUS PLT TO THIS #
          PREVPLTHDR = THISPLTHDR; # SAVE THIS PLT FOR LATER LINK # 
          THISPLTHDR = P<PLTDLID> + 1;  # NEXT PLT FOLLOWS LIDS # 
          PIDNPID = PIDNPID + 1;   # INCREMENT PID COUNT #
          END 
  
        IF (THISPLTHDR + PLTHDRL - FWAPLTHDR) GT PLTLEN 
        THEN
          BEGIN 
          NEXTPIDHDR = 0;          # NO ROOM FOR ADDITIONAL PIDS #
          END 
  
        END 
  
      P<PLTHDR> = PREVPLTHDR;      # LAST PLT ENTRY SAVED # 
      PLTNXTPID = FWAPLTHDR;       # CIRCULAR LINK TO FIRST PLT # 
      I = FREECMM(P<OLDPIDS>);     # RELEASE WORK SPACE BUFFER #
      IF PIDLPID EQ 0              # FIRST UPDATE OR PID DELETED #
      THEN
        BEGIN 
        P<PLTHDR> = LOC(PLTWD[0]); # SET PID ENTRY ADDR # 
        PIDLPID = P<PLTHDR>;
        END 
  
      SETPLTA(KD$LPID);            # FIRST PID ON CURRENT PAGE #
      KS$MAXPAGE[KDIS"PID"] = (PIDNPID + KS$ITPERPG[KDIS"PID"] - 1) 
                                   / KS$ITPERPG[KDIS"PID"]; 
      IF (KS$CURPAGE[KDIS"PID"] GT KS$MAXPAGE[KDIS"PID"]) 
        OR (PLTWD1 EQ 0)           # FIRST TIME OR PID DISAPPEARED #
      THEN
        BEGIN 
        KS$CURPAGE[KDIS"PID"] = 1;
        P<PLTHDR> = PIDLPID;       # SET TO LAST PID #
        KD$LPID = PLTPID; 
        KD$LPIDORD = 1;            # CURRENT PID ORDINAL #
        END 
  
      END      # GNDT # 
    TERM
