/****************************************************************************
**
**  Name:  chunk.c
**
**  Description:
**     Internal to memory manager: "heap.c".  Management routines for
**     any 64K memory block.
**
**  Status:  CODED
**
**  $Log:   S:/tbird/mt2_68k/malloc/chunk.c_v  $
** 
**    Rev 1.0   13 Feb 1997 08:51:58   gene
** Initial revision.
** 
**    Rev 1.0   07 Sep 1995 10:41:38   gene
** Initial revision.
** 
**    Rev 1.10   12 Oct 1992 09:58:44   doug
** give more specific error message when trying to free with a bad address
** pointer
** 
**    Rev 1.9   30 Aug 1992 11:25:32   doug
** works now
** 
**    Rev 1.8   29 Aug 1992 17:33:36   doug
** clean compile
** 
**    Rev 1.7   29 Aug 1992 17:08:02   kend
** Added a couple of externs I forgot.
** 
**    Rev 1.6   29 Aug 1992 16:52:20   kend
** Update for Sanity Checks
** 
**    Rev 1.5   14 May 1992 14:19:28   courtney
** MessageBox calls now call ErrDisplayError, which gets the text
** of the string without littering the code in numerous places.
** 
**    Rev 1.4   18 Mar 1992 15:23:44   kend
** Merge loop was searching in wrong direction!
** 
**    Rev 1.3   16 Mar 1992 07:27:14   kend
** fixed bug that caused heap corruption error to be reported
** 
**    Rev 1.2   13 Mar 1992 12:53:40   kend
** Now clears free list and displays message on detection of heap curruption
** 
**    Rev 1.1   06 Mar 1992 11:52:56   kend
** Fixed bug in CFree where one of the pointers was being dropped
** when merging free memory back together.
** 
**    Rev 1.0   19 Aug 1991 15:49:12   kend
** Initial revision.
**
**  $Header:   S:/tbird/mt2_68k/malloc/chunk.c_v   1.0   13 Feb 1997 08:51:58   gene  $
**
**  Copyright (C) 1991 Microtek International.  All rights reserved.
**
** IMPLEMENTATION NOTES
*> Free memory blocks are chained together as a doubly linked list.  This
**  list is memory ordered.
*> All blocks are bounded on either end by their length-in-bytes + alloc-tag.
*> Size is # bytes between boundary tags.  It eXcludes next & previous ptrs.
*> First Fit allocation is used.
*> See "An Implementation of New and Dispose using Boundary Tags", 
**  by Branko J. Gerovac, Pascal News #19, September 1980.
**
** BASIC ASSUMPTION
*> 64 KB block is alligned at 64K memory address (i.e. no segment overflow
**  on unsigned arithmetic within 64K).
**
** NOTE ALSO:
** Typical max incremental overhead of allocation is 11 (2 tags + round-up).
** Minimum allocation is 8 bytes (=> 16 bytes used total).
**
*****************************************************************************/

                       /****************************
                        *                          *
                        *       INCLUDE FILES      *
                        *                          *
                        ****************************/
#ifndef  _BASEWIND_
#include "basewind.h"
#endif


#ifndef  _chunk_
#include "chunk.h"
#endif

#ifndef _HOSTERRS_
#include "hosterrs.h"
#endif

                       /****************************
                        *                          *
                        *     LOCAL DEFINITIONS    *
                        *                          *
                        ****************************/

#define LONG_SIZE                sizeof(U32)

/* min and max allocation sizes; min alloc == 2 * sizeof(long_pointer) */
#define MIN_ALLOC                (2 * LONG_SIZE)
#define MAX_FREE_BYTES           ((64 * 1024L) - (7 * LONG_SIZE))

#define TAG_OVERHEAD             (2 * LONG_SIZE)

typedef struct  {
   U32              info ;    /* conforms to 1st field of CHUNK_TYPE */
} TAG_TYPE ;



typedef TAG_TYPE FAR * TAG_PTR ;


typedef struct chunk_type {   /* tag for the head of a free chunk */
   U32              info ;    /* # of bytes alloc'ed in chunk + lo-bit tag */
   struct chunk_type FAR * next ;    /* doubly linked list of free blocks */
   struct chunk_type FAR * previous ;
} CHUNK_TYPE ;

typedef CHUNK_TYPE FAR * CHUNK_PTR ;


/* 
 * Chunk info contains size (always even) and allocated (bit 1 iff alloc'ed)
 */

#define BSIZE( c_ptr )             (U32)((c_ptr)->info & 0xFFFFFFFE)
#define SET_SIZE( c_ptr, size ) \
              (c_ptr)->info = ((size) | (((c_ptr)->info) & 0x00000001))
#define ALLOCED_P( c_ptr )       (BOOLEAN)((c_ptr)->info & 0x00000001)
#define FREE_P( c_ptr )          ( ! ALLOCED_P( c_ptr ) )
#define ALLOCATE(  c_ptr )       ((c_ptr)->info |= 0x00000001)
#define FREE( c_ptr )            ((c_ptr)->info &= 0xFFFFFFFE)


                       /****************************
                        *                          *
                        *    EXTERNAL VARIABLES    *
                        *                          *
                        ****************************/

#ifdef DEBUG
extern U32 amountAllocated ;
extern U32 amountFreed ;
#endif

                       /****************************
                        *                          *
                        *     LOCAL PROTOTYPES     *
                        *                          *
                        ****************************/

/* None */

                       /****************************
                        *                          *
                        *      EXECUTABLE CODE     *
                        *                          *
                        ****************************/

/****************************************************************************
**
**  CFree  -- free chunk pointer allocated via CAlloc
**
*****************************************************************************/
RETCODE CFree( LPSTR chunkAddr, LPSTR memoryAddr ) {
   CHUNK_PTR  memoryPtr, LAPtr, UAPtr, chunkBasePtr ;
   TAG_PTR    aTagPtr ;
   BOOLEAN    merged_P ;

   chunkBasePtr = (CHUNK_PTR)chunkAddr ;

#ifdef DEBUG
   /* check tag at base */
   if ( chunkBasePtr->info != (MIN_ALLOC + 1) ) {
      chunkBasePtr->next = chunkBasePtr->previous = chunkBasePtr ;
      ErrDisplayError(ER_HEAP_CORRUPT, FORCE_POPUP);
      return( ER_HEAP_CORRUPT ) ;
   }
   /* Note: heap.c checks for (pointer within segment) */
#endif 


   /* STRATEGY:
    *
    * UA = upper adjacent; LA = lower adjacent (Upper=>higher mem location)
    *
    * if LA is free merge with LA  -- see picture, below
    * if UA is free merge with UA  -- see picture, below
    * if not merged, find proper place in free list & splice in; reset tags
    */

    /* pointer points just after tag */
   memoryPtr = (CHUNK_PTR)((U32)memoryAddr - LONG_SIZE) ;
   merged_P = FALSE ;

#ifdef DEBUG
   /* sanity check -- leave in? */
   if (BSIZE( memoryPtr ) > (64 * 1024L)) {
      chunkBasePtr->next = chunkBasePtr->previous = chunkBasePtr ;
      /* post error alert */
      ErrDisplayError(ER_HEAP_CORRUPT, FORCE_POPUP);
      return( ER_HEAP_CORRUPT ) ;
   }
   if (FREE_P( memoryPtr )) {
      /* post error alert */
      ErrDisplayError(ER_HEAP_BAD_FREE_ADDRESS, FORCE_POPUP);
      return( ER_HEAP_BAD_FREE_ADDRESS ) ;
   }
   amountFreed += BSIZE( memoryPtr ) ;
#endif

   /* end tag for Lower Adjacent */
   aTagPtr = (TAG_PTR)( (U32)memoryPtr - LONG_SIZE ) ;
   /* chunk head for Upper Adjacent */
   UAPtr   = (CHUNK_PTR)
              ( (U32)memoryPtr + BSIZE(memoryPtr) + TAG_OVERHEAD ) ;

#ifdef DEBUG
   /* sanity checks */
   if ( (BSIZE(UAPtr) > (64 * 1024L)) || (BSIZE(aTagPtr) > (64 * 1024L)) ) {
      chunkBasePtr->next = chunkBasePtr->previous = chunkBasePtr ;
      /* post error alert */
      ErrDisplayError(ER_HEAP_CORRUPT, FORCE_POPUP);
      return( ER_HEAP_CORRUPT ) ;
   }
#endif


   /* LA free? */
   if ( FREE_P(aTagPtr) ) {

      /* Merge with lower neighbor.  Splice ok, just adjust size. */
      /* find LA struct from length */
      LAPtr = (CHUNK_PTR)
                ( (U32)aTagPtr - (BSIZE(aTagPtr) + LONG_SIZE) ) ;

      if ( (LAPtr->info != aTagPtr->info) || ALLOCED_P(LAPtr) ) {
         chunkBasePtr->next = chunkBasePtr->previous = chunkBasePtr ;
         /* post error alert */
         ErrDisplayError(ER_HEAP_CORRUPT, FORCE_POPUP);
         return( ER_HEAP_CORRUPT ) ;  /* !!HEAP CORRUPT!! */
      }
      /* set lower (top) tag */
      SET_SIZE( LAPtr, (BSIZE(LAPtr) + BSIZE(memoryPtr) + TAG_OVERHEAD) ) ;
      
      /* set higher (bottom) tag; old memoryPtr tag now LAPtr tag */
      aTagPtr = (TAG_PTR)( (U32)memoryPtr + BSIZE(memoryPtr) + LONG_SIZE ) ;
      aTagPtr->info = LAPtr->info ;
      
      /* rebase for possible merge next */
      memoryPtr = LAPtr ;      
      
      merged_P = TRUE ;
   }

   /* Find upper memory (bottom) tag of Upper Adjacent memory chunk */
   aTagPtr = (TAG_PTR)( (U32)UAPtr + BSIZE(UAPtr) + LONG_SIZE ) ;

   /* UA free? */
   if ( FREE_P(UAPtr) ) {
      /* merge with upper adjacent neighbor. */

      if ( (UAPtr->info != aTagPtr->info) || ALLOCED_P(aTagPtr) ) {
         chunkBasePtr->next = chunkBasePtr->previous = chunkBasePtr ;
         /* post error alert */
         ErrDisplayError(ER_HEAP_CORRUPT, FORCE_POPUP);
         return( ER_HEAP_CORRUPT ) ;  /* !!HEAP CORRUPT!! */
      }
      
      /* splice into free list */
      if (merged_P) { /* merged -- some LA values ok */
        memoryPtr->next = UAPtr->next ; 
        /* previous and previous->next are ok (from LA) */
        memoryPtr->next->previous = memoryPtr ; 
      }
      else {  /* not merged -- use UA values & do some more work */
         memoryPtr->next     = UAPtr->next ; 
         memoryPtr->previous = UAPtr->previous ;
         memoryPtr->previous->next = memoryPtr ;
         memoryPtr->next->previous = memoryPtr ; 
      }
      
      /* set lower memory (top) tag */
      SET_SIZE( memoryPtr,
                (BSIZE(memoryPtr) + BSIZE(UAPtr) + TAG_OVERHEAD) ) ;
      FREE( memoryPtr ) ;
      
      /* set upper memory (bottom) tag */
      aTagPtr->info = memoryPtr->info ;

      merged_P = TRUE ;

#ifdef DEBUG
      if ( aTagPtr != 
           (TAG_PTR)( (U32)memoryPtr + BSIZE(memoryPtr) + LONG_SIZE )
         ) {
         chunkBasePtr->next = chunkBasePtr->previous = chunkBasePtr ;
         /* post error alert */
         ErrDisplayError(ER_HEAP_CORRUPT, FORCE_POPUP);
         return( ER_HEAP_CORRUPT ) ;
      }
#endif

   }
   
   /*
    * Note: the following code block is the only place which cares which
    * way previous & next point.  It is also the only place where previous
    * and next are set, so feel free to change the order!           
    */

   if ( !merged_P ) { /* find place to fit */

      /* mark tags as free -- size already ok */
      FREE( memoryPtr ) ;
      aTagPtr = (TAG_PTR)( (U32)memoryPtr + BSIZE(memoryPtr) + LONG_SIZE ) ;
      FREE( aTagPtr ) ;
     
      /* search from high memory to low memory */
      for ( LAPtr = chunkBasePtr->previous ;
            LAPtr > memoryPtr   ;  /* n.b.: ok within same DS */
            LAPtr = LAPtr->previous
          ) {
         ; /* loop */
      }
      
      /* we have LA for free memory block below our block; splice ours in */
      memoryPtr->previous = LAPtr ;       /* previous points lower */
      memoryPtr->next     = LAPtr->next ; /* next points higher */
      LAPtr->next         = memoryPtr ;
      memoryPtr->next->previous = memoryPtr;
   }

   return( SUCCESS );       /* Whew! */
}




/*
 *  Before Merge of LA:
 *
 *                      ~     . . .      ~   
 *                      |                |
 *                      ------------------          ^
 *                      |   size=X     F |          |
 *                   +--|   next         |          |
 *  Lower Adjacent   |  |   previous     | ---------+
 *                   |  |   size=X     F |
 *                   |  ------------------
 *                   |  |   Size=Y     F |
 *                   |  |                |      
 *                   |  |                |      LOWER MEMORY
 *                   |  |  Newly         |           |
 *                   |  |    Freed...    |           |
 *                   |  |                |           V
 *                   |  |                |      HIGHER MEMORY
 *                   V  |   Size=Y     F |
 *                      ------------------
 *                      |                |
 *                      ~     . . .      ~   
 *
 *===================== 
 * After merge with LA:
 *
 *                      ~     . . .      ~   
 *                      |                |
 *                      ------------------          ^
 *                      | size=X+Y+8   F |          |
 *                   +--|   next         |          |
 *  Lower Adjacent   |  |   previous     | ---------+
 *                   |  |                |
 *                   |  |                |
 *                   |  |                |
 *                   |  |                |      
 *                   |  |                |      LOWER MEMORY
 *                   |  |  Newly         |           |
 *                   |  |    Freed...    |           |
 *                   |  |                |           V
 *                   |  |                |      HIGHER MEMORY
 *                   V  | size=X+Y+8   F |
 *                      ------------------
 *                      |                |
 *                      ~     . . .      ~   
 *
 */




/*
 * Before Merge of UA:
 *
 *                      ~     . . .      ~   
 *                      |                |
 *                      ------------------
 *                      |   Size=Y     F |
 *                      |                |      
 *                      |                |      LOWER MEMORY
 *                      |  Newly         |           |
 *                      |    Freed...    |           |
 *                      |                |           V
 *                      |                |      HIGHER MEMORY
 *                      |   Size=Y     F |
 *                      ------------------
 *                      |   size=Z     F |          ^
 *                   +--|   next         |          |
 *  Upper Adjacent   |  |   previous     | ---------+
 *                   |  |                |
 *                   |  |   size=Z     F |
 *                   |  ------------------
 *                   V  |                |
 *                      ~     . . .      ~   
 *
 *===================== 
 * After merge with UA:
 *                      ~     . . .      ~   
 *                      |                |
 *                      ------------------
 *                      | size=Z+Y+8   F |          ^
 *                   +--|   next         |          |
 *                   |  |   previous     | ---------+
 *                   |  |                |      
 *                   |  |                |      
 *                   |  |  Newly         |      LOWER MEMORY
 *                   |  |    Freed...    |           |
 *                   |  |                |           V
 *                   |  |                |      HIGHER MEMORY
 *                   |  |                |
 *                   |  |                |
 *                   |  |                |           
 *                   |  |                |           
 *  Upper Adjacent   |  |                |           
 *                   |  |                |
 *                   |  | size=Z+Y+8   F |
 *                   |  ------------------
 *                   V  |                |
 *                      ~     . . .      ~   
 *
 */


/****************************************************************************
**
**  CMalloc -- allocate chunk of numBytes from block; return long pointer or 0
**
*****************************************************************************/
LPSTR CMalloc ( LPSTR chunkAddr, U16 numBytes ) {
   CHUNK_PTR  chunkBasePtr, scanPtr ;
   TAG_PTR    aTagPtr, newPtr ;


   chunkBasePtr = (CHUNK_PTR)chunkAddr ;

#ifdef DEBUG
   /* check tag at base */
   if ( chunkBasePtr->info != (MIN_ALLOC + 1) ) {
      ErrDisplayError(ER_HEAP_CORRUPT, FORCE_POPUP);
      return( (LPSTR) 0 ) ;
   }
#endif 
   
   numBytes = ( (numBytes + 3) & 0xFFFC ) ; /* round up to even quad */

   if ( numBytes == 0 ) {
      return( (LPSTR) 0 ) ;  /* can't alloc above 64K-3 bytes */
   }

   if (numBytes < MIN_ALLOC) {
      numBytes = MIN_ALLOC ;
   }
   
   /* "First fit" allocation -- note: can search in either direction */

   for ( scanPtr = chunkBasePtr->previous ;
         (scanPtr->info < numBytes) && (scanPtr != chunkBasePtr) ;
         scanPtr = scanPtr->previous
       ) {
       ; /* loop */
   }

   if ( scanPtr == chunkBasePtr ) {

      return ( (LPSTR) 0 ) ;  /* can't alloc */
   }
   
   /* found free block of sufficient size to do allocation */
   
   if ( BSIZE(scanPtr) <= (numBytes + TAG_OVERHEAD + MIN_ALLOC) ) {

      /* consider it an exact fit -- allocate the whole block */
      
      /* set lower memory tag */
      ALLOCATE( scanPtr ) ;  

      /* set upper memory tag */
      aTagPtr  = (TAG_PTR)( (U32)scanPtr + BSIZE(scanPtr) + LONG_SIZE ) ;
      aTagPtr->info = scanPtr->info ;

#ifdef DEBUG
      amountAllocated += BSIZE( scanPtr ) ;
#endif

      /* splice chunk out of free list */
      scanPtr->next->previous = scanPtr->previous ;
      scanPtr->previous->next = scanPtr->next ;
      
      /* return pointer to store just after size tag */
      return( (LPSTR)((U32)scanPtr + LONG_SIZE) ) ;

   } 
   else { /* do block split -- alloc from high mem */

      /* reduce size of free chunk */
      SET_SIZE( scanPtr, (BSIZE(scanPtr) - (numBytes + TAG_OVERHEAD)) ) ;

      /* make new tag for other end */
      aTagPtr       = (TAG_PTR)( (U32)scanPtr + BSIZE(scanPtr) + LONG_SIZE ) ;
      aTagPtr->info = scanPtr->info ;
      
      /* alloc'ed chunk is just above end tag of reduced free chunk */
      newPtr = aTagPtr + 1 ;
      SET_SIZE( newPtr, numBytes ) ;
      ALLOCATE( newPtr ) ;

#ifdef DEBUG
      amountAllocated += BSIZE( newPtr ) ;
#endif

      /* set tag for other end of alloc'ed chunk */
      aTagPtr       = (TAG_PTR)( (U32)newPtr + numBytes + LONG_SIZE ) ;
      aTagPtr->info = newPtr->info ;

      /* return pointer to store just after size tag */
      return( (LPSTR)((U32)newPtr + LONG_SIZE) ) ;

   }
}


/* Before block split
 *                      ~     . . .      ~   
 *                      |                |
 *                      ------------------
 *                      | size=X       F |          ^
 *                   +--|   next         |          |
 *                   |  |   previous     | ---------+
 *                   |  |                |      
 *                   |  |                |      
 *                   |  |                |      LOWER MEMORY
 *                   |  |    FREE        |           |
 *                   |  |                |           V
 *                   |  |                |      HIGHER MEMORY
 *                   |  |                |
 *                   |  |                |
 *                   |  |                |           
 *                   |  |                |           
 *                   |  |                |           
 *                   |  |                |
 *                   |  | size=X       F |
 *                   |  ------------------
 *                   V  |                |
 *                      ~     . . .      ~   
 *==================
 * After block split
 *       
 *                      ~     . . .      ~   
 *                      |                |
 *                      ------------------
 *                      | size=X-numB-8 F|          ^
 *                   +--|   next         |          |
 *                   |  |   previous     | ---------+
 *                   |  |                |      
 *                   |  |                |      
 *                   |  |   FREE         |      LOWER MEMORY
 *                   |  |                |           |
 *                   |  |                |           V
 *                   |  | size=X-numB-8 F|      HIGHER MEMORY
 *                   |  ------------------
 *                   |  | size=numB    A | 
 *                   |  |                |<- Pointer returned from CMalloc
 *                   |  |                |           
 *                   |  |   ALLOC'ed     |           
 *                   |  |                |
 *                   |  | size=numB    A |
 *                   |  ------------------
 *                   V  |                |
 *                      ~     . . .      ~   
 */

/****************************************************************************
**
**  CVerify -- Verify Sanity of this Chunk
**
*****************************************************************************/
RETCODE CVerify ( LPSTR chunkAddr ) {
   CHUNK_PTR  chunkBasePtr, scanPtr ;
   TAG_PTR    aTagPtr, endTagPtr ;
/********** comparison of huge pointers is broken ******
   U8 HUGE   *minAddress ;
   U8 HUGE   *maxAddress ;
**************/

   chunkBasePtr = (CHUNK_PTR)chunkAddr ;
/********** comparison of huge pointers is broken ******
   minAddress   = (U8 HUGE *)chunkAddr ;
   maxAddress   = (U8 HUGE *)(chunkAddr + SEGMENT_SIZE) ;   
**************/

   /* check tag at base */
   if ( BSIZE(chunkBasePtr) != MIN_ALLOC ) {
      ErrDisplayError(ER_HEAP_CORRUPT, FORCE_POPUP);
      return( ER_HEAP_CORRUPT ) ;
   }

   /*
    *   Check tags for sanity 
    */


   endTagPtr  = (TAG_PTR)( (U32)chunkAddr + ((64 * 1024L) - LONG_SIZE) ) ;
   for ( aTagPtr = (TAG_PTR)( (U32)chunkAddr ) ;
         (U32)aTagPtr < (U32)endTagPtr ;
         aTagPtr = (TAG_PTR)((U32)aTagPtr + BSIZE(aTagPtr) + TAG_OVERHEAD) 
       ) {
      if ( (U32)aTagPtr < (U32)endTagPtr ) {
         if ( ((U32)aTagPtr < (U32)chunkAddr) ||
            ((U32)aTagPtr > (U32)endTagPtr) ||
            (aTagPtr->info != 
               ((TAG_PTR)((U32)aTagPtr + BSIZE(aTagPtr) + LONG_SIZE))->info) 
             ) {
             ErrDisplayError(ER_HEAP_CORRUPT, FORCE_POPUP);
             return( ER_HEAP_CORRUPT ) ;
      }  }
    }
   
   

/********** comparison of huge pointers is broken ******   
   /*
    *  Check free list: forward chain 
    *@

   for ( scanPtr = chunkBasePtr->next ;
        (scanPtr->info < numBytes) && (scanPtr != chunkBasePtr) ;
         scanPtr = scanPtr->next
       ) {
         if (minAddr > scanPtr) || (scanPtr > maxAddress) {
            ErrDisplayError(ER_HEAP_CORRUPT, FORCE_POPUP);
            return( ER_HEAP_CORRUPT ) ;
         }
   }

   if ( scanPtr != chunkBasePtr ) {
      ErrDisplayError(ER_HEAP_CORRUPT, FORCE_POPUP);
      return ( ER_HEAP_CORRUPT ) ;
   }


   /*
    *  Check free list: reverse chain 
    *@

   for ( scanPtr = chunkBasePtr->previous ;
        (scanPtr->info < numBytes) && (scanPtr != chunkBasePtr) ;
         scanPtr = scanPtr->previous
       ) {
         if (minAddr > scanPtr) || (scanPtr > maxAddress) {
            ErrDisplayError(ER_HEAP_CORRUPT, FORCE_POPUP);
            return( ER_HEAP_CORRUPT ) ;
         }
   }

   if ( scanPtr != chunkBasePtr ) {
      ErrDisplayError(ER_HEAP_CORRUPT, FORCE_POPUP);
      return ( ER_HEAP_CORRUPT ) ;
   }
***********************/

   return( SUCCESS ) ;
   
}

/****************************************************************************
**
**  EmptyChunk_P -- Is the chunk empty of alloc'ed storage?
**
*****************************************************************************/
BOOLEAN EmptyChunk_P ( LPSTR chunkAddr ) {
   CHUNK_PTR baseChunkPtr, searchPtr ;
   
   
   baseChunkPtr = (CHUNK_PTR)chunkAddr ;
   
   if ( BSIZE(baseChunkPtr) != MIN_ALLOC ) {
      return( FALSE );  /* !!heap corrupt!! */
   }

   if (baseChunkPtr->next != baseChunkPtr->previous) {
      return( FALSE );
   }

   searchPtr = baseChunkPtr->next ;
   if ( BSIZE(searchPtr) == MAX_FREE_BYTES ) {
      return( TRUE ) ;
   }
   
   return( FALSE ) ;
}


/****************************************************************************
**
**  FinalizeChunk -- do any requisite cleanup of 64K block.
**
*****************************************************************************/
RETCODE FinalizeChunk ( LPSTR chunkAddr ) {

   /* no work to do  -- clean memspace just in case... */
   return( InitChunk( chunkAddr ) ) ;
}


/****************************************************************************
**
**  InitChunk  -- initialize, once, a 64 KB chunk of storage.
**
*****************************************************************************/
RETCODE InitChunk ( LPSTR chunkAddr ) {
   CHUNK_PTR  chunkBasePtr ;
   CHUNK_PTR  chunkFreePtr ;
   TAG_PTR    aTagPtr ;

   
   chunkBasePtr = (CHUNK_PTR)chunkAddr ;
   chunkFreePtr = (CHUNK_PTR)
                   ((U32)chunkBasePtr + TAG_OVERHEAD + MIN_ALLOC) ;
   
   SET_SIZE( chunkBasePtr, MIN_ALLOC );   /* size of next + previous */
   ALLOCATE( chunkBasePtr ) ;             /* mark header as allocated */

   SET_SIZE( chunkFreePtr, MAX_FREE_BYTES ) ;
   FREE( chunkFreePtr ) ;
   
   chunkBasePtr->next = chunkBasePtr->previous = chunkFreePtr ;
   chunkFreePtr->next = chunkFreePtr->previous = chunkBasePtr ;
   
   /* end tag for chunkBasePtr @ 4th long */
   aTagPtr       = (TAG_PTR)((U32)chunkAddr + (3 * LONG_SIZE)) ;
   aTagPtr->info = chunkBasePtr->info ;


   /* end tag for entire chunk */
   aTagPtr       = (TAG_PTR)( (U32)chunkAddr + ((64 * 1024L) - LONG_SIZE) ) ;
//   SET_SIZE( aTagPtr, 0L ) ;
//   ALLOCATE( aTagPtr ) ;
   aTagPtr->info = 0x00000001 ;  /* allocated; size=0 */

   /* end tag for free area */
   aTagPtr  -= 1 ;
   aTagPtr->info = chunkFreePtr->info ;

   return ( SUCCESS );


/*
 * Memory block now looks like this:
 *   (Nota Bene: size is # bytes between tags).
 *
 *                      ------------------
 *         base + 0 --> |   size=8     A |
 *           ^  ^       |   next         |--------------->+
 *           |  |       |   previous     |------------->+ |
 *           |  |       |   size=8     A |              | |     
 *           |  |       ------------------              V |
 *           |  |       |  size=64K-28  F|<---------------+
 *           |  +<------|   next         |
 *           +<---------|   previous     |
 *                      ------------------
 *                      |                |
 *                      |                |      
 *                      ~                ~      LOWER MEMORY
 *                         FREE STORAGE              
 *                            ...                    |
 *                                                   |
 *                      ~                ~           V
 *                      |                |      HIGHER MEMORY
 *                      |                |
 *                      ------------------
 *                      |  size=64K-28  F|   <-- base + 64K - 8
 *                      ------------------ 
 *                      |   size=0      A|   <-- base + 64K - 4
 *                      ------------------   
 *                                           <-- base + 64K
 */
}

/******************************** E O F ***********************************/
