/****************************************************************************
**
**  Name:  symclipr.cpp
**
**  Description:
**     This is a set of routines to print out symbols in the symbol table 
**     in the order in which they were entered.  All these routines send
**     messages to the cli.
**
**  Status:  PRELIMINARY
**
**  $Log:   S:/tbird/mt2_68k/symbol/symclipr.cpv  $
** 
**    Rev 1.0   13 Feb 1997 09:06:22   gene
** Initial revision.
** 
**    Rev 1.0   07 Sep 1995 11:16:50   gene
** Initial revision.
** 
**    Rev 1.45   28 Feb 1994 17:48:12   nghia
** Added SymStat[] to tally symbol types.  Revised SymbolName table to be used
** by the _count shell command.
** 
**    Rev 1.44   30 Sep 1993 15:03:20   nghia
** Revised PrintVariable to print out LifeTime information - "_varlife" option
** 
**    Rev 1.43   25 Jun 1993 17:55:24   paul
** make abortFromEsc a BOOLEAN
** 
**    Rev 1.42   25 Jun 1993 17:32:24   paul
** Change CHECK_ABORT to TskCheckAbort
** 
**    Rev 1.41   04 May 1993 15:17:34   nghia
** Fixed bugs:
** 1. When displaySymbols hits an invalid address for a symbol, it reports erro.
** the error and stop.  Now it will print out the symbol has "unknown"
** address and continue with the rest of all symbols.
** 2. Address Descriptors leakage in SymPrintLines() and PrintSymbolAddress.
** NOTES: problem 1 can be tested using \tbird\core\test\loader\l695\hp\
** vp20rom.tst {HP compiler generates BB6 with bogus address}.
** 
**    Rev 1.40   30 Mar 1993 08:06:34   ernie
** Changed interface to CpuFindRegisterName
** 
**    Rev 1.39   23 Mar 1993 17:11:04   courtney
** Symbol pointers are huge in declaration and cast.
** 
**    Rev 1.38   16 Dec 1992 07:03:28   brucea
** Added "external" to address when 0 length
** Display typedef name
** 
**    Rev 1.37   03 Dec 1992 07:45:26   brucea
** Changed: type to typedef for symbol output
** Added: void to list of complexTypeNames
** Changed: "Unknown" storage class to "Public"
** Added: capability to display the item that a pointer points to, including
**    a complex type; added display of complex type name
** 
** 
**    Rev 1.36   06 Nov 1992 07:13:08   brucea
** Added: CHECK_ABORT inside printout of linenums; there can be many linenums
**    (e.g. prnieee) and couldn't esc out before
** 
**    Rev 1.35   15 Sep 1992 11:45:22   brucea
** Changed: AdrConvAddressToTextNoFill to ..WithParams
** 
**    Rev 1.34   13 Aug 1992 19:27:24   brucea
** Output message when displaying linenums and no linenums loaded for module
** 
**    Rev 1.33   13 Aug 1992 11:07:46   brucea
** Removed: SymMessageBox and calls to MessageBox; changed to ErrDisplayError
** Changed: wsprintf to sprintf
** 
**    Rev 1.32   06 Aug 1992 10:14:44   brucea
** Changed access to .typeIndex.symType to use &0xF
** 
**    Rev 1.31   25 Jul 1992 16:47:30   brucea
** Removed: second parameter from SendMessageToCli call
** 
**    Rev 1.30   19 Jul 1992 22:03:38   brucea
** Fixed: display of linenums that started with 2 instead of 1
** 
**    Rev 1.29   10 Jul 1992 18:58:20   brucea
** Redesigned: FillInAddress.  Now it calls SymConvSymAddrToText which uses
**    local params so that it can be called from symcli.cpp.
** 
**    Rev 1.28   24 Jun 1992 17:55:58   brucea
** Changed: SymPrintSymbol, SymPrintSymbols to EXPORTed functions
** 
**    Rev 1.27   15 Jun 1992 09:19:56   brucea
** Changed: cast of second param to GetString to LPU8
** Fixed up: other compile warnings generated from Borland 3.0
** 
**    Rev 1.26   15 May 1992 14:28:54   brucea
** Changed: ER_SYM_ABORT to the generic ER_ABORT_FROM_ESC
** 
**    Rev 1.25   30 Apr 1992 18:37:26   brucea
** Changed: nesting level maximum to 6 for function/block/variable indenting
** Fixed: skip over symbols with no name
** Fixed: ignore modules with no lines which displaying lines
** 
**    Rev 1.24   20 Apr 1992 08:59:18   brucea
** Added: SymMessageBox
** Fixed: display of address range (end address points to last byte of range)
** Fixed: PPR5356, PPR5357 -> enum not displayed correctly
** Added: display of registers by name
** Removed: EXPORT from SymPrintSymbol and SymPrintSymbols
** Added: SymPrintLines
** 
**    Rev 1.23   01 Apr 1992 23:39:00   brucea
** Fixed: compiler warnings
** 
**    Rev 1.22   26 Mar 1992 18:01:50   brucea
** Changed: AdrConvAddressToText to ...TextNoFill
** 
**    Rev 1.21   27 Feb 1992 22:52:30   brucea
** ** Removed: definition of CheckAbort [moved to BASETYP.H]
** ** Renamed: CheckAbort() to CHECK_ABORT()
** 
**    Rev 1.20   14 Feb 1992 14:57:48   brucea
** Added CheckAbort() macro and the calls to it to allow aborting symbol display
**   with the ESC key
** 
**    Rev 1.19   04 Feb 1992 16:09:08   brucea
** In FillInAddress, added init to null string of tmpStr
** Fixed bug in FillInDetailedType to remove extra pointer reference for HPU8 var
** 
**    Rev 1.18   29 Jan 1992 15:05:20   brucea
** Turned off Symbol Usage for address descriptors in FillInAddress and
**    PrintSymbolAddress so that they are displayed in hex
** Removed \n in buffer before sending to CLI
** 
**    Rev 1.17   22 Jan 1992 14:40:28   brucea
** 
** Corrected display of symbol size for command displaysymbols
** Fixed displaysymbols debug option
**
**    Rev 1.16   10 Jan 1992 18:31:38   brucea
** Added single line print routines to display symbols to CLI
** 
**    Rev 1.15   11 Dec 1991 16:33:48   john
** Made many formatting changes.
** 
**    Rev 1.14   09 Dec 1991 12:17:36   john
** Made changes to allow two different symbol displays.  One for
** the user and one for debugging.
** Also made many formatting changes.
** 
**    Rev 1.13   03 Dec 1991 17:15:18   brucea
** moved PrintSymbols inside __cplusplus include
** changed lower case x to X for %8lX's
** 
**    Rev 1.12   29 Nov 1991 20:05:44   brucea
** NULL to NULL_SYMBOL
** endInfo to endAddrInfo
** 
**    Rev 1.11   18 Nov 1991 20:34:34   brucea
** Changed PrintVariable to support isConstant and isValidAddr
** 
**    Rev 1.10   15 Nov 1991 13:59:32   john
** COMMON_SYMBOL_HEADER was changed.  A pointer to this type was
** updated to match.
** 
**    Rev 1.9   11 Nov 1991 13:52:38   brucea
** Changed PrintModule to access and display linenumOffsetStart
**   and linenumOffsetEnd
** 
**    Rev 1.8   07 Nov 1991 13:50:22   john
** Fixed code to match new structure in symmgr.h
**
**    Rev 1.7   06 Nov 1991 13:29:56   john
** Removed compile time warnings w/max warning level enabled
** 
**    Rev 1.6   23 Oct 1991 17:14:08   john
** Removed EXPORT from not exportable functions
** 
**    Rev 1.5   22 Oct 1991 13:49:50   john
** Moved a portion of PrintSymbols into a new routine for printing just
** one symbol.  PrintSymbols now calls PrintSymbol for every symbol
** it wants to print.
** 
**    Rev 1.4   11 Oct 1991 15:09:30   brucea
** changed code that printed out the base structure
** 
**    Rev 1.3   03 Oct 1991 16:47:52   john
** moved structs from symadd.h to symmgr.h
** 
**    Rev 1.2   03 Oct 1991 15:01:24   john
** Changed symmgr.h include to the renamed symadd.h
** 
**    Rev 1.1   03 Oct 1991 11:47:06   john
** Changed the function calls to sendmessagetocli so that it did not
** require the size of the string to be passed as an argument.
** 
**    Rev 1.0   25 Sep 1991 13:35:04   john
** Initial revision.
** 
**  $Header:   S:/tbird/mt2_68k/symbol/symclipr.cpv   1.0   13 Feb 1997 09:06:22   gene  $
**
**  Copyright (C) 1991 Microtek International.  All rights reserved.
**
*****************************************************************************/

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

#ifndef _ADDR_
#include "addr.h"
#endif

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

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

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

#ifndef _CPU_
#include "cpu.h"
#endif

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

#ifndef _HEAP_
#include "heap.h"
#endif

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

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

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

#ifndef _PVTASK_
#include "pvtask.h"
#endif

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

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

#ifndef _SYMMGR_
#include "symmgr.h"
#endif

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

#ifndef _SYMCLIPR_
#include "symclipr.h"
#endif

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

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

PRIVATE S8 globalStr[MAX_SYMNAME_LENGTH * 2];
PRIVATE COMMON_SYMBOL_HEADER HUGE *rootPtr;

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

extern LinenumTable lt;
extern BaseIndexTable bit; // base index table ;
extern OrdinalTable ot;    // ordinal table ;
extern MemPool st;   // symbol table ;
extern TABLE_OFFSET rootOffset;

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

RETCODE PRIVATE FillInAddress(SYM_DESCRIPTOR symbol);
RETCODE PRIVATE GetDestinationOfPtr(TYPE_INDEX typeIndex, LPSTR returnName);
VOID    PRIVATE FillInDetailedType(SYM_DESCRIPTOR symbol);
RETCODE PRIVATE FillInTypeAndName(SYM_DESCRIPTOR symbol, U8 nesting);
RETCODE PRIVATE GetSymbolPrintLine(SYM_DESCRIPTOR   symbol,
                                   SYM_DISPLAY_TYPE displayType,
                                   U16              nesting);
VOID PRIVATE SpaceToColumn(U8 column);

RETCODE PRIVATE PrintBlockHeader(HPU8 symPtr, SYM_DISPLAY_TYPE displayType);
RETCODE PRIVATE PrintCommonHeader(HPU8 symPtr, SYM_DISPLAY_TYPE displayType);
RETCODE PRIVATE PrintFunction(HPU8 symPtr, SYM_DISPLAY_TYPE displayType);
RETCODE PRIVATE PrintModule(HPU8 symPtr, SYM_DISPLAY_TYPE displayType);
RETCODE PRIVATE PrintSymbolAddress(HPU8 symPtr, SYM_DISPLAY_TYPE displayType);
RETCODE PRIVATE PrintVariable(TABLE_OFFSET inputSymbol, HPU8 symPtr,
                              SYM_DISPLAY_TYPE displayType);

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

//--------------------------------------------------------------------------
// PrintBlock
//--------------------------------------------------------------------------
RETCODE PRIVATE PrintBlock(HPU8 symPtr, SYM_DISPLAY_TYPE displayType) {

   RETCODE err;

   // print the information common to all block/function/module symbols ;
   if ((err = PrintBlockHeader(symPtr, displayType)) != GOOD) return(err);

   return(GOOD);

}

#define NAME_COLUMN          14
#define DETAILED_TYPE_COLUMN 30
#define ADDRESS_COLUMN       55


//--------------------------------------------------------------------------
// SymConvSymAddrToText
//
// Design:
//    Calculates symbol address and returns it in string alloc'ed by caller
//    Fixed addresses:
//       Displays fixed address as xxx-yyy where xxx is the start address and
//       yyy is the end address; then displays the range as [rrr].
//       Start and end addresses are is hex, the range is in decimal
//    Stack-based addresses:
//       Displays as a single signed decimal number followed by [sss] size.
//
// Input Parameter:
//    symbol: symbol being printed
//
// Output Parameter:
//    str: alloc'ed by caller using size SYMCLIPR_ADDR_TEXT_WIDTH
//--------------------------------------------------------------------------
RETCODE SymConvSymAddrToText(SYM_DESCRIPTOR symbol, LPSTR str)  {

   RETCODE          err;
   HPU8             symPtr;
   U32              startAddr, endAddr, tmpAddrSize;
   DESCRIPTOR       startAddrDesc, endAddrDesc;
   S8               tmpStr[SYMCLIPR_ADDR_TEXT_WIDTH];
   TYPE_HEADER_TYPE typeHeader;
   LPSTR            strPtr;
   U8               n;

   strPtr = str;  // set string pointer at beginning of passed-in string
   tmpStr[0] = '\0';  // init string
   str[0] = '\0';  // init string

   symPtr = st.GetHugeDataPtr(symbol);

   if((err = AdrCreateAddress(&startAddrDesc)) != GOOD)
      return(err);
   if((err = AdrSetAddrSymbolUsage(startAddrDesc, FALSE)) != GOOD)
      return err;
   if((err = AdrCreateAddress(&endAddrDesc)) != GOOD)
      return(err);
   if((err = AdrSetAddrSymbolUsage(endAddrDesc, FALSE)) != GOOD)
      return err;
   switch (((COMMON_SYMBOL_HEADER HUGE *)symPtr)->typeIndex.symType & 0xF) {
      case SYM_LOCAL_VAR:
      case SYM_GLOBAL_VAR:
      case SYM_USER_DEFINED_VAR:
      case SYM_PUBLIC_VAR:
         if (NOT_REG != ((SYM_TYPE_VARIABLE HUGE *)symPtr)->registerClass) {
            // if reg, get size from type info
            typeHeader.typeName = tmpStr;
            if ((err =
               SymGetTypeHeader(((SYM_TYPE_VARIABLE HUGE *)symPtr)->
                                typeIndex, &typeHeader)) != GOOD) {
               return err;
            }
            n = sprintf(strPtr, "[%ld]", typeHeader.sizeInMAUs);
            strPtr += n;
            break; /* out of the switch statement */
         }

         if (AUTO_VAR_CLASS == ((SYM_TYPE_VARIABLE *)symPtr)->storageClass) {
            startAddr = ((SYM_TYPE_VARIABLE *)symPtr)->
                          symHeader.beginAddrInfo.autoVarOffset;
            n = sprintf(strPtr, "%+d", startAddr);
            strPtr += n;

            // insert auto size
            n = sprintf(strPtr, " [%ld]", ((SYM_TYPE_VARIABLE *)symPtr)->
                    symHeader.endAddrInfo.varSize);
            strPtr += n;
            break; /* out of the switch statement */
         }

      // PURPOSELY FALLING THROUGH HERE
      default:    // fixed address cases
         // get the logical address
         if((err = UtilSetAddrParams(
            ((COMMON_SYMBOL_HEADER *)symPtr)->typeIndex.baseIndex,
            ((COMMON_SYMBOL_HEADER *)symPtr)->beginAddrInfo.startAddr,
            ((COMMON_SYMBOL_HEADER *)symPtr)->endAddrInfo.endAddr,
            startAddrDesc)) != GOOD) {
            // 05/04/93 - Nghia - Handle Invalid adddress cases
            // symbol didn't have a valid address; print "unknown"
            n = sprintf(strPtr, "unknown");
            strPtr += n;
            break; /* out of the switch statement */
         }
         if((err = AdrGetAddrOffset(startAddrDesc, &startAddr)) != GOOD)
            return(err);

         if ((err = AdrGetAddrRangeLength(startAddrDesc, &tmpAddrSize))
            != GOOD)
            return(err);
         if (0L == tmpAddrSize) {
            // symbol didn't have a valid address; print "external"
            n = sprintf(strPtr, "external");
            strPtr += n;
         } else {

            // convert logical address to a string
            if ((err = AdrConvAddressToTextWithParams(startAddrDesc,
                                                      TRUE,
                                                      FALSE,
                                                      (LPSTR)tmpStr))
               != GOOD)
               return err;
            strPtr = stpcpy(strPtr, tmpStr);
            strPtr = stpcpy(strPtr, "-");  // insert the "to" character

            // do same for end address; must put into separate descriptor
            // so that adr text conversion routine is used and so it doesn't
            // modify end address of the previous desc. which is used to
            // later calculate and display the address range
            if((err = AdrGetEndAddrOffset(startAddrDesc, &endAddr)) != GOOD)
               return(err);

            if((err = AdrSetAddrOffset(endAddrDesc, endAddr)) != GOOD)
               return(err);
            if ((err = AdrConvAddressToTextWithParams(endAddrDesc,
                                                      TRUE,
                                                      FALSE,
                                                      (LPSTR)tmpStr))
               != GOOD)
               return err;
            strPtr = stpcpy(strPtr, tmpStr);

            if ((err = AdrGetAddrRangeLength(startAddrDesc, &startAddr))
               != GOOD)
               return(err);
            // addresses now being stored such that end address points to last
            // byte, therefore 0x1000-0x1000 is size 1
            sprintf(strPtr, " [%lu]", startAddr);
         }
   } // end of switch
   if((err = AdrDestroyAddress(startAddrDesc)) != GOOD)
      return(err);
   if((err = AdrDestroyAddress(endAddrDesc)) != GOOD)
      return(err);
   return GOOD;

}  // end of SymConvSymAddrToText


//--------------------------------------------------------------------------
// FillInAddress
//
// Design:
//    Gets symbol address and inserts it into globalStr
//
// Input Parameter:
//    symbol: symbol being printed
//--------------------------------------------------------------------------
RETCODE PRIVATE FillInAddress(SYM_DESCRIPTOR symbol)  {

   RETCODE          err;
   S8               tmpStr[SYMCLIPR_ADDR_TEXT_WIDTH];

   SpaceToColumn(ADDRESS_COLUMN);

   // tmpStr is modified by call
   if ((err = SymConvSymAddrToText(symbol, tmpStr)) != GOOD)
      return err;
   strcat(globalStr, tmpStr);
   return GOOD;
}  // end of FillInAddress


PRIVATE const S8 *complexTypeNames[] = {
   "unknown",
   "pascal enum",
   "general",
   "enum",
   "small ptr",
   "ptr",
   "range",
   "struct",
   "typedef",
   "union",
   "void",
   "function",
   "C array",
   "bit field",
   "function",
   "not valid complex"  // only displayed if stored complex value is invalid
};

PRIVATE U8 complexTypeNamesMap[] = {      // can't be const because writing to
   0x21,                                // last entry
   0x45,
   0x47,
   0x4E,
   0x4F,
   0x50,
   0x52,
   0x53,
   0x54,
   0x55,
   0x56,
   0x58,
   0x5A,
   0x67,
   0x78,
   0x00  // filler to place complex type value for match if no others match
};

U8 varStorageClass[][9] = {
   "Local ",
   "Static ",
   "Global ",
   "Based ",
   "Public "
};

//--------------------------------------------------------------------------
// GetDestinationOfPtr 
//
// Design:
//    Given a pointer type index, return text of what it points to
//    It may point to another complex in which case, return complex name
//
// Input Parameter:
//    typeIndex: index of type pointer points to
//    returnName: string pointer of where to put:
//          "to <type name>"
//--------------------------------------------------------------------------
RETCODE PRIVATE
GetDestinationOfPtr(TYPE_INDEX typeIndex, LPSTR returnName)  {

   TYPE_INDEX       ptrToTypeIndex;
   RETCODE          err;
   TYPE_HEADER_TYPE ptrToTypeHeader;

   // get type of what pointer points to
   if ((err = SymGetTypePointerTypeIndex(typeIndex, &ptrToTypeIndex)) != GOOD)
      return err;

   strcpy(returnName, " to ");
   // get info on dest of ptr
   // must supply data structure with string memory to be filled in
   ptrToTypeHeader.typeName = &returnName[4];  // point to after " to "
   if ((err = SymGetTypeHeader(ptrToTypeIndex, &ptrToTypeHeader)) != GOOD)
      return err;

   if (ptrToTypeHeader.typeChoice == COMPLEX_TYPE_CLASS)  {
      // match complex type number to constant index table; extract
      //   index for complexTypeNames string table
            
      complexTypeNamesMap[sizeof(complexTypeNamesMap) - 1] =
         ptrToTypeHeader.t.complexType;
      // scan array for match
      for (U8 i=0; i < sizeof(complexTypeNamesMap); i++) {
         if (ptrToTypeHeader.t.complexType == complexTypeNamesMap[i])
            break;
      };
      strcat(returnName, " ");
      strcat(returnName, complexTypeNames[i]);
   }
   return GOOD;
}  // end of GetDestinationOfPtr


//--------------------------------------------------------------------------
// FillInDetailedType
//--------------------------------------------------------------------------
VOID FillInDetailedType(SYM_DESCRIPTOR symbol)  {

   HPU8             symPtr;
   LINENUM_TYPE     firstLinenum;
   LINENUM_TYPE     lastLinenum;
   S8               tmpStr[MAX_SYMNAME_LENGTH]; // used for type names
   TYPE_HEADER_TYPE typeHeader;
   REG_INDEX        regIndex;
   S8               regName[MAX_REGNAME];
   RETCODE          err;
   LPSTR            strPtr;
   U8               n;

   SpaceToColumn(DETAILED_TYPE_COLUMN);
   tmpStr[0] = '\0';  // init string

   strPtr = globalStr;  // set pointer to beginning of string
   while (*strPtr != '\0') strPtr++;  // point to null string terminator
   symPtr = (HPU8)st.GetHugeDataPtr(symbol);

   // get symbol type index
   switch (((COMMON_SYMBOL_HEADER *)symPtr)->typeIndex.symType & 0xF) {
      case SYM_MODULE:  // display linenum range
         if (SUCCESS ==
               (lt.GetLinenumFirstLast(symbol, firstLinenum, lastLinenum))) {
            strPtr = stpcpy(strPtr, "Lines ");
            n = sprintf(strPtr, "%u-%u", firstLinenum, lastLinenum);
            strPtr += n;
            }
         break;

      case SYM_FUNCTION:   // display local/global and return type
         if (((SYM_TYPE_FUNCTION *)symPtr)->funcClass == FUNC_GLOBAL)  {
            strPtr = stpcpy(strPtr, "Global returning ");
         } else {
            strPtr = stpcpy(strPtr, "Local returning ");
         }
         // insert the return type name
         // assign the string pointer in typeHeader to the local string
         typeHeader.typeName = tmpStr;

         U32 attribute;
         U8  frameType;
         U32 pushMask;
         U8  argCount;
         U8  level;
         U8  fatherName[MAX_SYMNAME_LENGTH];
         TYPE_INDEX returnIndexType;

         
         if (GOOD == SymGetFuncType(symbol,
                                    &attribute,
                                    &frameType,
                                    &pushMask,
                                    &typeHeader,  // contains tmpStr ptr
                                    &argCount,
                                    &level,
                                    (LPSTR)fatherName)) {
            // tmpStr filled in with simple name or null
            if (typeHeader.typeChoice == COMPLEX_TYPE_CLASS)  {
               // add complex name
               // match complex type number to constant index table; extract
               //   index for complexTypeNames string table
            
               complexTypeNamesMap[sizeof(complexTypeNamesMap) - 1] =
                  typeHeader.t.complexType;
               // scan array for match
               for (U8 i=0; i < sizeof(complexTypeNamesMap); i++) {
                  if (typeHeader.t.complexType == complexTypeNamesMap[i])
                     break;
               };
               // if type is ptr, add text indicating what it points to
               strPtr = stpcpy(strPtr, complexTypeNames[i]);

               // tmpStr freed up here inside if stmt
               if ((typeHeader.t.complexType == 0x4F) ||   // small ptr
                   (typeHeader.t.complexType == 0x50)) {   // large ptr
                  // although a kludge, the SymGetFuncType does not return
                  // the return type INDEX, it only fills out the values
                  // of the type; therefore, must use following function...

                  if (GOOD != (err = 
                     SymGetFuncReturnTypeIndex(symbol,
                                               &returnIndexType)))
                  if (GOOD !=
                     (err = GetDestinationOfPtr(returnIndexType,
                                                tmpStr)))
                     goto CLEANUP;
                  strPtr = stpcpy(strPtr, tmpStr);  // copy " to <type name>"
               }
            } else {
               strPtr = stpcpy(strPtr, tmpStr);
            }
         }
         break;

      case SYM_GLOBAL_VAR:
      case SYM_LOCAL_VAR:
      case SYM_USER_DEFINED_VAR:
      case SYM_PUBLIC_VAR:   // display built-in type or general complex type
         // insert basic variable type
         if (NOT_REG == ((SYM_TYPE_VARIABLE *)symPtr)->registerClass) {
            // insert non-register typename
            strPtr = stpcpy(strPtr,
                (S8 FAR *)varStorageClass[((SYM_TYPE_VARIABLE *)symPtr)->
                storageClass]);
         } else {
            strPtr = stpcpy(strPtr, "Reg ");
            // insert register name
            regIndex =
               ((COMMON_SYMBOL_HEADER *)symPtr)->beginAddrInfo.registerIndex;

            err = CpuFindRegisterName(regIndex, regName);
            if (err) {  // print out reg number if no matching name
               n = sprintf(strPtr, "%02u ", regIndex);
               strPtr += n;
            } else {    // insert register name
               strPtr = stpcpy(strPtr, regName);
               strPtr = stpcpy(strPtr, " ");
            }
         }
         // insert the type name even if a built-in
         typeHeader.typeName = tmpStr;  // give routine string memory
         // get the type header info
         if (GOOD != (err =
            SymGetTypeHeader(((SYM_TYPE_VARIABLE *)symPtr)->typeIndex,
                              &typeHeader))) {
            goto CLEANUP;
            }
         // if the type is complex, insert complex type name first
         if (typeHeader.typeChoice == COMPLEX_TYPE_CLASS)  {
            // add complex name
            // match complex type number to constant index table; extract
            //   index for complexTypeNames string table
            
            if (tmpStr[0] != '\0') {  // if text in string, copy typedef name
               strPtr = stpcpy(strPtr, tmpStr);
               strPtr = stpcpy(strPtr, " ");
            }
            complexTypeNamesMap[sizeof(complexTypeNamesMap) - 1] =
               typeHeader.t.complexType;
            // scan array for match
            for (U8 i=0; i < sizeof(complexTypeNamesMap); i++) {
               if (typeHeader.t.complexType == complexTypeNamesMap[i])
                  break;
            };
            strPtr = stpcpy(strPtr, complexTypeNames[i]);
            if ((typeHeader.t.complexType == 0x4F) ||   // small ptr
                (typeHeader.t.complexType == 0x50)) {   // large ptr

               if (GOOD != 
                  (err = GetDestinationOfPtr(
                            ((SYM_TYPE_VARIABLE *)symPtr)->typeIndex,
                            tmpStr)))
                  goto CLEANUP;
               strPtr = stpcpy(strPtr, tmpStr);  // copy " to <type name>"
            }
         } else {
            // now insert the type name if not complex
            strPtr = stpcpy(strPtr, tmpStr);
         }
         break;

      default: ; // insert nothing
   } // end of switch
   return;

CLEANUP:
   ErrDisplayError(err, CHECK_MODE);
   return;
}  // end of FillInDetailedType


// Text table definition
#define MAX_SYM_TYPE_NAMES 11
const S8 *symTypeName[MAX_SYM_TYPE_NAMES] = {
   "MODULE",
   "FUNCTION",
   "BLOCK",
   "VARIABLE",
   "LABEL",
   "CONSTANT",
   "USER VAR",
   "USER LABEL",
   "PUBLIC VAR",
   "PUBLIC LABEL",
   "PUBLIC"
};

// The values in this array map the SYM_TYPE_TYPE enum entries (which start at
// 0) to the string array <symTypeName> above.  A value of 0xFF means there is
// no string name for that symbol type
U8 symTypeMap[MAX_SYM_TYPE] = {
   0xFF, //SYM_ROOT
   0,    //SYM_MODULE
   1,    //SYM_FUNCTION
   2,    //SYM_BLOCK
   3,    //SYM_GLOBAL_VAR
   3,    //SYM_LOCAL_VAR
   4,    //SYM_LABEL
   5,    //SYM_CONSTANT
   0xFF, //SYM_TYPE
   6,    //SYM_USER_DEFINED_VAR
   7,    //SYM_USER_DEFINED_LABEL
   8,    //SYM_PUBLIC_VAR
   9,    //SYM_PUBLIC_LABEL
   10,   //SYM_PUBLIC_UNKNOWN
   0xFF, //SYM_MISCELLANEOUS
   0xFF  //SYM_UNDEFINED
};

//--------------------------------------------------------------------------
// FillInTypeAndName
//--------------------------------------------------------------------------
RETCODE PRIVATE FillInTypeAndName(SYM_DESCRIPTOR symbol, U8 nesting)  {

   COMMON_SYMBOL_HEADER HUGE *symPtr;
   S8 name[MAX_SYMNAME_LENGTH];
   U8 symTypeMapIndex;
   RETCODE retCode;

   globalStr[0] = '\0';   // init string
   SpaceToColumn(min(nesting, 6) * 2);
   symPtr = (COMMON_SYMBOL_HEADER HUGE *)st.GetHugeDataPtr(symbol);

   // get symbol type index; map to string index; if index > number of entries
   // in the string table, return; otherwise copy string into char array
   if ((symTypeMapIndex = symTypeMap[(symPtr->typeIndex.symType) & 0xF]) >
      MAX_SYM_TYPE_NAMES)
      return ER_STRING_LENGTH_ZERO;
   // map symbol type to symbol type name string
   strcat(globalStr, symTypeName[symTypeMapIndex]);
   SpaceToColumn(NAME_COLUMN);

   // install name
   if (((symPtr->typeIndex.symType) & 0xF) == SYM_MODULE) {
      if ((retCode = SymAddGetModuleName(symbol, name)) != SUCCESS)
         return retCode;
   }
   else {
      st.GetString(symPtr->symbolNameOffset, (LPU8)name);
   }
   strcat(globalStr, name);
   return GOOD;   
}

//--------------------------------------------------------------------------
// GetSymbolPrintLine
//--------------------------------------------------------------------------
#pragma argsused
RETCODE PRIVATE
GetSymbolPrintLine(SYM_DESCRIPTOR   symbol,
                   SYM_DISPLAY_TYPE displayType,
                   U16              nesting)  {

   RETCODE err;

   if ((err = FillInTypeAndName(symbol, nesting)) != GOOD)
      return err;
   FillInDetailedType(symbol);
   if ((err = FillInAddress(symbol)) != GOOD)
      return err;
   return GOOD;
} // end of GetSymbolPrintLine


//--------------------------------------------------------------------------
// SpaceToColumn
//
// Design:
//    fills spaces up to but not including requested column (column 1 = first
//    character, i.e. string[0])
//    If requested column is less than or equal to the position of the null
//    termination, then insert one space and put the null character one
//    location after its present position.
//
// Input Parameter:
//    column:
//       indicates what column to insert spaces to; i.e. if the value is 10,
//       spaces should be inserted through column 9, where column 1 is the
//       first character field.
//--------------------------------------------------------------------------
VOID SpaceToColumn(U8 column) {

   U16 len;

   if (column == 0) return;      // no request for space padding
   len = strlen(globalStr);
   if (column <= len) {
      column = len + 1;   // fill in one additional space, then null terminate
   }
/* as defined, sizeof(globalStr) is always larger than a U8 (256 * 2) */
// if (column > sizeof(globalStr))
//    return;              // don't fill if request is beyond size of string

   for (; len < column; globalStr[len++] = ' ');

   globalStr[len] = '\0'; // add null termination
   
}  // end of SpaceToColumn


//--------------------------------------------------------------------------
// PrintBlockHeader
//--------------------------------------------------------------------------
RETCODE PRIVATE PrintBlockHeader(HPU8 symPtr, SYM_DISPLAY_TYPE displayType) {

   RETCODE err;
   COMMON_BLOCK_HEADER *blkPtr;

   // Don't print any of the block info if this is a user symbol display ;
   if (displayType == DEBUG_DISPLAY) {
      blkPtr=(COMMON_BLOCK_HEADER *)symPtr;
      sprintf((LPSTR)globalStr,"Child Descriptor:  %8lX",blkPtr->child);
      if((err =
         SendMessageToCli((U8 FAR *)globalStr)) != GOOD) 
         return(err);
      sprintf((LPSTR)globalStr,"Variable List Descriptor:  %8lX   "
          "Label List Descriptor:  %8lX", blkPtr->list.varListOffset, 
          blkPtr->list.labelListOffset);
      if((err =
         SendMessageToCli((U8 FAR *)globalStr)) != GOOD) 
         return(err);
      sprintf((LPSTR)globalStr,"Constant List Descriptor:  %8lX   "
         "Misc. List Descriptor:  %8lX", blkPtr->list.constListOffset,
         blkPtr->list.miscListOffset);
      if((err =
         SendMessageToCli((U8 FAR *)globalStr)) != GOOD) 
         return(err);
   }
   return(GOOD);

}

//--------------------------------------------------------------------------
// PrintCommonHeader
//--------------------------------------------------------------------------
RETCODE PRIVATE PrintCommonHeader(HPU8 symPtr, SYM_DISPLAY_TYPE displayType) {

   RETCODE err;
   COMMON_SYMBOL_HEADER *headPtr;
   U8 name[MAX_SYMNAME_LENGTH];
   U8 *namePtr;

   headPtr=(COMMON_SYMBOL_HEADER *)symPtr;

   // get the name of the symbol ;
   if ( (headPtr->symbolNameOffset == NULL_SYMBOL) && 
      (displayType == DEBUG_DISPLAY)) {
      sprintf((LPSTR) globalStr, "Unnamed symbol");
      if((err =
         SendMessageToCli((U8 FAR *)globalStr)) != GOOD) 
         return(err);
   } else {
      if (headPtr->symbolNameOffset) {
         st.GetString(headPtr->symbolNameOffset,(LPU8)name);
         if (headPtr->typeIndex.symType == SYM_MODULE) {
            // move the pointer past the extra two characters prepended to ;
            // module names to make them unique. ;
            namePtr = name + 2;
         } else {
            namePtr = name;
         }
         sprintf((LPSTR)globalStr,"Name:  %s",(LPSTR)namePtr);
         if((err = SendMessageToCli((U8 FAR *)globalStr)) 
            != GOOD) return(err);
      }
   }
   
   if ((err = PrintSymbolAddress(symPtr, displayType)) != GOOD)
      return(err);
   
   if (displayType == DEBUG_DISPLAY) {
      sprintf((LPSTR)globalStr,"Type:    %4d   Base Index:      %d",
         ((headPtr->typeIndex.symType) & 0xF), headPtr->typeIndex.baseIndex);
      if((err =
         SendMessageToCli((U8 FAR *)globalStr)) != GOOD) 
         return(err);
      sprintf((LPSTR)globalStr,"Parent Descriptor:  %8lX   "
         "Sibling Descriptor:  %8lX", headPtr->symParentOffset,
         headPtr->symSiblingOffset);
      if((err =
         SendMessageToCli((U8 FAR *)globalStr)) != GOOD) 
         return(err);
      sprintf((LPSTR)globalStr,"Ordinal Value:  %8lX",headPtr->ordinalVal);
      if((err =
         SendMessageToCli((U8 FAR *)globalStr)) != GOOD) 
         return(err);
   }
   return(GOOD);
}

//--------------------------------------------------------------------------
// PrintFunction
//--------------------------------------------------------------------------
RETCODE PRIVATE PrintFunction(HPU8 symPtr, SYM_DISPLAY_TYPE displayType) {
   
   RETCODE err;
   SYM_TYPE_FUNCTION *funcPtr;

   // print the information common to all block/function/module symbols ;
   if ((err = PrintBlockHeader(symPtr, displayType)) != GOOD) return(err);
   
   if (displayType == DEBUG_DISPLAY) {
      // print the information specific to modules ;
      funcPtr=(SYM_TYPE_FUNCTION *)symPtr;
   
      sprintf((LPSTR)globalStr,"Function Class:  %4x",funcPtr->funcClass);
      if ((err =
         SendMessageToCli((U8 FAR *) globalStr))!=GOOD) 
         return(err);
   
      sprintf((LPSTR)globalStr,"Stack Space:  %8lX  Type Index:  %8lX",
         funcPtr->stackSpace,funcPtr->typeIndex);
      if ((err =
         SendMessageToCli((U8 FAR *)globalStr)) != GOOD) 
         return(err);
   }
   return(GOOD);
}

//--------------------------------------------------------------------------
// PrintModule
//--------------------------------------------------------------------------
RETCODE PRIVATE PrintModule(HPU8 symPtr, SYM_DISPLAY_TYPE displayType) {
   
   RETCODE err;
   SYM_TYPE_MODULE *modPtr;
   U8 name[MAX_SYMNAME_LENGTH];

   // print the information common to all block/function/module symbols ;
   if ((err = PrintBlockHeader(symPtr, displayType)) != GOOD) return(err);

   if (displayType == DEBUG_DISPLAY) {
      // print the information specific to modules ;
      modPtr=(SYM_TYPE_MODULE *)symPtr;
      
      sprintf((LPSTR)globalStr,"Line Number Offset Start:  %8lX",
         modPtr->linenumOffsetStart);
      if(( err =
         SendMessageToCli((U8 FAR *)globalStr)) != GOOD) 
         return(err);

      sprintf((LPSTR)globalStr,"Line Number Offset End:  %8lX",
         modPtr->linenumOffsetEnd);
      if((err =
         SendMessageToCli((U8 FAR *)globalStr)) != GOOD) 
         return(err);
   }
   
   // get the source file name ;
   st.GetString(modPtr->srcFilenameOffset, (LPU8)name);
   
   sprintf((LPSTR)globalStr,"Filename: %s",(LPSTR)name);
   if ((err =
       SendMessageToCli((U8 FAR *)globalStr)) != GOOD) 
      return(err);

   if (displayType == DEBUG_DISPLAY) {
      sprintf((LPSTR)globalStr,"%#02d-%#02d-%#04d", modPtr->timestamp.day,
         modPtr->timestamp.month, modPtr->timestamp.year);
      if((err =
         SendMessageToCli((U8 FAR *)globalStr)) != GOOD) 
         return(err);
   
      sprintf((LPSTR)globalStr,"%#02d:%#02d:%#02d", modPtr->timestamp.hour,
         modPtr->timestamp.minute, modPtr->timestamp.second);
      if((err =
         SendMessageToCli((U8 FAR *)globalStr)) != GOOD) 
         return(err);
   }
   return(GOOD);
}

//--------------------------------------------------------------------------
// PrintSymbolAddress
//--------------------------------------------------------------------------
RETCODE PRIVATE
PrintSymbolAddress(HPU8 symPtr, SYM_DISPLAY_TYPE displayType) {

   RETCODE err = GOOD, err1 = GOOD;
   COMMON_SYMBOL_HEADER *headPtr;
   SYM_TYPE_VARIABLE *varPtr;
   U32 startAddr, endAddr;
   DESCRIPTOR tmpVarAddrDesc;

   if((err = AdrCreateAddress(&tmpVarAddrDesc)) != GOOD) return(err);
   if((err = AdrSetAddrSymbolUsage(tmpVarAddrDesc, FALSE)) != GOOD) {
      goto cleanup;
   }
   headPtr = (COMMON_SYMBOL_HEADER *)symPtr;
   switch (headPtr->typeIndex.symType & 0xF) {
      case SYM_FUNCTION:
      case SYM_MODULE:
      case SYM_LABEL:
      case SYM_PUBLIC_LABEL:
      case SYM_PUBLIC_UNKNOWN:
         if((err = UtilSetAddrParams(headPtr->typeIndex.baseIndex,
            headPtr->beginAddrInfo.startAddr, headPtr->endAddrInfo.endAddr,
            tmpVarAddrDesc)) != GOOD)
            break; // out of switch
         if((err = AdrGetAddrOffset(tmpVarAddrDesc, &startAddr)) != GOOD) 
            break; // out of switch
         sprintf((LPSTR) globalStr, "    Address:  %8lX", startAddr);
         if ((err = SendMessageToCli((U8 FAR *) globalStr)) !=GOOD)
            break; // out of switch
         if (displayType == DEBUG_DISPLAY) {
            if((err = AdrGetEndAddrOffset(tmpVarAddrDesc, &endAddr)) != GOOD) 
               break; // out of switch
            sprintf((LPSTR) globalStr, "    End Address:  %8lX", endAddr);
            err = SendMessageToCli((U8 FAR *) globalStr);
         }
      break;

      case SYM_LOCAL_VAR:
      case SYM_GLOBAL_VAR:
      case SYM_PUBLIC_VAR:
         varPtr = (SYM_TYPE_VARIABLE *)symPtr;
         switch (varPtr->storageClass) {
            case STATIC_VAR_CLASS:
            case UNKNOWN_VAR_CLASS:
            case GLOBAL_VAR_CLASS:
               if((err = UtilSetAddrParams(
                  varPtr->symHeader.typeIndex.baseIndex,
                  varPtr->symHeader.beginAddrInfo.startAddr, 
                  varPtr->symHeader.endAddrInfo.endAddr, tmpVarAddrDesc)) 
                     != GOOD) goto cleanup;
               if ((err = AdrGetAddrOffset(tmpVarAddrDesc, &startAddr)) 
                  != GOOD) goto cleanup;
               if ((err = AdrGetEndAddrOffset(tmpVarAddrDesc, &endAddr))
                  != GOOD) goto cleanup;
            break;

            case AUTO_VAR_CLASS:
               startAddr = varPtr->symHeader.beginAddrInfo.autoVarOffset;
            break;

            default:
               startAddr = 0xFFFFFFFFL;
               endAddr   = 0L;
         }  /* end of switch */
         sprintf((LPSTR) globalStr,"    Address:  %8lX", startAddr);
         if ((err = SendMessageToCli((U8 FAR *) globalStr)) !=GOOD)
            break;
         if (displayType == DEBUG_DISPLAY) {
            if (varPtr->storageClass == AUTO_VAR_CLASS)  {
               sprintf((LPSTR)globalStr, "    Size: %8d ", 
                  varPtr->symHeader.endAddrInfo.varSize);
            } else {
               sprintf((LPSTR)globalStr,"    End Address: %8lX  ", endAddr);
            }
            err = SendMessageToCli((U8 FAR *)globalStr);
         }
      break;
   } /* end of switch */
cleanup:
   err1 = AdrDestroyAddress(tmpVarAddrDesc);
   return((err != GOOD ? err : err1));
}

//--------------------------------------------------------------------------
// SymPrintBases
//--------------------------------------------------------------------------
RETCODE SymPrintBases(SYM_DISPLAY_TYPE displayType) {

   RETCODE err;
   BaseSymbol HUGE *base;
   ByAddressTable HUGE *byAddrTablePtr;
   U8 name[MAX_SYMNAME_LENGTH];
   TABLE_OFFSET baseOffset, byAddrBaseOffset;
   
   // get the offset of the first base ;
   if((baseOffset = bit.GetRootBaseSymbolOffset()) == NULL_SYMBOL)
      return ER_INDEX_NOT_IN_TABLE;

   do {    
      // get a pointer to the base ;
      base = (BaseSymbol HUGE *)st.GetHugeDataPtr(baseOffset);

      // print out the BASES info ;
      st.GetString(base->GetBaseNameOffset(), (LPU8)name);
      strcpy(globalStr,"-----------------------------------------------------------------");
      if ((err = SendMessageToCli((U8 FAR *)globalStr)) != GOOD)
         return(err);

      // print base name
      sprintf((LPSTR)globalStr, "Name:  %s", (LPSTR)name);
      if ((err = SendMessageToCli((U8 FAR *)globalStr)) != GOOD)
         return(err);

      // print base address and the next base offset
      sprintf((LPSTR)globalStr,"Base Address:  %8lX", base->GetBaseAddress());
      if ((err = SendMessageToCli((U8 FAR *)globalStr)) != GOOD)
         return(err);

      if (displayType == DEBUG_DISPLAY) {
         // print address min and max ;
         sprintf((LPSTR)globalStr,"Address Min: %8lX   Address Max: %8lX",
            base->GetAddressMin(), base->GetAddressMax());
         if((err = SendMessageToCli((U8 FAR *)globalStr))
            != GOOD) return(err);

         // print by-address table offset and number of entries ;
         byAddrBaseOffset = base->GetByAddressTableOffset();
         byAddrTablePtr = 
            (ByAddressTable HUGE *)st.GetHugeDataPtr(byAddrBaseOffset);
         sprintf((LPSTR)globalStr,
                  "Address Count:  %8lX   Address Table:  %8lX",
                  byAddrTablePtr->GetSymbolCount(), byAddrBaseOffset);
         if ((err = SendMessageToCli((U8 FAR *)globalStr)) != GOOD)
            return(err);
         sprintf((LPSTR)globalStr,"Next Base Offset:  %8lX", 
            base->GetNextBaseOffset());
         if ((err = SendMessageToCli((U8 FAR *)globalStr)) != GOOD) return(err);
      }

      // print the base type and table dirty status
      strcpy(globalStr, "Base Type:  ");
      switch (base->GetBaseType()) {
         case BASE_UNKNOWN:   strcat(globalStr, "UNKNOWN BASE"); break;
         case BASE_CODE:      strcat(globalStr, "CODE BASE");  break;
         case BASE_DATA:      strcat(globalStr, "DATA BASE");  break;
         case BASE_CODE_DATA: strcat(globalStr, "CODE_DATA BASE");  break;
         default:             strcat(globalStr, "ERROR");
      }

      if(displayType == DEBUG_DISPLAY) {
         strcpy(globalStr, "Table Dirty:  ");
         if (base->GetAddrTableDirty()) strcat(globalStr, "TRUE\n\0");
         else strcat(globalStr, "FALSE\n\0");
         if((err = SendMessageToCli((U8 FAR *)globalStr)) != GOOD) return(err);
      }

      // go to next base object
      baseOffset=base->GetNextBaseOffset();
   } while(baseOffset);
   return(GOOD);
}


//--------------------------------------------------------------------------
// SymPrintSymbol
//--------------------------------------------------------------------------
RETCODE EXPORT
SymPrintSymbol(TABLE_OFFSET symbol, 
               SYM_DISPLAY_TYPE displayType,
               U16 indentLevel) {

   RETCODE err;
   HPU8    symPtr;
   BOOLEAN abortFromEsc;

   if ((displayType != DEBUG_DISPLAY) &&
       (displayType != VARLIFE_DISPLAY)) {
      if (GOOD != (err = GetSymbolPrintLine(symbol, displayType, indentLevel)))
         return err;
      if((err = SendMessageToCli((U8 FAR *)globalStr)) != GOOD)
         return(err);

      // abort key was or is pressed
      err = TskCheckAbort(&abortFromEsc);
      if ((err != GOOD) || abortFromEsc) {
         return ER_ABORT_FROM_ESC;
      }
      return GOOD;
   }

   // fall thru and display the debug lines
   // get a ptr to that symbol and print out the common info ;
   symPtr=st.GetHugeDataPtr(symbol);

   // Display Register variable information
   if (displayType == VARLIFE_DISPLAY) { 
      if (GOOD != (err = GetSymbolPrintLine(symbol, displayType, indentLevel)))
         return err;
      if((err = SendMessageToCli((U8 FAR *)globalStr)) != GOOD)
         return(err);
       switch(((COMMON_SYMBOL_HEADER *)symPtr)->typeIndex.symType & 0xF) {
          case SYM_LOCAL_VAR:
          case SYM_GLOBAL_VAR:
          case SYM_PUBLIC_VAR:
             return(PrintVariable(symbol, symPtr, displayType));
       }
       return(GOOD);
   } 
         
   // find out what type the symbol is and then print the specific info ;
   switch (((COMMON_SYMBOL_HEADER *)symPtr)->typeIndex.symType & 0xF) {
      case SYM_ROOT:
      case SYM_MODULE:
         if ((err = PrintCommonHeader(symPtr, displayType)) != GOOD) break;
         err = PrintModule(symPtr, displayType);
         break;
      case SYM_FUNCTION:
         if ((err = PrintCommonHeader(symPtr, displayType)) != GOOD) break;
         err = PrintFunction(symPtr, displayType);
         break;
      case SYM_BLOCK:
         if ((err = PrintCommonHeader(symPtr, displayType)) != GOOD) break;
         err = PrintBlock(symPtr, displayType);
         break;
      case SYM_LABEL:
      case SYM_PUBLIC_LABEL:
      case SYM_PUBLIC_UNKNOWN:
         err = PrintCommonHeader(symPtr, displayType);
         break;
      case SYM_LOCAL_VAR:
      case SYM_GLOBAL_VAR:
      case SYM_PUBLIC_VAR:
         err = PrintCommonHeader(symPtr, displayType);
         err = PrintVariable(symbol, symPtr, displayType);
         break;
      default:
         err = ER_SYMBOL_NOT_FOUND;
   }

   // abort key was or is pressed
   err = TskCheckAbort(&abortFromEsc);
   if ((err != GOOD) || (abortFromEsc))
      return ER_ABORT_FROM_ESC;

   return(err);
}

//--------------------------------------------------------------------------
// SymPrintSymbols
//--------------------------------------------------------------------------
RETCODE EXPORT
SymPrintSymbols(SYM_DISPLAY_TYPE displayType) {

   RETCODE err;
   U32 i,maxEntries;
   TABLE_OFFSET varOffset;
   COMMON_SYMBOL_HEADER HUGE *symPtr;

   // get a pointer to the root symbol ;
   rootPtr = (COMMON_SYMBOL_HEADER HUGE *)st.GetHugeDataPtr(rootOffset);
   
   maxEntries=ot.GetOrdinalCount();
   for(i=0;i<maxEntries;i++) {
      // get the offset into the symbol table of the nth symbol ;
      if((err=ot.GetOffset(i,varOffset))!=GOOD) return(err);

      // print the symbol when DEBUGGING or when it has a valid name. ;
      symPtr = (COMMON_SYMBOL_HEADER HUGE *)st.GetHugeDataPtr(varOffset);
      if ( ((symPtr->symbolNameOffset) && 
         (symPtr->symbolNameOffset != rootPtr->symbolNameOffset)) || 
         (displayType == DEBUG_DISPLAY)) {
         // print the symbol ;
         strcpy(globalStr,"-----------------------------------"
                     "-----------------------------------");
         if ((err = SendMessageToCli((U8 FAR *)globalStr)) != GOOD)
            return(err);
         err = SymPrintSymbol(varOffset, displayType, 0);
         if ((err != GOOD) && (err != ER_SYMBOL_NOT_FOUND))
            return(err);
         // this routine can take a LONG TIME.  So yield to other ;
         // applications every time through the loop. ;
         Yield();
      }
   }
   return(GOOD);
}

//--------------------------------------------------------------------------
// SymPrintLines - prints all linenums for input module;
//--------------------------------------------------------------------------
RETCODE SymPrintLines(SYM_DESCRIPTOR moduleDesc) {

   RETCODE            err, err1;
   LINENUM_DESCRIPTOR linenumIndex, nextLinenumIndex;
   DESCRIPTOR         linenumAddr;
   LINENUM_TYPE       linenum;
   COLUMN_TYPE        column;
   U16                linenumCount;
   BOOLEAN            abortFromEsc;
   S8                 addrBuf[ADDR_BUFF_SZ];

   // get starting index to walk linenum table
   err = lt.GetLinenumFirstIndex(moduleDesc, &linenumIndex);
   if (err) {
      if (ER_NO_LINENUMS_ADDED == err) {
         globalStr[0] = '\0';
         strcat(globalStr, "   No line numbers loaded");
         if ((err = SendMessageToCli((U8 FAR *)globalStr)) != GOOD)
            return(err);
         return GOOD;  // let caller continue with other modules
      } else {
         return err;
      }
   }
   linenumCount = 1;
   // Create a temp address descriptor
   if ((err = AdrCreateAddress(&linenumAddr)) != GOOD)
      return err;

   do {
      if ((err = lt.GetRawLinenumByIndex(moduleDesc, linenumIndex,
            linenumAddr, &linenum, &column, &nextLinenumIndex)) != GOOD) {
         if (err == ER_LINENUM_INDEX_TOO_LARGE)
            err = GOOD; // No error report.
         break; // out of do_while
      }
      //------------------
      // display linenum
      //------------------
      // convert address to string
      if ((err = AdrConvAddressToTextWithParams(linenumAddr,
                     TRUE, FALSE, (LPSTR)&addrBuf[0])) != GOOD)
         break; // out of do_while
      sprintf(globalStr, "%5u: Line#%-5u Col#%-3hu  %s",
               linenumCount, linenum, column, (LPSTR)&addrBuf[0]);
      if ((err = SendMessageToCli((U8 FAR *)globalStr)) != GOOD)
         break; // out of do_while

      // set up for next iteration
      linenumIndex = nextLinenumIndex;
      linenumCount++;

  // abort key was or is pressed
      err = TskCheckAbort(&abortFromEsc);
      if(err!=GOOD) break;
      if (abortFromEsc!=0) {
         err = ER_ABORT_FROM_ESC;
         break; // out of do_while
      }

   } while (TRUE);
   // Destroy descriptor
   err1 = AdrDestroyAddress(linenumAddr);
   return((err != GOOD ? err : err1));
}  // end of SymPrintLines

      
//--------------------------------------------------------------------------
// PrintVariable
//--------------------------------------------------------------------------
RETCODE PRIVATE PrintVariable(TABLE_OFFSET inputSymbol,
                              HPU8 symPtr, SYM_DISPLAY_TYPE displayType) {
   
   RETCODE err;
   SYM_TYPE_VARIABLE *varPtr;

   // print the information specific to variables ;
   varPtr=(SYM_TYPE_VARIABLE *)symPtr;

   if (displayType == DEBUG_DISPLAY ) {
      sprintf((LPSTR)globalStr,"Variable Type:  %8lX    isConstant: %1d"
         "    isValidAddr: %1d", varPtr->typeIndex,varPtr->isConstant,
         varPtr->typeIndex,varPtr->isValidAddr);
      if ((err = SendMessageToCli((U8 FAR *)globalStr)) != GOOD) 
         return(err);

      sprintf((LPSTR)globalStr,"Storage Class:  %8X  Register Class:  %8X",
         varPtr->storageClass,varPtr->registerClass);
      if ((err = SendMessageToCli((U8 FAR *)globalStr)) != GOOD) 
         return(err);
   }

   if ((displayType == VARLIFE_DISPLAY) &&
          ((varPtr->registerClass) != NOT_REG)) {
      // Define some locals
      TABLE_OFFSET lifetimeOffset, currentOffset;
      SYM_LIFETIME_START_INFO HUGE *lifetimeStartPtr;
      SYM_LIFETIME_INFO HUGE    *lifetimePtr;

      switch (varPtr->registerClass) {
         case LOCKED_REG:
            /* Locked registers are living until first DEATH record
            ** occurs telling of the DEATH of the register.
            */
            lifetimeOffset = inputSymbol +
                          sizeof(SYM_TYPE_VARIABLE) + 
                          sizeof(AUTO_VAR_OFFSET);
            sprintf((LPSTR)globalStr,"    Locked Register");
            if ((err = SendMessageToCli((U8 FAR *)globalStr)) != GOOD)
               return(err);
            break;

         case LIVING_REG:
            /* ATN2 - living registers are LIVE until BIRTH record occurs
            ** indicating where register starts DEAD/ALIVE.
            */
            lifetimeOffset = inputSymbol + sizeof(SYM_TYPE_VARIABLE);
            sprintf((LPSTR)globalStr,"    Living Register");
            if ((err = SendMessageToCli((U8 FAR *)globalStr)) != GOOD)
               return(err);
            break;
         case SHADOW_REG:
         default:
            return(ER_REGISTER_CLASS_UNKNOWN);
      }
      
      // Get pointer to first lifetime data.  If value is NULL_SYMBOL, there
      // is no lifetime data; return LIVE.
      lifetimeStartPtr = (SYM_LIFETIME_START_INFO HUGE *)
                                     st.GetHugeDataPtr(lifetimeOffset);
      if ((currentOffset = lifetimeStartPtr->firstEntry) == NULL) {
         sprintf((LPSTR)globalStr,"    No lifetime Info existed.");
         return(SendMessageToCli((U8 FAR *)globalStr));
      }
      // The while loop compares print out the life information
      // addresses in the lifetime linked list and the variable living
      // state.
      while (currentOffset != NULL_SYMBOL) {
         lifetimePtr = (SYM_LIFETIME_INFO HUGE *)
                                   st.GetHugeDataPtr(currentOffset);
         if ((lifetimePtr->lifetimeInfo.lifetimeClass) == LIVE)
            sprintf((LPSTR)globalStr,"    Local Offset: 0x%lX - LIVE",
                    lifetimePtr->lifetimeInfo.lifetimeAddr);
         else
            sprintf((LPSTR)globalStr,"    Local Offset: 0x%lX - DEAD",
                    lifetimePtr->lifetimeInfo.lifetimeAddr);
         if ((err = SendMessageToCli((U8 FAR *)globalStr)) != GOOD)
            return(err);
         // Next lifetimeInfo - follow linked list
         currentOffset = lifetimePtr->nextLifetimeInfo;  
      }
   }
   return(GOOD);
}


/******************************** E O F ***********************************/
