/****************************************************************************
**
**  Name:  basetbl.cpp
**
**  Description:
**     This module contains routines for accessing BASE symbols.
**
**  Status:  PRELIMINARY
**
**  $Log:   S:/tbird/mt2_68k/symbol/basetbl.cpv  $
** 
**    Rev 1.0   13 Feb 1997 09:06:06   gene
** Initial revision.
** 
**    Rev 1.0   07 Sep 1995 11:16:28   gene
** Initial revision.
** 
**    Rev 1.13   25 Jul 1992 16:30:36   brucea
** Added: init of baseCount to 0L in ::ObliterateTable; fixes bug where
**    base count kept getting larger with each new symbol load
** 
**    Rev 1.12   10 Jul 1992 18:50:50   brucea
** Changed: return structure in BaseSymbol constructor
** Added: incrementing baseCount to keep track of number of base indices 
** 
**    Rev 1.11   20 Apr 1992 08:41:48   brucea
** 
**    Rev 1.10   20 Apr 1992 07:58:18   brucea
** Changed: initialization of cached PRIVATE variables now done in
**    BasetblResetCacheVars which is now called from RemoveAllByAdrTables.
**    The initialization at the point of declaration was removed.
** Changed: private variable err to globalErr
** Fixes: PPR5473
** 
**    Rev 1.9   01 Apr 1992 23:39:40   brucea
** Fixed: compiler warnings
** 
**    Rev 1.8   11 Dec 1991 16:31:04   john
** Added function to get base offsets given a base name
**
**    Rev 1.7   06 Dec 1991 17:09:34   john
** Moved the "inline code" from the header here since the code was too
** involved to be left inline.
** Added routine to remove the dynamically allocated by-address tables.
**
**    Rev 1.6   29 Nov 1991 19:56:22   brucea
** changed NULL to NULL_SYMBOL
**
**    Rev 1.5   15 Oct 1991 13:37:46   john
** Changed the name of the return code "err" to "retErr" so that it did
** not override the global "err".
**
**    Rev 1.4   14 Oct 1991 14:02:50   brucea
** Put check for NULL for previousBaseOffset which handles the initial condition
** for updating the nextBaseOffset
** 
**    Rev 1.3   14 Oct 1991 13:57:14   john
** The global variable err was overriden by the passed parameter.  I renamed
** the passed parameter to remove the name conflict.
** 
**    Rev 1.2   14 Oct 1991 11:46:40   brucea
** No change.
** 
**    Rev 1.1   11 Oct 1991 15:17:00   brucea
** Changed BaseSymbol to a class and added access methods
** 
**    Rev 1.0   03 Oct 1991 11:42:56   john
** Initial revision.
**
**  $Header:   S:/tbird/mt2_68k/symbol/basetbl.cpv   1.0   13 Feb 1997 09:06:06   gene  $
**
**  Copyright (C) 1991 Microtek International.  All rights reserved.
**
*****************************************************************************/

                       /****************************
                        *                          *
                        *       INCLUDE FILES      *
                        *                          *
                        ****************************/

#ifndef _BASETBL_
#include "basetbl.h"
#endif

#ifndef _BASEWIND_
#include "basewind.h"
#endif

#ifndef _BYADRTBL_
#include "byadrtbl.h"
#endif

#ifndef _MEMPOOL_
#include "mempool.h"
#endif

#ifndef _INDEXTBL_
#include "indextbl.h"
#endif

#ifndef __STRING_H
#include "string.h"
#endif

#ifndef _SYMUTIL_
#include "symutil.h"
#endif
                       /****************************
                        *                          *
                        *     GLOBAL DEFINITIONS   *
                        *                          *
                        ****************************/

BaseIndexTable bit;   // Create Base Index Table object

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

#define ALL_ONES 0xFFFF

PRIVATE RETCODE globalErr;    // "global" error holder

// The purpose of these cached vars is to speed up access to the base instance
// and the by-address table instance, since many symbols are added to the same
// by-address table.  The code checks that the requested base is the same as
// the cached one.  If true, the offsets are used to access the information or
// add to the tables.
// NOTE: the actual HPU8 physical address to the tables cannot be cached
// because the table can move around.

// Set to non-legal values so they will be updated upon first use
// Must be re-initialized during the removal of symbols
PRIVATE BASE_INDEX   cachedBaseIndex;
PRIVATE TABLE_OFFSET cachedByAddressOffset;
PRIVATE TABLE_OFFSET cachedBaseOffset;

// USED FOR TABLE CREATION AND FOR ADDING A BASE
PRIVATE TABLE_OFFSET previousBaseOffset;
PRIVATE TABLE_OFFSET currentBaseOffset;

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

extern MemPool st;

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


//--------------------------------------------------------------------------
// UpdateCacheVars
//
// Description:
//    Internal routine to update cached variables for base and by-address
//    table access
//--------------------------------------------------------------------------
RETCODE PRIVATE UpdateCacheVars(BASE_INDEX baseIndex);

                       /**************
                        *            *
                        *    CODE    *
                        *            *
                        **************/

//--------------------------------------------------------------------------
//  BaseSymbol::BaseSymbol  (Parameterized CONSTRUCTOR)
//
//  Description:
//     Creates an instance of a BaseSymbol and puts it in st
//     Creates an instance of a ByAddressTable and puts it in st
//     Fills in the passed parameters into the BaseSymbol and initializes
//        all other BaseSymbol vars.
//     
//  Parameters:
//    input:
//       baseName: a pointer to the name of this base
//       baseIndex: the index into the base index table
//       baseAddress: the base address
//       baseTypeParam: type of base; code, data, both, unknown
//
//    output:
//       retErr: pass-by-reference error code, returning error code
//               from "new" constructor
//
//--------------------------------------------------------------------------
BaseSymbol::BaseSymbol(LPSTR baseName, BASE_INDEX baseIndex,
                       BASE_ADDRESS baseAddr, BASE_TYPE baseTypeParam,
                       RETCODE& retErr) {

   ByAddressTable bat;
   BaseSymbol * previousBasePtr;

   // operator "new" writes to the global variable <globalErr>; check it
   // before going on
   if (globalErr != SUCCESS) {
      retErr = globalErr;
      return;
   }

   // fill in all known parameters and nullify those not yet known
   baseAddress=baseAddr;
   addressMin=0xFFFFFFFFL;
   addressMax=0L;
   baseType=(U8)baseTypeParam;
   addrTableDirty=FALSE;
   nextBaseOffset=NULL_SYMBOL;

   // put the base name into the symbol table memory pool
   if((retErr = st.PutString(baseName, baseNameOffset)) != SUCCESS) return;

   // put the instance of the by-address sorted table into the symbol
   // table memory pool
   if((retErr = st.PutBytes((U8 *)&bat, sizeof(ByAddressTable),
                         byAddressTableOffset))
      != SUCCESS ) return;

   // update the previous base's nextBaseOffset to point to this one, but
   // only if it is not the first one created
   // update previousBaseOffset
   if (previousBaseOffset != NULL_SYMBOL)  {
      previousBasePtr =
         (BaseSymbol *)st.GetHugeDataPtr(previousBaseOffset);
      previousBasePtr->nextBaseOffset = currentBaseOffset;
   }
   previousBaseOffset = currentBaseOffset;

   // put the index value of the newly created base into "bit" - the 
   // base index table.
   retErr = bit.BaseAddIndex(baseIndex, currentBaseOffset);
   return;
}


//--------------------------------------------------------------------------
// BaseSymbol::operator new
//
// Purpose: allocates memory for a new BaseSymbol
//
// Input parameter:
//    size: amount of space to allocate
//
// Global Output parameter:
//    globalErr: RETCODE from memory allocation
//
// Return parameter: (huge?) pointer to allocated memory
//--------------------------------------------------------------------------
void *BaseSymbol::operator new(size_t size)  {

   TABLE_OFFSET stOffset;

   globalErr = st.AllocBytes(size, stOffset);
   if (globalErr == SUCCESS)  {
      // save offset context for linking bases together
      currentBaseOffset = stOffset;

      return (VOID *)st.GetHugeDataPtr(currentBaseOffset);
      }
   else
      return NULL;
   }  // end of BaseSymbol::operator new

//---------------------------------------------------------------------------
//  Member functions for BaseIndexTable
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
//  BaseAddIndex
//---------------------------------------------------------------------------
RETCODE BaseIndexTable::BaseAddIndex(TABLE_INDEX index, 
                                     TABLE_OFFSET itemOffset) {
   RETCODE retCode;

   retCode = AddIndex(index, itemOffset);
   if (retCode == SUCCESS) {
      if (rootBaseSymbolOffset == NULL_SYMBOL)  {
         rootBaseSymbolOffset = itemOffset;
      }
   }
   // increment base count
   baseCount++;

   return retCode;
} // end of BaseAddIndex

//---------------------------------------------------------------------------
//  ObliterateTable
//---------------------------------------------------------------------------
VOID BaseIndexTable::ObliterateTable(VOID) {
   RemoveAllByAdrTables();
   IndexTable::ObliterateTable();
   rootBaseSymbolOffset = NULL_SYMBOL;
   baseCount = 0L;
} 

                       /****************************
                        *                          *
                        *    NON-CLASS FUNCTIONS   *
                        *                          *
                        ****************************/

//--------------------------------------------------------------------------
//  AddAddrToByAddrTable
//
//  Description:
//    Adds a symbol offset to the by-address sorted table maintained by 
//    the base symbol.  It also updates the base min and max address vars
//     
//  Parameters:
//    input:
//       baseIndex: the index into the base index table
//       symAddr: the offset to the symbol being added
//       minAddr, maxAddr: values to update min and max base address vars
//    output:
//       none:
//
//  Private vars:
//    cachedBaseIndex, cachedBaseOffset, cachedByAddressOffset, err
//
//  Errors:
//    reports error if baseIndex is not in the table
//
//--------------------------------------------------------------------------
RETCODE
AddAddrToByAddrTable(BASE_INDEX baseIndex, TABLE_OFFSET symOffset,
                     U32 minAddr, U32 maxAddr)  {
   
   ByAddressTable *byAddressTablePtr;
   BaseSymbol     *baseSymbolPtr;
   RETCODE        err;

   // check to see if last baseIndex is same as present baseIndex
   if (cachedBaseIndex != baseIndex)  {
      if ((err = UpdateCacheVars(baseIndex)) != SUCCESS) return err;
      }

   // the by-address table itself is GlobalAlloc'ed; must get pointer to table
   byAddressTablePtr =
      (ByAddressTable *)st.GetHugeDataPtr(cachedByAddressOffset);

   // put the new symbol offset (which contains its address) into the
   // by-address sorted table
   byAddressTablePtr->PutU32(symOffset);

   baseSymbolPtr = (BaseSymbol *)st.GetHugeDataPtr(cachedBaseOffset);

   // mark the by-address table unsorted
   baseSymbolPtr -> SetAddrTableDirty(TRUE);

   // update min and max address vars
   baseSymbolPtr -> UpdateAddrVars(minAddr, maxAddr);
   
   return(SUCCESS);
}  // end of AddAddrToByAddrTable


//--------------------------------------------------------------------------
//  BaseSetAddr
//
//  Description:
//    Modifies the base address of <baseIndex>
//     
//  Parameters:
//    input:
//       baseIndex: the index into the base index table
//       baseAddress: the base address
//    output:
//       none:
//--------------------------------------------------------------------------
RETCODE BaseSetAddr(BASE_INDEX baseIndex, BASE_ADDRESS baseAddr) {
   
   BaseSymbol *basePtr;
   RETCODE    err;

   // check to see if last baseIndex is same as present baseIndex
   if (cachedBaseIndex != baseIndex)  {
      if ((err = UpdateCacheVars(baseIndex)) != SUCCESS) return err;
      }

   // get pointer to BaseSymbol and fill in base address
   basePtr = (BaseSymbol *)st.GetHugeDataPtr(cachedBaseOffset);
   basePtr -> SetBaseAddr(baseAddr);
   return(SUCCESS);
}  // end of BaseSetAddr


//--------------------------------------------------------------------------
//  GetBaseOffsetByName
//
//  Description:
//    Gets a base index by its base name.
//     
//  Parameters:
//    input:
//       baseName: the name of the base.
//
//    output:
//       baseIndex: the index of the base found. 
//    error:
//       if the base is not found.
//--------------------------------------------------------------------------
RETCODE GetBaseOffsetByName(LPSTR baseName, TABLE_OFFSET &baseOffset) {

   BaseSymbol  *basePtr;
   TABLE_OFFSET baseNameOffset;
   TABLE_OFFSET tmpBaseOffset;
   U8 name[MAX_SYMNAME_LENGTH];

   tmpBaseOffset = bit.GetRootBaseSymbolOffset();

   while (tmpBaseOffset) {
      // get the name of the base ;
      basePtr = (BaseSymbol *) st.GetHugeDataPtr(tmpBaseOffset);
      baseNameOffset = basePtr->GetBaseNameOffset();
      st.GetString(baseNameOffset, name);

      // check to see if the names match;
      if (!strcmp(baseName, (S8 *)name)) {
         // the names match;
         baseOffset = tmpBaseOffset;
         return(GOOD);
      }
      tmpBaseOffset = basePtr->GetNextBaseOffset();
   }
   return(ER_SYMBOL_NOT_FOUND);
}


//--------------------------------------------------------------------------
//  UpdateCacheVars
//
//  Description:
//    Updates the cached variables containing the base index context
//
//  Parameters:
//    input:
//       baseIndex: the index into the base index table
//       baseType: the new type for this base
//    output:
//       The cached vars are PRIVATE to this module
//
//  Errors:
//    returns error from GetOffset that can indicate index not in table
//    or an out-of-bounds index
//--------------------------------------------------------------------------
RETCODE UpdateCacheVars(BASE_INDEX baseIndex) {

   BaseSymbol   *baseSymbolPtr;
   TABLE_OFFSET tmpBaseOffset;
   RETCODE      err;

   // get new by-address table offset or generate error if not a valid index
   if((err = bit.GetOffset(baseIndex, tmpBaseOffset)) != SUCCESS)
      return(err);
   cachedBaseOffset = tmpBaseOffset;   // only update cached var if valid
   cachedBaseIndex = baseIndex;
   baseSymbolPtr = (BaseSymbol *)st.GetHugeDataPtr(cachedBaseOffset);

   // get the offset of the address table instance from base instance
   // (the address table instance is also in st)
   cachedByAddressOffset =
      baseSymbolPtr->GetByAddressTableOffset();
   return SUCCESS;
   }

//--------------------------------------------------------------------------
//  RemoveAllByAdrTables
//
//  Description:
//    Sequentially removes all the by address tables
//
//  Parameters:
//    input: none
//    output: none
//--------------------------------------------------------------------------
VOID RemoveAllByAdrTables(VOID) {
   TABLE_OFFSET  tableOffset, byAddrTableOffset;
   BaseSymbol    *basePtr;    // ptr to Base object ;
   ByAddressTable *byAddrTablePtr;  // ptr to ByAddressTable object ;

   tableOffset = bit.GetRootBaseSymbolOffset();
   while (tableOffset != NULL_SYMBOL) {
      // get a pointer to the by address sorted table ;
      basePtr = (BaseSymbol *)st.GetHugeDataPtr(tableOffset);
      byAddrTableOffset = basePtr -> GetByAddressTableOffset();
      byAddrTablePtr = (ByAddressTable *)st.GetHugeDataPtr(byAddrTableOffset);
      
      // delete the by address table object ;
      byAddrTablePtr->ObliterateTable();
      
      // get link to next base object ;
      tableOffset = basePtr -> GetNextBaseOffset();
   }  // end of while ;
   BasetblResetCacheVars();
   return;
}

//--------------------------------------------------------------------------
//  BasetblResetCacheVars
//
//  Description:
//    Re-initialize all cached vars after removal of symbols
//
//  Parameters:
//    input: none
//    output: none
//--------------------------------------------------------------------------
VOID BasetblResetCacheVars(VOID) {

   cachedBaseIndex = ALL_ONES;
   cachedByAddressOffset = NULL_SYMBOL;
   cachedBaseOffset = NULL_SYMBOL;

   // USED FOR TABLE CREATION AND FOR ADDING A BASE
   previousBaseOffset = NULL_SYMBOL;
   currentBaseOffset  = NULL_SYMBOL;

} // end of BasetblResetCacheVars
/******************************** E O F ***********************************/
