*DECK S$GNINV 
          PROC  S$GNINV(SPEC$, REC$); 
  
#**       S$GNINV -  GENERATE INVERT CODE                              #
#                                                                      #
#     CALLING SEQUENCE-                                                #
#         S$GNINV(SPEC$, REC$):                                        #
#                                                                      #
#     GIVEN-                                                           #
#         SPEC$ = USER SPECIFICATION.                                  #
#         REC$ = FORMAT OF INTERNAL RECORD.                            #
#                                                                      #
#     GENERATES-                                                       #
#                 INVERT RECORD FROM WSAS$OREC TO SLOT IN              #
#                  WSAS$ORSA SPECIFIED IN "RECDESC".                   #
#                 IF ERRORS IN KEYS,                                   #
#                     WRITE RECORD TO EXCEPTION FILE                   #
#                     JUMP TO "GETREC"  (IF EXCEPTION FILE)            #
#         "GOTREC":                                                    #
  
  
          BEGIN 
  
*CALL A 
  
*CALL REC$
  
*CALL SPEC$ 
  
  
*CALL MACHINE 
  
*CALL KT$ 
  
          XREF
              BEGIN 
              PROC  S$ABORT;           # HANDLE INTERNAL ERROR         #
              PROC  S$GNCNI;           # GEN- COPY NON-KEY TO INTERNAL #
              PROC  S$GNCVI;           # GEN- COPY VAR. PART TO INT.   #
              PROC  S$GNIVK;           # GEN- INVERT A SINGLE KEY      #
              PROC  S$GNIV9;           # GEN- FINISH UP INVERSION      #
              PROC  S$GNIV8;           # FINISH INVERSION-VARIABLE #
              PROC  S$GNLEN;           # GEN- APPEND LENGTH FIELD      #
              PROC  S$GNORD;           # GEN- APPEND RECORD ORDINAL    #
              END 
  
          XREF
              BEGIN 
              ITEM  S$IRRL   I;        # REC$IRRL                      #
              ITEM  S$LK     I;        # NUMBER OF USED KEY BITS       #
              ITEM  S$LR     I;        # NUMBER OF BITS FOR REC. NUM.  #
              ITEM  S$OREC   I;        # WSA$ OFFSET TO EXTERNAL REC   #
              ITEM  S$ORSA   I;        # WSA$ OFFSET TO REC STOR AREA  #
              END 
  
               ARRAY KEY$ [1:200] S(2); 
              BEGIN 
                    ITEM  KEY$LENGTH    I( 0, 0,30);
                    ITEM  KEY$OFFSET    I( 0,30,30);
                    ITEM  KEY$OVERLAP   B( 1, 0,30);
                    ITEM  KEY$CONTAIN   B( 1,30,30);
              END 
  
                   ARRAY OVER [1:200];
                       ITEM  OVERLAP$OFLN  I( 0, 0,60); 
             ITEM OVERLAP$PNTR    I;
             ITEM LASTONE         I;
          ITEM  I;           # INDEX TO SPEC$ KEY ENTRY                #
          ITEM  SI                    I; # INDEX TO SPEC$ SUM ENTRY   # 
          ITEM  LKOLD                 I; # PREVIOUS VALUE OF S$LK     # 
          ITEM  K            I;        # INDEX TO SPEC$ OR KEY$        #
          ITEM  LENGTH       I;        # LENGTH OF A NON-KEY FIELD     #
          ITEM  NKEYS        I;        # NUMBER OF KEYS                #
          ITEM  OFFSET       I;        # OFFSET OF A NON-KEY FIELD     #
          ITEM  SORTED       B;        # FLAG TO HELP SORT             #
          ITEM SUM       B = TRUE;
          ITEM KEY       B= FALSE;
          ITEM REP          I;         # TEMP. REPETITION COUNTER      #
          ITEM TEMPSUMBIT   I;         # CALCULATE OFFSET FOR          #
                                       # REPEATED SUM FIELDS           #
  
          CONTROL DISJOINT; 
  
          CONTROL INERT;
  
CONTROL EJECT;
  
  
          FOR I = SPEC$1STKEY WHILE I NQ 0 DO 
              BEGIN 
              S$GNIVK(SPEC$KEYTYPE[I],
                      BYTE*SPEC$KEYNBYT[I]+SPEC$KEYNBIT[I], 
                      BYTE*SPEC$KEYBYTE[I]+SPEC$KEYBIT[I],
                      SPEC$KEYASC[I], 
                      LOC(SPEC$CSORDER[SPEC$KEYCS[I]]), 
                      KEY); 
              I = SPEC$NEXTKEY[I];
              END 
  
          $BEGIN
          IF S$LK GR (REC$LK1 + REC$LK2) THEN 
              S$ABORT("S$GNINV-1"); 
          $END
          S$LK = REC$LK1+REC$LK2; 
  
          # IF THE RETAIN OPTION WAS SPECIFIED, APPEND THE             #
          # RECORD ORDINAL TO THE INTERNAL RECORD                      #
  
          IF SPEC$RETAIN THEN 
              S$GNORD(REC$LO1+REC$LO2);    # S$IRRL,S$LK,S$ORSA        #
  
  
#     IF SUM FIELD OPTION CHOSEN, INVERT SUM FIELD                   #
  
          IF SPEC$1STSUM NQ 0 THEN
              BEGIN 
              LKOLD = S$LK; 
              FOR SI = SPEC$1STSUM WHILE SI NQ 0 DO 
                  BEGIN 
                  SPEC$SUMOFF[SI] = 1 + 1 + REC$LR + S$LK;
                                    # 2ND  +1  FOR SUM-DELETE BIT      #
                  # HANDLE THE REPETITION FACTOR FOR SUM FIELDS        #
  
                  FOR REP = 1 STEP 1 UNTIL SPEC$SUMREP[SI] DO 
                      BEGIN 
                      TEMPSUMBIT = SPEC$SUMBIT[SI] +
                          ( SPEC$SMLENE[SI] * ( REP - 1 )); 
                      S$GNIVK(SPEC$SUMTYPE[SI], 
                              SPEC$SMLENE[SI],
                              TEMPSUMBIT, 
                              TRUE, 
                              0,
                              SUM); 
                      IF REP EQ 1 THEN
                          BEGIN 
                          # DOUBLE CHECK ALL SUM LENGTHS #
                          TEMPSUMBIT = S$LK - LKOLD;
                          IF SPEC$SMLENI[SI] NQ TEMPSUMBIT THEN 
                              S$ABORT("S$GNINV-2"); 
                          END 
                      END   # HANDLING OF REPETITION FACTOR            #
                  LKOLD = S$LK; 
                  SI = SPEC$NEXTSUM[SI];
                  END 
              END 
#     IF THIS IS A VARIABLE-LENGTH RECORD,                             #
#         APPEND A LENGTH FIELD                                        #
  
          IF NOT SPEC$FIXED THEN
              S$GNLEN(REC$LL1+REC$LL2, SPEC$MNR);#(S$IRRL,S$LK,S$ORSA)# 
  
#     THE NEXT TASK IS TO APPEND THE NON-KEY PARTS OF THE MINIMUM      #
#      PORTION OF THE EXTERNAL RECORD.  THIS IS DONE BY SORTING        #
#      THE KEY FIELDS ACCORDING TO OFFSET AND THEN STEPPING            #
#      THROUGH THEM APPENDING NON-KEY PARTS.                           #
  
#     ***NOTE***                                                       #
#     ANY CHANGES BELOW MUST BE REFLECTED IN THE                       #
#     CORRESPONDING CODE IN S$GNREV.                                   #
  
          NKEYS = 0;
          FOR K = SPEC$1STKEY WHILE K NQ 0 DO 
              BEGIN 
              IF ((SPEC$KEYTYPE[K] EQ KT$T"DISPLAY") AND SPEC$KEYALT[K])
                        OR (SPEC$KEYTYPE[K] NQ KT$T"DISPLAY")  THEN 
                        # ALTER HAS BEEN SPECIFIED                     #
                  BEGIN 
                  NKEYS = NKEYS + 1;
                  KEY$LENGTH[NKEYS] = BYTE * SPEC$KEYNBYT[K] +
                      SPEC$KEYNBIT[K];
                  KEY$OFFSET[NKEYS] = BYTE * SPEC$KEYBYTE[K] +
                      SPEC$KEYBIT[K]; 
                  END 
              K = SPEC$NEXTKEY[K];
              END 
#     ADD SUM FIELDS TO KEY FIELD ARRAY                               # 
  
          IF SPEC$1STSUM NQ 0 THEN
              BEGIN 
              FOR SI = SPEC$1STSUM WHILE SI NQ 0 DO 
                  BEGIN 
                  NKEYS = NKEYS+1;
                  KEY$OFFSET[NKEYS] = SPEC$SUMBIT[SI];
                  KEY$LENGTH[NKEYS] = SPEC$SMLENE[SI] * 
                      SPEC$SUMREP[SI];
                  SI = SPEC$NEXTSUM[SI];
                  END 
              END 
  
          IF NKEYS GQ 2 THEN
              BEGIN 
              SORTED = FALSE; 
              FOR I=I WHILE NOT SORTED DO 
                  BEGIN 
                  SORTED = TRUE;
                  FOR I = 1 STEP 1 UNTIL NKEYS-1 DO 
                      BEGIN 
                IF (KEY$OFFSET[I] GR KEY$OFFSET[I+1]) OR
                   ((KEY$OFFSET[I] EQ KEY$OFFSET[I+1]) AND
                    (KEY$LENGTH[I] LS KEY$LENGTH[I+1])) THEN
                          BEGIN 
                          KEY$OFFSET[I] == KEY$OFFSET[I+1]; 
                          KEY$LENGTH[I] == KEY$LENGTH[I+1]; 
                          SORTED = FALSE; 
                          END 
                      END 
                  END 
              END 
  
                FOR I = 1 STEP 1 UNTIL 200 DO 
                   BEGIN
                    OVERLAP$OFLN[I] = 0;
                    KEY$OVERLAP[I] = FALSE; 
                    KEY$CONTAIN[I] = FALSE; 
                   END
                IF NKEYS GQ 2 THEN
                BEGIN 
                    FOR I = 1 STEP 1 UNTIL NKEYS DO 
                     OVERLAP$OFLN[I]= KEY$OFFSET[I] + KEY$LENGTH[I]-1;
                    FOR I = 1 STEP 1 UNTIL NKEYS-1 DO 
                    BEGIN 
                       IF (OVERLAP$OFLN[I] GQ OVERLAP$OFLN[I+1]) AND
                          (KEY$OFFSET[I] LQ KEY$OFFSET[I+1]) THEN 
                           KEY$CONTAIN[I+1] = TRUE; 
                    END 
                    FOR I = 1 STEP 1 UNTIL NKEYS-1 DO 
                    BEGIN 
                      IF NOT ( KEY$CONTAIN[I] ) THEN
                      BEGIN 
                       FOR K= I+1 STEP 1 UNTIL NKEYS   DO 
                       BEGIN
                         IF NOT(  KEY$CONTAIN[K])  THEN 
                         BEGIN
                         IF KEY$OFFSET[K] LQ OVERLAP$OFLN[I] THEN 
                            KEY$OVERLAP[K] = TRUE;
                         IF (OVERLAP$OFLN[I] GQ OVERLAP$OFLN[K]) AND
                            (KEY$OFFSET[I] LQ KEY$OFFSET[K]) THEN 
                            BEGIN 
                            KEY$CONTAIN[K] = TRUE;
                            KEY$OVERLAP[K] = FALSE; 
                            END 
                         END
                       END
                      END 
                    END 
                END 
          OFFSET = 0; 
          FOR K = 1 STEP 1 UNTIL NKEYS DO 
              BEGIN 
                  IF NOT KEY$CONTAIN[K] THEN
                  BEGIN 
                  IF NOT KEY$OVERLAP[K] THEN
                  BEGIN 
                  LENGTH = KEY$OFFSET[K] - OFFSET;
                  # GENERATE- COPY NON-KEY PART TO INTERNAL RECORD     #
                  S$GNCNI(OFFSET,LENGTH);#(S$IRRL,S$LK,S$LR,S$OREC, 
                                                                S$ORSA)#
                  OFFSET = OFFSET + LENGTH + KEY$LENGTH[K]; 
                  END 
                  ELSE
                  OFFSET = KEY$OFFSET[K] + KEY$LENGTH[K]; 
                  END 
              END 
          IF SPEC$FIXED THEN
              LENGTH = BYTE*SPEC$FIXLEN - OFFSET; 
          ELSE
              LENGTH = BYTE*SPEC$MNR - OFFSET;
          S$GNCNI(OFFSET,LENGTH);#(S$IRRL,S$LK,S$LR,S$OREC,S$ORSA)# 
  
#     ***NOTE***                                                       #
#     END OF CHANGES NEEDING TO BE REFLECTED IN S$GNREV.   @# 
  
#     THE FINAL TASK IS TO COPY THE REMAINDER OF THE                   #
#      VARIABLE-LENGTH RECORD TO THE INTERNAL RECORD.                  #
  
          IF NOT SPEC$FIXED THEN
              S$GNCVI(SPEC$MNR);#(S$IRRL,S$LK,S$LR,S$OREC,S$ORSA)#
  
          # FINISH UP INVERSION AND PERFORM MERGE-VERIFY  # 
          # IF IT IS WANTED                               # 
  
          IF SPEC$FIXED THEN
              S$GNIV9;
          ELSE
              S$GNIV8;
  
          END  # S$GNINV #
          TERM
