/**********************************************************************/
/*                                                                    */
/*     Module:    MEMLIB.C                                            */
/*                                                                    */
/*     This module contains the C MEMORY MANAGER - a group of C       */
/*     callable routines that manage expanded memory.  These          */
/*     routines alleviate many of the housekeeping chores necessary   */
/*     when dealing with expanded memory and make allocating and      */
/*     freeing expanded memory look as much like allocating and       */
/*     freeing conventional memory as possible.                       */
/*                                                                    */
/*     The routines called by an application are:                     */
/*                                                                    */
/*     ememavl         Approximate amount of free expanded memory     */
/*     ememmax         Size of the largest contiguous free block      */
/*     emsize          Size of a specified block                      */
/*     efmalloc        Allocate a block of memory                     */
/*     effree          Free a previously allocated block              */
/*     seteptrs        Access n different blocks                      */
/*     set1eptr        Access 1 block                                 */
/*     set2eptrs       Access 2 blocks                                */
/*     set3eptrs       Access 3 blocks                                */
/*     push_context    Push the current mapping context               */
/*     pop_context     Pop a mapping context                          */
/*     effreeall       Frees ALL blocks                               */
/*                                                                    */
/**********************************************************************/
  
#include "memintrl.c"
  
/*$PAGE*/
/**********************************************************************/
/*                                                                    */
/*     Name:    unsigned int ememavl (*size)                          */
/*              unsigned long *size;                                  */
/*                                                                    */
/*     Description:                                                   */
/*        Computes the size of expanded memory available in bytes but */
/*     due to memory fragmentation, the largest useable block may be  */
/*     smaller than the amount returned by this function.  See        */
/*     ememmax.                                                       */
/*                                                                    */
/*     Parameters:                                                    */
/*        output  size       The size computed.                       */
/*                                                                    */
/*     Results returned:                                              */
/*        PASSED     The size is valid                                */
/*        error      Non-zero value, see "ERRORS.H" or EMS table A-2  */
/*                                                                    */
/*     Calling sequence:                                              */
/*     #include "memlib.h"                                            */
/*     #include "errors.h"                                            */
/*         ...                                                        */
/*     unsigned long size;                                            */
/*     unsigned int  status;                                          */
/*         ...                                                        */
/*     status = ememavl (&size);                                      */
/*     if (status == PASSED)                                          */
/*         printf("Expanded memory available = %lu \n", size);        */
/*     else                                                           */
/*         { error condition }                                        */
/*                                                                    */
/*     Calls: prepare_dir_mapping()                                   */
/*            get_unalloc_page_count()                                */
/*            restore_memlib_context()                                */
/*            map_dir_page()                                          */
/*                                                                    */
/*     Called by:  Application                                        */
/*                                                                    */
/*     Globals referenced/modified: directory                         */
/*                                  dir_page_count                    */
/*                                                                    */
/**********************************************************************/
  
unsigned int ememavl (size)
unsigned long *size;
{
    unsigned int status;             /* The status of EMM and MEMLIB    */
    unsigned int num_unalloc_pages;  /* Number of unallocated pages     */
    unsigned int index;              /* Index into a directory page     */
    unsigned int dir_page;           /* The directory page to map in    */
    unsigned int context_saved;      /* Whether the contexted was saved */
  
    *size = 0;
  
   /**********************************************/
   /* Call prepare_dir_mapping() to save context */
   /* before mapping in the directory.           */
   /**********************************************/
  
    status = prepare_dir_mapping (&context_saved);
  
    if (status == PASSED)
    {
      /********************************************************/
      /* Add up the number of 16K pages that are unallocated. */
      /********************************************************/
  
        status = get_unalloc_page_count (&num_unalloc_pages);
        if (status == PASSED)
        {
            *size += PAGE_SIZE * (long) num_unalloc_pages;
        }
  
      /***************************************************/
      /* Go through entire directory one page at a time. */
      /***************************************************/
  
        for (dir_page = 0; ((status == PASSED) &&
            (dir_page < dir_page_count)); dir_page++)
        {
         /***********************************/
         /* Map in the this directory page. */
         /***********************************/
  
            status = map_dir_page (dir_page, FIRST_PHYS_PAGE);
            if (status == PASSED)
            {
            /******************************************/
            /* Add up all freed blocks for this page. */
            /******************************************/
  
                for (index = 0; (index < DIR_ENTRIES_PER_PAGE); index++)
                {
                    if (directory[0][index].token == UNASSIGNED_TOKEN)
                        *size += directory[0][index].size;
                }
            }
        }
    }
   /**************************************************************/
   /* Unmap the directory - remap the pages that were in before. */
   /**************************************************************/
  
    if (context_saved)
        status = restore_memlib_context (status);
  
   /*************************************/
   /* If some error return a size of 0. */
   /*************************************/
  
    if (status != PASSED)
        *size = 0;
  
    return (status);
  
}  /** end of ememavl **/
  
  
  
/*$PAGE*/
/**********************************************************************/
/*                                                                    */
/*     Name:    unsigned int ememmax (*size)                          */
/*              unsigned int *size;                                   */
/*                                                                    */
/*     Description:                                                   */
/*        Computes the size of the largest block of expanded memory   */
/*     that MEMLIB can allocate.                                      */
/*                                                                    */
/*     Parameters:                                                    */
/*        output  size  The size of the largest allocatable block.    */
/*                                                                    */
/*     Results returned:                                              */
/*        PASSED     Operation successful                             */
/*        error      Non-zero value, see "ERRORS.H" or EMS table A-2  */
/*                                                                    */
/*     Calling sequence:                                              */
/*     #include "memlib.h"                                            */
/*     #include "errors.h"                                            */
/*         ...                                                        */
/*     unsigned int size;                                             */
/*     unsigned int status;                                           */
/*         ...                                                        */
/*     status = ememmax (&size);                                      */
/*     if (status == PASSED)                                          */
/*         printf("Largest block available = %u \n", size);           */
/*     else                                                           */
/*         { error condition }                                        */
/*                                                                    */
/*     Calls: prepare_dir_mapping()                                   */
/*            map_dir_page()                                          */
/*            get_unalloc_page_count()                                */
/*            restore_memlib_context()                                */
/*                                                                    */
/*     Called by:  Application                                        */
/*                                                                    */
/*     Globals referenced/modified: directory                         */
/*                                  dir_page_count                    */
/*                                                                    */
/**********************************************************************/
  
unsigned int ememmax (size)
unsigned int *size;
{
    unsigned int status;     /* The status of EMM and MEMLIB   */
    unsigned int num_pages;  /* Number of unallocated pages    */
    unsigned int page;       /* Directory page to map in       */
    unsigned int index;      /* Index into a directory page    */
    unsigned int saved;      /* whether the context was saved  */
  
   /**********************************************/
   /* Call prepare_dir_mapping() to save context */
   /* before mapping in the directory            */
   /**********************************************/
  
    status = prepare_dir_mapping (&saved);
  
    if (status == PASSED)
    {
      /***************************************************************/
      /* If more than 64K worth of unallocated pages, set max to     */
      /* the largest allocateable block (64K-1).  Otherwise, test    */
      /* the number of unallocated pages * 16K against *size.        */
      /***************************************************************/
  
        status = get_unalloc_page_count (&num_pages);
        if (status == PASSED)
        {
            if (num_pages >= MAX_ALLOCATABLE_PAGES)
                *size = LARGEST_ALLOCATABLE_BLOCK;
            else
                *size = PAGE_SIZE * num_pages;
        }
    }
  
   /**************************************/
   /* Go through all the directory pages */
   /**************************************/
  
    for (page = 0; ((status == PASSED) &&
        (page < dir_page_count)); page++)
    {
      /***********************************/
      /* Map in the this directory page. */
      /***********************************/
  
        status = map_dir_page (page, FIRST_PHYS_PAGE);
        if (status == PASSED)
        {
         /********************************/
         /* Find the maximum free block. */
         /********************************/
  
            for (index = 0; index < DIR_ENTRIES_PER_PAGE; index++)
            {
                if ((directory[0][index].token == UNASSIGNED_TOKEN) &&
                    (directory[0][index].size > *size))
                    *size = directory[0][index].size;
            }
        }
    }
  
   /**************************************************************/
   /* Unmap the directory - remap the pages that were in before. */
   /**************************************************************/
  
    if (saved)
        status = restore_memlib_context (status);
  
   /*************************************/
   /* If some error return a size of 0. */
   /*************************************/
  
    if (status != PASSED)
        *size = 0;
  
    return (status);
  
}  /** end of ememmax **/
  
#ifdef notdef
  
/*$PAGE*/
/**********************************************************************/
/*                                                                    */
/*     Name:    unsigned int emsize (token, *size)                    */
/*              unsigned int token;                                   */
/*              unsigned int *size;                                   */
/*                                                                    */
/*     Description:                                                   */
/*        Returns the size, in bytes, of the allocated block of       */
/*     memory identified by 'token.' (A token returned from           */
/*     efmalloc).                                                     */
/*                                                                    */
/*     Parameters:                                                    */
/*        input   token       identifies the block desired            */
/*        output  size        the size, in bytes, of the block        */
/*                                                                    */
/*     Results returned:                                              */
/*        PASSED     Operation successful                             */
/*        error      Non-zero value, see "ERRORS.H" or EMS table A-2  */
/*                                                                    */
/*     Calling sequence:                                              */
/*     #include "memlib.h"                                            */
/*     #include "errors.h"                                            */
/*         ...                                                        */
/*     unsigned int status;                                           */
/*     unsigned int token;                                            */
/*     unsigned int size;                                             */
/*                                                                    */
/*     status = efmalloc (200, &token);                               */
/*         ...                                                        */
/*     status = emsize (token, &size);                                */
/*     if (status == PASSED)                                          */
/*         printf ("Size of block = %u bytes\n", size);               */
/*                                                                    */
/*     Calls: prepare_dir_mapping()                                   */
/*            map_dir_page()                                          */
/*            check_token()                                           */
/*            restore_memlib_context()                                */
/*                                                                    */
/*     Called by:  Application                                        */
/*                                                                    */
/*     Globals referenced/modified: directory                         */
/*                                                                    */
/**********************************************************************/
  
unsigned int emsize (token, size)
unsigned int token;
unsigned int *size;
{
    unsigned int status;        /* The status of EMM and MEMLIB    */
    unsigned int page;          /* Directory page to map in        */
    unsigned int index;         /* The index into a directory page */
    unsigned int context_saved; /* Whether the context was saved   */
  
   /**********************************************/
   /* Call prepare_dir_mapping() to save context */
   /* before mapping in the directory            */
   /**********************************************/
  
    status = prepare_dir_mapping (&context_saved);
  
   /***************************/
   /* Check for a valid token */
   /***************************/
  
    if (status == PASSED)
        status = check_token (token);
  
    if (status == PASSED)
    {
      /*****************************************************/
      /* Set 'page' to the directory page this token is in */
      /*****************************************************/
  
        page = token / DIR_ENTRIES_PER_PAGE;
  
      /**********************************************/
      /* Convert the token into an index that falls */
      /* within the size of a directory page        */
      /**********************************************/
  
        index = token % DIR_ENTRIES_PER_PAGE;
  
      /******************************/
      /* Map in this directory page */
      /******************************/
  
        status = map_dir_page (page, FIRST_PHYS_PAGE);
        if (status == PASSED)
        {
         /*****************************/
         /* Check size for this index */
         /*****************************/
  
            if (directory[0][index].token == token)
            {
                *size = directory[0][index].size;
                status = PASSED;
            }
            else
            {
                *size = 0;
                status = INVALID_TOKEN;
            }
        }
    }
  
   /*************************************************************/
   /* Unmap the directory - remap the pages that were in before */
   /*************************************************************/
  
    if (context_saved)
        status = restore_memlib_context (status);
  
   /************************************/
   /* If some error return a size of 0 */
   /************************************/
  
    if (status != PASSED)
        *size = 0;
  
    return (status);
  
}  /** end of emsize **/
  
#endif
  
/*$PAGE*/
/**********************************************************************/
/*                                                                    */
/*     Name:    unsigned int efmalloc (size, token);                  */
/*              unsigned int size;                                    */
/*              unsigned int *token;                                  */
/*                                                                    */
/*     Description:                                                   */
/*        This function is analagous to fmalloc except it allocates a */
/*     block of memory from the expanded memory pool.                 */
/*                                                                    */
/*     Parameters:                                                    */
/*        input    size   The desired size, in bytes, of the block of */
/*                        memory.                                     */
/*        output   token  A tag needed for subsequent calls to the C  */
/*                        Memory Manager to unquiely identify the     */
/*                        block of memory allocated.                  */
/*                                                                    */
/*     Results returned:                                              */
/*        PASSED    Operation successful                              */
/*        error     Non-zero value, see "ERRORS.H" or EMS table A-2   */
/*                                                                    */
/*     Calling sequence:                                              */
/*     #include "memlib.h"                                            */
/*     #include "errors.h"                                            */
/*         ...                                                        */
/*     unsigned int token;                                            */
/*     unsigned int size;                                             */
/*     unsigned int status                                            */
/*         ...                                                        */
/*     size = 100;                                                    */
/*     status = efmalloc (size, &token);                              */
/*     if (status == PASSED)                                          */
/*        { continue normal code - we have allocated space to }       */
/*        { store 100 byte values                             }       */
/*     else                                                           */
/*        { error condition }                                         */
/*                                                                    */
/*     Calls: allocate_new_block()                                    */
/*            check_best_fit()                                        */
/*            prepare_dir_mapping()                                   */
/*            restore_memlib_context()                                */
/*            split_block()                                           */
/*            map_dir_page()                                          */
/*                                                                    */
/*     Called by:  Application                                        */
/*                                                                    */
/*     Globals reference/modified: directory                          */
/*                                 directory_map                      */
/*                                                                    */
/**********************************************************************/
  
unsigned int efmalloc (size, token)
unsigned int size;
unsigned int *token;
  
{
    unsigned int found_block;       /* memory block found                */
    unsigned int status;            /* Status of EMM and MEMLIB          */
    unsigned int best_indexs_page;  /* best_index's dir entry's log page */
    unsigned int best_indexs_index; /* best_index's index into its page  */
    unsigned int best_index;        /* Index of the current best fit     */
    unsigned int context_saved;     /* whether the context was saved     */
    long         min_difference;    /* Minimum difference - best size    */
  
   /**********************************************/
   /* Attempting to allocate 0 bytes is an error */
   /**********************************************/
  
    if (size > 0)
        status = PASSED;
    else
        status = REQUEST_FOR_ZERO_LENGTH_BLOCK;
  
   /**********************************************/
   /* Call prepare_dir_mapping() to save context */
   /* before mapping in the directory            */
   /**********************************************/
  
    if (status == PASSED)
        status = prepare_dir_mapping (&context_saved);
  
    if (status == PASSED)
    {
      /*************************************/
      /* check to see if there exists a    */
      /* "best size" fit in memory blocks. */
      /*************************************/
  
        status = check_best_fit (size, &best_index, &min_difference);
  
      /********************************************/
      /* If best_index is not an UNASSIGNED_TOKEN */
      /* then we found a block.                   */
      /********************************************/
  
        if ((status == PASSED) &&
            (best_index != UNASSIGNED_TOKEN))
        {
            found_block = TRUE;
  
         /****************************************************/
         /* We're going to use a free block to put our block */
         /* into.  First we need to map in the free block's  */
         /* (best_index) directory entry's logical page.     */
         /****************************************************/
  
         /******************************************************************/
         /* Convert best_index to its respective directory page and index. */
         /******************************************************************/
  
            best_indexs_page  = best_index / DIR_ENTRIES_PER_PAGE;
            best_indexs_index = best_index % DIR_ENTRIES_PER_PAGE;
  
         /***************************************/
         /* Map in best_index's directory page. */
         /***************************************/
  
            status = map_dir_page (best_indexs_page, FIRST_PHYS_PAGE);
  
  
         /********************************************************/
         /* If the size of the best fit that we found was 0 then */
         /* what we found was an unallocated block.  Allocate a  */
         /* a new block.                                         */
         /********************************************************/
  
            if (directory[0][best_indexs_index].size == 0)
                status = allocate_new_block (size, best_index);
            else
            {
            /******************************************************/
            /* When using a previously allocated block we need to */
            /* check the size and if any space is left over we    */
            /* should make a new available block.                 */
            /******************************************************/
  
                if ((status == PASSED) &&
                    (min_difference != 0))
                {
                    status = split_block (best_index, size);
                }
  
            } /** end else **/
  
        }  /** end if best_index ... **/
  
    }   /** end if passed from prepare_dir_mapping() **/
  
   /********************************************************/
   /* We found a block - set the token value and directory */
   /* entries.  (The directory pointer (offset) is set     */
   /* either in allocate_new_block or was already valid.)  */
   /********************************************************/
    if (status == PASSED)
    {
        if (found_block)
        {
            status = map_dir_page (best_indexs_page, FIRST_PHYS_PAGE);
            if (status == PASSED)
            {
                *token = best_index;
                directory[0][best_indexs_index].token = best_index;
                directory[0][best_indexs_index].size  = size;
            }
        }
        else
        {
            *token = UNASSIGNED_TOKEN;
            if (!found_block)
                status = TOO_MANY_DIRECTORY_ENTRIES;
        }
    }
  
   /*************************************************************/
   /* Unmap the directory - remap the pages that were in before */
   /*************************************************************/
  
    if (context_saved)
        status = restore_memlib_context (status);
  
    return (status);
  
}  /** end efmalloc **/
  
/*$PAGE*/
/**********************************************************************/
/*                                                                    */
/*     Name:  unsigned int effree (token)                             */
/*            unsigned int token;                                     */
/*                                                                    */
/*     Description:                                                   */
/*        This function frees a block of memory from expanded memory  */
/*     that was allocated by efmalloc().                              */
/*                                                                    */
/*     Parameters:                                                    */
/*        input  token  The token returned by efmalloc when this      */
/*                      block was allocated.                          */
/*                                                                    */
/*     Results returned:                                              */
/*        PASSED    Operation successful                              */
/*        error     Non-zero value, see "ERRORS.H" or EMS table A-2   */
/*                                                                    */
/*     Calling sequence:                                              */
/*     #include "memlib.h"                                            */
/*     #include "errors.h"                                            */
/*         ...                                                        */
/*     unsigned int token;                                            */
/*     unsigned int status;                                           */
/*         ...                                                        */
/*     status = efmalloc (100, &token);                               */
/*         ...                                                        */
/*     status = efree(token);                                         */
/*     if (status == PASSED)                                          */
/*        { continue normal code }                                    */
/*     else                                                           */
/*        { error condition }                                         */
/*                                                                    */
/*     Calls: check_if_all_blocks_free()                              */
/*            check_token()                                           */
/*            prepare_dir_mapping()                                   */
/*            restore_memlib_context()                                */
/*            search_after()                                          */
/*            search_before()                                         */
/*            map_dir_page()                                          */
/*            effreeall()                                             */
/*                                                                    */
/*     Called by: Application                                         */
/*                                                                    */
/*     Globals referenced/modified: directory                         */
/*                                  dir_start                         */
/*                                                                    */
/**********************************************************************/
  
unsigned int effree (token)
unsigned int token;
{
    unsigned int status;             /* Status of EMM and MEMLIB           */
    unsigned int all_blocks_free;    /* Whether all blocks are free or not */
    unsigned int j;                  /* Looping variable                   */
    unsigned int usable_entry;       /* A usuable directory entry          */
    unsigned int size_mod_page_size; /* Size of a block MOD PAGE_SIZE      */
    unsigned int tokens_index;       /* Token's index into its log page    */
    unsigned int tokens_page;        /* Token's dir entry's logical page   */
    unsigned int usable_entrys_index;/* Usable_entry's index into its page */
    unsigned int usable_entrys_page; /* Usable_entry's dir entry's log page*/
    unsigned int final_entrys_index; /* Final_entry's index into its page  */
    unsigned int final_entrys_page;  /* Final_entry's dir entry's log page */
    unsigned int final_entry;        /* Directory entry of the final       */
                                    /* coalesced block                    */
    unsigned int context_saved;      /* Whether the context was saved      */
  
   /******************************/
   /* Initialize some variables. */
   /******************************/
  
    all_blocks_free = FALSE;
    context_saved   = FALSE;
  
   /******************************/
   /* Check for an invalid token */
   /******************************/
  
    status = check_token (token);
  
   /**********************************************/
   /* Call prepare_dir_mapping() to save context */
   /* before mapping in the directory            */
   /**********************************************/
    if (status == PASSED)
        status = prepare_dir_mapping (&context_saved);
  
    if (status == PASSED)
    {
      /************************************************/
      /* Convert token to its index and logical page. */
      /************************************************/
  
        tokens_index = token % DIR_ENTRIES_PER_PAGE;
        tokens_page  = token / DIR_ENTRIES_PER_PAGE;
  
      /*******************************/
      /* Map in this directory page. */
      /*******************************/
  
        status = map_dir_page (tokens_page, FIRST_PHYS_PAGE);
    }
  
    if (status == PASSED)
    {
      /*************************************************/
      /* If token does not identify an allocated block */
      /* or if its size is zero return an error code.  */
      /*************************************************/
  
        if ((directory[0][tokens_index].token != token) ||
            (directory[0][tokens_index].size == 0))
            status = INVALID_TOKEN;
  
        if (status == PASSED)
        {
         /*******************************************************/
         /* Set token to UNASSIGNED_TOKEN showing freed status. */
         /*******************************************************/
  
            directory[0][tokens_index].token = UNASSIGNED_TOKEN;
  
         /****************************************************/
         /* If this token is less than the current starting  */
         /* location then set the new starting location used */
         /* when searching for free directory entries.       */
         /****************************************************/
  
            if (token < dir_start)
                dir_start = token;
  
         /**********************************/
         /* Check if all pages are free.   */
         /* If not, try to coalesce blocks */
         /**********************************/
  
            status = check_if_all_blocks_free (&all_blocks_free);
        }
        if ((status == PASSED) &&
            (all_blocks_free))
        {
         /*****************************************/
         /* We need to restore the context before */
         /* the pages and handles.                */
         /*****************************************/
  
            if (context_saved)
                status = restore_memlib_context (status);
  
            if (status == PASSED)
            {
                context_saved = FALSE;
                status = effreeall();
            }
        }
        else if ((status == PASSED) &&
            (!all_blocks_free))
        {
         /*****************************************************/
         /* Search for a free block of memory after this free */
         /* block to coalesce into one free block.  This      */
         /* makes sure that if there are a number of little   */
         /* blocks that could actually be put together into   */
         /* one large block that we do so.                    */
         /*****************************************************/
  
            status = search_after (token, &final_entry, &usable_entry);
  
         /*******************************************************/
         /* Search for a free block of memory before this block */
         /* to coalesce into one free block.                    */
         /*******************************************************/
  
            if (status == PASSED)
                status = search_before (token, &final_entry, &usable_entry);
  
         /**************************************************/
         /* Test to see if we coalesced any blocks.  If so */
         /* we need to check that the coalesced block does */
         /* not overlap too many logical pages.            */
         /**************************************************/
  
            if ((status == PASSED) &&
                (final_entry != UNASSIGNED_TOKEN))
            {
            /*****************************************/
            /* Convert final_entry to its respective */
            /* directory page and index.             */
            /*****************************************/
  
                final_entrys_page  = final_entry / DIR_ENTRIES_PER_PAGE;
                final_entrys_index = final_entry % DIR_ENTRIES_PER_PAGE;
  
            /****************************************/
            /* Map in final_entry's directory page. */
            /****************************************/
  
                status = map_dir_page (final_entrys_page, FIRST_PHYS_PAGE);
                if (status == PASSED)
                {
               /*******************************************************/
               /* We can't have a block taking up more logical pages  */
               /* than it needs.  We always guarantee that a block of */
               /* memory take the least amount of logical pages as    */
               /* possible.  If it overlaps too many blocks we need   */
               /* to break it up.  Check the block final_index for    */
               /* too much overlap.                                   */
               /*******************************************************/
  
                    size_mod_page_size =
                    directory[0][final_entrys_index].size % PAGE_SIZE;
                    if (size_mod_page_size == 0)
                        size_mod_page_size = PAGE_SIZE;
  
                    if ((PAGE_SIZE - directory[0][final_entrys_index].offset) <
                        size_mod_page_size)
  
                    {
                  /*********************************************************/
                  /* Convert usable_block to its respective directory page */
                  /* and index.  We're going to map this page into the     */
                  /* second physical page.                                 */
                  /*********************************************************/
  
                        usable_entrys_page  = usable_entry / DIR_ENTRIES_PER_PAGE;
                        usable_entrys_index = usable_entry % DIR_ENTRIES_PER_PAGE;
  
                  /****************************************************/
                  /* Map in usable_block's directory page using the   */
                  /* directory_map's second array element to map this */
                  /* page in at physical page one while keeping the   */
                  /* block that was coalesced's directory page at     */
                  /* physical page zero.                              */
                  /***************************************************/
  
                        status = map_dir_page (usable_entrys_page, SECOND_PHYS_PAGE);
  
                  /*************************************************/
                  /* This block overlaps too many logical pages.   */
                  /* We need to break it into two pieces at a      */
                  /* a logical page boundry.  Use the usable_block */
                  /* set when coalescing.                          */
                  /*************************************************/
  
                        if (status == PASSED)
                        {
                     /*************************************************/
                     /* Set the second block's (usable_entry) size to */
                     /* the size of the first piece after the first   */
                     /* page boundry of the whole block.              */
                     /*************************************************/
  
                            directory[1][usable_entrys_index].size =
                            directory[0][final_entrys_index].size -
                            PAGE_SIZE + directory[0][final_entrys_index].offset;
  
                     /**************************************/
                     /* Set the offset of the second block */
                     /* to start at the page boundry.      */
                     /**************************************/
  
                            directory[1][usable_entrys_index].offset = 0;
  
                     /***********************************************/
                     /* Set the logical pages for the second block. */
                     /***********************************************/
  
                            for (j = 0; j < NUM_PAGES (directory[1][usable_entrys_index].size); j++)
                            {
                                directory[1][usable_entrys_index].logical_page[j] =
                                directory[0][final_entrys_index].logical_page[j + 1];
                            }
  
                     /***********************************************/
                     /* Set the first block size to the amount of   */
                     /* memory before the logical page boundry (the */
                     /* space before the second block).             */
                     /***********************************************/
  
                            directory[0][final_entrys_index].size -=
                            directory[1][usable_entrys_index].size;
                        }
  
                    } /** end if PAGE_SIZE ... **/
  
                } /** status passed **/
  
            } /** end if final_index ... **/
  
        } /** end if check_of_all_blocks_free **/
  
    } /** end if status passed **/
  
   /*************************************************************/
   /* Unmap the directory - remap the pages that were in before */
   /*************************************************************/
  
    if ((!all_blocks_free) &&
        (context_saved))
        status = restore_memlib_context (status);
  
    return (status);
  
} /** end effree **/
  
/*$PAGE*/
/**********************************************************************/
/*                                                                    */
/*     Name:  unsigned int seteptrs (num_blocks, token, pointer)      */
/*            unsigned int num_blocks;                                */
/*            unsigned int token[];                                   */
/*            void far*    pointer[];                                 */
/*                                                                    */
/*     Description:                                                   */
/*        Attempts to map all the pages required by the block(s) of   */
/*     memory identified by token[].  Returns pointers to each block  */
/*     that has been mapped in.  If the requested block(s) could not  */
/*     mapped in then we return an error.                             */
/*                                                                    */
/*     Parameters:                                                    */
/*        input  num_blocks          Number of blocks to get access   */
/*                                   to.                              */
/*        input  token[num_blocks]   An array of tokens that identify */
/*                                   the blocks to be mapped in. (The */
/*                                   tokens returned by efmalloc when */
/*                                   the block(s) were allocated.)    */
/*        output pointer[num_blocks] An array of far pointers returned*/
/*                                   to the application.  Pointer[i]  */
/*                                   will point to the block of       */
/*                                   memory identified by token[i].   */
/*                                                                    */
/*     Results returned:                                              */
/*        PASSED    Operation successful                              */
/*        error     Non-zero value, see "ERRORS.H" or EMS table A-2   */
/*                                                                    */
/*     Calling sequence:                                              */
/*     #include "memlib.h"                                            */
/*     #include "errors.h"                                            */
/*         ...                                                        */
/*     void far*    pointers[2];                                      */
/*     unsigned int tokens[2];                                        */
/*     unsigned int status;                                           */
/*         ...                                                        */
/*     status = efmalloc (200, &token[0]);                            */
/*     if (status != PASSED)                                          */
/*        { error condition }                                         */
/*     else                                                           */
/*        { continue normal code }                                    */
/*         ...                                                        */
/*     status = efmalloc (600, &token[1]);                            */
/*     if (status != PASSED)                                          */
/*        { error condition }                                         */
/*     else                                                           */
/*        { continue normal code }                                    */
/*         ...                                                        */
/*     status = seteptrs (2, tokens, pointers)                        */
/*     if (status == PASSED)                                          */
/*       { blocks mapped in - use pointers to reference them }        */
/*     else                                                           */
/*       { error - a token was bad or not all blocks could fit }      */
/*                                                                    */
/*     Calls: map_dir_page()                                          */
/*            map_unmap_pages()                                       */
/*                                                                    */
/*     Called by: Application                                         */
/*                set1eptr()                                          */
/*                set2eptrs()                                         */
/*                set3eptrs()                                         */
/*                                                                    */
/*     Globals referenced/modified: directory                         */
/*                                  app_handle                        */
/*                                  directory_map                     */
/*                                  num_pages_in_page_frame           */
/*                                  number_pages_mapped               */
/*                                  page_frame_base_address           */
/*                                  pages_mapped                      */
/*                                                                    */
/**********************************************************************/
  
unsigned int seteptrs (num_blocks, token, pointer)
unsigned int num_blocks;
unsigned int token[];
void far*    pointer[];
{
    unsigned int status;             /* Status of EMM & MEMLIB               */
    unsigned int i;                  /* looping variable                     */
    unsigned int j;                  /* looping variable                     */
    unsigned int start_phys_page;    /* Starting physical page in page frame */
    unsigned int log_page_match;     /* Match was found? TRUE/FALSE          */
    unsigned int log_page;           /* temporarily store log page we're on  */
    unsigned int current_dir_page;   /* The current directory page mapped in */
    unsigned int tokens_page;        /* Token's dir entry's logical page     */
    unsigned int tokens_index;       /* Token's index into its logical page  */
    unsigned int num_pages_for_token;/* Number of logical pages for token's  */
                                    /* block                                */
    void far*    tokens_ptr;         /* pointer to token's block             */
  
   /*******************************/
   /* Initialize local variables. */
   /*******************************/
  
    status = PASSED;
    current_dir_page = UNMAPPED;
  
   /***************************************/
   /* Make sure all the tokens are valid. */
   /***************************************/
  
    for (i = 0; ((status == PASSED) &&
        (i < num_blocks)); i++)
    {
        status = check_token (token[i]);
    }
  
    if (status == PASSED)
    {
      /*******************************************************/
      /* Set each page in the page frame to UNMAPPED status. */
      /*******************************************************/
  
        for (i = 0; i < num_pages_in_page_frame; i++)
            pages_mapped[i].log_page = UNMAPPED;
  
        number_pages_mapped = 0;
  
      /***********************************************/
      /* For each block requested, try to map it in. */
      /***********************************************/
  
        for (i = 0; ((status == PASSED) &&
            (i < num_blocks)); i++)
        {
            tokens_page  = token[i] / DIR_ENTRIES_PER_PAGE;
            tokens_index = token[i] % DIR_ENTRIES_PER_PAGE;
  
            if (tokens_page != current_dir_page)
            {
                current_dir_page = tokens_page;
                status = map_dir_page (current_dir_page, FIRST_PHYS_PAGE);
            }
  
            if ((status == PASSED) &&
                (token[i] != directory[0][tokens_index].token))
                status = INVALID_TOKEN;
  
            if (status == PASSED)
            {
            /*********************************/
            /* Initialize variable for loop. */
            /*********************************/
  
                start_phys_page      = 0;
                log_page_match       = FALSE;
                num_pages_for_token  = NUM_PAGES (directory[0][tokens_index].size);
  
            /***********************************************************/
            /* While there's potentially room to map the logical pages */
            /* need for the i'th block and it isn't already mapped in. */
            /***********************************************************/
  
                while (((start_phys_page + num_pages_for_token)
                    <= num_pages_in_page_frame)
                    && (!log_page_match))
                {
               /*****************************************/
               /* Assume the logical pages need for the */
               /* i'th block are already mapped in.     */
               /*****************************************/
  
                    log_page_match = TRUE;
  
               /**************************************************/
               /* Test each of the logical pages in the i'th     */
               /* block against the logical pages already mapped */
               /* in the page frame starting at start_phys_page. */
               /**************************************************/
  
                    for (j = 0; (j < num_pages_for_token); j++)
                    {
                        log_page = directory[0][tokens_index].logical_page[j];
  
                  /**********************************************/
                  /* We won't have a match if the logical page  */
                  /* we're looking for is not already mapped in */
                  /* and if the page is unmapped.               */
                  /**********************************************/
  
                        if ((log_page != pages_mapped[start_phys_page + j].log_page) &&
                            (pages_mapped[start_phys_page + j].log_page != UNMAPPED))
                            log_page_match = FALSE;
                    }
               /*************************************************/
               /* If the i'th block isn't mapped in (starting   */
               /* at start_phys_page) increment start_phys_page */
               /* and try again.                                */
               /*************************************************/
  
                    if (!log_page_match)
                        start_phys_page++;
  
                }  /** end while **/
  
            /**************************************************/
            /* If a match was found set pages_mapped array to */
            /* include the logical pages for this block.  If  */
            /* no match was found we can't map this block     */
            /**************************************************/
  
                if (log_page_match)
                {
                    for (j = 0; (j < num_pages_for_token); j++)
                    {
                        pages_mapped[start_phys_page + j].log_page =
                        directory[0][tokens_index].logical_page[j];
  
                  /*************************************************/
                  /* Update pointer[i] to point to the i'th block. */
                  /* The offset of the pointer we return is equal  */
                  /* to the offset of this block within the first  */
                  /* logical page for this block.  These pointers  */
                  /* are only good modulus 16K since, for example, */
                  /* we could have allocated a block when it was   */
                  /* mapped in at phys page 0 and now want to map  */
                  /* it in at phys page 3 or some such.            */
                  /*************************************************/
  
                        FP_OFF (tokens_ptr) = directory[0][tokens_index].offset;
                        FP_SEG (tokens_ptr) = FP_SEG(page_frame_base_address) +
                        start_phys_page * OFFSET_SIZE;
                        pointer[i]          = tokens_ptr;
                    }
                }
                else
                    status = CANNOT_MAP_ALL_BLOCKS;
  
            } /** if status PASSED **/
  
        }  /** end for i **/
  
    }  /** end if status PASSED **/
  
   /*************************************************************/
   /* Unmap the directory - remap the pages that were in before */
   /*************************************************************/
  
    if (status == PASSED)
    {
      /*************************************/
      /* Count the number of pages to map. */
      /*************************************/
  
        number_pages_mapped = 0;
        for (i = 0; i < num_pages_in_page_frame; i++)
        {
            if (pages_mapped[i].log_page != UNMAPPED)
                number_pages_mapped++;
        }
      /************************************/
      /* Map in all the blocks requested. */
      /************************************/
  
        status = map_unmap_pages (PHYS_PAGE_MODE, number_pages_mapped,
        pages_mapped, app_handle);
    }
    return(status);
  
} /** end seteptrs **/
  
/*$PAGE*/
/**********************************************************************/
/*                                                                    */
/*     Name:  unsigned int set1eptr (token, pointer)                  */
/*            unsigned int token;                                     */
/*            void far*    *pointer;                                  */
/*                                                                    */
/*     Description:                                                   */
/*        Convenience routine that calls seteptrs to just get access  */
/*     to one block.                                                  */
/*                                                                    */
/*     Parms Passed:                                                  */
/*        input  token     A token that identifies the block to be    */
/*                         mapped in. (The token returned by efmalloc */
/*                         when the block was allocated.)             */
/*        output pointer   A far pointer returned to the application. */
/*                         It will point to the block of memory       */
/*                         identified by token.                       */
/*                                                                    */
/*     Results returned:                                              */
/*        PASSED     Operation successful                             */
/*        error     Non-zero value, see "ERRORS.H" or EMS table A-2   */
/*                                                                    */
/*     Calling sequence:                                              */
/*     #include "memlib.h"                                            */
/*     #include "errors.h"                                            */
/*         ...                                                        */
/*     void far*     pointer;                                         */
/*     unsigned int  token;                                           */
/*     unsigned int  status;                                          */
/*         ...                                                        */
/*     status = efmalloc (500, &token);                               */
/*     if (status != PASSED)                                          */
/*        { error condition }                                         */
/*     else                                                           */
/*        { continue normal code }                                    */
/*         ...                                                        */
/*     status = set1eptr(token, &pointer)                             */
/*     if (status == PASSED)                                          */
/*       { block mapped in - use pointer to reference it }            */
/*     else                                                           */
/*       { error - the token was invalid }                            */
/*                                                                    */
/*     Calls: seteptrs()                                              */
/*                                                                    */
/*     Called by: Application                                         */
/*                                                                    */
/*     Globals referenced/modified: None                              */
/*                                                                    */
/**********************************************************************/
  
unsigned int set1eptr (token, pointer)
unsigned int token;
void far*    *pointer;
{
    unsigned int tokens[1];     /* Set one array entry to pass to   */
                               /* seteptrs()                       */
    void far*    pointers[1];   /* Set one array entry to be passed */
                               /* back from seteptrs()             */
    unsigned int status;        /* Status of EMM and MEMLIB         */
  
    tokens[0] = token;
  
   /**************************************************/
   /* Call seteptrs() to map in the block identified */
   /* by token and return it pointer.                */
   /**************************************************/
  
    status = seteptrs (1, tokens, pointers);
  
    if (status == PASSED)
        *pointer = pointers[0];
  
    return (status);
  
}  /** end set1eptr **/
  
  
#ifdef notdef
  
/*$PAGE*/
/**********************************************************************/
/*                                                                    */
/*     Name:  unsigned int set2eptrs (token1, token2, pointer1,       */
/*                                      pointer2)                     */
/*            unsigned int token1;                                    */
/*            unsigned int token2;                                    */
/*            void far*    *pointer1;                                 */
/*            void far*    *pointer2;                                 */
/*                                                                    */
/*     Description:                                                   */
/*        Convenience routine that calls seteptrs to get access to    */
/*     two different blocks of memory at one time.                    */
/*                                                                    */
/*     Parameters:                                                    */
/*        input  token1    A token that identifies the first block to */
/*                         be mapped in. (The token returned by       */
/*                         efmalloc when the block was allocated.)    */
/*        input  token2    A token that identifies the second block   */
/*                         to be mapped in. (The token returned by    */
/*                         efmalloc when the block was allocated.)    */
/*        output pointer1  A far pointer returned to the application. */
/*                         It will point to the block of memory       */
/*                         identified by token1.                      */
/*        output pointer2  A far pointer returned to the application. */
/*                         It will point to the block of memory       */
/*                         identified by token2.                      */
/*                                                                    */
/*     Results returned:                                              */
/*        PASSED    Operation successful                              */
/*        error     Non-zero value, see "ERRORS.H" or EMS table A-2   */
/*                                                                    */
/*     Calling sequence:                                              */
/*     #include "memlib.h"                                            */
/*     #include "errors.h"                                            */
/*         ...                                                        */
/*     void far*    ptr1;                                             */
/*     void far*    ptr2;                                             */
/*     unsigned int token1;                                           */
/*     unsigned int token2;                                           */
/*     unsigned int status;                                           */
/*         ...                                                        */
/*     status = efmalloc (500, &token1);                              */
/*     if (status != PASSED)                                          */
/*        { error condition }                                         */
/*     else                                                           */
/*        { continue normal code }                                    */
/*         ...                                                        */
/*     status = efmalloc (900, &token2);                              */
/*     if (status != PASSED)                                          */
/*        { error condition }                                         */
/*     else                                                           */
/*        { continue normal code }                                    */
/*         ...                                                        */
/*     status = set2eptrs (token1, token2, &ptr1, &ptr2);             */
/*     if (status == PASSED)                                          */
/*       { blocks mapped in - use pointers to reference them }        */
/*     else                                                           */
/*       { error - a token was invalid or blocks couldn't fit }       */
/*                                                                    */
/*     Calls: seteptrs()                                              */
/*                                                                    */
/*     Called by: Application                                         */
/*                                                                    */
/*     Globals referenced/modified: None                              */
/*                                                                    */
/**********************************************************************/
  
unsigned int set2eptrs (token1, token2, pointer1, pointer2)
unsigned int token1;
unsigned int token2;
void far*    *pointer1;
void far*    *pointer2;
{
    unsigned int tokens[2];      /* Set two array entries to pass to   */
                                /* seteptrs()                         */
    void far*    pointers[2];    /* Set two array entries to be passed */
                                /* back from seteptrs()               */
    unsigned int status;         /* Status of EMM and MEMLIB           */
  
    tokens[0] = token1;
    tokens[1] = token2;
  
   /***************************************************/
   /* Call seteptrs() to map in the blocks identified */
   /* by token1 and token2 and return their pointers. */
   /***************************************************/
  
    status = seteptrs (2, tokens, pointers);
  
    if (status == PASSED)
    {
        *pointer1 = pointers[0];
        *pointer2 = pointers[1];
    }
  
    return (status);
  
}  /** end set2eptrs **/
  
/*$PAGE*/
/**********************************************************************/
/*                                                                    */
/*     Name:  unsigned int set3eptrs (token1, token2, token3,         */
/*                                      pointer1, pointer2, pointer3) */
/*            unsigned int token1;                                    */
/*            unsigned int token2;                                    */
/*            unsigned int token3;                                    */
/*            void far*    *pointer1;                                 */
/*            void far*    *pointer2;                                 */
/*            void far*    *pointer3;                                 */
/*                                                                    */
/*     Description:                                                   */
/*        Convenience routine that calls seteptrs to get access to    */
/*     three different blocks of memory at one time.                  */
/*                                                                    */
/*     Parameters:                                                    */
/*        input  token1    A token that identifies the first block to */
/*                         be mapped in. (The token returned by       */
/*                         efmalloc when the block was allocated.)    */
/*        input  token2    A token that identifies the second block   */
/*                         to be mapped in. (The token returned by    */
/*                         efmalloc when the block was allocated.)    */
/*        input  token3    A token that identifies the third block to */
/*                         be mapped in. (The token returned by       */
/*                         efmalloc when the block was allocated.)    */
/*        output pointer1  A far pointer returned to the application. */
/*                         It will point to the block of memory       */
/*                         identified by token1.                      */
/*        output pointer2  A far pointer returned to the application. */
/*                         It will point to the block of memory       */
/*                         identified by token2.                      */
/*        output pointer3  A far pointer returned to the application. */
/*                         It will point to the block of memory       */
/*                         identified by token3.                      */
/*                                                                    */
/*     Results returned:                                              */
/*        PASSED    Operation successful                              */
/*        error     Non-zero value, see "ERRORS.H" or EMS table A-2   */
/*                                                                    */
/*                                                                    */
/*     Calling sequence:                                              */
/*     #include "memlib.h"                                            */
/*     #include "errors.h"                                            */
/*         ...                                                        */
/*     void far*    ptr1;                                             */
/*     void far*    ptr2;                                             */
/*     void far*    ptr3;                                             */
/*     unsigned int tok1;                                             */
/*     unsigned int tok2;                                             */
/*     unsigned int tok3;                                             */
/*     unsigned int status;                                           */
/*         ...                                                        */
/*     status = efmalloc (500, &tok1);                                */
/*     if (status != PASSED)                                          */
/*        { error condition }                                         */
/*     else                                                           */
/*        { continue normal code }                                    */
/*         ...                                                        */
/*     status = efmalloc (900, &tok2);                                */
/*     if (status != PASSED)                                          */
/*        { error condition }                                         */
/*     else                                                           */
/*        { continue normal code }                                    */
/*         ...                                                        */
/*     status = efmalloc (300, &tok3);                                */
/*     if (status != PASSED)                                          */
/*        { error condition }                                         */
/*     else                                                           */
/*        { continue normal code }                                    */
/*         ...                                                        */
/*     status = set3eptrs (tok1, tok2, tok3, &ptr1, &ptr2, &ptr3);    */
/*     if (status == PASSED)                                          */
/*       { blocks mapped in - use pointers to reference them }        */
/*     else                                                           */
/*       { error - a token was invalid or blocks couldn't fit }       */
/*                                                                    */
/*     Calls: seteptrs()                                              */
/*                                                                    */
/*     Called by: Application                                         */
/*                                                                    */
/*     Globals referenced/modified: None                              */
/*                                                                    */
/**********************************************************************/
  
unsigned int set3eptrs (token1, token2, token3, pointer1, pointer2,
pointer3)
unsigned int token1;
unsigned int token2;
unsigned int token3;
void far*    *pointer1;
void far*    *pointer2;
void far*    *pointer3;
{
    unsigned int tokens[3];      /* Set three array entries to pass */
                                /* seteptrs()                      */
    void far*    pointers[3];    /* Set three array entries to be   */
                                /* passed back from seteptrs()     */
    unsigned int status;         /* Status of EMM and MEMLIB        */
  
    tokens[0] = token1;
    tokens[1] = token2;
    tokens[2] = token3;
  
   /*********************************************************/
   /* Call seteptrs() to map in the blocks identified by    */
   /* token1, token2, and token3 and return their pointers. */
   /*********************************************************/
  
    status = seteptrs (3, tokens, pointers);
  
    if (status == PASSED)
    {
        *pointer1 = pointers[0];
        *pointer2 = pointers[1];
        *pointer3 = pointers[2];
    }
    return (status);
  
}  /** end set3eptrs **/
  
/*$PAGE*/
/**********************************************************************/
/*                                                                    */
/*     Name:  unsigned int push_context (void)                        */
/*                                                                    */
/*     Description:                                                   */
/*        Pushes the current mapping context onto an internal stack.  */
/*     The routine pop_context() can be used to restore the context   */
/*     saved by this routine.  Note that for each push we do we must  */
/*     do a pop.                                                      */
/*                                                                    */
/*     Parameters: None                                               */
/*                                                                    */
/*     Results returned:                                              */
/*        PASSED    Operation successful                              */
/*        error     Non-zero value, see "ERRORS.H" or EMS table A-2   */
/*                                                                    */
/*     Calling sequence:                                              */
/*     #include "memlib.h"                                            */
/*     #include "errors.h"                                            */
/*      ...                                                           */
/*     unsigned int status;                                           */
/*      ...                                                           */
/*     status = push_context();                                       */
/*     if (status == PASSED)                                          */
/*         { continue normal code }                                   */
/*     else                                                           */
/*         { error condition }                                        */
/*                                                                    */
/*     Calls: get_partial_context()                                   */
/*            init_exp_mem()                                          */
/*                                                                    */
/*     Called by: Application                                         */
/*                                                                    */
/*     Globals referenced/modified: context_ptrs                      */
/*                                  context_size                      */
/*                                  exp_initialized                   */
/*                                  partial_page_map                  */
/*                                  context_top                       */
/*                                                                    */
/**********************************************************************/
  
unsigned int push_context (void)
{
    unsigned int status;         /* The status of EMM and MELIB */
  
   /**************************/
   /* Assume this will pass. */
   /**************************/
  
    status = PASSED;
  
   /*************************************************************/
   /* Initialize expanded memory if we haven't already done so. */
   /*************************************************************/
  
    if (!exp_initialized)
        status = init_exp_mem();
  
    if (status == PASSED)
    {
      /**************************************/
      /* Increment our variable for keeping */
      /* track of top of our context stack. */
      /**************************************/
  
        context_top++;
  
      /***********************************************************/
      /* We have an array of pointers that keep track of the     */
      /* saved context.  Make sure we stay with our array limit. */
      /***********************************************************/
  
        if (context_top < MAX_CONTEXTS_AVAILABLE)
        {
         /***************************************************************/
         /* Allocate space in conventional memory to save this context. */
         /* Then call get_partial_page_map to do the actual save.       */
         /***************************************************************/
  
            context_ptrs[context_top] = (CONTEXT_STRUCT *) malloc (context_size);
  
         /*************************************************/
         /* Make sure we have enough conventional memory. */
         /*************************************************/
  
            if (context_ptrs[context_top] == NULL)
                status = MALLOC_FAILURE;
            else
                status = get_partial_context (&partial_page_map,
                context_ptrs[context_top]);
        }
        else
            status = MAX_PUSH_CONTEXTS_EXCEEDED;
  
      /*************************************************/
      /* If status failed, reset top of context stack. */
      /*************************************************/
  
        if (status != PASSED)
            context_top--;
    }
  
    return (status);
  
} /** end push_context **/
  
/*$PAGE*/
/**********************************************************************/
/*                                                                    */
/*     Name:  unsigned int pop_context (void)                         */
/*                                                                    */
/*     Description:                                                   */
/*        Pops the last context saved by a call to push_context().    */
/*     Note that for each push we do we must do a pop.                */
/*                                                                    */
/*     Parameters: None                                               */
/*                                                                    */
/*     Results returned:                                              */
/*        PASSED    Operation successful                              */
/*        error     Non-zero value, see "ERRORS.H" or EMS table A-2   */
/*                                                                    */
/*     Calling sequence:                                              */
/*     #include "memlib.h"                                            */
/*     #include "errors.h"                                            */
/*      ...                                                           */
/*     unsigned int status;                                           */
/*      ...                                                           */
/*     status = pop_context();                                        */
/*     if (status == PASSED)                                          */
/*         { continue normal code }                                   */
/*     else                                                           */
/*         { error condition }                                        */
/*                                                                    */
/*     Calls: set_partial_context()                                   */
/*            init_exp_mem()                                          */
/*                                                                    */
/*     Called by: Application                                         */
/*                                                                    */
/*     Globals referenced/modified: context_ptrs                      */
/*                                  exp_initialized                   */
/*                                  context_top                       */
/*                                                                    */
/**********************************************************************/
  
unsigned int pop_context (void)
{
    unsigned int status;         /* The status of EMM and MEMLIB) */
  
   /**************************/
   /* Assume this will pass. */
   /**************************/
  
    status = PASSED;
  
   /*************************************************************/
   /* Initialize expanded memory if we haven't already done so. */
   /*************************************************************/
  
    if (!exp_initialized)
        status = init_exp_mem();
  
    if (status == PASSED)
    {
      /********************************************/
      /* Make sure there is a context to restore. */
      /********************************************/
  
        if (context_top != NO_CONTEXTS)
        {
         /*********************************************************/
         /* Save the context using set_partial_context(), storing */
         /* the information an our stack (context_ptrs array).    */
         /*********************************************************/
  
            status = set_partial_context (context_ptrs[context_top]);
            if (status == PASSED)
  
            /**************************************************************/
            /* Free the conventional memory we used to save this context. */
            /**************************************************************/
  
                free (context_ptrs[context_top]);
        }
        else
            status = NO_CONTEXT_AVAILABLE_TO_POP;
  
      /**********************************************/
      /* If status passed, decrement stack pointer. */
      /**********************************************/
  
        if (status == PASSED)
            if (context_top > 0)
                context_top--;
            else
                context_top = NO_CONTEXTS;
    }
  
    return (status);
  
} /** end pop_context **/
  
#endif
  
/*$PAGE*/
/**********************************************************************/
/*                                                                    */
/*     Name:  unsigned int effreeall (void)                           */
/*                                                                    */
/*     Description:                                                   */
/*        Frees all handles, pages and blocks.  Prepare for program   */
/*     termination.                                                   */
/*                                                                    */
/*     Parameters: None                                               */
/*                                                                    */
/*     Results returned:                                              */
/*        PASSED    Operation successful                              */
/*        error     Non-zero value, see "ERRORS.H" or EMS table A-2   */
/*                                                                    */
/*     Calling sequence:                                              */
/*     #include "memlib.h"                                            */
/*     #include "errors.h"                                            */
/*                                                                    */
/*     unsigned int status;                                           */
/*      ...                                                           */
/*     status = effree();                                             */
/*     if (status == PASSED)                                          */
/*        { continue normal code }                                    */
/*     else                                                           */
/*        { error condition }                                         */
/*                                                                    */
/*     Calls: dealloc_pages()                                         */
/*            map_umap_page()                                         */
/*                                                                    */
/*     Called by: Application                                         */
/*                effree()                                            */
/*                                                                    */
/*     Globals referenced/modified: app_handle                        */
/*                                  exp_initialized                   */
/*                                  man_handle                        */
/*                                  num_pages_in_page_frame           */
/*                                  context_ptrs                      */
/*                                  context_top                       */
/*                                                                    */
/**********************************************************************/
  
unsigned int effreeall (void)
{
    unsigned int status;         /* The status of EMM and MEMLIB */
    unsigned int j;              /* Looping variable             */
  
    status = PASSED;
  
   /*****************************************************************/
   /*  If MEMLIB has not been initialized no need to free anything. */
   /*****************************************************************/
  
    if (exp_initialized)
    {
  
      /**************************************/
      /* Unmap all pages in the page frame. */
      /**************************************/
  
        for (j = 0; (status == PASSED) &&
            (j < num_pages_in_page_frame); j++)
        {
            status = map_unmap_page(j, UNMAPPED, man_handle);
        }
  
        if (status == PASSED)
        {
         /***********************************************/
         /* Deallocate the pages and handle for MEMLIB. */
         /***********************************************/
  
            status = dealloc_pages (man_handle);
        }
        if (status == PASSED)
        {
         /********************************************************/
         /* Deallocate the pages and handle for the application. */
         /********************************************************/
  
            status = dealloc_pages (app_handle);
  
         /***********************************/
         /* Reset exp_initialized to FALSE. */
         /***********************************/
  
            if (status == PASSED)
            {
                exp_initialized = FALSE;
  
            /***********************************************/
            /* Free up all space taken by pushed contexts. */
            /***********************************************/
  
                if (context_top != NO_CONTEXTS)
                {
                    for (j = 0; j < context_top; j++)
                    {
                        if (context_ptrs[j] != NULL)
                            free (context_ptrs[j]);
                    }
                }
            }
        }
    }
    return(status);
  
} /** end effreeall **/
  
  
  
