/****************************************************************************
**
**  Name:  symadd.cpp
**
**  Description:
**     This module contains routines for adding to the symbol pool.
**
**  Status: CODED
**
**  $Log:   S:/tbird/mt2_186/symbol/symadd.cpv  $
** 
**    Rev 1.2   22 Jul 1997 10:10:36   Judy
** 
**    Rev 1.1   26 Feb 1997 11:43:10   Judy
** 
**    Rev 1.1   14 Jan 1997 15:31:10   Judy
** No change.
** 
**    Rev 1.0   14 Jun 1996 16:42:24   Judy
** Initial revision.
** 
**    Rev 1.89   10 Mar 1995 14:59:28   nghia
** Revised UpdateBlockInfo() to handle block context correctly. 
** currentOpenContext = the current opened context.
** symStack[top] = the parent opened context of currentOpenContext.
** prevSym = the last closed open context.
** Revised SymAddModule/FuncOpen() to call the UpdateBlockInfo() correctly.
** 
**    Rev 1.88   09 Jan 1995 16:10:02   nghia
** Merged PV 2.3a (rev 1.86.1.0) to trunk (rev 1.87) for PV 2.4 build.
** 
**    Rev 1.87   02 Nov 1994 12:29:22   nghia
** Merged PV 2.2d (rev. 1.76.1.0) to trunk.
** 
**    Rev 1.86.1.0   05 Jan 1995 16:38:40   nghia
** Fixed GPF bug for PV 2.3a - GE reports
** Revised SymAddBaseCreate, SymAddBaseCreateFromSegment and
** SymAddBaseCreateFromSelector to initialize the BaseSymbol object's
** baseNameOffset and byAddressTableOffset after the object is constructed.
** The GPF bug is caused by the <st> table is extended while the constructor
** is still initialized the object's data members.
** 
**    Rev 1.86   21 Oct 1994 18:26:32   nghia
** Fixed PPR9986 - Revise SymAddModuleClose() to update the module information
** before updating the Symbol server context states.  This also applied to
** SymAddFunctionClose().  Added check for currentOpenContext symbol with
** correct types (SYM_MODULE, SYM_BLOCK, SYM_FUNC) before allow closing.
** 
**    Rev 1.85   26 Sep 1994 10:12:52   nghia
** Revised SymAddBaseCreateFromSegment/Selector to set the gdt:ldt parts of
** symbol bases correctly.
** 
**    Rev 1.84   22 Sep 1994 14:58:32   nghia
** Revised UpdateBlockInfo() to handle all current context for both
** symbolCreate/Open calls.  Cleanup all symbolOpen calls that directly
** manipulate the global variables that control the current context.
** 
**    Rev 1.83   19 Sep 1994 18:36:42   brucea
** Added: SymAddTypeRegVar and REG_VAR_TYPE typedef
** 
**    Rev 1.82   06 Sep 1994 16:02:10   nghia
** Removed setting sizeInMAUs = 0L when sizeCalculated == FALSE.  Used whatever
** the value that the caller provided.
** 
**    Rev 1.81   17 Aug 1994 13:22:34   nghia
** Revised SymAddVar and SymAddVarPublic to use SymGetTypeHeader() to ensure
** that the type information (i.e. sizeInMAUs) is resolved before using it.
** 
**    Rev 1.80   03 Aug 1994 11:45:00   brucea
** In SymAddSymbolSetAddr, added code to update the last linenum if the
** address changes is being made to a module.
** Temp mod to SymAddVarPublic to change an input address of 0 to 0xFFFF in
** order to get source searching to work properly.
** 
**    Rev 1.79   25 Jul 1994 11:30:40   brucea
** Added two global vars for displaying 0x or not 0x, then initialize them in
**    symInitialize()
** Added cast for tmpSymType in SymAddSymbolSetAddr()
** 
** 
**    Rev 1.78   14 Jul 1994 02:00:32   brucea
** Added: SymAddBaseCreateFromSegment, Selector
** 
**    Rev 1.77   20 Jun 1994 10:59:32   nghia
** Added CreateAllAddrRanges to convert public label into address ranges.
**
**    Rev 1.76.1.0   27 Oct 1994 09:49:08   nghia
** Added SymSetSymbolAddrByDesc() to support updating symbol address range.
** 
**    Rev 1.76   28 Feb 1994 17:43:46   nghia
** Fixed bug for PV 2.1:  GPF in Symbol server when load Tandberg's BSG000_.ABS
** on-demand.  GlobalReAlloc() expands table caused pointer to be invalid.
** Added SymStat[] to tally symbol types.
** 
**    Rev 1.75   22 Nov 1993 13:26:48   nghia
** Fixed bug: Cannot Create Base Index for loading symbol.
** Added check for bit EntryCount in SymAddLoadStart() to detect symbol loaded.
** 
**    Rev 1.74   22 Oct 1993 09:20:18   nghia
** Fixed UAE bug. - When symbol table extends its size, any pointer dereference
** to the symbol table prior to the size extending will be wiped out.  Updated
** pointer after operations that might cause the symbol table to extend its size
** st.AllocBytes(), st.PutString(), st.PutBytes()....
** Fixed Bug - Cannot set section base.  Checked if the lastOpened offset is
** > the rootOffset, which indicates that there are symbol in table.
** 
**    Rev 1.73   30 Sep 1993 14:59:42   nghia
** Removed check for typeIndex in adding function symbol.
** 
**    Rev 1.72   24 Sep 1993 10:24:34   nghia
** Support forward reference types
** Fixed record size of typedef type.
** SymAddFunctionOpen will use UNKNOWN type if the input type is undefined.
** 
**    Rev 1.71   14 Jul 1993 12:03:18   nghia
** Added SymAddModuleOpenByDesc() to allow the Loader open module by desc.
** 
**    Rev 1.70   08 Dec 1992 07:00:28   brucea
** Cosmetic cleanups
** 
**    Rev 1.69   03 Dec 1992 07:41:06   brucea
** Changed comparison of symbol descriptors to compare to NULL_SYMBOL rather
**    than if (!...)
** 
**    Rev 1.68   06 Nov 1992 07:05:56   brucea
** Modified: SymAddModuleCreate by removing call to ht.LookupName in order to
**    speed up module adds.  The call to ht.PutName is still made.
**    If it returns
**    duplicate name, then the name is modified (second control byte) and the
**    exercise repeated.
** 
**    Rev 1.67   04 Nov 1992 07:23:16   brucea
** Cleanup
** 
**    Rev 1.66   15 Oct 1992 18:43:28   brucea
** Added: localsLoaded parameter to SymAddModuleClose which sets fileOffset to
**    SYMBOLS_LOADED
** 
**    
** 
**    Rev 1.65   08 Sep 1992 13:04:56   brucea
** Added: events.h include
** 
**    Rev 1.64   13 Aug 1992 19:22:50   brucea
** Fixed: on-demand bug where local vars were not going into function;
**    now setting currentOpenContext in SymAddFuncOpen
** 
**    Rev 1.63   13 Aug 1992 11:04:10   brucea
** Changed: wsprintf to sprintf
** 
**    Rev 1.62   06 Aug 1992 15:23:34   brucea
** Bug fix: comparison to tmpSymType not correct in SymAddSymbolSetAddr
**          same type of comparison in SymAddVarPublic and SymAddVarLifetimeInfo
** 
** 
**    Rev 1.61   06 Aug 1992 10:13:20   brucea
** Changed access to .typeIndex.symType to use &0xF
** 
**    Rev 1.60   25 Jul 1992 16:41:36   brucea
** Added: SymInitialize
** Removed: SymInitSymServer
** 
**    Rev 1.59   19 Jul 1992 21:58:50   brucea
** Added: check for public label already in hash table
** Added: adding public var address to by-address table
** 
**    Rev 1.58   10 Jul 1992 19:08:20   brucea
** Added: HUGE to all casts of st.GetHugeDataPtr()  (didn't make a difference in
**    the memory access bug
** 
** 
**    Rev 1.57   24 Jun 1992 18:01:30   brucea
** Fixed: bug which put static vars located outside a function inside the
**    previously closed function.  SW was not keeping the state of the current
**    open symbol (module, func, or unnamed block).  Required the recalculation
**    of lastLabel and lastVariable that point to the end of the label/variable
**    linked list of the current symbol when a new one becomes the current
**    context.
** 
** 
**    Rev 1.56   15 Jun 1992 09:23:46   brucea
** Fixed up: LPU8 cast of second param to GetString
** Changed: enumValue to U32 in SymAddTypeEnum
** Bug fix: added breaks in case clauses in registerClass test in function
**    SymAddVarLifetimeInfo
** Fixed up: switch statements in UpdateBlockInfo
** 
**    Rev 1.55   11 May 1992 09:55:36   brucea
** Added: PRIVATE lastPublicLabel and lastPublicVariable.  Public labels and vars
**    are now added separately from module-level labels and vars.  This fixes a
**    bug in which public labels were being added to the last module rather than
**    root.  To do this, SymAddLabelPublic and SymAddVarPublic were modified; the
**    latter heavily.
** 
**    Rev 1.54   30 Apr 1992 18:31:10   brucea
** Fixed: SymAddVar to set up the correct size for static vars
** 
**    Rev 1.53   20 Apr 1992 09:06:14   brucea
** Removed: initialization of PRIVATE vars at point of declaration
** Added: init of PRIVATE vars in InitSymTable including calls to 
**    BasetblResetCacheVars and AdlookupResetCacheVars
** Bug fix: PPR5356, PPR5357 -> in SymAddVarPublic, now fill in type index from
**    previously entered var type in order to calculate size of var correctly
** 
**    Rev 1.52   01 Apr 1992 23:43:20   brucea
** Fixed: compiler warnings
** 
**    Rev 1.51   14 Feb 1992 15:11:18   brucea
** Removed code which initialized symbol table from SymAddLoadStart
** Changed casting of loadFilename to (LPSTR)
** 
**    Rev 1.50   04 Feb 1992 16:23:08   brucea
** In SymAddLoadStart, added call to SymInitialize if a new load and symbols
**    have not been loaded yet.
** 
**    Rev 1.49   29 Jan 1992 15:07:20   brucea
** Changed the initial value of the typeHdr.memberCount to 0.
** 
**    Rev 1.48   22 Jan 1992 14:58:34   brucea
** Changed tmpArray[255] to tmpArray[MAX_SYMNAME_LENGTH]
** 
**    Rev 1.47   13 Jan 1992 17:21:26   john
** Added code to check for valid symbol descriptors.
** Added code to add variable lifetime information.
** 
**    Rev 1.46   08 Jan 1992 16:18:54   john
** Member count was being initialized incorrectly.
** 
**    Rev 1.45   08 Jan 1992 11:27:24   john
** Added new commands.  Increased command count
** 
**    Rev 1.44   07 Jan 1992 09:42:34   john
** Previous code fix didn't work
** 
**    Rev 1.43   06 Jan 1992 16:56:16   john
** SymAddGetModuleName was not stripping the leading chars from the
** module name properly.
** 
**    Rev 1.42   06 Jan 1992 16:02:48   john
** New public vars were being added to the wrong block
** 
**    Rev 1.41   03 Jan 1992 09:22:04   john
** Fixed SymAddFuncOpen and SymAddModuleOpen to correctly set up
** the symbol table context.  The code only worked the initial time
** it was called.  Subsequent calls caused incorrect operation.
** 
**    Rev 1.40   02 Jan 1992 12:01:56   john
** SymAddLoadStart now checks to see if an on demand load is being
** performed.  If it is then it checks to make sure the filename
** and timestamp of the load module are correct.  It then sets up
** preload state.
** If this is not an on demand load it makes sure no symbols are
** loaded and then sets up preload state.
** 
**    Rev 1.39   20 Dec 1991 09:22:02   john
** Fixed symaddtypeheader to fill in the name offset field
** correctly.
** Made changes to make symaddfuncopen to correctly set up the
** symbol table state variables.
** 
**    Rev 1.38   18 Dec 1991 11:19:04   john
** Needed to set the isValidAddr flag to true when a global vars 
** address was updated.
** 
**    Rev 1.37   18 Dec 1991 09:38:10   john
** Added return code to PushSymStack
** 
**    Rev 1.36   17 Dec 1991 16:12:10   john
** Changed symaddmodulecreate to pass back a descriptor to the
** module just created.  This is used for adding line numbers.
** 
**    Rev 1.35   16 Dec 1991 17:17:48   john
** Removed parameter that wasn't going to be used from
** SymAddModuleCreate.
** Created function to add a module path reference to an existing
** module symbol entry.
** 
**    Rev 1.34   16 Dec 1991 15:15:06   john
** Made changes to SymAddModuleOpen to support on demand loading.
** 
**    Rev 1.33   16 Dec 1991 11:39:16   brucea
** Inside SymAddLoadEnd, added call to SortAllByAddrTable
** 
**    Rev 1.32   16 Dec 1991 09:20:26   john
** Fixed SymAddSymbolSetAdrr.  A valid end address was only being
** set if there was a valid start address.
** 
**    Rev 1.31   13 Dec 1991 14:30:30   john
** Added code to update the max/min addresses of the last symbols BASE.
** 
**    Rev 1.30   13 Dec 1991 12:24:14   brucea
** Added global var: loadFilename to hold loaded filename
** Added SymAddGetModuleName
** SymAddLoadStart: added copying of filename into loadFilename
** SymAddModuleInvalidate: changed return to ER_NOT_IMPLEMENTED
** 
**    Rev 1.29   12 Dec 1991 17:55:02   john
** Changed how modulereference gets filled in
** 
**    Rev 1.28   12 Dec 1991 16:16:34   john
** Fixed SymAddSymbolSetAddr
** 
**    Rev 1.27   09 Dec 1991 12:06:24   john
** Made changes necessary to add another CLI command.
** Added code to correctly re-initialize the symbol table after all 
** symbols have been deleted.
** 
**    Rev 1.26   05 Dec 1991 15:59:10   john
** Fixed bug in SymAddVar that improperly checked for duplicate
** global names.
** Implemented code for LIVING registers types.
** 
**    Rev 1.25   02 Dec 1991 14:53:52   john
** removed functions that are not currently supported
** 
**    Rev 1.24   02 Dec 1991 14:37:58   john
** Integrated changes brought about by the address handling modifications.
** 
**    Rev 1.23   02 Dec 1991 11:27:00   brucea
** Removed SymAddCloseLoad
** 
**    Rev 1.22   02 Dec 1991 10:19:00   john
** Merged branches 1.21.1 and 1.21.2
** 
**    Rev 1.21.2.1   27 Nov 1991 16:14:06   brucea
** Changed LOGICAL_ to OFFSET_
** removed unimplemented functions
** name change: startInfo to startAddrInfo, endInfo to endAddrInfo
** added code to support LOCKED_REG type
** 
**    Rev 1.21.1.5   27 Nov 1991 12:57:46   john
** Added real code to SymAddStartLoad.
** Added code to SymAddModuleOpen.
** Created SymAddFuncOpen.
** 
**    Rev 1.21.1.4   25 Nov 1991 17:13:36   john
** Fixed check for null string
** 
**    Rev 1.21.1.3   25 Nov 1991 14:09:08   john
** Added a "size" field to auto-variables.  This removes the need
** for a call to get the variables size from its type header.
** 
**    Rev 1.21.1.2   21 Nov 1991 16:18:38   john
** Fixed the code that determined if there is a name was being added
** to the func/block.  Now if funcName points to a 0 an unnamed block
** is created.
** 
**    Rev 1.21.1.1   21 Nov 1991 15:08:46   john
** Added SymAddVarPublic and SymAddLabelPublic to handle adding
** public symbols differently than local symbols.
** Removed SymAddBlockxxx.  We are using SymAddFuncxxx to create
** unnamed blocks.
** Added the code to SymAddTypeBitfield, SymAddTypeTypeIndex.
** Made fixes in SymAddVar to handle variable addresses better.
** 
** 
**    Rev 1.21   18 Nov 1991 20:31:30   brucea
** Removed RETCODE err; from SymAddSymbolSetAddr
** Added isConstant and isValidAddr to SymAddVar and fixed accesses
** Removed (storageClass == STATIC_VAR_CLASS) from check to
**    add var to global hash table because a static var
**    is NOT globally visible
** 
**    Rev 1.20   15 Nov 1991 13:51:42   john
** - The COMMON_SYMBOL_HEADER structure changed.  All the variables
**   referencing this structure were changed to comply.
** - Added new code to handle most of the variable types in
**   SymAddVar.  This routine was not complete because complex types
**   had not been completed.
** - Added the code for SymAddSymbolSetAddr.
** 
**    Rev 1.19   13 Nov 1991 16:09:30   john
** Added SymAddTypeEnum code.
** Removed all calls to UpdateMAUSize because this info is added
** when the type header is created.
** 
**    Rev 1.18   11 Nov 1991 19:02:06   brucea
** Removed SymAddLinenum
** 
**    Rev 1.17   11 Nov 1991 17:43:04   john
** added code for struct and C array types
** 
**    Rev 1.16   11 Nov 1991 15:12:26   john
** Added real code to some of the routines to add type info.
** This code has not been tested.
** 
**    Rev 1.15   08 Nov 1991 13:50:12   john
** Moved InitBasicTypes to typetbl.cpp
** 
**    Rev 1.14   07 Nov 1991 13:51:44   john
** Stubbed out many SymAdd routines
** 
**    Rev 1.13   05 Nov 1991 17:23:08   brucea
** Fixed up AddOrdinalValue
** Changed the initialization of st to store 0 in the first location
** 
**    Rev 1.12   04 Nov 1991 16:01:44   john
** Variable names weren't being put into the global hash table
** if they were global.
** 
**    Rev 1.11   01 Nov 1991 17:11:46   john
** Matched functions to their prototypes
** 
**    Rev 1.10   31 Oct 1991 17:45:16   brucea
** Made SymAddFuncCreate and SymAddModuleCreate compatible with
** reference params and additional params 
** 
**    Rev 1.9   31 Oct 1991 16:56:48   john
** Made changes to reflect new hash table interface.
** Needed to clear the variable entry to make sure it is in a known
** state.
** 
**    Rev 1.8   30 Oct 1991 15:57:02   john
** Added stub code for the loader.
** Removed initialization code and moved it to LIBMAIN.
** 
**    Rev 1.7   24 Oct 1991 17:58:12   john
** Fixed the code that handles module name collision.  It was 
** inserting a null in the middle of the module name.
** 
**    Rev 1.6   23 Oct 1991 17:11:58   john
** Removed EXPORT from functions that will not be exportable beyond
** the DLL.
** 
**    Rev 1.5   17 Oct 1991 10:08:38   john
** Removed an unnecessary pointer from SymAddBaseCreate.
** Added error code for duplicate name collisions in the hash table.
** Modified the module name fixup code as a cleanup pass.
** 
**    Rev 1.4   11 Oct 1991 15:39:32   john
** Added hash table routines back in
** 
**    Rev 1.3   11 Oct 1991 15:06:38   brucea
** Many changes: made BaseSymbol a class; all base calls go through different
** calls.  Fixed bug in ht initialization.
** 
**    Rev 1.2   04 Oct 1991 14:49:28   john
** made changes suggested after a code review
** 
**    Rev 1.1   03 Oct 1991 16:46:16   john
** symblsvr.h changed a typedef
** 
**    Rev 1.0   03 Oct 1991 11:43:10   john
** Initial revision.
**
**  $Header:   S:/tbird/mt2_186/symbol/symadd.cpv   1.2   22 Jul 1997 10:10:36   Judy  $
**
**  Copyright (C) 1991 Microtek International.  All rights reserved.
**
*****************************************************************************/

                       /****************************
                        *                          *
                        *       INCLUDE FILES      *
                        *                          *
                        ****************************/
#ifndef __MEM_H 
#include <mem.h>
#endif

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

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

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

#ifndef _ENLIB_
#include "enlib.h"
#endif

#ifndef _EVENTS_
#include "events.h"
#endif

#ifndef _HASHTBL_
#include "hashtbl.h"
#endif

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

#ifndef _LINENUM_
#include "linenum.h"
#endif

#ifndef _MEMMANAG_
#include "memmanag.h"
#endif

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

#ifndef _ORDTBL_
#include "ordtbl.h"
#endif

#ifndef __STRING_H
#include <string.h>
#endif

#ifndef _PROC_
#include "proc.h"
#endif

#ifndef _INIUTIL_
#include "iniutil.h"
#endif

#ifndef _SYMBLSVR_
#include "symblsvr.h"
#endif

#ifndef _SYMADD_
#include "symadd.h"
#endif

#ifndef _SYMCLI_
#include "symcli.h"
#endif

#ifndef _SYMERROR_
#include "symerror.h"
#endif

#ifndef _SYMUTIL_
#include "symutil.h"
#endif

#ifndef _TYPETBL_
#include "typetbl.h"
#endif

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

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

extern VOID AdlookupResetCacheVars(VOID);

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

#define SYM_STACK_SIZE 32
#define SYM_STACK_EMPTY -1

PRIVATE TABLE_OFFSET lastLabel;
PRIVATE TABLE_OFFSET lastVariable;

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

PRIVATE BOOLEAN      moduleOpen;
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;

// Flag for symbol lookup case sensitivity
BOOLEAN CaseFlag=TRUE;

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

//---------------------------------------------------------------------------
// Symbol Server - PowerViews INI setting
// Create public labels ranges flag
BOOLEAN createLabelRanges = FALSE;

//---------------------------------------------------------------------------
// 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);

                       /****************************
                        *                          *
                        *      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;

   //i = entrySize-1;
   i = entrySize;//Hera 5/9/97
   while(i--) {
      *((U8 *)entry) = 0;
      ((U8 *)entry)++;
   }
}


//--------------------------------------------------------------------------
// 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;
   // get the PWRVIEWS ini settings for Symbol Server
   return InitIniSettings();
   
} // 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;

   // 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;
   UpdateBlockInfo(rootOffset, SYM_OPEN, FALSE);
   moduleOpen = FALSE;

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

//--------------------------------------------------------------------------
// InitIniSettings
//--------------------------------------------------------------------------
PRIVATE RETCODE InitIniSettings()  {
   RETCODE err;
   U32 iniNum = 0L;
   // get settings from PWRVIEWS.INI 
   // CreateLabelRanges=0|1
   err = IniGetNumber((LPSTR) SAPP_NAME, (LPSTR) SAPP_LABEL,
                       (LPSTR) PWRVIEWS_INI_DEFAULT, &iniNum);
   createLabelRanges = (BOOLEAN) iniNum;
   return err; 
} // end of InitIniSetting

/****************************************************************************
**
**  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];
   symStack[topSymStack--] = 0L; // clear entry on context stack
   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;
   topSymStack++;
   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)  {

   TABLE_OFFSET tmpBaseOffset, tmpNameOffset, tmpByAddrTableOffset;
   BaseSymbol HUGE *basePtr;
   ByAddressTable bat;
   RETCODE err;
   
   // check for validity of baseIndex; should not yet exist
   err = bit.GetOffset(baseIndex, tmpBaseOffset);
   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(baseIndex, baseAddress, baseTypeParam, err);
   if (err != GOOD)  // either mem alloc problem or out of segments
      return err;

   // 01/05/95 - Nghia  
   // Data members of <this> BaseSymbol object cannot be used in
   // reference passing; because their addresses can be invalid when the
   // st table is changed. 
   // NOTES: Test file is o:\customer\386real\ge\em3_tcp.sys
   // Used local variable as references in st.PutString and st.PutBytes,
   // then store the return values into <this> BaseSymbol object.

   // Put the base name into the symbol table memory pool
   // <tmpTableOffset> is passed by reference.
   if ((err = st.PutString(baseName, tmpNameOffset)) != GOOD)
      return err;
   
   // put the instance of the by-address sorted table into the symbol
   // table memory pool
   // <tmpByAddrTableOffset> is passed by reference.
   if((err = st.PutBytes((U8 *)&bat, sizeof(ByAddressTable),
                         tmpByAddrTableOffset))
      != GOOD ) return err;

   // Getting offset of the newly created BaseSymbol object
   if((err = bit.GetOffset(baseIndex, tmpBaseOffset)) != GOOD)
      return err;

   // get pointer to BaseSymbol object and fill in the information
   if ((basePtr = (BaseSymbol HUGE *)st.GetHugeDataPtr(tmpBaseOffset)) == NULL)
      return ER_SYM_OUT_OF_MEMORY;
   
   // set parameters
   basePtr -> SetBaseNameOffset(tmpNameOffset);
   basePtr -> SetByAddressTableOffset(tmpByAddrTableOffset);
  
   return GOOD;
}  // end of SymAddBaseCreate


//--------------------------------------------------------------------------
// SymAddBaseCreateFromSegment
//
// Pseudo-code
//    First checks for already existing or out-of-bounds baseIndex.
//    Execute the "new" operator for BaseSymbol, which stores baseAddress
//       if error, returns error code, including too many segments
//    Add segment and segAddrSpace and set mode to REAL
//--------------------------------------------------------------------------
RETCODE EXPORT
SymAddBaseCreateFromSegment(LPSTR          baseName,
                            BASE_INDEX     baseIndex, 
                            U16            segment,
                            BASE_TYPE      baseTypeParam,
                            SEG_ADDR_SPACE segAddrSpace) {

   TABLE_OFFSET tmpBaseOffset, tmpNameOffset, tmpByAddrTableOffset;
   BaseSymbol HUGE *basePtr;
   ByAddressTable bat;
   RETCODE      err;
   
   // check for validity of baseIndex; should not yet exist
   err = bit.GetOffset(baseIndex, tmpBaseOffset);
   if (err == ER_INDEX_OUT_OF_BOUNDS)
      return err;
   if (err == GOOD)
      return ER_INDEX_ALREADY_EXISTS;

   // index not in table, create new base and put its index into <bit>
   new BaseSymbol(baseIndex, (((U32)segment)<<4), baseTypeParam, err);
   if (err != GOOD)  // either mem alloc problem or out of segments
      return err;
   // 01/05/95 - Nghia  
   // Data members of <this> BaseSymbol object cannot be used in
   // reference passing; because their addresses can be invalid when the
   // st table is changed. 
   // NOTES: Test file is o:\customer\386real\ge\em3_tcp.sys
   // Used local variable as references in st.PutString and st.PutBytes,
   // then store the return values into <this> BaseSymbol object.

   // Put the base name into the symbol table memory pool
   // <tmpTableOffset> is passed by reference.
   if ((err = st.PutString(baseName, tmpNameOffset)) != GOOD)
      return err;
   
   // put the instance of the by-address sorted table into the symbol
   // table memory pool
   // <tmpByAddrTableOffset> is passed by reference.
   if((err = st.PutBytes((U8 *)&bat, sizeof(ByAddressTable),
                         tmpByAddrTableOffset))
      != GOOD ) return err;

   // Add segment value, segAddrSpace to base object and set to real mode
   // Requires getting pointer to base object
   if((err = bit.GetOffset(baseIndex, tmpBaseOffset)) != GOOD)
      return err;
   // get pointer to BaseSymbol and fill in all new parameters
   if ((basePtr = (BaseSymbol HUGE*)st.GetHugeDataPtr(tmpBaseOffset)) == NULL)
      return ER_SYM_OUT_OF_MEMORY;

   // set parameters
   basePtr -> SetBaseNameOffset(tmpNameOffset);
   basePtr -> SetByAddressTableOffset(tmpByAddrTableOffset);
   basePtr -> SetSegOrLDTsel(segment);
   basePtr -> SetSegAddrSpace(segAddrSpace);  // USER or SMM
   basePtr -> SetSymMode(SYM_REAL);  // segments are in real mode
   
   return GOOD;
}  // end of SymAddBaseCreateFromSegment


//--------------------------------------------------------------------------
// SymAddBaseCreateFromSelector
//
// Pseudo-code
//    First checks for already existing or out-of-bounds baseIndex.
//    Then, executes the "new" operator for BaseSymbol;
//       set baseAddress=0
//       if error, returns error code, including too many selectors
//    Add gdtSelector and ldtSelector and set mode to PROTECTED
//--------------------------------------------------------------------------
RETCODE EXPORT
SymAddBaseCreateFromSelector(LPSTR      baseName,
                             BASE_INDEX baseIndex,
                             BASE_TYPE  baseTypeParam,
                             U16        gdtSelector,
                             U16        ldtSelector) {

   TABLE_OFFSET tmpBaseOffset, tmpNameOffset, tmpByAddrTableOffset;
   BaseSymbol HUGE *basePtr;
   ByAddressTable bat;
   RETCODE      err;
   
   // check for validity of baseIndex; should not yet exist
   err = bit.GetOffset(baseIndex, tmpBaseOffset);
   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(baseIndex, 0L, baseTypeParam, err);
   if (err != GOOD)  // either mem alloc problem or out of segments
      return err;

   // 01/05/95 - Nghia  
   // Data members of <this> BaseSymbol object cannot be used in
   // reference passing; because their addresses can be invalid when the
   // st table is changed. 
   // NOTES: Test file is o:\customer\386real\ge\em3_tcp.sys
   // Used local variable as references in st.PutString and st.PutBytes,
   // then store the return values into <this> BaseSymbol object.

   // Put the base name into the symbol table memory pool
   // <tmpTableOffset> is passed by reference.
   if ((err = st.PutString(baseName, tmpNameOffset)) != GOOD)
      return err;
   
   // put the instance of the by-address sorted table into the symbol
   // table memory pool
   // <tmpByAddrTableOffset> is passed by reference.
   if((err = st.PutBytes((U8 *)&bat, sizeof(ByAddressTable),
                         tmpByAddrTableOffset))
      != GOOD ) return err;

   if((err = bit.GetOffset(baseIndex, tmpBaseOffset)) != GOOD)
      return(err);
   // get pointer to BaseSymbol and fill in all new parameters
   if ((basePtr = (BaseSymbol HUGE*)st.GetHugeDataPtr(tmpBaseOffset)) == NULL)
      return ER_SYM_OUT_OF_MEMORY;

   // set parameters
   basePtr -> SetBaseNameOffset(tmpNameOffset);
   basePtr -> SetByAddressTableOffset(tmpByAddrTableOffset);
   basePtr -> SetGDTsel(gdtSelector);
   basePtr -> SetSegOrLDTsel(ldtSelector);
   basePtr -> SetSymMode(SYM_PROTECTED);
              // selectors are equivalent to protected mode
   return GOOD;
}  // end of SymAddBaseCreateFromSelector


//--------------------------------------------------------------------------
// SymAddBaseSetAddr
//--------------------------------------------------------------------------
RETCODE EXPORT SymAddBaseSetAddr(BASE_INDEX baseIndex,
                                 BASE_ADDRESS baseAddress) {

   return BaseSetAddr(baseIndex, baseAddress);
}

//--------------------------------------------------------------------------
// SymAddCaseSensitive
//--------------------------------------------------------------------------
VOID EXPORT SymAddCaseSensitive(BOOLEAN caseFlag) {
  CaseFlag = caseFlag;
}

//--------------------------------------------------------------------------
// SymAddFuncCreate
//--------------------------------------------------------------------------
RETCODE EXPORT
SymAddFuncCreate(LPSTR funcName,BASE_INDEX baseIndex, U16 segment,
                 FUNC_CLASS funcClass, U32 stackSize,
                 OFFSET_ADDR_RANGE_TYPE *codeAddrRange,
                 TYPE_INDEX typeIndex) {
   
   SYM_TYPE_FUNCTION HUGE *function;
   SYM_TYPE_MODULE HUGE *module; //Hera 5/15/97
   TABLE_OFFSET nameOffset;
   RETCODE err;
   TABLE_OFFSET funcOffset, baseOffset;
   BOOLEAN duplicateName;
   SYM_TYPE_TYPE symType = SYM_FUNCTION;
   S16 index;
      
   // 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[0]) {
      if((err = st.PutString(funcName,nameOffset)) != GOOD) return err;
   } else {
      nameOffset = 0;
   }

   //Hera 5/15/97
   module = (SYM_TYPE_MODULE HUGE *)st.GetHugeDataPtr(lastModuleLoaded);
   index = module->symHeader.symHeader.segNum;
   if (index == 0) {
       module->symHeader.symHeader.segment[index] = segment;       
       module->symHeader.symHeader.beginAddr[index] =
					  codeAddrRange->offsetStartAddr;
       module->symHeader.symHeader.segNum++;
   }
   else {
      
      if (module->symHeader.symHeader.segment[index-1] != segment) {
	 module->symHeader.symHeader.segment[index] = segment;
	 module->symHeader.symHeader.beginAddr[index] =
					  codeAddrRange->offsetStartAddr;
	 module->symHeader.symHeader.segNum++;
      }
      else
         index--;
   } 
   module->symHeader.symHeader.endAddr[index] =
					   codeAddrRange->offsetEndAddr;
   //Hera

   // 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->offsetStartAddr;
   function->symHeader.symHeader.endAddrInfo.endAddr =
      codeAddrRange->offsetEndAddr;
   function->funcClass  = funcClass; 
   function->stackSpace = stackSize;
   function->typeIndex  = typeIndex;
   function->segment = segment; //Hera 5/9/97
   function->symHeader.symHeader.segment[0] = segment; //Hera 6/4/97
   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->offsetStartAddr,
				   codeAddrRange->offsetEndAddr))
      != 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 = 0L;
   RETCODE                   err, firstErr = GOOD;
   U8                        tmpSymType;

   // 03/06/95 - Nghia
   // <currentOpenContext> must be a function or a block.
   // Make sure that the currentOpenContext is a function or a block
   symPtr = (COMMON_SYMBOL_HEADER HUGE *)st.GetHugeDataPtr(currentOpenContext);
   if (!symPtr) return ER_INVALID_SYM_DESCRIPTOR;
   tmpSymType = (symPtr->typeIndex.symType) & 0xF;
   if ((tmpSymType != SYM_FUNCTION) && (tmpSymType != SYM_BLOCK))
      return ER_SYMBOL_NOT_A_FUNCTION;
   
   // Close and get the currentOpenContext -> Which is a MODULE
   firstErr = UpdateBlockInfo(dummyOffset,SYM_CLOSE,TRUE);
   // Update the current open context - function then update the state
   // of the symbol table.
   // The <lastLabel> and <lastVariable> are of the parent opened context
   // which should be a function or module.
   err = SymGetEndList(currentOpenContext, SYM_LABEL, &lastLabel);
   if (GOOD == firstErr) firstErr = err;
   err = SymGetEndList(currentOpenContext, SYM_LOCAL_VAR, &lastVariable);
   if (GOOD == firstErr) firstErr = err;
   return (firstErr != GOOD) ? firstErr : err; 
}  // 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];
   
   // 03/07/95 - Nghia
   // <currentOpenContext>  must be a module symbol, otherwiser it's an error.
   symPtr =
      (COMMON_SYMBOL_HEADER HUGE *)st.GetHugeDataPtr(currentOpenContext);
   if (!symPtr) return ER_INVALID_SYM_DESCRIPTOR;
   if (((symPtr->typeIndex.symType) & 0xF) != SYM_MODULE) 
      return ER_SYMBOL_NOT_A_MODULE;
   
   // The module child offset is the first function in module
   if ((err = SymGetSymbolChild(currentOpenContext,
                                &symType, &tmpOffset)) != GOOD) 
      return err;
   // <tmpOffset> should be function symbol else error.
   if (NULL_SYMBOL == tmpOffset)  // don't allow access if 0; otherwise UAEs
      return ER_SYMBOL_HAS_NO_CHILD;
   if ((symType & 0xF) != SYM_FUNCTION)
      return ER_SYMBOL_NOT_FOUND;      
   do {
      symPtr = (COMMON_SYMBOL_HEADER HUGE *)st.GetHugeDataPtr(tmpOffset);
      st.GetString(symPtr->symbolNameOffset, name);
      if ((CaseFlag && !strcmp(funcName,(S8 *) name)) ||
          (!CaseFlag && !stricmp(funcName,(S8 *) 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 of the currentOpenContext - the opening function. 
   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) return ER_INVALID_SYM_DESCRIPTOR;
   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 = strlen(modName) - 2;
   do {
      *modName++ = *from++;
   } while (length--);
   return SUCCESS;
   } // end of SymAddGetModuleName


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

   RETCODE err;
   COMMON_SYMBOL_HEADER HUGE *labelSym;
   TABLE_OFFSET nameOffset,labelOffset,baseOffset;
   HPU8 label;

   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);
   if (!labelSym) return ER_INVALID_SYM_DESCRIPTOR;

   // fill in the label data ;
   ClearEntry(labelSym,sizeof(COMMON_SYMBOL_HEADER)); //Hera 5/22/97
   labelSym->typeIndex.symType = SYM_LABEL;
   labelSym->typeIndex.baseIndex = baseIndex;
   labelSym->symbolNameOffset = nameOffset;
   labelSym->symParentOffset = currentOpenContext;  
   labelSym->symSiblingOffset = 0;
   labelSym->beginAddrInfo.startAddr = addr;
   labelSym->endAddrInfo.endAddr = addr+1;

   // 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;
}


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

   RETCODE err;
   COMMON_SYMBOL_HEADER HUGE *labelSym;
   TABLE_OFFSET nameOffset,labelOffset,baseOffset;
   HPU8 label;
   U8 misses;
   BOOLEAN duplicateName;

   // 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);
   if (!labelSym) return ER_INVALID_SYM_DESCRIPTOR;
   ClearEntry(labelSym,sizeof(COMMON_SYMBOL_HEADER)); //Hera 5/22/97
   // 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;
   // only create label address ranges if the user said so
   if (globalProcFamily == FAMILY_68K && createLabelRanges) {
      if ((err = CreateAllAddrRanges(SYM_PUBLIC_LABEL)) != 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 = 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;
   } else {  // called to load new set of symbols
      rootPtr = (COMMON_BLOCK_HEADER HUGE *)st.GetHugeDataPtr(rootOffset);
      // NOTES: Nghia - 10/20/93
      // If prevSym > rootOffset then table had symbols in it.
      if ( (prevSym != 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 = currentOpenContext = rootOffset;
      prevAction = SYM_OPEN;
      strcpy((LPSTR)loadFilename, filename);
      loadTimestamp = *timestamp;
   }
   
   // 03/06/95 - Nghia
   // Open <root> as currentOpenContext.  SymAddLoadEnd() will close the
   // <root> context when done.
   UpdateBlockInfo(rootOffset, SYM_OPEN, FALSE);
   // only if load is successful should the state flag be set
   onDemandState = onDemand;

   return GOOD;
}

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

   moduleOpen = FALSE;
   if (localsLoaded) {
      // currentOpenContext must be a module
      modPtr = (SYM_TYPE_MODULE *)st.GetHugeDataPtr(currentOpenContext);
      if (!modPtr) return ER_INVALID_SYM_DESCRIPTOR;
      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;
   }

   // 03/06/95 - Nghia
   // Close module context and return to the root symbol context.
   firstErr = UpdateBlockInfo(dummyOffset,SYM_CLOSE,TRUE);   
   // 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;
   return (firstErr != GOOD) ? firstErr : err;
}  // end of SymAddModuleClose


//--------------------------------------------------------------------------
// SymAddModuleCreate
//--------------------------------------------------------------------------
RETCODE EXPORT
SymAddModuleCreate(LPSTR                   moduleName,
                   BASE_INDEX              baseIndex,
                   TIMESTAMP_TYPE         *timestamp, 
                   OFFSET_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;

   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->offsetStartAddr;

   module->symHeader.symHeader.endAddrInfo.endAddr =
      codeAddrRange->offsetEndAddr;
   
   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;
   module->auxFileOffset = 0L;
   module->langType      = LANG_UNKNOWN;
   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->offsetStartAddr,
                                   codeAddrRange->offsetEndAddr))
      != 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 of the currentOpenContext - the module itself
   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);
   if (!modPtr) return ER_INVALID_SYM_DESCRIPTOR;
   // get the module file offset
   *fileOffset = modPtr->fileOffset;
   // get the typeDelta ;
   *typeDelta = modPtr->typeDelta;
   moduleOpen = TRUE;
   return GOOD;
}

//--------------------------------------------------------------------------
// SymAddModuleExtraInfo
//--------------------------------------------------------------------------
RETCODE EXPORT SymAddModuleExtraInfo(SYM_DESCRIPTOR moduleDescriptor,
                                     U32 auxFileOffset,
                                     LANGUAGE_TYPE langType) {
   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) return ER_INVALID_SYM_DESCRIPTOR;
   if (((modPtr->symHeader.symHeader.typeIndex.symType) & 0xF) != SYM_MODULE)
      return ER_SYMBOL_NOT_A_MODULE;

   modPtr->auxFileOffset = auxFileOffset;
   modPtr->langType      = langType;
   return GOOD;
}  // end of SymAddModuleExtraInfo

//--------------------------------------------------------------------------
// 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) return ER_INVALID_SYM_DESCRIPTOR;

   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 last open context 
   if (prevSym == rootOffset)
      return ER_INVALID_SYM_DESCRIPTOR;
   symPtr = (COMMON_SYMBOL_HEADER HUGE *)st.GetHugeDataPtr(prevSym);
   if (!symPtr) return ER_INVALID_SYM_DESCRIPTOR;

   tmpSymType = (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;
}

//--------------------------------------------------------------------------
// SymSetSymbolAddrByDesc
//--------------------------------------------------------------------------
RETCODE EXPORT SymSetSymbolAddrByDesc(SYM_DESCRIPTOR symDesc,
                                      OFFSET_ADDR_RANGE_TYPE *addrRange) {

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

   if (!addrRange ||
       !(addrRange->offsetStartAddr || addrRange->offsetEndAddr))
      return ER_NO_VALID_ADDRESS;
  
   // Get symbol storage structure of the input symDesc 
   if (!symDesc) return ER_INVALID_SYM_DESCRIPTOR;
   symPtr = (COMMON_SYMBOL_HEADER HUGE *)st.GetHugeDataPtr(symDesc);
   if (!symPtr) return ER_INVALID_SYM_DESCRIPTOR;
   
   tmpSymType = (symPtr->typeIndex.symType) & 0xF;
   switch (tmpSymType) {
      case SYM_FUNCTION:
      case SYM_BLOCK:
      case SYM_MODULE:
         break;  // valid cases to update address
      default:
         return ER_INVALID_SYM_DESCRIPTOR;
   }
   
   // update the symbol address range
   symPtr->beginAddrInfo.startAddr = addrRange->offsetStartAddr;
   symPtr->endAddrInfo.endAddr = addrRange->offsetEndAddr;
   
   // 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(addrRange->offsetStartAddr,
                           addrRange->offsetEndAddr);
   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;
}

//--------------------------------------------------------------------------
// 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[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;
}

//--------------------------------------------------------------------------
// 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,
                         BASE_INDEX         baseIndex, 
                         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] = "";  

   // 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(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->fixedAddr;
               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, BASE_INDEX baseIndex,
                               TYPE_INDEX typeIndex, 
                               OFFSET_ADDR_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] = "";  

   // 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);
      if (!symPtr) return ER_INVALID_SYM_DESCRIPTOR;
      tmpSymType = (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;
                     // 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 {
      // NOTES: 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);
      if (!varSym) return ER_INVALID_SYM_DESCRIPTOR;
      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;
      // 03/03/95 - Nghia
      // Default storage class for Public Variable is UNKNOWN_VAR_CLASS
      varSym->storageClass =  UNKNOWN_VAR_CLASS;   
      if (0L == varAddr) {
         varSym->symHeader.beginAddrInfo.startAddr = 0xFFFFL;
         varSym->symHeader.endAddrInfo.endAddr = 0xFFFFL;
      } else {
         // varAddr is valid
         varSym->symHeader.beginAddrInfo.startAddr = varAddr;
         // 03/03/95 - Nghia
         // if address is valid then the Public Variable is a GLOBAL_VAR_CLASS
         varSym->storageClass = GLOBAL_VAR_CLASS;         
         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->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 = (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.
**    NOTES: 03/07/95 - Nghia
**    <currentOpenContext> = The current opened symbol context.
**    <prevSym>            = The previous closed symbol context.
**    <topSymStack>        = The parent opened symbol context of
**                           <currentOpenContext>.
**
************************************************************************/
PRIVATE RETCODE UpdateBlockInfo(TABLE_OFFSET symbol,
                                SYM_ACTION action,
                                BOOLEAN updateLinks) {
   RETCODE err;
   COMMON_BLOCK_HEADER HUGE *prevSymPtr;
   COMMON_BLOCK_HEADER HUGE *parentSymPtr;
   COMMON_BLOCK_HEADER HUGE *curSymPtr;

   if (action == SYM_OPEN) {
      if ((symbol == NULL_SYMBOL) ||
         !(curSymPtr  = (COMMON_BLOCK_HEADER HUGE *)st.GetHugeDataPtr(symbol)))
      return ER_INVALID_SYM_DESCRIPTOR;         
   }

#ifdef DEBUG_CONTEXT
   // 03/06/1995 - Nghia
   CHAR  bufStr[MAX_STRING_SIZE] = "";
   LPSTR bufStrPtr = bufStr;

   bufStrPtr += ((action == SYM_OPEN) ?
       sprintf(bufStrPtr, "Action: Open ") :
       sprintf(bufStrPtr, "Action: Close "));
   *bufStrPtr = '\0';
   SendMessageToCli((U8 FAR *)bufStr);

   bufStrPtr = bufStr;
   bufStrPtr += sprintf(bufStrPtr,"1: OpenCntxt: %X ",
                        currentOpenContext);
   bufStrPtr += sprintf(bufStrPtr,"prevSym: %X ",
                        prevSym);
   bufStrPtr += sprintf(bufStrPtr,"Symbol: %X ",
                        symbol);
   *bufStrPtr = '\0';
   SendMessageToCli((U8 FAR *)bufStr);
#endif
   
   // NOTES:
   // 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:
               // Create a child symbol of the <currentOpenContext>,
               // save the parent opened context.
               if (updateLinks) {
                  parentSymPtr = (COMMON_BLOCK_HEADER HUGE *)st.GetHugeDataPtr(currentOpenContext);
                  if (!parentSymPtr) return ER_INVALID_SYM_DESCRIPTOR;
                  parentSymPtr->child = symbol;
                  curSymPtr->symHeader.symParentOffset = currentOpenContext;
               }
               // Open a new symbol context as the <currentOpenContext>,
               // save the <currentOpenContext> onto the stack
               if ((err = PushSymStack(currentOpenContext)) != GOOD)
                  return err;
               currentOpenContext = symbol; 
               break;

            case SYM_CLOSE:
               // Close the <currentOpenContext>, Set the closed context
               // as <prevSym> so that SymAddSymbolSetAddr() can use.
               // Restore the parent opened context as the
               // <currentOpenContext> for next input symbol.
               prevSym = currentOpenContext;
               if ((err = PopSymStack(&currentOpenContext)) != GOOD)
                  return err;              
               break;

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

      case SYM_CLOSE:
         switch (action) {
            case SYM_OPEN:
               // Create a sibling symbol of the <currentOpenContext>.child
               // Save the currentOpenContext as parent context of symbol.
               if (updateLinks) {
                  prevSymPtr = (COMMON_BLOCK_HEADER HUGE *)st.GetHugeDataPtr(prevSym);
                  if (!prevSymPtr) return ER_INVALID_SYM_DESCRIPTOR;
                  curSymPtr->symHeader.symParentOffset = 
                     prevSymPtr->symHeader.symParentOffset;
                  prevSymPtr->symHeader.symSiblingOffset = symbol;
               }
               if ((err = PushSymStack(currentOpenContext)) != GOOD)
                  return err;
               currentOpenContext = symbol;
               break;

            case SYM_CLOSE:
               // Close the <currentOpenContext> and restore the
               // parent opened context for the next input symbol.
               // Set the closed context as <prevSym> so that other can use
               // in post-updating.
               prevSym = currentOpenContext;
               if ((err = PopSymStack(&currentOpenContext)) != GOOD)
                  return err;
               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 ;
   }
   prevAction = action;
   
#ifdef DEBUG_CONTEXT
   // 03/06/1995 - Nghia
   bufStr[0] = '\0';
   bufStrPtr = bufStr;
   bufStrPtr += sprintf(bufStrPtr,"2: OpenCntxt: %X ",currentOpenContext);
   bufStrPtr += sprintf(bufStrPtr,"prevSymbol: %X ", prevSym);
   bufStrPtr += sprintf(bufStrPtr,"Stack: %X ", symStack[topSymStack]);
   bufStrPtr += sprintf(bufStrPtr,"TopStack: %d", topSymStack);
   *bufStrPtr = '\0';
   SendMessageToCli((U8 FAR *)bufStr);
#endif
   
   return GOOD;
}
/******************************** E O F ***********************************/
