*DECK CBCKBUF 
      PROC CBCKBUF(BLOCK,WANT); 
      BEGIN 
 #
* *   CBCKBUF--DDL PASS 2 BUFFER MANAGER
* *   C O GIMBER                                 10.14.74 
* 
* DC  PURPOSE 
* 
*     CBCKBUF PROVIDES BUFFER MANAGEMENT FOR BASED ARRAYS.  IT WILL 
*     INCREASE THE SIZE OR DECREASE THE SIZE OF ARRAYS AND MOVE THEM
*     IN MANAGED MEMORY SPACE.
*     IF IT IS CALLED FOR AN ARRAY WHICH IT IS NOT CURRENTLY MANAGING,
*     IT WILL ALLOCATE SPACE FOR IT AND SET THE BASED ARRAY POINTER 
*     TO THE SPACE ALLOCATED. 
*     IF IT IS CALLED TO INCREASE OR DECREASE THE SIZE OF AN ARRAY, 
*     IT WILL DO IT KEEPING THE INTEGRITY OF THE DATA IN THE ARRAY. 
*     IT MAY BE NECESSARY FOR IT TO MOVE ARRAYS WHEN IT PERFORMS
*     ITS OPERATION ON ANOTHER ARRAY. 
* 
* DC  ENTRY CONDITIONS
* 
*     PARAMETERS
*       BLOCK = BASED ARRAY POINTER 
*       WANT = LENGTH OF ARRAY DESIRED
 #
  
# PASSED PARAMTERS# 
      ITEM BLOCK;            #BASED ARRAY POINTER#
      ITEM WANT;             #LENGTH DESIRED# 
  
# EXTERNAL REFERENCES#
      XREF ITEM DDLMEM;      #LWA+1 OF MEMORY#
      XREF ITEM DDLSU ;      # STORAGE USED (MIN FL NEEDED)            #
      XREF ITEM MAXFL ;      # MAX FIELD LENGTH ALLOWED                #
      XREF ITEM SUBSIZE;     # LENGTH OF SUBS ARRAY                    #
      XREF PROC ABRT1 ;      # ABORT RUN WITH INSUFF FIELD LENGTH MSG. #
      XREF PROC CBERROR;       #DDL PASS 2 ERROR HANDLER# 
      XREF PROC MEMORY ;     # ISSUE FIELD LENGTH REQUEST              #
  
#     LOCAL DECLARATIONS# 
  
      ITEM DELTA;                      #WORDS BETWEEN ARRAYS# 
      BASED ARRAY FROM;                #FROM ADDRESS FOR ARRAY MOVE#
        ITEM FROMWORD;
      ITEM I;                          #FOR LOOP INDEX# 
      ITEM INDEX;                      #INDEX INTO INFO ARRAY#
      ITEM INDEXI;                     #INDEX INTO INFO ARRAY OF# 
                                       #ARRAY BEING CHANGED#
      ITEM INDEXL = 0;                 #INDEX OF LAST ENTRY IN INFO ARR#
      ITEM J;                          # FOR LOOP INDEX                #
      BASED ARRAY INFO;                #CONTAINS INFO FOR MANAGED ARRAY#
                                       #THIS IS THE FIRST MANAGED ARRAY#
                                       #(FWA[INDEXL+1])=LWA+1 OF# 
                                       #  MANAGED MEMORY# 
        BEGIN 
        ITEM LENGTH (0,0,18);          #LENGTH OF ARRAY#
        ITEM POINTER (0,18,18);        #LOCATION OF POINTER#
        ITEM FWA (0,42,18);            #FWA OF ARRAY# 
        END 
      BASED ARRAY RA;                  #ARRAY FOR REFERENCING MEMORY# 
        BEGIN 
        ITEM WORD ; 
        ITEM RA65 U(O"65",42,18); 
        END 
*CALL COMSUBS 
      BASED ARRAY TO;                  #TO ADDRESS FOR ARRAY MOVES# 
        ITEM TOWORD;
      CONTROL EJECT;
      P<RA> = 0;
 #
*     FIND ARRAY IN INFO TABLE
*     INCREASE ARRAY SIZE IF IT CAN BE DONE WITHOUT REDISTRIBUTION
 #
      FOR INDEXI=1 STEP 1 UNTIL INDEXL DO 
        IF POINTER[INDEXI] EQ LOC(BLOCK) THEN 
          BEGIN 
          IF FWA[INDEXI]+WANT GR FWA[INDEXI+1] THEN 
            GOTO REDISTRIBUTE;
          IF  WANT LS LENGTH[INDEXI]    # IF DECREASE IN SIZE          #
          THEN ASU ;                    # ACCUMULATE STORAGE USED      #
          LENGTH[INDEXI] = WANT;
          RETURN; 
          END 
 #
*     IF ARRAY NOT IN INFO TABLE THEN ADD IT
*     IF TABLE EMPTY THEN SPECIAL CASE FOR FIRST CALL 
 #
      INDEXL = INDEXL+1;
      INDEXI = INDEXL;
      P<INFO> = RA65[0] - 10; 
      FWA[0] = LOC(INFO); 
      LENGTH[0] = INDEXL + 2; 
      FWA[INDEXL+1] = B<0,30>DDLMEM - SUBSIZE;
      POINTER[INDEXI] = LOC(BLOCK); 
      FWA[INDEXI] = BLOCK;
      IF INDEXL LQ 2 THEN 
        LENGTH[INDEXL] = WANT;
      ELSE
        LENGTH[INDEXL] = 0; 
 #
*     COMPACT ALL ARRAYS IN UPPER PART OF MANAGED MEMORY
 #
REDISTRIBUTE: 
      FOR INDEX=1 STEP 1 UNTIL INDEXL DO
        BEGIN 
        P<TO> = FWA[INDEX-1]+LENGTH[INDEX-1]; 
        P<FROM> = FWA[INDEX]; 
        FWA[INDEX] = LOC(TO); 
        WORD[POINTER[INDEX]] = FWA[INDEX] ; 
        FOR I=0 STEP 1 WHILE I LS LENGTH[INDEX] DO
          TOWORD[I] = FROMWORD[I];
        END 
 #
*     CALCULATE DELTA=WORDS BETWEEN ARRAYS
*     IF INSUFFICIENT MEMORY THEN ERROR 
 #
      LENGTH[0] = INDEXL + 3; 
      DELTA = FWA[INDEXL+1]-(FWA[INDEXL]+LENGTH[INDEXL])
        -(WANT-LENGTH[INDEXI]) - 1; 
      IF DELTA LS 0 THEN
        BEGIN 
          INDEX = ((B<0,30>DDLMEM + SUBSIZE - DELTA + 63) / 64) * 64; 
          IF  INDEX GR MAXFL THEN 
            BEGIN 
              DDLSU = INDEX ;          # FIELD LENGTH NEEDED           #
              CBERROR (310,0) ;        # EXCEEDS MAX ALLOWED           #
              ABRT1 ;                  # SO ABORT JOB                  #
            END 
          MEMORY (INDEX) ;             # REQUEST FIELD LENGTH          #
          I = B<0,30>DDLMEM - P<SUBS>;  # CALCULATE DISTANCE BTWN NEW  #
                                        # LAST WORD AND END OF SUBS    #
          P<SUBS> = INDEX;              # SET SUBS TO NEW END OF FL    #
          FOR J = 0 STEP -1 UNTIL -(SUBSIZE - 1)
          DO
            BEGIN                       # MOVE SUBS ARRAY DOWN TO NEW  #
            SUBSWRD[J] = SUBSWRD[J-I];  # END OF FIELD LENGTH, 1 WORD  #
            SUBSWRD[J-I] = 0;           # AT A TIME                    #
            END 
          DELTA = DELTA + INDEX - SUBSIZE - FWA[INDEXL+1];
          FWA[INDEXL+1] = INDEX - SUBSIZE;
        END 
      LENGTH[INDEXI] = WANT;
      DELTA = DELTA / INDEXL; 
 #
*     EXPAND ARRAYS IN MANAGED MEMORY 
 #
      FOR INDEX=INDEXL STEP -1 UNTIL 1 DO 
        BEGIN 
        P<FROM> = FWA[INDEX]; 
        P<TO> = FWA[INDEX+1]-LENGTH[INDEX]-DELTA; 
        FWA[INDEX] = LOC(TO); 
        WORD[POINTER[INDEX]] = FWA[INDEX] ; 
        FOR I=LENGTH[INDEX]-1 STEP -1 UNTIL 0 DO
          TOWORD[I] = FROMWORD[I];
        END 
      RETURN; 
  
  
  
      XDEF PROC ASU ; 
      PROC ASU ;
      BEGIN 
 #
* *   ASU - ACCUMULATE STORAGE USED . 
* *   R H GOODELL.                               77/05/24.
* 
* DC  PURPOSE.
* 
*     *ASU* TOTALS THE LENGTHS OF ALL OF THE TABLES MANAGED 
*     BY *CBCKBUF* AND UPDATES *DDLSU* (STORAGE USED).
 #
  
        ITEM S ;
  
        S = FWA[0] ;
        FOR INDEX = 0 STEP 1 UNTIL INDEXL DO
          S = S + LENGTH[INDEX];
        IF S + SUBSIZE GR DDLSU 
        THEN
          DDLSU = S + SUBSIZE;
        RETURN ;
      END 
  
      END 
      TERM; 
