
/***************************************************************************
**
**    $Header:   D:/ECB2S/SRC/LOG/SYMADD.CPP   1.2.1.4   17 Apr 1997 16:02:20   ZJRD  $
**
**    $Log:   D:/ECB2S/SRC/LOG/SYMADD.CPP  $
** 
**    Rev 1.2.1.4   17 Apr 1997 16:02:20   ZJRD
** No change.
** 
**    Rev 1.2.1.3   16 Apr 1997 10:35:18   ZJRD
** No change.
** 
**    Rev 1.2.1.2   10 Apr 1997 15:44:32   ZJRD
** No change.
** 
**    Rev 1.2.1.1   03 Apr 1997 15:23:12   ZJRD
** No change.
** 
**    Rev 1.2.1.0   28 Mar 1997 10:27:02   ZJRD
** easy pack sld 2.09d
** 
**    Rev 1.1   19 Mar 1997 11:36:50   ZJRD
** No change.
** 
**    Rev 1.0   12 Mar 1997 14:50:52   ZJRD
** Initial revision.
** 
****************************************************************************/

/****************************************************************************
**
**  Name:  symadd.cpp
**
**  Description:
**     This module contains routines for adding to the symbol pool.
**
**  Status:  PRELIMINARY
**
**  $Log$
**
**  $Header:   D:/ECB2S/SRC/LOG/SYMADD.CPP   1.2.1.4   17 Apr 1997 16:02:20   ZJRD  $
**
**  Copyright (C) 1995 Microtek International.  All rights reserved.
**
*****************************************************************************/

                       /****************************
                        *                          *
                        *       INCLUDE FILES      *
                        *                          *
                        ****************************/
#include "stdafx.h"                      
#include <memory.h>
#include <string.h>
#include "symbase.h"
#include "symwind.h"
#include "symbyadr.h"
#include "symhash.h"
#include "symindex.h"
#include "symline.h"
#include "symmanag.h"
#include "sympool.h"
#include "symord.h"
#include "symblsvr.h"
#include "symadd.h"          
#include "symheap.h"
#include "symerrs.h"
#include "symutil.h"
#include "symtype.h"

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

extern MemPool st;         // symbol table ;
extern BaseIndexTable bit;
extern TypeTable tt;       // type table ;
extern IndexTable typit;   // type index table ;

extern VOID AdlookupResetCacheVars(VOID);
extern RETCODE SymGetModuleNum(U16 FAR *numReturn);

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

#define SYM_STACK_SIZE 32
#define SYM_STACK_EMPTY -1

PRIVATE TABLE_OFFSET lastLabel;
PRIVATE TABLE_OFFSET lastOpened;
PRIVATE TABLE_OFFSET lastVariable;

PRIVATE TABLE_OFFSET lastPublicLabel;     // used for adding public labels
PRIVATE TABLE_OFFSET lastPublicVariable;  //  "                     vars

PRIVATE BOOLEAN      moduleOpen = FALSE;
PRIVATE SYM_ACTION   prevAction;
PRIVATE TABLE_OFFSET prevSym;
PRIVATE TABLE_OFFSET currentOpenContext;     // holds mod, func, unnamed block
PRIVATE TABLE_OFFSET symStack[SYM_STACK_SIZE];
PRIVATE S8           topSymStack;

// used to transfer SymAddLoadStart load type to SymAddLoadEnd for
// the type of event notification: initial load or on-demand load
PRIVATE BOOLEAN onDemandState = FALSE;

typedef struct {
   REG_INDEX regIndex;
   TYPE_INDEX baseTypeIndex;
} REG_VAR_TYPE;

                       /****************************
                        *                          *
                        *       GLOBAL VARS        *
                        *                          *
                        ****************************/

OrdinalTable ot;     // ordinal table ;
HashTable ht;        // hash table of global names ;

U8 loadFilename[MAX_SYMNAME_LENGTH];
TIMESTAMP_TYPE loadTimestamp;
TABLE_OFFSET rootOffset;

//---------------------------------------------------------------------------
// Table to collect symbol statistics
U32 symbolStat[MAX_SYM_TYPE];
TABLE_OFFSET lastModuleLoaded;

//---------------------------------------------------------------------------
// Processor family

//PROCESSOR_FAMILY globalProcFamily = FAMILY_UNKNOWN;
BOOLEAN          with0X = TRUE;

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

PRIVATE RETCODE AddOrdinalValue(TABLE_OFFSET offset);
PRIVATE VOID    ClearEntry(VOID *entry, U32 entrySize);
PRIVATE RETCODE PushSymStack(TABLE_OFFSET stackEntry);
PRIVATE RETCODE PopSymStack(TABLE_OFFSET &stackEntry);
PRIVATE RETCODE UpdateBlockInfo(TABLE_OFFSET symbolOff,SYM_ACTION action,
                                BOOLEAN updateLinks);
PRIVATE RETCODE InitIniSettings(VOID);
PRIVATE RETCODE AddSegmentTypesIntoBaseTable(VOID);

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

/****************************************************************************
**
**  AddOrdinalValue
**
**  Description:
**     Puts the ordinal value into the symbol table entry and adds it to the
**     ordinal table.
**
**  Parameters:
**     input:
**        offset: the offset of the symbol
**
**     output:
**        none:
**        (error): if value couldn't be put into ordinal table
**
*****************************************************************************/
PRIVATE RETCODE AddOrdinalValue(TABLE_OFFSET offset) {

   RETCODE err;
   COMMON_SYMBOL_HEADER HUGE *block;
   ORDINAL_INDEX ordinalValue;

   // get the ordinal value
   if ((err = ot.AddSymOffsetToOT(offset, ordinalValue)) == SUCCESS)  {
      // fill in the ordinal value of this symbol ;
      block = (COMMON_SYMBOL_HEADER HUGE*)st.GetHugeDataPtr(offset);
      block->ordinalVal = ordinalValue;
   }
   return err;
}

/****************************************************************************
**
**  ClearEntry
**
**  Description:
**     Zeroes out a symbol entry structure.  When some symbols are created
**     they may not be immediately filled in.  This routine is called to
**     make sure these symbols don't have garbage values in them.
**
**  Parameters:
**     input:
**        *entry: A pointer to the symbol structure to be cleared
**        entrySize: The size of the entry in BYTES.
**     output:
**        none:
**
*****************************************************************************/
PRIVATE VOID ClearEntry(VOID *entry, U32 entrySize) {
   U32 i;
// U8 *tmpPtr;

   i = entrySize-1;
   memset((LPSTR)entry, 0, (size_t)entrySize);
//   tmpPtr = (U8 *)entry;
//   while(i--) {
//      *((U8 *)entry) = 0;
//      tmpPtr++;
//   }
}


//--------------------------------------------------------------------------
// SymInitialize
//--------------------------------------------------------------------------
RETCODE EXPORT SymInitialize()  {

   RETCODE err;

// if ((err = ProcReturnProcFamily(&globalProcFamily)) != GOOD)
//    return err;
// if (globalProcFamily == FAMILY_X86) // used for address display
//    with0X = FALSE;
   if ((err = InitSymTable()) != GOOD)
      return err;
   if ((err = tt.InitBasicTypes()) != GOOD)
      return err;
   // Add Segments into base table
   return GOOD; AddSegmentTypesIntoBaseTable();
   
} // end of SymInitialize

//--------------------------------------------------------------------------
// InitSymTable
//--------------------------------------------------------------------------
RETCODE InitSymTable(VOID) {

   SYM_TYPE_MODULE HUGE *initMod;
   TABLE_OFFSET nameOffset;
   RETCODE err;
   U8 temp;

// initialize ht - the hash table
   if ((err = ht.InitOrExtendTable(GMEM_ZEROINIT)) != SUCCESS)
      return err;

   ht.SetHashTableSize();       // adjust size for hash function fit

// init cache variables
   BasetblResetCacheVars();

   AdlookupResetCacheVars();

// initialize PRIVATE vars in this module
   lastLabel = 0L;
   lastVariable = 0L;
   lastPublicLabel = 0L;
   lastPublicVariable = 0L;

// initialize the previous action for use by UpdateBlockInfo ;
   prevAction = SYM_OPEN;

   // initialize the NULL table entry in the symbol table to 0; this
   // means that if a string pointer (offset) is 0, the string length
   // is 0
   temp = 0;
   if((err = st.PutBytes(&temp, 1, nameOffset)) != GOOD) return err;

   // put the name of the root module into the symbol pool
   if((err = st.PutString((LPSTR)"ROOT",nameOffset)) != GOOD) return err;

   // initialize root symbol entry
   if((err = st.AllocBytes(sizeof(SYM_TYPE_MODULE),
      rootOffset)) != GOOD) return err;

   initMod = (SYM_TYPE_MODULE HUGE*)st.GetHugeDataPtr(rootOffset);

   // clear all the entries in the module to zero ;
   ClearEntry(initMod,sizeof(SYM_TYPE_MODULE));
   initMod->symHeader.symHeader.typeIndex.symType = SYM_ROOT;
   initMod->symHeader.symHeader.symbolNameOffset = nameOffset;

   // fill in the ordinal value of the root symbol ;
   if((err = AddOrdinalValue(rootOffset)) != GOOD) return err;

   // Save the offset of the previous symbol we were dealing with.
   // This will be used for manipulating the symbol pool later
   prevSym = currentOpenContext = rootOffset;

   // Save the offset of the module/block/function that was opened last ;
   lastOpened = rootOffset;

   // Initialize and save the offset on a stack.  The mod/blk/func will ;
   // nest and we will want to keep track of the order they were nested ;
   topSymStack = SYM_STACK_EMPTY;
   if ((err = PushSymStack(rootOffset)) != GOOD) return err;
   moduleOpen = FALSE;

   // Clear all symbol statistics - all entries equals zero
   memset(symbolStat, 0, sizeof(symbolStat));
   lastModuleLoaded = 0L;

   return GOOD;
}

//--------------------------------------------------------------------------
// AddSegmentTypesIntoBaseTable
//--------------------------------------------------------------------------
PRIVATE RETCODE AddSegmentTypesIntoBaseTable(VOID)  {
   RETCODE err;
   STATIC CHAR *segName[] = { "UNTYPED", "CODE", "DATA", "XDATA",
                              "BIT", "REGISTER", "CONST" };
   BASE_TYPE baseType[] = {BASE_UNKNOWN, BASE_CODE, BASE_DATA, BASE_DATA,
                           BASE_DATA, BASE_DATA, BASE_DATA};
                           
   for (LOOP_VAR i=SEG_UNTYPED; i<=SEG_CONST; i++) {
       if ((err=SymAddBaseCreate((LPSTR)segName[i], (BASE_INDEX)i, 0L,
            baseType[i])) != GOOD)
          return err;
   }
   return GOOD;
} // end of BuildSegmentTable

/****************************************************************************
**
**  PopSymStack
**
**  Description:
**     Pop the offset of the topmost nested block off the stack
**
**  Parameters:
**     input:
**        none:
**     output:
**        none:
**        (returns): offset of new top of stack block
**
*****************************************************************************/
PRIVATE RETCODE PopSymStack(TABLE_OFFSET &stackEntry) {

   if(topSymStack == -1)
      return ER_SYMBOL_STACK_EMPTY;
   stackEntry = symStack[topSymStack--];
   return GOOD;
}

/****************************************************************************
**
**  PushSymStack
**
**  Description:
**     The symbol stack is used to store symbol offsets.  The offsets
**     are saved to indicate the current nesting level of open modules,
**     blocks, and functions.
**
**  Parameters:
**     input:
**        stackEntry:  the function offset to be stored
**     output:
**        none:
**        (error): if stack is full
**
*****************************************************************************/
PRIVATE RETCODE PushSymStack(TABLE_OFFSET stackEntry) {

   if(topSymStack >= SYM_STACK_SIZE)
      return ER_SYM_STACK_FULL;
   symStack[++topSymStack] = stackEntry;
   return GOOD;
}

//--------------------------------------------------------------------------
// SymAddBaseCreate
//
// Pseudo-code
//    First checks for already existing or out-of-bounds baseIndex.
//    Then, execute the "new" operator for BaseSymbol;
//       if error, returns error code
//--------------------------------------------------------------------------
RETCODE EXPORT
SymAddBaseCreate(LPSTR baseName,
                 BASE_INDEX baseIndex,
                 BASE_ADDRESS baseAddress,
                 BASE_TYPE baseTypeParam)  {

   RETCODE err;
   TABLE_OFFSET dummy;
   
   // check for validity of baseIndex; should not yet exist
   err = bit.GetOffset(baseIndex, dummy);
   if (err == ER_INDEX_OUT_OF_BOUNDS)
      return err;
   if (err == SUCCESS)
      return ER_INDEX_ALREADY_EXISTS;
   
   // index not in table, create new base and put its index into <bit>
   new BaseSymbol(baseName, baseIndex, baseAddress,
                            baseTypeParam, err);
   return err;
}  // end of SymAddBaseCreate

//--------------------------------------------------------------------------
// SymAddFuncCreate
//--------------------------------------------------------------------------
RETCODE EXPORT
SymAddFuncCreate(LPSTR funcName,
                 FUNC_CLASS funcClass,
                 U32 stackSize,
                 ADDR_RANGE_TYPE *codeAddrRange,
                 TYPE_INDEX typeIndex) {

   SYM_TYPE_FUNCTION HUGE *function;
   TABLE_OFFSET nameOffset;
   RETCODE err;
   TABLE_OFFSET funcOffset, baseOffset;
   BOOLEAN duplicateName;
   SYM_TYPE_TYPE symType = SYM_FUNCTION;
   BASE_INDEX baseIndex=(BASE_INDEX)SEG_CODE;

   // NOTES: 09/20/93 - Nghia
   // If the return type 'typeIndex is undefined when create the function then
   // its type might be a forward reference type.  Eventually, it has to
   // resolve somehow, or else the compiler should catch that and report
   // error.  DO NOT NEED TO CHECK FOR TYPE INDEX EXISTING.
   // make sure the base exist
   if ((err = bit.GetOffset(baseIndex, baseOffset)) != GOOD)
      return err;

   lastLabel=lastVariable=0;

   // get memory for the function in the symbol pool
   if((err = st.AllocBytes(sizeof(SYM_TYPE_FUNCTION), funcOffset))
      != GOOD) return err;

   // if the name doesn't exist then this is an unnamed block ;
   if ((funcName != NULL) && funcName[0]) {
      if((err = st.PutString(funcName,nameOffset)) != GOOD) return err;
   } else {
      nameOffset = 0;
   }

   // get pointer
   function = (SYM_TYPE_FUNCTION HUGE *)st.GetHugeDataPtr(funcOffset);
   ClearEntry(function,sizeof(SYM_TYPE_FUNCTION));

   // initialize the rest of the function entry ;
   function->symHeader.symHeader.symbolNameOffset = nameOffset;

   // if there is not a name offset then this is a block symbol
   // the default is a function symbol
   if (!nameOffset)
      symType = SYM_BLOCK;

   function->symHeader.symHeader.typeIndex.symType = symType;
   function->symHeader.symHeader.typeIndex.baseIndex = baseIndex;
   function->symHeader.symHeader.beginAddrInfo.startAddr =
            codeAddrRange->startAddr;
   function->symHeader.symHeader.endAddrInfo.endAddr =
            codeAddrRange->endAddr;
   function->funcClass  = funcClass;
   function->stackSpace = stackSize;
   function->typeIndex  = typeIndex;

   if(funcClass==FUNC_GLOBAL) {
      if((err=ht.PutName(funcOffset,duplicateName)) != GOOD) return err;
      if(duplicateName)
         return ER_DUPLICATE_GLOBAL_NAME;
      // IMPORTANT: Nghia 02/17/94
      // Need to dereference the "function" again before use it, or else
      // It might crash the symbol - ReAlloc bug
   }

   // fill in the ordinal value ;
   if((err = AddOrdinalValue(funcOffset)) != GOOD) return err;
   if((err = UpdateBlockInfo(funcOffset,SYM_OPEN,TRUE)) != GOOD) return err;

   // update the base for this symbol ;
   if ((err = AddAddrToByAddrTable(baseIndex, funcOffset,
                                   codeAddrRange->startAddr,
                                   codeAddrRange->endAddr)) != GOOD)
      return err;
   // Tally the function symbol
   symbolStat[symType]++;

   return GOOD;
}  // end of SymAddFuncCreate


//--------------------------------------------------------------------------
// SymAddFuncClose
//--------------------------------------------------------------------------
RETCODE EXPORT SymAddFuncClose(VOID) {
   COMMON_SYMBOL_HEADER HUGE *symPtr;
   TABLE_OFFSET              dummyOffset = 0;
   RETCODE                   err, firstErr = GOOD;
   U8                        tmpSymType;

   // Make sure that the current context is a function
   symPtr = (COMMON_SYMBOL_HEADER HUGE *)st.GetHugeDataPtr(currentOpenContext);
   tmpSymType = (U8)((symPtr->typeIndex.symType) & 0xF);
   if ((tmpSymType != SYM_FUNCTION) && (tmpSymType != SYM_BLOCK))
      return ER_SYMBOL_NOT_A_FUNCTION;

   // Update the current open context - function then update the state
   // of the symbol table.
/*
   firstErr = SymGetEndList(currentOpenContext, SYM_LABEL, &lastLabel);

   err = SymGetEndList(currentOpenContext, SYM_LOCAL_VAR, &lastVariable);
   if (GOOD == firstErr) firstErr = err;

   err = UpdateBlockInfo(dummyOffset,SYM_CLOSE,TRUE);
*/   
   err = UpdateBlockInfo(dummyOffset,SYM_CLOSE,TRUE);
   firstErr = SymGetEndList(currentOpenContext, SYM_LABEL, &lastLabel);

   if (GOOD == firstErr) firstErr = err;
   err = SymGetEndList(currentOpenContext, SYM_LOCAL_VAR, &lastVariable);

   if (GOOD == firstErr) return err;
   return firstErr;
}  // end of SymAddFuncClose


//--------------------------------------------------------------------------
// SymAddFuncOpen
//--------------------------------------------------------------------------
RETCODE EXPORT SymAddFuncOpen(LPSTR funcName) {

   COMMON_SYMBOL_HEADER HUGE *symPtr;
   SYM_DESCRIPTOR tmpOffset;
   SYM_TYPE_TYPE  symType;
   RETCODE        err;
   U8             name[MAX_SYMNAME_LENGTH];

   if (prevAction == SYM_OPEN) {
      // the previously opened/changed symbol should be a module symbol
      symPtr = (COMMON_SYMBOL_HEADER HUGE *)st.GetHugeDataPtr(prevSym);
      if (((symPtr->typeIndex.symType) & 0xF) != SYM_MODULE)
         return ER_SYMBOL_NOT_A_MODULE;

      // get module child offset
      if ((err = SymGetSymbolChild(prevSym, &symType, &tmpOffset)) != GOOD)
         return err;
   } else {
      // the previously accessed symbol was a function and the next function
      // to be accessed is the sibling of the previous function.
      if((err = SymGetSymbolSibling(prevSym, &symType, &tmpOffset)) != GOOD)
         return err;
   }
   if (NULL_SYMBOL == tmpOffset)  // don't allow access if 0; otherwise UAEs
      return ER_SYMBOL_HAS_NO_CHILD;
   do {
      symPtr = (COMMON_SYMBOL_HEADER HUGE *)st.GetHugeDataPtr(tmpOffset);
      st.GetString(symPtr->symbolNameOffset, name);
      if ( !strcmp((char *)funcName,(char *)name))
         break;
      if (( err = SymGetSymbolSibling(tmpOffset, &symType, &tmpOffset))
         != GOOD) return err;
   } while ( tmpOffset );

   if (!tmpOffset)
      return ER_SYMBOL_NOT_FOUND;

   // set up the current context ;
   if ((err = UpdateBlockInfo(tmpOffset,SYM_OPEN,FALSE)) != GOOD) return(err);

   // set the lastlabel and lastvariable values to the end of the var/label ;
   // list. ;
   if ((err = SymGetEndList(tmpOffset, SYM_LABEL, &lastLabel)) != GOOD)
      return err;

   if ((err = SymGetEndList(tmpOffset, SYM_LOCAL_VAR, &lastVariable))
      != GOOD) return err;

   return GOOD;
}

//--------------------------------------------------------------------------
// SymAddGetModuleName
//
// Purpose: Single, isolated call to get the name string of a module,
//          minus the header bytes
//
// Input parameters: module offset
//
// Output Parameters: modName.  Code modifies pointer after name put into
//                    string.
//--------------------------------------------------------------------------
RETCODE
SymAddGetModuleName(SYM_DESCRIPTOR module, LPSTR modName)  {

   SYM_TYPE_MODULE HUGE *modPtr;
   S8 *from = modName+2;
   U8 length;

   // make sure the symbol descriptor is ok
   if (!UtilIsValidSymDescriptor(module)) return ER_INVALID_SYM_DESCRIPTOR;

   modPtr = (SYM_TYPE_MODULE HUGE *)st.GetHugeDataPtr(module);
   if (modPtr->symHeader.symHeader.symbolNameOffset == NULL_SYMBOL)
      return ER_STRING_LENGTH_ZERO;
   st.GetString(modPtr->symHeader.symHeader.symbolNameOffset,
                (LPU8)modName);
   // shift the module name left over the two prepended characters in the ;
   // module names that makes them unique ;
   length = (U8)(strlen(modName) - 2);
   do {
      *modName++ = *from++;
   } while (length--);
   return SUCCESS;
   } // end of SymAddGetModuleName


//--------------------------------------------------------------------------
// SymAddLabel
//--------------------------------------------------------------------------
RETCODE EXPORT SymAddLabel(LPSTR labelName,
                           OFFSET_ADDR_TYPE addr) {

   RETCODE err;
   COMMON_SYMBOL_HEADER HUGE *labelSym;
   TABLE_OFFSET nameOffset,labelOffset,baseOffset;
   HPU8 label;
   BASE_INDEX baseIndex=(BASE_INDEX)SEG_CODE;

   if((err = bit.GetOffset(baseIndex,baseOffset)) != GOOD)
      return err;

   // get memory for the label in the symbol memory pool ;
   if((err = st.AllocBytes(sizeof(COMMON_SYMBOL_HEADER),
      labelOffset)) != GOOD) return err;
   if((err = st.PutString(labelName,nameOffset)) != GOOD) return err;

   labelSym = (COMMON_SYMBOL_HEADER HUGE *)st.GetHugeDataPtr(labelOffset);

   // fill in the label data ;
   labelSym->typeIndex.symType = SYM_LABEL;
   labelSym->typeIndex.baseIndex = baseIndex;
   labelSym->symbolNameOffset = nameOffset;
   labelSym->symParentOffset = currentOpenContext;
   labelSym->symSiblingOffset = 0;
   labelSym->beginAddrInfo.startAddr = addr;
// Modified by Gates Hua , for improve label priority   
//   labelSym->endAddrInfo.endAddr = addr+1;
   labelSym->endAddrInfo.endAddr = addr;

   // if there was a label loaded previously in this block then its sibling ;
   // pointer points to this label
   if(lastLabel) {
      label = st.GetHugeDataPtr(lastLabel);
      ((COMMON_SYMBOL_HEADER *)label)->symSiblingOffset = labelOffset;
   } else {
      // if this is the first label loaded for this block then we want ;
      // that module/func/blocks label list pointer pointing to this label ;
      label = st.GetHugeDataPtr(currentOpenContext);
      ((COMMON_BLOCK_HEADER *)label)->list.labelListOffset = labelOffset;
   }
   lastLabel = labelOffset;

   // fill in the ordinal value of this symbol ;
   if((err = AddOrdinalValue(labelOffset)) != GOOD) return err;

   // update the base for this symbol and add it to the by-address table
   if ((err = AddAddrToByAddrTable(baseIndex, labelOffset, addr, addr+1))
      != GOOD) return err;

   // tally the symbol label
   symbolStat[SYM_LABEL]++;

   return GOOD;
}  /* SymAddLabel() */


//--------------------------------------------------------------------------
// SymAddLabelPublic
//--------------------------------------------------------------------------
RETCODE EXPORT SymAddLabelPublic(LPSTR labelName,
                                 OFFSET_ADDR_TYPE addr) {

   RETCODE err;
   COMMON_SYMBOL_HEADER HUGE *labelSym;
   TABLE_OFFSET nameOffset,labelOffset,baseOffset;
   HPU8 label;
   U8 misses;
   BOOLEAN duplicateName;
   BASE_INDEX baseIndex=(BASE_INDEX)SEG_CODE;


   // make sure the base exists for the symbol ;
   if((err = bit.GetOffset(baseIndex,baseOffset)) != GOOD)
      return err;

   // make sure there isn't a duplicate name in the global name table ;
   if((err = ht.LookupName(labelName, labelOffset, misses)) != GOOD)
      return err;

   if (labelOffset)
      return ER_PUBLIC_IGNORED;

   // get memory for the label in the symbol memory pool ;
   if((err = st.AllocBytes(sizeof(COMMON_SYMBOL_HEADER),
      labelOffset)) != GOOD) return err;
   if((err = st.PutString(labelName,nameOffset)) != GOOD) return err;

   labelSym = (COMMON_SYMBOL_HEADER HUGE *)st.GetHugeDataPtr(labelOffset);

   // fill in the label data ;
   labelSym->typeIndex.symType = SYM_PUBLIC_LABEL;
   labelSym->typeIndex.baseIndex = baseIndex;
   labelSym->symbolNameOffset = nameOffset;
   labelSym->symParentOffset = rootOffset;
   labelSym->symSiblingOffset = 0;
   labelSym->beginAddrInfo.startAddr = addr;
   labelSym->endAddrInfo.endAddr = addr;

   // if there were any public labels loaded previously, then its sibling ;
   // pointer points to this label
   if(lastPublicLabel) {
      label = st.GetHugeDataPtr(lastPublicLabel);
      ((COMMON_SYMBOL_HEADER *)label)->symSiblingOffset = labelOffset;
   } else {
      // first public label being loaded; chain off root symbol label linked
      // list
      label = st.GetHugeDataPtr(rootOffset);
      ((COMMON_BLOCK_HEADER *)label)->list.labelListOffset = labelOffset;
   }
   lastPublicLabel = labelOffset;  // save away for next time thru

   // put the label's name into the global hash table ;
   if ((err = ht.PutName(labelOffset,duplicateName)) != GOOD)
      return err;
   if(duplicateName) // should never be a duplicate, but leave anyway
      return ER_DUPLICATE_GLOBAL_NAME;

   // fill in the ordinal value of this symbol ;
   if((err = AddOrdinalValue(labelOffset)) != GOOD) return err;

   // update the base for this symbol and add it to the by-address table
   if ((err = AddAddrToByAddrTable(baseIndex, labelOffset, addr, addr))
      != GOOD) return err;

   // tally the symbol
   symbolStat[SYM_PUBLIC_LABEL]++;

   return GOOD;
}


//--------------------------------------------------------------------------
// SymAddLoadEnd
//--------------------------------------------------------------------------
RETCODE EXPORT SymAddLoadEnd(VOID) {
   RETCODE err;
   TABLE_OFFSET offset = 0;

   if ((err = UpdateBlockInfo(offset,SYM_CLOSE,TRUE)) != GOOD) return err;
   if ((err = SortAllByAddressTables()) != GOOD) return err;

   // notify interested parties; distinguish on-demand from initial load
// if (onDemandState) {
//    if((err = EnlEventNotify(EVENT_SYMBOL_ONDEMAND_LOAD)) != GOOD)
//       return err;
// } else {
//    if((err = EnlEventNotify(EVENT_SYMBOL_INIT_LOAD)) != GOOD)
//       return err;
// }
   return GOOD;
}


//--------------------------------------------------------------------------
// SymAddLoadStart
//--------------------------------------------------------------------------
RETCODE EXPORT SymAddLoadStart(LPSTR filename, BOOLEAN onDemand,
                               TIMESTAMP_TYPE *timestamp) {

   COMMON_BLOCK_HEADER HUGE *rootPtr;

   if (onDemand) { // called to loaded linenums and locals for existing module
      if (strcmp((S8 *)loadFilename, filename)) {
         return ER_LOADFILES_DONT_MATCH;
      }

      // setup basic state info. ;
      prevSym = lastOpened = currentOpenContext = rootOffset;
      prevAction = SYM_OPEN;

      // compare timestamps.  if they don't match then all of the file ;
      // offsets stored in the symbol table are invalid. ;
      if (UtilCmpTimestamp(timestamp, &loadTimestamp))
         return ER_TIMESTAMPS_DONT_MATCH;
      onDemandState = onDemand;
      return GOOD; 
   } else {  // called to load new set of symbols
      rootPtr = (COMMON_BLOCK_HEADER HUGE *)st.GetHugeDataPtr(rootOffset);
      // NOTES: Nghia - 10/20/93
      // If lastOpened > rootOffset then table had symbols in it.
      if ( (lastOpened > rootOffset) ||
           (rootPtr->child) || (rootPtr->list.varListOffset) ||
           (rootPtr->list.labelListOffset) ||
           (rootPtr->list.constListOffset) ||
           (rootPtr->list.miscListOffset)  ||
            bit.GetEntryCount()) {
         return ER_SYMBOLS_LOADED;
      }
      // setup basic state info. ;
      prevSym = lastOpened = currentOpenContext = rootOffset;
      prevAction = SYM_OPEN;
      strcpy((LPSTR)loadFilename, filename);
      loadTimestamp = *timestamp;
   }
   // only if load is successful should the state flag be set
   onDemandState = onDemand;
   return AddSegmentTypesIntoBaseTable();
}

//--------------------------------------------------------------------------
// SymAddModuleClose
//--------------------------------------------------------------------------
RETCODE EXPORT SymAddModuleClose(BOOLEAN localsLoaded) {
   TABLE_OFFSET         dummyOffset = 0;
   RETCODE              err, firstErr = GOOD;
   SYM_TYPE_MODULE HUGE *modPtr;

   moduleOpen = FALSE;
   if (localsLoaded) {
      modPtr = (SYM_TYPE_MODULE *)st.GetHugeDataPtr(currentOpenContext);
      if (((modPtr->symHeader.symHeader.typeIndex.symType) & 0xF)
          != SYM_MODULE)  return ER_SYMBOL_NOT_A_MODULE;
      // This signify that the module is completely loaded.
      modPtr->fileOffset = SYMBOLS_LOADED;
   }
   // get the end of the label/variable lists of the root.  This needs ;
   // to be done so public labels and vars can be added properly. ;
   err = SymGetEndList(currentOpenContext, SYM_LABEL, &lastLabel);
   if (GOOD == firstErr) firstErr = err;
   err = SymGetEndList(currentOpenContext, SYM_LOCAL_VAR, &lastVariable);
   if (GOOD == firstErr) firstErr = err;
   err = UpdateBlockInfo(dummyOffset,SYM_CLOSE,TRUE);
   if (GOOD == firstErr) return err;
   return firstErr;
}  // end of SymAddModuleClose


//--------------------------------------------------------------------------
// SymAddModuleCreate
//--------------------------------------------------------------------------
RETCODE EXPORT
SymAddModuleCreate(LPSTR                   moduleName,
                   TIMESTAMP_TYPE          *timestamp,
                   ADDR_RANGE_TYPE         *codeAddrRange,
                   U32                     fileOffset,
                   BOOLEAN                 onDemand,
                   U32                     typeDelta,
                   SYM_DESCRIPTOR          *moduleDescriptor) {

   SYM_TYPE_MODULE HUGE *module;
   TABLE_OFFSET          nameOffset;
   RETCODE               err;
   BOOLEAN               duplicateName;
   TABLE_OFFSET          moduleOffset, baseOffset;
   U8                    tmpArray[MAX_SYMNAME_LENGTH];
   HPU8                  hpNamePtr;
   U8                    i;
   BASE_INDEX            baseIndex=(BASE_INDEX)SEG_CODE;

   if(moduleOpen)
      return ER_MODULE_ALREADY_OPEN;
   moduleOpen = TRUE;

   // make sure the base exists
   if((err = bit.GetOffset(baseIndex,baseOffset)) != GOOD)
      return err;

   lastLabel = lastVariable = 0;

   // check module name collision here and then handle;
   i=0x01;     // keep track of how many times we try to prepend a character ;
               // to the module name. ;
   // prepend an 0101 to the module name
   sprintf((LPSTR)tmpArray,(LPSTR)"%c%c%s",0x1,0x1,moduleName);

   // allocate memory in symbol pool and get pointer to it
   if((err = st.AllocBytes(sizeof(SYM_TYPE_MODULE),
      moduleOffset)) != GOOD) return err;

   module = (SYM_TYPE_MODULE HUGE *)st.GetHugeDataPtr(moduleOffset);
   // clear the module since many of the final values are zero ;
   ClearEntry(module, sizeof(SYM_TYPE_MODULE));

   // Need to put the mangled name into the symbol table since this ;
   // is what the hash table uses to find a module name ;
   if ((err = st.PutString((LPSTR)tmpArray, nameOffset)) != GOOD)
      return err;

   // NOTE: 02/17/94 - Nghia
   // BUG in GlobalReAlloc that might trash module pointer
   module = (SYM_TYPE_MODULE HUGE *)st.GetHugeDataPtr(moduleOffset);

   // initialize module name entry ;
   module->symHeader.symHeader.symbolNameOffset = nameOffset;

   // now get pointer to name string
   hpNamePtr = st.GetHugeDataPtr(nameOffset);
   while (TRUE) {
      // put the module offset (indirectly the name) into the name hash table
      if ((err = ht.PutName(moduleOffset, duplicateName)) != GOOD)
         return err;
      if (!duplicateName)
         break;

      if (i < 0xff) {
         return ER_DUPLICATE_GLOBAL_NAME;
      }
      i++;
      // modify name each time thru loop when duplicate found
      hpNamePtr[1] = i;  // insert in second byte of name header (01xx)
   }

   // NOTE: 02/17/94 - Nghia
   // BUG in symbol table. GlobalReAlloc() might wipe out the value of
   // module - Need to dereference again just in case
   module = (SYM_TYPE_MODULE HUGE *)st.GetHugeDataPtr(moduleOffset);

   // initialize the rest of the module entry ;
   module->symHeader.symHeader.typeIndex.symType = SYM_MODULE;
   module->symHeader.symHeader.typeIndex.baseIndex = baseIndex;
   module->symHeader.symHeader.beginAddrInfo.startAddr=codeAddrRange->startAddr;
   module->symHeader.symHeader.endAddrInfo.endAddr    =codeAddrRange->endAddr;

   module->timestamp.year = timestamp->year;
   module->timestamp.month = timestamp->month;
   module->timestamp.day = timestamp->day;
   module->timestamp.hour = timestamp->hour;
   module->timestamp.minute = timestamp->minute;
   module->timestamp.second = timestamp->second;
   module->typeDelta = typeDelta;
   if (onDemand) {
      module->fileOffset = fileOffset;  // more to come
   } else {
      module->fileOffset = SYMBOLS_LOADED;       // defined in symutil.h
   }
   // fill in ordinal value ;
   if((err = AddOrdinalValue(moduleOffset)) != GOOD)
      return err;

   if((err = UpdateBlockInfo(moduleOffset,SYM_OPEN,TRUE)) != GOOD)
      return err;

   // update the base for this symbol and add it to the by-address table
   if ((err = AddAddrToByAddrTable(baseIndex, moduleOffset,
                                   codeAddrRange->startAddr,
                                   codeAddrRange->endAddr))
      != GOOD)
      return err;

   *moduleDescriptor = moduleOffset;

   // tally the module symbol and save the lastModuleLoaded for progress
   // indicator
   symbolStat[SYM_MODULE]++;
   lastModuleLoaded = moduleOffset;

   return GOOD;
}  // end of SymAddModuleCreate

//--------------------------------------------------------------------------
// SymAddModuleOpen
//--------------------------------------------------------------------------
RETCODE EXPORT SymAddModuleOpen(LPSTR moduleName, LPSTR moduleReference,
                                U32 *fileOffset, U32 *typeDelta) {
   RETCODE err;
   TABLE_OFFSET moduleOffset; /* Module Descriptor */

   if ((err = SymGetModuleDesc(moduleName, moduleReference, &moduleOffset))
         != GOOD)
      return(err);
   return(SymAddModuleOpenByDesc(moduleOffset, fileOffset, typeDelta));
}

//--------------------------------------------------------------------------
// SymAddModuleOpenByDesc
//--------------------------------------------------------------------------
RETCODE EXPORT SymAddModuleOpenByDesc(SYM_DESCRIPTOR moduleDesc,
      U32 *fileOffset, U32 *typeDelta) {

   TABLE_OFFSET moduleOffset = moduleDesc;
   SYM_TYPE_MODULE HUGE *modPtr;
   RETCODE err;

   // update current context information
   if ((err = UpdateBlockInfo(moduleDesc, SYM_OPEN, FALSE)) != GOOD)
      return(err);

   // set the lastlabel and lastvariable values to the end of the var/label ;
   // list. ;
   if ((err = SymGetEndList(moduleOffset, SYM_LABEL, &lastLabel)) != GOOD)
      return err;

   if ((err = SymGetEndList(moduleOffset, SYM_LOCAL_VAR, &lastVariable))
      != GOOD)
      return err;

   // get the file descriptor ;
   modPtr = (SYM_TYPE_MODULE HUGE *) st.GetHugeDataPtr(moduleOffset);
   *fileOffset = modPtr->fileOffset;
   // get the typeDelta ;
   *typeDelta = modPtr->typeDelta;

   moduleOpen = TRUE;

   return GOOD;
}

//--------------------------------------------------------------------------
// SymAddModuleSourceFilePosition
//--------------------------------------------------------------------------
RETCODE EXPORT
SymAddModuleSourceFilePosition( SYM_DESCRIPTOR  moduleDescriptor ,
                                U32             srcFileOffset) {
   SYM_TYPE_MODULE HUGE *modPtr;

   // make sure the symbol descriptor is ok
   if (!UtilIsValidSymDescriptor(moduleDescriptor))
      return ER_INVALID_SYM_DESCRIPTOR;

   modPtr = (SYM_TYPE_MODULE HUGE *) st.GetHugeDataPtr(moduleDescriptor);
   if (((modPtr->symHeader.symHeader.typeIndex.symType) & 0xF) != SYM_MODULE)
      return ER_SYMBOL_NOT_A_MODULE;

   modPtr->srcFilePosition = srcFileOffset;
   return GOOD;

}  // end of SymAddModuleSourceFilePosition

//--------------------------------------------------------------------------
// SymAddModuleReference
//--------------------------------------------------------------------------
RETCODE EXPORT SymAddModuleReference(SYM_DESCRIPTOR moduleDescriptor,
                                     LPSTR moduleReference) {
   RETCODE err;
   SYM_TYPE_MODULE HUGE *modPtr;
   TABLE_OFFSET nameOffset;

   // make sure we have something to add
   if (!*moduleReference)
      return ER_NAME_NOT_ADDED;

   // make sure the symbol descriptor is ok
   if (!UtilIsValidSymDescriptor(moduleDescriptor))
      return ER_INVALID_SYM_DESCRIPTOR;

   modPtr = (SYM_TYPE_MODULE HUGE *) st.GetHugeDataPtr(moduleDescriptor);
   if (((modPtr->symHeader.symHeader.typeIndex.symType) & 0xF) != SYM_MODULE)
      return ER_SYMBOL_NOT_A_MODULE;

   if((err = st.PutString(moduleReference,nameOffset)) != GOOD)
      return err;

   // NOTES: Nghia - 10/20/93
   // BUG in symbol table.  When st.PutString() extends the table size,
   // GlobalReAlloc() wiped out modPtr old value.  Which caused a UAE.
   // TEST: load Tandberg\t2.abs nodemand.
   // SOLUTION: Update the modPtr in case table is changed.
   //
   modPtr = (SYM_TYPE_MODULE HUGE *) st.GetHugeDataPtr(moduleDescriptor);
   modPtr->srcFilenameOffset = nameOffset;
   return GOOD;
}  // end of SymAddModuleReference


//--------------------------------------------------------------------------
// SymAddSymbolSetAddr
//--------------------------------------------------------------------------
RETCODE EXPORT SymAddSymbolSetAddr(QUAL_ADDR_RANGE_TYPE *qualAddrRange) {

   RETCODE err;
   COMMON_SYMBOL_HEADER HUGE *symPtr;
   BaseSymbol HUGE *basePtr;
   SYM_DESCRIPTOR baseOffset;
   U8             tmpSymType;

   // prevSym is actually the current open context ;
   symPtr = (COMMON_SYMBOL_HEADER HUGE *)st.GetHugeDataPtr(prevSym);

   tmpSymType = (U8)((symPtr->typeIndex.symType) & 0xF);
   switch ((SYM_TYPE_TYPE)tmpSymType) {
      case SYM_FUNCTION:
      case SYM_BLOCK:
         break;  // valid cases
      case SYM_MODULE:
         // update last linenum if there are any and if last address is valid
         if (qualAddrRange->endValid) {
            UpdateLinenumEndAddr((SYM_TYPE_MODULE *)symPtr,
                                 qualAddrRange->endAddr);
         }
         break;  // valid cases

      default:
         return ER_SYMBOL_NOT_A_FUNCTION;
   }
   if (qualAddrRange->startValid)
      symPtr->beginAddrInfo.startAddr = qualAddrRange->startAddr;
   if (qualAddrRange->endValid)
      symPtr->endAddrInfo.endAddr = qualAddrRange->endAddr;
   if (!(qualAddrRange->startValid || qualAddrRange->endValid))
      return ER_NO_VALID_ADDRESS;

   // update the base address range.  This can only be done for code bases
   // here.
   if ((err = bit.GetOffset(symPtr->typeIndex.baseIndex, baseOffset)) != GOOD)
      return err;
   basePtr = (BaseSymbol HUGE *)st.GetHugeDataPtr(baseOffset);
   basePtr->UpdateAddrVars(qualAddrRange->startAddr, qualAddrRange->endAddr);

   return GOOD;
}


//--------------------------------------------------------------------------
// SymAddTypeBitfield
//--------------------------------------------------------------------------
RETCODE EXPORT SymAddTypeBitfield(TYPE_INDEX typeIndex,
                                  TYPE_BITFIELD_STRUCT *bitfieldStruct) {
   RETCODE err;
   TABLE_OFFSET offset;

   if (typeIndex != tt.GetTypeIndex())
      return ER_TYPE_IDXS_DONT_MATCH;

   if ((err = tt.PutBytes((U8 *)bitfieldStruct, sizeof(TYPE_BITFIELD_STRUCT),
      offset)) != GOOD) return err;
   if ((err = tt.UpdateRecordSize(sizeof(TYPE_BITFIELD_STRUCT))) != GOOD)
      return err;
   if ((err = tt.IncrementMemberCount()) != GOOD) return err;

   return GOOD;
}


//--------------------------------------------------------------------------
// SymAddTypeCArray
//--------------------------------------------------------------------------
RETCODE EXPORT SymAddTypeCArray(TYPE_INDEX typeIndex,
                                TYPE_Z_STRUCT *cArrayStruct) {
   RETCODE err;
   TABLE_OFFSET offset;

   if (typeIndex != tt.GetTypeIndex())
      return ER_TYPE_IDXS_DONT_MATCH;

   if ((err = tt.PutBytes((U8 *)cArrayStruct, sizeof(TYPE_Z_STRUCT),
      offset)) != GOOD) return err;
   if ((err = tt.UpdateRecordSize(sizeof(TYPE_Z_STRUCT))) != GOOD)
      return err;
   if ((err = tt.IncrementMemberCount()) != GOOD) return err;

   return GOOD;
}

//--------------------------------------------------------------------------
// SymAddTypeArray51
//--------------------------------------------------------------------------
RETCODE EXPORT SymAddTypeArray51(TYPE_INDEX typeIndex,
                                 TYPE_OMF51_ARRAY_STRUCT *arrayStruct) {
   RETCODE err;
   TABLE_OFFSET offset;

   if (typeIndex != tt.GetTypeIndex())
      return ER_TYPE_IDXS_DONT_MATCH;

   if ((err = tt.PutBytes((U8 *)arrayStruct, sizeof(TYPE_OMF51_ARRAY_STRUCT),
      offset)) != GOOD) return err;
   if ((err = tt.UpdateRecordSize(sizeof(TYPE_OMF51_ARRAY_STRUCT))) != GOOD)
      return err;
   if ((err = tt.IncrementMemberCount()) != GOOD) return err;

   return GOOD;
}

//--------------------------------------------------------------------------
// SymAddTypeArrayDimSize
//--------------------------------------------------------------------------
RETCODE EXPORT SymAddTypeArrayDimSize(TYPE_INDEX typeIndex,
                                      DIMENSION  dimSize) {

   RETCODE err;
   TABLE_OFFSET typeOffset;

   // check to make sure the type index matches the index of the last
   // type header created.
   if (typeIndex != tt.GetTypeIndex())
      return ER_TYPE_IDXS_DONT_MATCH;

   if ((err = tt.PutBytes((U8 *)&dimSize, sizeof(DIMENSION),
      typeOffset)) != GOOD) return err;
   if ((err = tt.UpdateRecordSize(sizeof(DIMENSION))) != GOOD) return err;
   if ((err = tt.IncrementMemberCount()) != GOOD) return err;

   return GOOD;
}

//--------------------------------------------------------------------------
// SymAddTypeEnum
//--------------------------------------------------------------------------
RETCODE EXPORT SymAddTypeEnum(TYPE_INDEX typeIndex, U32 enumValue,
                              LPSTR enumName) {
   RETCODE err;
   TABLE_OFFSET offset;
   ENUM_TYPE_STRUCT enumStruct;

   if (typeIndex != tt.GetTypeIndex())
      return ER_TYPE_IDXS_DONT_MATCH;

   if ((err = st.PutString(enumName, offset)) != GOOD) return err;

   enumStruct.enumValue = enumValue;
   enumStruct.enumName = offset;

   if ((err = tt.PutBytes((U8 *)&enumStruct, sizeof(ENUM_TYPE_STRUCT),
      offset)) != GOOD) return err;
   if ((err = tt.UpdateRecordSize(sizeof(ENUM_TYPE_STRUCT))) != GOOD)
      return err;
   if ((err = tt.IncrementMemberCount()) != GOOD) return err;

   return GOOD;
}

//--------------------------------------------------------------------------
// SymAddTypeFunc
//--------------------------------------------------------------------------
RETCODE EXPORT SymAddTypeFunc(TYPE_INDEX typeIndex, U32 attribute,
               U8 frameType, U32 pushMask, TYPE_INDEX returnType,
               U8 argCount, U8 level, LPSTR fatherName) {

   FUNC_TYPE_HEADER funcTypeHeader;
   TABLE_OFFSET nameOffset,typeOffset;
   RETCODE err;

   // check to make sure the type index matches the index of the last ;
   // type header created. ;
   if (typeIndex != tt.GetTypeIndex())
      return ER_TYPE_IDXS_DONT_MATCH;

   // put the type name into the symbol table, if it exists ;
   if (fatherName[0]) {
      if ((err = st.PutString(fatherName,nameOffset)) != GOOD) return err;
   } else {
      nameOffset = NULL_SYMBOL;
   }

   funcTypeHeader.attribute = attribute;
   funcTypeHeader.frameType = frameType;
   funcTypeHeader.pushMask = pushMask;
   funcTypeHeader.returnType = returnType;
   funcTypeHeader.argCount = argCount;
   funcTypeHeader.level = level;
   funcTypeHeader.fatherName = nameOffset;

   // put the function info into the type table. ;
   if ((err = tt.PutBytes((U8 *)&funcTypeHeader, sizeof(FUNC_TYPE_HEADER),
      typeOffset)) != GOOD) return err;
   if ((err = tt.UpdateRecordSize(sizeof(FUNC_TYPE_HEADER))) != GOOD)
      return err;
   if ((err = tt.IncrementMemberCount()) != GOOD) return err;


   return GOOD;
}


//--------------------------------------------------------------------------
// SymAddTypeFuncParam
//--------------------------------------------------------------------------
RETCODE EXPORT SymAddTypeFuncParam(TYPE_INDEX typeIndex,
                                   TYPE_INDEX paramTypeIndex) {

   RETCODE err;
   TABLE_OFFSET typeOffset;

   // check to make sure the type index matches the index of the last
   // type header created.
   if (typeIndex != tt.GetTypeIndex())
      return ER_TYPE_IDXS_DONT_MATCH;

   if ((err = tt.PutBytes((U8 *)&paramTypeIndex, sizeof(TYPE_INDEX),
      typeOffset)) != GOOD) return err;
   if ((err = tt.UpdateRecordSize(sizeof(TYPE_INDEX))) != GOOD) return err;
   if ((err = tt.IncrementMemberCount()) != GOOD) return err;

   return GOOD;
}


//--------------------------------------------------------------------------
// SymAddTypeHeader
//--------------------------------------------------------------------------
RETCODE EXPORT SymAddTypeHeader(TYPE_INDEX typeIndex,
                                TYPE_HEADER_TYPE *typeHeader) {
   RETCODE err;
   TYPE_HEADER_TYPE2 typeHdr;
   TABLE_OFFSET nameOffset = 0L;

   // initialize typeHdr to 0
   memset(&typeHdr, 0, sizeof(typeHdr));
   typeHdr.typeChoice = typeHeader->typeChoice;
   if (typeHdr.typeChoice == SIMPLE_TYPE_CLASS) 
      typeHdr.t.simpleType = typeHeader->t.simpleType;
   else 
      typeHdr.t.complexType = typeHeader->t.complexType;


   // NOTES: 09/15/93  Nghia
   // Fill in the size of MAU if known, otherwise wait to calculate the
   // sizeInMAUs of this type until it's get access by someone.
   // This way forward reference type will never need to know the sizeInMAUs
   // of its type before hand.
   // NOTES: 09/02/94 - Nghia
   // The <sizeCalculated> is used to indicate other fields of the type
   // header are undefined at this point; therefore the sizeInMAUs can be
   // valid - remove the check for sizeCalculated here.
   typeHdr.sizeCalculated = typeHeader->sizeCalculated;
   typeHdr.sizeInMAUs = typeHeader->sizeInMAUs;

   typeHdr.recordSize = sizeof(TYPE_HEADER_TYPE2);
   // set member count to 0; the first member added will bump it to the
   // valid value of 1.
   typeHdr.memberCount = 0;

   // put the header name if it exists ;
   if (typeHeader->typeName) {
      if(typeHeader->typeName[0]) {
         if ((err = st.PutString(typeHeader->typeName,nameOffset)) != GOOD)
            return err;
      }
      typeHdr.typeName = nameOffset;
   }   

   if ((err = tt.PutHeader((U8 *)&typeHdr,typeHdr.recordSize,typeIndex))
      != GOOD) return err;
   return GOOD;
}

//--------------------------------------------------------------------------
// SymAddTypeOverwriteSize
//--------------------------------------------------------------------------
RETCODE EXPORT SymAddTypeOverwriteSize(U8 typeIndex, U8 typeMAUSize) {
   RETCODE err;
   TYPE_HEADER_TYPE2 HUGE *typePtr;
   TABLE_OFFSET typeOffset;

   if((err = typit.GetOffset(typeIndex,typeOffset)) != GOOD) return err;
   typePtr = (TYPE_HEADER_TYPE2 HUGE *) tt.GetHugeDataPtr(typeOffset);
   typePtr->sizeInMAUs = typeMAUSize;
   typePtr->sizeCalculated = TRUE;
   return GOOD;
}

//--------------------------------------------------------------------------
// SymAddTypePointerTypeIndex
//--------------------------------------------------------------------------
RETCODE EXPORT SymAddTypePointerTypeIndex(TYPE_INDEX typeIndex,
                                          TYPE_INDEX pointerTypeIndex) {
   RETCODE err;
   TABLE_OFFSET offset;

   if (typeIndex != tt.GetTypeIndex())
      return ER_TYPE_IDXS_DONT_MATCH;
   if ((err = tt.PutBytes((U8 *)&pointerTypeIndex, sizeof(TYPE_INDEX),
      offset)) != GOOD)
      return err;
   if ((err = tt.UpdateRecordSize(sizeof(TYPE_INDEX))) != GOOD)
      return err;
   return tt.IncrementMemberCount();
}

//--------------------------------------------------------------------------
// SymAddTypeRegVar
//--------------------------------------------------------------------------
RETCODE EXPORT
SymAddTypeRegVar(TYPE_INDEX typeIndex,
                 REG_INDEX  regIndex,
                 TYPE_INDEX baseTypeIndex) {

   REG_VAR_TYPE regVarType;
   RETCODE      err;
   TABLE_OFFSET offset;

   // make sure last type index created with SymAddTypeHeader is same
   // as the one being added to
   if (typeIndex != tt.GetTypeIndex())
      return ER_TYPE_IDXS_DONT_MATCH;

   // place params into structure so it can be put into type table
   regVarType.regIndex = regIndex;
   regVarType.baseTypeIndex = baseTypeIndex;

   if ((err = tt.PutBytes((U8 *)&regVarType, sizeof(REG_VAR_TYPE),
      offset)) != GOOD)
      return err;
   if ((err = tt.UpdateRecordSize(sizeof(REG_VAR_TYPE))) != GOOD)
      return err;
   return tt.IncrementMemberCount();

} // end of SymAddTypeRegVar


//--------------------------------------------------------------------------
// SymAddTypeStructUnion
//--------------------------------------------------------------------------
RETCODE EXPORT SymAddTypeStructUnion(TYPE_INDEX typeIndex,
                                     TYPE_S_U_STRUCT *structOrUnion) {
   RETCODE err;
   TABLE_OFFSET offset;
   TYPE_STRUCT_HEADER structHdr;

   if (typeIndex != tt.GetTypeIndex())
      return ER_TYPE_IDXS_DONT_MATCH;

   if ((err = st.PutString(structOrUnion->name,offset)) != GOOD)
      return err;

   structHdr.nameOffset = offset;
   structHdr.typeIndex = structOrUnion->typeIndex;
   structHdr.offset = structOrUnion->offset;

   if ((err = tt.PutBytes((U8 *)&structHdr, sizeof(TYPE_STRUCT_HEADER),
      offset)) != GOOD) return err;
   if ((err = tt.UpdateRecordSize(sizeof(TYPE_STRUCT_HEADER))) != GOOD)
      return err;
   if ((err = tt.IncrementMemberCount()) != GOOD) return err;

   return GOOD;
}

//--------------------------------------------------------------------------
// SymAddTypeTypeIndex
//--------------------------------------------------------------------------
/*
RETCODE EXPORT SymAddTypeTypeIndex(TYPE_INDEX typeIndex,
                                   TYPE_INDEX typeTypeIndex) {
   RETCODE err;
   TABLE_OFFSET offset;

   if (typeIndex != tt.GetTypeIndex())
      return ER_TYPE_IDXS_DONT_MATCH;

   if ((err = tt.PutBytes((U8 *)&typeTypeIndex, sizeof(TYPE_INDEX),
      offset)) != GOOD) return err;
   // NOTES: 09/15/93 - Nghia
   // Update record size with sizeof(TYPE_INDEX) only,
   // not sizeof(TYPE_STRUCT_HEADER) which is way too big
   if ((err = tt.UpdateRecordSize(sizeof(TYPE_INDEX))) != GOOD)
      return err;
   if ((err = tt.IncrementMemberCount()) != GOOD) return err;

   return GOOD;
}
*/
RETCODE EXPORT SymAddTypeTypeIndex(TYPE_INDEX typeIndex,
                                   TYPE_INDEX typeTypeIndex) {
   RETCODE err;
   TABLE_OFFSET offset;
   TYPE_TYPE typeType;
   
   if (typeIndex != tt.GetTypeIndex())
      return ER_TYPE_IDXS_DONT_MATCH;
   
   typeType.typeIndex = typeTypeIndex;
   typeType.segType = SEG_UNTYPED;
   
//   if ((err = tt.PutBytes((U8 *)&typeTypeIndex, sizeof(TYPE_INDEX),
   if ((err = tt.PutBytes((U8 *)&typeType, sizeof(TYPE_TYPE),
      offset)) != GOOD) return err;
   // NOTES: 09/15/93 - Nghia
   // Update record size with sizeof(TYPE_INDEX) only,
   // not sizeof(TYPE_STRUCT_HEADER) which is way too big
   if ((err = tt.UpdateRecordSize(sizeof(TYPE_TYPE))) != GOOD)
      return err;
   if ((err = tt.IncrementMemberCount()) != GOOD) return err;

   return GOOD;
}

RETCODE EXPORT SymAddTypeTypeType(TYPE_INDEX typeIndex,
                                  TYPE_INDEX typeTypeIndex,
                                  SEGMENTTYPE segType ) {
   RETCODE err;
   TABLE_OFFSET offset;
   TYPE_TYPE typeType;
   
   if (typeIndex != tt.GetTypeIndex())
      return ER_TYPE_IDXS_DONT_MATCH;
   
   typeType.typeIndex = typeTypeIndex;
   typeType.segType = segType;
   
//   if ((err = tt.PutBytes((U8 *)&typeTypeIndex, sizeof(TYPE_INDEX),
   if ((err = tt.PutBytes((U8 *)&typeType, sizeof(TYPE_TYPE),
      offset)) != GOOD) return err;
   // NOTES: 09/15/93 - Nghia
   // Update record size with sizeof(TYPE_INDEX) only,
   // not sizeof(TYPE_STRUCT_HEADER) which is way too big
   if ((err = tt.UpdateRecordSize(sizeof(TYPE_TYPE))) != GOOD)
      return err;
   if ((err = tt.IncrementMemberCount()) != GOOD) return err;

   return GOOD;
}

//--------------------------------------------------------------------------
// SymAddTypePointer51
//--------------------------------------------------------------------------
RETCODE EXPORT SymAddTypePointer51(TYPE_INDEX typeIndex,
                                   TYPE_OMF51_PTR_STRUCT *ptrStruct) {
   RETCODE err;
   TABLE_OFFSET offset;

   if (typeIndex != tt.GetTypeIndex())
      return ER_TYPE_IDXS_DONT_MATCH;

   if ((err = tt.PutBytes((U8 *)ptrStruct, sizeof(TYPE_OMF51_PTR_STRUCT),
      offset)) != GOOD) return err;
   if ((err = tt.UpdateRecordSize(sizeof(TYPE_OMF51_PTR_STRUCT))) != GOOD)
      return err;
   if ((err = tt.IncrementMemberCount()) != GOOD) return err;

   return GOOD;
}

//--------------------------------------------------------------------------
// SymAddVar
//
// NOTES: variable size is held in variable symbol record; i.e. it does not
//        have to be extracted from the type field
//--------------------------------------------------------------------------
RETCODE EXPORT SymAddVar(LPSTR              varName,
                         TYPE_INDEX         typeIndex,
                         VAR_STORAGE_CLASS  storageClass,
                         VAR_REGISTER_CLASS registerClass,
                         ADD_VAR_ADDR_UNION FAR *varAddr,
                         BOOLEAN            isConstant,
                         BOOLEAN            isValidAddr,
                         SYM_DESCRIPTOR FAR *varDesc) {

   RETCODE                err;
   TABLE_OFFSET           nameOffset,varOffset,baseOffset;
   HPU8                   var;
   BOOLEAN                duplicateName = FALSE;
   U16                    allocSize;
   SYM_TYPE_VARIABLE HUGE *varSym;
   TYPE_HEADER_TYPE       typeHeader;
   VAR_BASED_VAR HUGE     *basedPtr;
   AUTO_VAR_OFFSET HUGE   *autoVarPtr;
   SYM_LIFETIME_START_INFO HUGE *lifetimePtr;
   SYM_TYPE_TYPE          tmpSymType;
   U8                     misses;
   CHAR                   typeName[MAX_STRING_SIZE] = "";
   BASE_INDEX             baseIndex=varAddr->addr.segType;

   // check to make sure the type index and base index exist;
   if((err = bit.GetOffset(baseIndex,baseOffset)) != GOOD)
      return err;

   // Notes: 08/16/94 - Nghia
   // get the type header type to resolve the sizeInMAUs of the type
   // do not access the type information directly.
   typeHeader.typeName = (LPSTR)typeName;
   if ((err = SymGetTypeHeader(typeIndex, &typeHeader)) != GOOD)
      return err;

   if ((storageClass == GLOBAL_VAR_CLASS) ||
      (storageClass == UNKNOWN_VAR_CLASS)) {
      // find out if the variable name already exists.
      if ((err = ht.LookupName(varName, varOffset, misses)) != GOOD)
         return err;
      if (varOffset)
         return ER_DUPLICATE_GLOBAL_NAME;
   }
   // trap on items not implemented yet
   if (( registerClass == SHADOW_REG ) ||
      ( (registerClass != NOT_REG) && (storageClass == BASED_VAR_CLASS)))
      return ER_NOT_IMPLEMENTED;

   if((err = st.PutString(varName,nameOffset)) != GOOD)
      return err;

   // get memory for the variable in the symbol pool
   switch (registerClass) {
      case NOT_REG:
         if (storageClass != BASED_VAR_CLASS) {
            allocSize = sizeof(SYM_TYPE_VARIABLE);
         } else {
            allocSize = sizeof(SYM_TYPE_VARIABLE) + sizeof(VAR_BASED_VAR);
         }
         break;
      case LIVING_REG:
         allocSize = sizeof(SYM_LIFETIME_START_INFO) +
            sizeof(SYM_TYPE_VARIABLE);
         break;
      case SHADOW_REG:
         // @@ !!! this is a dummy value ;
         allocSize = sizeof(SYM_TYPE_VARIABLE);
         break;
      case LOCKED_REG:
         allocSize = sizeof(AUTO_VAR_OFFSET) + sizeof(SYM_TYPE_VARIABLE) +
                     sizeof(SYM_LIFETIME_START_INFO);
         break;
   }

   // allocate the number of bytes just calculated.
   if((err = st.AllocBytes((U8)allocSize, varOffset)) != GOOD)
      return err;

   varSym = (SYM_TYPE_VARIABLE HUGE *)st.GetHugeDataPtr(varOffset);
   ClearEntry(varSym, sizeof(SYM_TYPE_VARIABLE));

   // put the offset of the symbol name into the variable entry
   // before it gets put into the global hash table.
   varSym->symHeader.symbolNameOffset = nameOffset;

   // an unknown var is considered a global; put either into hash table
   if ((storageClass == GLOBAL_VAR_CLASS) ||
                        (storageClass == UNKNOWN_VAR_CLASS)) {
      varSym->symHeader.typeIndex.symType = SYM_GLOBAL_VAR;
      if((err = ht.PutName(varOffset,duplicateName)) != GOOD)
         return err;
      // this should never happen, but leave it anyway.
      if(duplicateName)
         return ER_DUPLICATE_GLOBAL_NAME;
   }
   else {
      varSym->symHeader.typeIndex.symType = SYM_LOCAL_VAR;
   }

   // NOTE: 02/17/94 - Nghia
   // BUG in GlobalReAlloc() that trash pointer
   varSym = (SYM_TYPE_VARIABLE HUGE *)st.GetHugeDataPtr(varOffset);

   // save the type of symbol for tally
   tmpSymType = varSym->symHeader.typeIndex.symType;

   varSym->symHeader.typeIndex.baseIndex = baseIndex;
   varSym->symHeader.symParentOffset = currentOpenContext;
   varSym->symHeader.symSiblingOffset = 0;

   // store the address info of the register using the storageClass and
   // the registerClass of the variable.  Make sure the address is valid.
   if (isValidAddr) {
      if (registerClass == NOT_REG) {
         switch (storageClass) {
            case STATIC_VAR_CLASS:
            case UNKNOWN_VAR_CLASS:
            case GLOBAL_VAR_CLASS:
               varSym->symHeader.beginAddrInfo.startAddr =
                  varAddr->addr.addr;
               if (typeHeader.sizeInMAUs == 0L) {
                  // a size of 0 is not represented by the address start-end
                  // structure.  Set end equal to start for this case anyway
                  varSym->symHeader.endAddrInfo.endAddr =
                  varSym->symHeader.beginAddrInfo.startAddr;
               } else {
                  varSym->symHeader.endAddrInfo.endAddr =
                  varSym->symHeader.beginAddrInfo.startAddr +
                                 typeHeader.sizeInMAUs - 1L;
               }
            break;

            case AUTO_VAR_CLASS:
               varSym->symHeader.beginAddrInfo.autoVarOffset =
                  varAddr->autoVar;
               varSym->symHeader.endAddrInfo.varSize = typeHeader.sizeInMAUs;
            break;

            case BASED_VAR_CLASS:
               // based variables have a separate structure to hold data
               varSym->symHeader.beginAddrInfo.startAddr = 0L;
               varSym->symHeader.endAddrInfo.varSize = typeHeader.sizeInMAUs;

               // get a pointer to the memory just below the common header
               basedPtr = (VAR_BASED_VAR HUGE *)st.GetHugeDataPtr(varOffset +
                  sizeof(SYM_TYPE_VARIABLE));
               basedPtr->offsetVal = varAddr->basedVar.offsetVal;
               basedPtr->controlNum = varAddr->basedVar.controlNum;
               basedPtr->publicLocal = varAddr->basedVar.publicLocal;
               basedPtr->memorySpace = varAddr->basedVar.memorySpace;
               basedPtr->baseSize = varAddr->basedVar.baseSize;
            break;

            default:
               return ER_STORAGE_CLASS_UNKNOWN;
         }
      } else {
         if (registerClass == LOCKED_REG) {
            // store the "address"
            varSym->symHeader.beginAddrInfo.registerIndex =
               varAddr->lockedReg.regIndex;
            varSym->symHeader.endAddrInfo.varSize =
               typeHeader.sizeInMAUs;

            // the additional frame offset (autoVarOffset) must be
            // placed in separate space after the standard variable
            // data (like based variable)
            autoVarPtr = (AUTO_VAR_OFFSET HUGE *)st.GetHugeDataPtr(varOffset +
               sizeof(SYM_TYPE_VARIABLE));
            *autoVarPtr = varAddr->lockedReg.autoVarOffset;

            lifetimePtr = (SYM_LIFETIME_START_INFO HUGE *)
               st.GetHugeDataPtr(varOffset + sizeof(SYM_TYPE_VARIABLE) +
               sizeof(AUTO_VAR_OFFSET));
            lifetimePtr->firstEntry = NULL_SYMBOL;
            lifetimePtr->lastEntry = NULL_SYMBOL;

         } else if (registerClass == LIVING_REG) {
            // store away the "address" ;
            varSym->symHeader.beginAddrInfo.registerIndex =
               varAddr->registerIndex;
            varSym->symHeader.endAddrInfo.varSize =
               typeHeader.sizeInMAUs;

            lifetimePtr = (SYM_LIFETIME_START_INFO HUGE *)
               st.GetHugeDataPtr(varOffset + sizeof(SYM_TYPE_VARIABLE));
            lifetimePtr->firstEntry = NULL_SYMBOL;
            lifetimePtr->lastEntry = NULL_SYMBOL;

         } else {
            // this should never happen.  See above.
            return ER_NOT_IMPLEMENTED;
         }
      }
   } // end isValidAddr

   varSym->typeIndex = typeIndex;
   varSym->storageClass = storageClass;
   varSym->registerClass = registerClass;
   varSym->isConstant = isConstant;    // indicates a const var or not
   varSym->isValidAddr = isValidAddr;  // sets flag for valid addr or not

   // fill in the ordinal value of this symbol
   if((err = AddOrdinalValue(varOffset)) != GOOD)
      return err;

   // if there was a var loaded previously in this block then its sibling
   // pointer points to this variable
   if(lastVariable) {
      var = st.GetHugeDataPtr(lastVariable);
      ((SYM_TYPE_VARIABLE *)var)->symHeader.symSiblingOffset = varOffset;
   } else {
      // if this is the first variable loaded for this block then we want
      // that module/func/blocks var list pointer pointing to this variable
      var = st.GetHugeDataPtr(currentOpenContext);
      ((COMMON_BLOCK_HEADER *)var)->list.varListOffset = varOffset;
   }
   // update the base for this symbol and add it to the by-address table
   // if it is static/global/unknown and the address given is valid.
   if (((storageClass == STATIC_VAR_CLASS) ||
      (storageClass == GLOBAL_VAR_CLASS) ||
      (storageClass == UNKNOWN_VAR_CLASS)) && isValidAddr ) {
      if ((err = AddAddrToByAddrTable(baseIndex, varOffset,
         varSym->symHeader.beginAddrInfo.startAddr,
         varSym->symHeader.endAddrInfo.endAddr))
         != GOOD)
         return err;
   }
   lastVariable = varOffset;

   // return a descriptor to the variable.  In this case it is the offset
   // into the global symbol table.
   *varDesc = varOffset;

   // tally the symbol
   symbolStat[tmpSymType]++;

   return GOOD;
}  // end of SymAddVar


//--------------------------------------------------------------------------
// SymAddVarPublic
//--------------------------------------------------------------------------
RETCODE EXPORT SymAddVarPublic(LPSTR varName,
                               TYPE_INDEX typeIndex,
                               ADDRESS_TYPE varAddr) {

   COMMON_SYMBOL_HEADER HUGE *symPtr;
   RETCODE            err;
   TABLE_OFFSET       varOffset,baseOffset;
   U8                 misses;
   SYM_TYPE_VARIABLE  HUGE *varSym;
   SYM_TYPE_VARIABLE  HUGE *varAccessPtr;
   VAR_STORAGE_CLASS  storageClass;
   TABLE_OFFSET       nameOffset;
   BOOLEAN            duplicateName;
   U8                 tmpSymType;
   TYPE_HEADER_TYPE   typeHeader;
   CHAR               typeName[MAX_STRING_SIZE] = "";
   BASE_INDEX         baseIndex=(BASE_INDEX)varAddr.segType;

   // check to make sure the type index and base index exist;
   if((err = bit.GetOffset(baseIndex,baseOffset)) != GOOD)
      return err;
   // Notes: 08/16/94 - Nghia
   // get the type header type to resolve the sizeInMAUs of the type
   // do not access the type information directly.
   typeHeader.typeName = (LPSTR)typeName;
   if ((err = SymGetTypeHeader(typeIndex, &typeHeader)) != GOOD)
      return err;

   // find out if the variable name already exists. ;
   if ((err = ht.LookupName(varName, varOffset, misses)) != GOOD)
      return err;

   if (varOffset) {
      symPtr = (COMMON_SYMBOL_HEADER HUGE *)st.GetHugeDataPtr(varOffset);
      tmpSymType = (U8)((symPtr->typeIndex.symType) & 0xF);
      if (!((tmpSymType == SYM_GLOBAL_VAR) ||
           (tmpSymType == SYM_PUBLIC_VAR) ||
           (tmpSymType == SYM_PUBLIC_LABEL) ||
           (tmpSymType == SYM_PUBLIC_UNKNOWN))) {
         return ER_NOT_A_VARIABLE;
      } else {
         varSym = (SYM_TYPE_VARIABLE *)symPtr;
         if (varSym->isValidAddr)
            return ER_PUBLIC_IGNORED;
         else {
            // fill in the address and return ;
            // must get valid type index from variable record
            typeIndex = varSym->typeIndex;

            // Notes: 08/16/94 - Nghia
            // get the type information to recalculate symbol address
            if ((err = SymGetTypeHeader(typeIndex, &typeHeader)) != GOOD)
               return err;

            // update the base index for the public symbol ;
            varSym->symHeader.typeIndex.baseIndex = baseIndex;
            // update the address for the existing public symbol ;
            if (varSym->registerClass == NOT_REG) {
               storageClass = varSym->storageClass;
               switch (storageClass) {
                  case STATIC_VAR_CLASS:
                  case UNKNOWN_VAR_CLASS:
                  case GLOBAL_VAR_CLASS:
                     varSym->symHeader.beginAddrInfo.startAddr = varAddr.addr;
                     // enter end address.  Points to last byte of var
                     // which equals startAddr + sizeInMAUs - 1.
                     // If size is zero, set to start address
                     if (typeHeader.sizeInMAUs == 0L) {
                        varSym->symHeader.endAddrInfo.endAddr =
                        varSym->symHeader.beginAddrInfo.startAddr;
                     } else {
                        varSym->symHeader.endAddrInfo.endAddr =
                        varSym->symHeader.beginAddrInfo.startAddr +
                        (typeHeader.sizeInMAUs - 1);
                     };
                     varSym->isValidAddr = TRUE;
                     // now add to by-address-table
                     if ((err = AddAddrToByAddrTable(
                                   baseIndex,
                                   varOffset,
                                   varSym->symHeader.beginAddrInfo.startAddr,
                                   varSym->symHeader.endAddrInfo.endAddr))
                        != GOOD) return err;
                  break;
               default:
                  return ER_STORAGE_CLASS_UNKNOWN;
               }
            } else {
               return ER_SYM_REG_VAR_NOT_ALLOWED;
            }  // end of varPtr->registerClass ;
            return ER_ADDRESS_UPDATED;
         }
      }
   } else {  // variable not already loaded; chain off root directory as
             // a public variable
      if((err = st.PutString(varName,nameOffset)) != GOOD) return err;
      if((err = st.AllocBytes(sizeof(SYM_TYPE_VARIABLE), varOffset))
         != GOOD) return err;

      // NOTE: 02/17/94 - Nghia
      // BUG in GlobalReAlloc() that might trash the varSym pointer
      varSym = (SYM_TYPE_VARIABLE HUGE *)st.GetHugeDataPtr(varOffset);
      ClearEntry(varSym, sizeof(SYM_TYPE_VARIABLE));

      varSym->symHeader.typeIndex.symType = SYM_PUBLIC_VAR;
      varSym->symHeader.typeIndex.baseIndex = baseIndex;
      varSym->symHeader.symbolNameOffset = nameOffset;
      varSym->symHeader.symParentOffset = rootOffset;
      varSym->symHeader.symSiblingOffset = 0;

      if (0L == varAddr.addr) {
         varSym->symHeader.beginAddrInfo.startAddr = 0xFFFFL;
         varSym->symHeader.endAddrInfo.endAddr = 0xFFFFL;
      } else {
         // varAddr is valid
         varSym->symHeader.beginAddrInfo.startAddr = varAddr.addr;
         if (typeHeader.sizeInMAUs == 0L) {
            // a size of 0 is not represented by the address start-end
            // structure.  Set end equal to start for this case anyway
            varSym->symHeader.endAddrInfo.endAddr =
            varSym->symHeader.beginAddrInfo.startAddr;
         } else {
            varSym->symHeader.endAddrInfo.endAddr =
            varSym->symHeader.beginAddrInfo.startAddr +
               typeHeader.sizeInMAUs - 1L;
         }
      }
      varSym->typeIndex =     typeIndex;
      varSym->storageClass =  UNKNOWN_VAR_CLASS;
      varSym->registerClass = NOT_REG;
      varSym->isConstant =    FALSE;
      varSym->isValidAddr =   TRUE;

      // if there were any public vars loaded previously, its sibling
      // pointer points to this variable
      if(lastPublicVariable) {
         varAccessPtr =
            (SYM_TYPE_VARIABLE HUGE *)st.GetHugeDataPtr(lastPublicVariable);
         ((SYM_TYPE_VARIABLE *)varAccessPtr)->symHeader.symSiblingOffset =
            varOffset;
      } else {
         // first public variable; chain off root symbol var linked list
         varAccessPtr =
            (SYM_TYPE_VARIABLE HUGE *)st.GetHugeDataPtr(rootOffset);
         ((COMMON_BLOCK_HEADER *)varAccessPtr)->list.varListOffset =
            varOffset;
      }
      lastPublicVariable = varOffset;  // save away for next time thru

      // put the public var name into the global hash table ;
      if((err = ht.PutName(varOffset,duplicateName)) != GOOD) return err;
      if(duplicateName) // should never be a duplicate, but leave anyway
         return ER_DUPLICATE_GLOBAL_NAME;

      // NOTE: 02/17/94 - Nghia
      // BUG in GlobalReAlloc() that might trash the varSym pointer
      varSym = (SYM_TYPE_VARIABLE HUGE *)st.GetHugeDataPtr(varOffset);

      if (GOOD != (err =
         AddAddrToByAddrTable(baseIndex,
                              varOffset,
                              varSym->symHeader.beginAddrInfo.startAddr,
                              varSym->symHeader.endAddrInfo.endAddr)))
         return err;

      // fill in the ordinal value of this symbol ;
      if((err = AddOrdinalValue(varOffset)) != GOOD) return err;

      // tally variable symbol
      symbolStat[varSym->symHeader.typeIndex.symType]++;
   }
   return GOOD;
}  // end of SymAddVarPublic


//--------------------------------------------------------------------------
// SymAddVarLifetimeInfo
//--------------------------------------------------------------------------
RETCODE EXPORT SymAddVarLifetimeInfo(SYM_DESCRIPTOR variable,
                                     VAR_LIFETIME_INFO *lifetimeVarInfo) {
   RETCODE                      err;
   SYM_TYPE_VARIABLE HUGE       *varPtr;
   SYM_LIFETIME_START_INFO HUGE *lifetimeStartPtr;
   SYM_LIFETIME_INFO HUGE       *lifetimePtr;
   TABLE_OFFSET                 lifetimeOffset, lifetimeStartOffset;
   U8                           tmpSymType;

   // make sure the symbol descriptor is ok
   if (!UtilIsValidSymDescriptor(variable))
      return ER_INVALID_SYM_DESCRIPTOR;

   // make sure this is a variable symbol ;
   varPtr = (SYM_TYPE_VARIABLE HUGE *)st.GetHugeDataPtr(variable);
   tmpSymType = (U8)((varPtr->symHeader.typeIndex.symType) & 0xF);
   if (!((tmpSymType == SYM_GLOBAL_VAR) ||
        (tmpSymType == SYM_LOCAL_VAR)  ||
        (tmpSymType == SYM_PUBLIC_VAR) ||
        (tmpSymType == SYM_PUBLIC_UNKNOWN))) {
      return ER_NOT_A_VARIABLE;
   }
   if (varPtr->registerClass == NOT_REG)
      return ER_NO_LIFETIME_INFO;

   // allocate the memory for the new lifetime info. ;
   if ((err = st.AllocBytes(sizeof(SYM_LIFETIME_INFO), lifetimeOffset))
      != GOOD) return err;

   // NOTES: Nghia - 10/20/93
   // BUG in symbol table.  When st.AllocsBytes() extends the table size,
   // GlobalReAlloc() wiped out varPtr old value.  Which caused a UAE.
   // Update the old varPtr.
   varPtr = (SYM_TYPE_VARIABLE HUGE *)st.GetHugeDataPtr(variable);

   switch (varPtr->registerClass) {
      case LOCKED_REG:
         lifetimeStartOffset = variable + sizeof(AUTO_VAR_OFFSET) +
            sizeof(SYM_TYPE_VARIABLE);
         break;

      case LIVING_REG:
         lifetimeStartOffset = variable + sizeof(SYM_TYPE_VARIABLE);
         break;

      case SHADOW_REG:
         return ER_NOT_IMPLEMENTED;

      default:
         return ER_NOT_IMPLEMENTED;
   }
   lifetimeStartPtr = (SYM_LIFETIME_START_INFO HUGE *)
      st.GetHugeDataPtr(lifetimeStartOffset);

   if (NULL_SYMBOL == lifetimeStartPtr->lastEntry) {
      lifetimeStartPtr->firstEntry = lifetimeOffset;
   } else {
      // fill in the link to the new lifetime info. ;
      lifetimePtr = (SYM_LIFETIME_INFO HUGE *)
                    st.GetHugeDataPtr(lifetimeStartPtr->lastEntry);
      lifetimePtr->nextLifetimeInfo = lifetimeOffset;
   }
   // fix up the pointer to the last lifetime info added. ;
   lifetimeStartPtr->lastEntry = lifetimeOffset;

   // fill in the new lifetime info. ;
   lifetimePtr = (SYM_LIFETIME_INFO HUGE *) st.GetHugeDataPtr(lifetimeOffset);

   lifetimePtr->lifetimeInfo.lifetimeAddr = lifetimeVarInfo->lifetimeAddr;
   lifetimePtr->lifetimeInfo.lifetimeClass = lifetimeVarInfo->lifetimeClass;
   lifetimePtr->nextLifetimeInfo = NULL_SYMBOL;

   return GOOD;
}


/****************************************************************************
**
**  UpdateBlockInfo
**
**  Description:
**     This function updates all of the pointers associated with the
**     currently open block/function/module symbols.  It performs
**     different actions based upon what the current action is
**     (opening/closing a symbol) and what the previous symbol action
**     was.  Using this information the symbol stack will be modified,
**     symbol pointers will be filled in, etc...
**
**  Parameters:
**     input:
**        symbolOff:  The offset into the symbol memory pool of the symbol
**                    to be modified.  (NULL on a CLOSE symbol command)
**        action: The current action to be performed on the symbol table.
**                ie. OPEN a symbol, or CLOSE a symbol.
**     output:
**        none:
**        (returns): error code
**
*****************************************************************************/

/****************************************************************************
**
**    UpdateBlockInfo: Theory of Operation
**
**    The UpdateBlockInfo function is implemented using a state machine.
**    The state machine uses the previous open/close action along with the
**    current open/close action to decide the function to be performed.
**    These functions are:
**       previous action      current action    function performed
**------------------------------------------------------------------------
**       OPEN_SYMBOL          OPEN_SYMBOL       we are creating a child
**                                              symbol to the last symbol
**                                              that was created.
**       OPEN_SYMBOL          CLOSE_SYMBOL      we are closing the current
**                                              symbol (either a child or
**                                              a sibling symbol).
**       CLOSE_SYMBOL         OPEN_SYMBOL       we are creating a sibling
**                                              symbol to the last symbol
**                                              that was created.
**       CLOSE_SYMBOL         CLOSE_SYMBOL      we are popping back to the
**                                              parent of the last symbol
**                                              created.
**
**    At each of these actions are performed the parent/child/sibling
**    pointers that are known are filled in.  (ie. if we are creating a
**    child symbol, then the parent symbols child pointer (got that?) is
**    filled in with the address of the child symbol.  Likewise, the child
**    symbols parent pointer is filled in with the address of the parent
**    symbol.)  In the cases where the symbol is being closed, no pointers
**    are filled in and only the next symbol we will deal with is operated
**    upon.
**
************************************************************************/
PRIVATE RETCODE UpdateBlockInfo(TABLE_OFFSET symbolOff,SYM_ACTION action,
                                BOOLEAN updateLinks) {

   TABLE_OFFSET symbol;
   COMMON_BLOCK_HEADER HUGE *prevSymPtr;
   COMMON_BLOCK_HEADER HUGE *curSymPtr;

   if(action ==SYM_OPEN) {
      symbol = lastOpened = symbolOff;
      curSymPtr = (COMMON_BLOCK_HEADER HUGE *)st.GetHugeDataPtr(symbol);
      prevSymPtr = (COMMON_BLOCK_HEADER HUGE *)st.GetHugeDataPtr(prevSym);
   }


// determine what action to take based upon the last OPEN/CLOSE operation. ;
// the initial value is defined before creating the ROOT entry in ;
// InitSymTable ;
   switch (prevAction) {
      case SYM_OPEN:
         switch (action) {
            case SYM_OPEN:
               if (updateLinks) {
                  prevSymPtr->child = symbol;
                  curSymPtr->symHeader.symParentOffset = prevSym;
               }
               currentOpenContext = symbol;
               PushSymStack(prevSym);
               break;

            case SYM_CLOSE:
               symbol = lastOpened;
               currentOpenContext = symStack[topSymStack];
               break;

            default:
               return ER_UPDATE_BLOCK_FAIL; // this error should never occur
         }
         break;  //prevAction SYM_OPEN

      case SYM_CLOSE:
         switch (action) {
            case SYM_OPEN:
               if (updateLinks) {
                  curSymPtr->symHeader.symParentOffset =
                     prevSymPtr->symHeader.symParentOffset;
                  prevSymPtr->symHeader.symSiblingOffset = symbol;
               }
               currentOpenContext = symbol;
               break;

            case SYM_CLOSE:
               PopSymStack(symbol); // pass by reference
               currentOpenContext = symStack[topSymStack];
               break;

            default:
               return ER_UPDATE_BLOCK_FAIL; // this error should never occur
         }
         break;  //prevAction SYM_CLOSE

      default:
         return ER_UPDATE_BLOCK_FAIL; // this error should never occur ;
   }
   prevSym = symbol;
   prevAction = action;
   return GOOD;
}

//--------------------------------------------------------------------------
// SymAddLoadStart
//--------------------------------------------------------------------------
RETCODE EXPORT SymAddLoadStartAgain() {

   COMMON_BLOCK_HEADER HUGE *rootPtr;
    SYM_DESCRIPTOR *descArray;
    char temp[200];
    U16 numReturn , i;       
    int len;
    int nFlag;
    LINENUM_DESCRIPTOR index ;

   // setup basic state info. ;
//   prevSym = lastOpened = currentOpenContext = rootOffset;
//   prevAction = SYM_OPEN;

    if ( GOOD != SymGetModuleNum( &i ) ) {
        return FAILURE;
    }
    descArray = new SYM_DESCRIPTOR[ i+1 ];
    if ( descArray == NULL ) return FAILURE; 
    if (GOOD != SymGetAllModules(descArray,i,&numReturn)){
        delete descArray;
        return FAILURE;
    }                         
    if ( numReturn == 0 ) {
        delete descArray;
        return FAILURE;       
    }
    
   prevSym = lastOpened = currentOpenContext = descArray[numReturn-1];
   prevAction = SYM_CLOSE;
                                 
   delete descArray;
   return GOOD; 
}
/******************************** E O F ***********************************/
