/*
 * Code to Manage the FreeList.
 * 
 * a) Allocate
 *     1) Scan for the smallest block larger than the request.
 *     2) Fix or delete the FreeList node.
 *     3) Create an Allocation node.
 *     4) Return the allocation node.
 * b) Free
 *     1) Scan the free list for an adjacent node.
 *     2) If found
 *          i) Adjust adjacent node offset/length
 *     3) If NOT found
 *          i) Create a FreeList entry
 *         ii) Link the FreeList entry into the FreeList in a position
 *             relative to its address in the file.
 */

#include "vm.h"

struct VM_FreeList *
VM_Allocate(struct VM_FreeList **VM_F, long Size) {
   struct VM_FreeList **VM_P = NULL ;
   struct VM_FreeList *VM_N = NULL ;
   ULONG largest = 0xFFFFFFFF ;
   ULONG len ;

   while (*VM_F) {
      len = (*VM_F)->VM_Length ;
      if (!len) {
	 VM_N = (struct VM_FreeList *)
	        TMemAlloc(sizeof(struct VM_FreeList),MEMF_PUBLIC) ;
	 if (!VM_N)
	    return NULL ;
	 if (VM_P) {
	    VM_N->VM_Offset = (*VM_P)->VM_Offset ;
	    VM_N->VM_Length = Size ;
	    (*VM_P)->VM_Offset += Size ;
	    (*VM_P)->VM_Length -= Size ;
	    }
	 else {
	    VM_N->VM_Offset = (*VM_F)->VM_Offset ;
	    VM_N->VM_Length = Size ;
	    (*VM_F)->VM_Offset += Size ;
	    }
	 return VM_N ;
         }
      if (len == Size) {
         VM_N = *VM_F ;
	 *VM_F = VM_N->VM_Next ;
	 return VM_N ;
         }
      if (len < largest) {
	 VM_P = VM_F ;
	 largest = len ;
         }
      VM_F = &((*VM_F)->VM_Next) ;
      }
   }

void
VM_Free(struct VM_FreeList **VM_F, struct VM_FreeList *VM_A) {
   struct VM_FreeList *VM_N ;
   ULONG offset ;
   ULONG end ;
   ULONG here = VM_A->VM_Offset ;
   ULONG len = VM_A->VM_Length ;
   ULONG there = here + len ;

   while (*VM_F) {

      VM_N = (*VM_F)->VM_Next ;

      offset = (*VM_F)->VM_Offset ;
      end = offset + (*VM_F)->VM_Length ;

      if (end == here) {
	 if (VM_N && (VM_N->VM_Offset == there)) {
	    if (VM_N->VM_Length)
	       (*VM_F)->VM_Length += (len + VM_N->VM_Length );
	    (*VM_F)->VM_Next = VM_N->VM_Next ;
	    FreeTrackedItem(VM_N) ;
	    }
	 else {
	    if (VM_N)
	       (*VM_F)->VM_Length += len ;
	    }
	 FreeTrackedItem(VM_A) ;
	 return ;
         }
      if (offset == there) {
	 (*VM_F)->VM_Offset -= len ;
	 if (VM_N)
	    (*VM_F)->VM_Length += len ;
	 FreeTrackedItem(VM_A) ;
	 return ;
         }
      if (offset > here) {
         VM_A->VM_Next = *VM_F ;
	 *VM_F = VM_A ;
	 return ;
         }
      VM_F = &((*VM_F)->VM_Next) ;
      }
   }

void
VM_FlushFreeList(struct VM_FreeList **VM_F) {

   /*
    * Dispose of the free list attached to the VM_Construct structure.
    */

   struct VM_FreeList *VM_A ;

   while (*VM_F) {

      /*
       * Unlink the first node.
       */
      VM_A = *VM_F ;
      *VM_F = VM_A->VM_Next ;

      /*
       * Free It.
       */
      FreeTrackedItem(VM_A) ;
      }

   }
