/****************************************************************************
**
**  Name:  symcli.cpp
**
**  Description:
**     This module parses the info coming from the cli server and then 
**     dispatches the appropriate modules.
**
**  Status:  TESTED
**
**  $Log:   S:/tbird/mt2_186/symbol/symcli.cpv  $
** 
**    Rev 1.3   04 Jun 1998 14:19:56   hera
** 
**    Rev 1.2   22 Jul 1997 10:10:44   Judy
** 
**    Rev 1.1   26 Feb 1997 11:43:20   Judy
** 
**    Rev 1.1   14 Jan 1997 15:31:28   Judy
** No change.
** 
**    Rev 1.0   14 Jun 1996 16:42:14   Judy
** Initial revision.
** 
**    Rev 1.43   16 May 1995 10:06:30   nghia
** Revised 'DisplayTypes' to out put member types of composite structure.
** 
**    Rev 1.42   09 May 1995 10:29:42   nghia
** Added symbol pointers validation.  Return error if pointer is NULL.
** 
**    Rev 1.41   20 Jan 1995 09:56:18   nghia
** Fixed PPR 10012 for PV 2.4
** Revised ConfigSymbol command to convert the input base address text using
** the address server interface.  Generated event EVENT_SYMBOL_BASE_CHANGED
** to notify the interested parties.
** 
**    Rev 1.40   12 Jan 1995 17:29:26   nghia
** Fixed PPR 9763 - Intel virtual address range used the new format.
**    [ldt]:<seg>:<startoffset>..<endoffset>
** 
**    Rev 1.39   03 Jan 1995 13:20:06   nghia
** Updated for PV 2.4 - Cleanup string table. 
** 
**    Rev 1.38   04 Nov 1994 10:08:46   nghia
** Fixed bug for PV 2.4 - Added check for x86 processor for getBase().
** 
**    Rev 1.37   11 Oct 1994 18:08:56   nghia
** Added ConfigSymbols Shell command.
** 
**    Rev 1.36   10 Oct 1994 17:34:06   nghia
** Revised PrintBase() to print Protected mode bases with header and column
** align.
** 
**    Rev 1.35   26 Sep 1994 10:22:50   nghia
** Revised PrintBase() to use the correct base address parts.
** 
**    Rev 1.34   06 Sep 1994 16:06:58   nghia
** Fixed _displayTypes to convert type index for radix (base 10, 16).
** 
**    Rev 1.33   17 Aug 1994 13:25:10   nghia
** Extend _displaytypes to support display the type information of an input
** type index.
** 
**    Rev 1.32   03 Aug 1994 11:49:02   brucea
** Added: DisplaySortedSymbols
** 
**    Rev 1.31   28 Jul 1994 13:09:38   brucea
** Made displaysymbol commands so user can enter partial parameter
** SetBase function input parameter is now always hex whether 0x or not.
** Made symbolclosefile print previously opened filename
** 
**    Rev 1.30   25 Jul 1994 12:44:42   brucea
** Modified DisplayTypes to support 16_16 and 16_32
** 
**    Rev 1.29   14 Jul 1994 01:51:52   brucea
** Added: ability to capture symbol display information into a file
**        rather than go to Shell.
** Modified: PrintBase to output base information in real and protected modes
** 
**    Rev 1.28   20 Jun 1994 10:50:32   nghia
** Added CreateLabelRanges routine.
** 
**    Rev 1.27   20 Jun 1994 09:38:02   marilyn
** Updated address server interfaces.
** 
**    Rev 1.26   25 Feb 1994 12:46:44   nghia
** Added output count for each symbol types in _count shell command.
** 
**    Rev 1.25   30 Sep 1993 15:04:40   nghia
** Revised _displayTypes to include "built-in|user" options.
** Added displaysymbols _varlife to dump out all symbol + var lifetime info.
** 
**    Rev 1.24   24 Sep 1993 10:36:00   nghia
** Added SymCheckForNoSymbols() to all symbol shell command to report the error
** appropriately.  In the past it reported "Index invalid....@#$!".
** Added DisplayTypes() to dump out the type table for debug and testing purpose
** 
**    Rev 1.23   05 Jul 1993 08:20:56   doug
** Use general syntax error.
** 
**    Rev 1.22   25 Jun 1993 17:54:00   paul
** make abortFromEsc a BOOLEAN.
** 
**    Rev 1.21   25 Jun 1993 17:34:44   paul
** Change CHECK_ABORT to TskCheckAbort
** 
**    Rev 1.20   23 Mar 1993 17:10:38   courtney
** Symbol pointers are huge in declaration and cast.
** 
**    Rev 1.19   08 Dec 1992 06:56:58   brucea
** Changed (!funcDesc) type tests to (NULL_SYMBOL != ...)
** 
**    Rev 1.18   03 Dec 1992 07:35:12   brucea
** Added: DisplayModule to provide means of displaying symbols for a single
**    module
** 
**    Rev 1.17   15 Oct 1992 18:41:22   brucea
** Added: pc to command parameter of nameof
** 
**    Rev 1.16   15 Sep 1992 11:43:44   brucea
** Changed: AdrConvAddressToTextNoFill to ..WithParams
** 
**    Rev 1.15   14 Sep 1992 17:49:34   brucea
** Only generate EVENT_SYMBOL_DELETED when the command is given from the CLI,
**    not when a reload is done via loader.
** Changed: AdrConvAddressToText call to ...WithParams
** 
**    Rev 1.14   08 Sep 1992 13:05:46   brucea
** Added: events.h include
** 
**    Rev 1.13   29 Aug 1992 22:09:38   brucea
** Addressof: call to SymGetAddrFromName now does not destroy addr desc when
**    error returned
** 
**    Rev 1.12   20 Aug 1992 20:29:46   brucea
** Removed: create address prior to call to SymGetAddrFromName since it is 
**    alloc'ed in this function
** 
**    Rev 1.11   13 Aug 1992 19:26:18   brucea
** Comment change
** 
**    Rev 1.10   13 Aug 1992 11:20:54   brucea
** Removed compiler warnings
** Changed: wsprintf to sprintf
** 
**    Rev 1.9   08 Aug 1992 10:50:18   tom
** New CLI registration changes.
** 
**    Rev 1.8   25 Jul 1992 16:45:26   brucea
** Moved: InitCServer, SendMessageToCli into this module; removed second
**    parameter from SendMessageToCli
** Added: (U16) casts to all argv parameters
** 
** 
**    Rev 1.7   19 Jul 1992 21:15:16   brucea
** Added to count output for alloc'ed size of each table
** Implemented: NameOf
** 
** 
**    Rev 1.6   10 Jul 1992 18:54:14   brucea
** Removed: SymLoad
** Added: Count, NameOf, and AddressOf, 
** 
**    Rev 1.5   24 Jun 1992 18:05:34   brucea
** Removed: #include "load.h"
** Changed: SymLoad to #if 0 out the load command.  At a future time, this
**    code should be removed entirely.
** 
**    Rev 1.4   15 Jun 1992 09:29:30   brucea
** Fixed up: compiler warnings about no returns
** 
**    Rev 1.3   30 Apr 1992 17:42:20   brucea
** Changed: made internal functions PRIVATE
** Fixed: DisplayFunctions, DisplayModules to handle nested blocks
** Cleaned up: PrintBase code
** 
**    Rev 1.2   20 Apr 1992 08:43:14   brucea
** Added: DisplayLines
** Changed: internal CLI commands use _ in front of command name
** 
**    Rev 1.1   01 Apr 1992 23:37:36   brucea
** Fixed: compiler warnings
** 
**    Rev 1.0   04 Mar 1992 13:23:20   brucea
** Initial revision.
** 
**    Rev 1.16   27 Feb 1992 22:50:00   brucea
** Removed: definition of CheckAbort [moved to BASETYP.H]
** Renamed: CheckAbort() to CHECK_ABORT()
** 
**    Rev 1.15   14 Feb 1992 15:03:12   brucea
** Added CheckAbort() macro and a call to it to initialize the aborting of the
**    symbol display with the ESC key
** Changed strtol to strtoul (for unsigned addresses) and check for invalid
**    parsing of the address string
** 
**    Rev 1.14   04 Feb 1992 16:25:18   brucea
** Added #pragma argsused to RemoveSymbols function
** 
**    Rev 1.13   22 Jan 1992 14:56:40   brucea
** Changed display code so that module mode does not display variables.
** In GetBase, now only check for (argc > 2)
** Added parameter count check in RemoveSymbols
** Changed param count check from 4 to 3 in SetBase
** Changed last param in strtol call to 0 from 16 to allow octal, decimal, or
**   hex input as valid.
** 
**    Rev 1.12   10 Jan 1992 19:23:36   brucea
** Added event notification when modifying a base address
** Fixed bug to indent module variables when they are printed
** 
**    Rev 1.11   08 Jan 1992 11:30:36   john
** Created new commands:  GetBase and SetBase.
** 
**    Rev 1.10   06 Jan 1992 16:05:36   john
** Added code to walk the symbol table to print out all symbols
** according to their precedence.
** 
**    Rev 1.9   20 Dec 1991 16:51:32   john
** Changed code for display of symbols.  Not complete
** 
**    Rev 1.8   11 Dec 1991 16:31:44   john
** Started adding new commands.  These are incomplete.
** 
**    Rev 1.7   10 Dec 1991 11:55:46   john
** Added header to get prototype for symremovesymbols
** 
**    Rev 1.6   09 Dec 1991 14:44:46   john
** Added code to remove symbols.
** Added code to print all symbols in a user/debug format.
** Renamed SymPrintSymbols to PrintSymbols to make the CLI interface
** better.
** 
**    Rev 1.5   06 Nov 1991 13:30:12   john
** Removed compile time warnings w/max warning level enabled
** 
**    Rev 1.4   11 Oct 1991 15:39:58   john
** Modified if statements to return err as the primary action.
** 
**    Rev 1.3   03 Oct 1991 11:45:56   john
** Made changes to allow much longer path names, and fixed the code
** that tried to make all the cli parsed text lower case.
** 
**    Rev 1.2   27 Sep 1991 17:56:54   brucea
** Added #include "load.h"
** 
**    Rev 1.1   27 Sep 1991 17:45:12   john
** Added call to ascii file loader.
** 
**    Rev 1.0   25 Sep 1991 13:35:12   john
** Initial revision.
**
**  $Header:   S:/tbird/mt2_186/symbol/symcli.cpv   1.3   04 Jun 1998 14:19:56   hera  $
**
**  Copyright (C) 1991 Microtek International.  All rights reserved.
**
*****************************************************************************/

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

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

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

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

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

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

#ifndef _CLISRV_
#include "clisrv.h"
#endif

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

#ifndef __CTYPE_H
#include <ctype.h>
#endif

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

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

#ifndef _HASHTBL_
#include "hashtbl.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 __STDLIB_H
#include <stdlib.h>
#endif

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

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

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

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

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

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

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

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

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

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

extern TABLE_OFFSET rootOffset;

extern BaseIndexTable bit;
extern MemPool st;
extern OrdinalTable ot;
extern HashTable ht;
extern TypeTable tt;
extern LinenumTable lt;
extern IndexTable typit;
extern PROCESSOR_FAMILY globalProcFamily;

//----------------------------------------------------------------------------
// Report each symbol type
extern U32 symbolStat[]; // defined in SYMADD.CPP
extern const U8 *symTypeName[];  // defined in SYMCLIPR.CPP
extern U8 symTypeMap[];
extern BOOLEAN createLabelRanges;  // defined in SYMADD.CPP
extern BOOLEAN with0X;  // indicates how to display addresses

                       /****************************
                        *                          *
                        *     LOCAL VARIABLES      *
                        *                          *
                        ****************************/
PRIVATE HANDLE  cliServerHandle;
PRIVATE BOOLEAN sendToFile = FALSE;  // steer output to file or Shell
PRIVATE S16     hFile;  // handle to open file for putting symbol text into
PRIVATE LPSTR   fileNamePtr;  //pointer to open filename

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

RETCODE PRIVATE DisplayModules(SYM_DISPLAY_TYPE displayType);
RETCODE PRIVATE DisplayFunctions(SYM_DESCRIPTOR moduleDescriptor, 
                         SYM_DISPLAY_TYPE displayType, U16 indentLevel);
RETCODE PRIVATE DisplayVariables(SYM_DESCRIPTOR symbolDescriptor, 
                         SYM_DISPLAY_TYPE displayType, U16 indentLevel);
RETCODE PRIVATE PrintBase(TABLE_OFFSET baseOffset, BOOLEAN *printHeader);

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

#define NESTING_LEVEL  1

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


//--------------------------------------------------------------------------
// InitCServer
//
// Description:
//
// Input Parameters:
//
// Output Parameters:
//
// Errors:
//
//--------------------------------------------------------------------------
RETCODE EXPORT InitCServer(HANDLE cliHandle, HANDLE dllHandle) {

   CSERVER_NEW_REGISTRATION FAR * msgBufPtr;

   cliServerHandle = cliHandle;
   msgBufPtr =
      (CSERVER_NEW_REGISTRATION FAR *)TMalloc(sizeof(CSERVER_VARIABLE_VALUE));
   if (msgBufPtr == NULL) {
      return(ER_OUT_OF_MEMORY);
   }

   msgBufPtr->stringResourceHandle = dllHandle;
   msgBufPtr->serverNameIndex = 0;
   msgBufPtr->dllNameIndex = 1;
   msgBufPtr->numberOfCommandsIndex = 2;
   msgBufPtr->commandStartIndex = 3;
   SendMessage(cliHandle, CLI_NEW_SVR_REGISTRATION, CLI_NEW_SVR_REGISTRATION,
      (DWORD)msgBufPtr);
   return GOOD;
}  // end of InitCServer


//--------------------------------------------------------------------------
// SendMessageToCli
//--------------------------------------------------------------------------
RETCODE SendMessageToCli(U8 FAR *msgPtr) {

   HANDLE msgBufHandle;
   LPSTR cpPtr;
   U16 i;
   U16 size;

   size = strlen((CHAR *)msgPtr);
   if (sendToFile) {
      // send message string to file output
      if (!size)      // no message
         return GOOD;
      // insert CR/LF
      msgPtr[size++] = '\r';
      msgPtr[size++] = '\n';
      if (0 == (_lwrite(hFile, (LPSTR)msgPtr, size)))  // returns size written
          return ER_CANNOT_WRITE_TO_FILE;
      return GOOD;  // used so the regular code below doesn't have to be
                    // indented
   }
   // allocate enough memory for the string passed in and the size
   // of the CSERVER_RESULTS packet, and then subtract out the extra ;
   // space allocated to the messageText field. ;
   if ((msgBufHandle =
      GlobalAlloc(GMEM_MOVEABLE,
                  (size + sizeof(CSERVER_RESULTS) + 2))) == (HANDLE)NULL) {
      return(ER_OUT_OF_MEMORY);
   } else if ((cpPtr = GlobalLock(msgBufHandle)) == NULL) {
      GlobalFree(msgBufHandle);
      return(ER_WINDOWS_MEMLOCK);
   }

   ((CSERVER_RESULTS *)cpPtr)->target = 0;  // address to the cli server;
   ((CSERVER_RESULTS *)cpPtr)->variantCode = CLI_SERVER_RESULTS;
   ((CSERVER_RESULTS *)cpPtr)->resultTextLength = size; // size of message;
   // add sizeof CSERVER_RESULTS header to cpPtr and then fill in the ;
   // message to be sent to the cli server ;
   cpPtr = ((CSERVER_RESULTS *)cpPtr)->messageText;
   /* copy the data from msgPtr to the global memory space */
   for(i = 0; i < size; i++) {
      *cpPtr++ = *msgPtr++;
   }
   /*TRUE on success*/
   if (!(SendMessage(cliServerHandle, CLI_SERVER_RESULTS, msgBufHandle,
                     (CLI_SERVER_RESULTS | 0x0L)))) {
      ErrDisplayError(ER_SYM_SEND_MESSAGE, FORCE_POPUP);
   }
   return GOOD;
}  // end of SendMessageToCli


//--------------------------------------------------------------------------
// DisplayFunctions
//
// Parameters:
//    symbolDescriptor: desc to function to be displayed
//    displayType: indicates what level of printing is to be done
//    indentLevel: what level of indent nesting for this call
//--------------------------------------------------------------------------
RETCODE PRIVATE DisplayFunctions(SYM_DESCRIPTOR   funcDesc,
                                 SYM_DISPLAY_TYPE displayType,
                                 U16              indentLevel) {
   RETCODE        err;
   SYM_DESCRIPTOR newFuncDesc;
   SYM_TYPE_TYPE  symType;
   
   if (NULL_SYMBOL != funcDesc) {
      if ((err = SymPrintSymbol(funcDesc,
                                displayType, 
                                indentLevel)) != GOOD)
         return err;
      if ((err = DisplayVariables(funcDesc,
                                  displayType, 
                                  indentLevel + NESTING_LEVEL)) != GOOD)
         return err;
      
      // recurse down child pointer
      if ((err = SymGetSymbolChild(funcDesc, &symType, &newFuncDesc))
         != GOOD)
         return err;

      if((err = DisplayFunctions(newFuncDesc, displayType, 
                                 indentLevel + NESTING_LEVEL)) != GOOD)
         return err;

      // recurse down sibling pointer
      if ((err = SymGetSymbolSibling(funcDesc, &symType,
                                     &newFuncDesc)) != GOOD)
         return err;
      if((err = DisplayFunctions(newFuncDesc, displayType, 
                                 indentLevel)) != GOOD)
         return err;
   }
   return GOOD;
}

   
//--------------------------------------------------------------------------
// DisplayModules
//
// Description: Sends module information to the CLI for the user.
//
// Input Parameters:
//    moduleDesc: descriptor of module to display
//    displayType: indicates how much to display
//--------------------------------------------------------------------------
RETCODE PRIVATE
DisplayModule(SYM_DESCRIPTOR   moduleDesc,
              SYM_DISPLAY_TYPE displayType) {

   RETCODE        err;
   SYM_DESCRIPTOR funcDesc;
   SYM_TYPE_TYPE  symType;
   BOOLEAN abortFromEsc = FALSE;
   

   // print out the module info;
   if (GOOD != (err = SymPrintSymbol(moduleDesc, displayType, 0)))
         return err;

   if (displayType != MODULE_DISPLAY) {
      // display all module global vars
      if (GOOD != (err = DisplayVariables(moduleDesc,
                                          displayType,
                                          NESTING_LEVEL)))
         return err;
   }
   // escape when key pressed
   if ((TskCheckAbort(&abortFromEsc) != GOOD) || abortFromEsc) 
      return ER_ABORT_FROM_ESC;     

   // loop through the functions
   if ((err = SymGetSymbolChild(moduleDesc, &symType,
                                &funcDesc)) != GOOD)
      return err;
   if ((NULL_SYMBOL != funcDesc) && (displayType != MODULE_DISPLAY)) {
      if((err = DisplayFunctions(funcDesc,
                                 displayType,
                                 NESTING_LEVEL)) != GOOD)
      return err;
   }
   return GOOD;
}  // end of DisplayModule


//--------------------------------------------------------------------------
// DisplayModules
//
// Description: Sends module symbol information to the CLI for the user.
//
// Input Parameters:
//    displayType: how much of symbol hierarchy to display
//--------------------------------------------------------------------------
RETCODE PRIVATE DisplayModules(SYM_DISPLAY_TYPE displayType) {

   RETCODE        err;
   SYM_DESCRIPTOR moduleDesc;
   SYM_TYPE_TYPE  symType;
   
   // display all module names ;
   if ((err = SymGetModuleListHead(&moduleDesc)) != GOOD) 
      return err;
   
   while (moduleDesc) {
      if (GOOD != (err = DisplayModule(moduleDesc, displayType)))
         return err;
      
      if ((err = SymGetSymbolSibling(moduleDesc, &symType,
         &moduleDesc)) != GOOD)
         return err;
   }
   return GOOD;
}  // end of DisplayModules


//--------------------------------------------------------------------------
// DisplayVariables
//--------------------------------------------------------------------------
RETCODE PRIVATE
DisplayVariables(SYM_DESCRIPTOR   symbolDescriptor, 
                 SYM_DISPLAY_TYPE displayType,
                 U16              indentLevel) {

   RETCODE        err;
   SYM_DESCRIPTOR currentVarDesc;
   SYM_TYPE_TYPE  symType;
   U16            listCount, i;
   
   // make sure we are supposed to display variables. ;
   if (displayType == FUNCTION_DISPLAY)
      return GOOD;
   
   for (i=0; i<4; i++) {
      
      // cycle through all of the possible lists. ;
      switch (i) {
         case 0: 
            symType = SYM_LOCAL_VAR;
            break;
         case 1:
            symType = SYM_LABEL;
            break;
         case 2:
            symType = SYM_CONSTANT;
            break;
         case 3:
            symType = SYM_MISCELLANEOUS;
            break;
      }
      if ((err = SymGetSymbolHeadList(symbolDescriptor, symType,
                                      &currentVarDesc, &listCount)) != GOOD) 
         return err;
      
      // print out all elements of the list. ;
      while (listCount--) {
         if ((err = SymPrintSymbol(currentVarDesc, displayType, indentLevel))
            != GOOD)
            return err;
         if ((err = SymGetSymbolSibling(currentVarDesc, &symType, 
                                       &currentVarDesc)) != GOOD)
            return err;
      }
   }
   return GOOD;
}  // DisplayVariables

   
//--------------------------------------------------------------------------
// DisplayLines
//--------------------------------------------------------------------------
RETCODE PRIVATE DisplayLines(SYM_DISPLAY_TYPE displayType) {

   RETCODE        err;
   SYM_DESCRIPTOR moduleDesc, tmpDesc;
   SYM_TYPE_TYPE  symType;
   U16            indentLevel = 0;

   // get start of module linked list
   if ((err = SymGetModuleListHead(&moduleDesc)) != GOOD) 
      return err;
   
   do {
      // print out the module info;
      if((err = SymPrintSymbol(moduleDesc, displayType, indentLevel)) 
         != GOOD) return err;

      // display all linenums if they have been loaded; check first
      if (GOOD != (err = SymPrintLines(moduleDesc)))
         return err;

      // get next module
      if ((err = SymGetSymbolSibling(moduleDesc, &symType,
         &tmpDesc)) != GOOD) return err;
      moduleDesc = tmpDesc;
   } while(moduleDesc);

   return GOOD;
}  // end of DisplayLines


//--------------------------------------------------------------------------
// DisplaySortedSymbols
//
// Algorithm:
//    loop from basetbl root to end of linked list
//       loop from beginning of byaddrtable to end
//          SymPrintSymbol
//       }
//    }
//--------------------------------------------------------------------------
RETCODE PRIVATE DisplaySortedSymbols() {

   RETCODE         err;
   SYM_DESCRIPTOR  symDesc;
   TABLE_OFFSET    baseOffset, byAddrTableOffset;
   BaseSymbol      HUGE* basePtr;
   ByAddressTable  HUGE* byAddrTablePtr;
   U32             symbolCount;
   BOOLEAN         printHeader = TRUE;
   
   baseOffset = bit.GetRootBaseSymbolOffset();
   if (!baseOffset)
      return ER_SYMBOL_NOT_A_MODULE;  // report no symbols loaded

   while (baseOffset) {
      basePtr = (BaseSymbol HUGE*)st.GetHugeDataPtr(baseOffset);
      if (!basePtr) return ER_INVALID_SYM_DESCRIPTOR;
      // print base information
      if (GOOD != (err = PrintBase(baseOffset, &printHeader)))
         return err;

      byAddrTableOffset = basePtr->GetByAddressTableOffset();
      byAddrTablePtr = (ByAddressTable HUGE*)st.GetHugeDataPtr(byAddrTableOffset);
      // get size of table
      symbolCount = byAddrTablePtr->GetSymbolCount();
      for (U32 i = 0; i < symbolCount; i++)  {
         // get offset of symbol from byadrtbl, then print
         symDesc = byAddrTablePtr->GetOffset(i);
         if (GOOD != (err = SymPrintSymbol(symDesc, MODULE_DISPLAY, 1)))
            return err;
      } // end of for
      baseOffset = basePtr->GetNextBaseOffset();
      // 10/06/94 - Nghia
      // reprint heading for each base
      printHeader = TRUE; 
   } // end while (baseOffset)
   return GOOD;
}  // end of DisplaySortedSymbols


//--------------------------------------------------------------------------
// DisplaySymbols
//--------------------------------------------------------------------------
RETCODE EXPORT
DisplaySymbols(LPSTR cmdString, U32 argc, U32 argv[]) {

   RETCODE          err;
   S8               command[(MAX_SYMNAME_LENGTH/4)];
   SYM_DISPLAY_TYPE displayType;
   BOOLEAN          noSymbolsLoaded;
   LPSTR            cmdPtr;
   S8               nullStr[1];
   SYM_DESCRIPTOR   moduleDesc;
   BOOLEAN          abortFromEsc;
   U8               cmdLength;
   

   // this is checking for the basic debug PRINT command
   if( (argc > 2) || (argc < 1)) {
      return(ER_CLI_SYNTAX);
   }
   if (GOOD != (err = SymCheckForNoSymbols(&noSymbolsLoaded)))
      return err;
   if (noSymbolsLoaded) {
      return ER_SYMBOL_NOT_A_MODULE;  // reports "no symbols are loaded"
   }
   // clears keyboard of any residual escape key hit
   err = TskCheckAbort(&abortFromEsc);
   if(err!=GOOD) return err;

   if (argc == 2) {
      cmdPtr = &cmdString[(U16)argv[1]];
      if (*cmdPtr == '#') {
         cmdPtr++;
         nullStr[0] = '\0';
         if (GOOD != (err = SymGetModuleDesc(cmdPtr,
                                             (LPSTR)nullStr,
                                             &moduleDesc)))
            return err;
         return DisplayModule(moduleDesc, PUBLIC_DISPLAY);
      }
      strcpy(command, &cmdString[(U16)argv[1]]);
      cmdLength = strlen(command);
      if (!strncmpi(command, "_debug", cmdLength)) {
         displayType = DEBUG_DISPLAY;
         if((err = SymPrintSymbols(displayType)) != GOOD)
            return err;
         if((err = SymPrintBases(displayType)) != GOOD)
            return err;

      } else if (!strncmpi(command, "modules", cmdLength)) {
         displayType = MODULE_DISPLAY;
         // print out all modules ;
         if((err = DisplayModules(displayType)) != GOOD)
            return err;

      } else if (!strncmpi(command, "functions", cmdLength)) {
         displayType = FUNCTION_DISPLAY;
         // print out all modules, and all functions;
         if((err = DisplayModules(displayType)) != GOOD)
            return err;

      } else if (!strncmpi(command, "publics", cmdLength)) {
         displayType = PUBLIC_DISPLAY;
         // print out everything including publics ;
         err = DisplayModules(displayType);
         if ((GOOD != err) && (ER_SYM_NO_MODULES_LOADED != err))
            return err;
         // print out all of the public variables
         if((err = DisplayVariables(rootOffset, displayType, 0)) != GOOD)
            return err;

      } else if (!strncmpi(command, "lines", cmdLength)) {
         displayType = LINES_DISPLAY;
         // print out module and all lines in module ;
         if((err = DisplayLines(displayType)) != GOOD)
            return err;

      } else if (!strncmpi(command, "sorted", cmdLength)) {
         displayType = LINES_DISPLAY;
         // print out all symbols in sorted order
         if((err = DisplaySortedSymbols()) != GOOD)
            return err;

      } else if (!strncmpi(command, "_varlife", cmdLength)) {
        displayType = VARLIFE_DISPLAY;
        // print out module and all var with it life-time information
        if ((err = DisplayModules(displayType)) != GOOD)
           return err;
      } else {
         return(ER_CLI_SYNTAX);
      }
   } else {
      // default is to display all symbols except publics
      displayType = USER_DISPLAY;
      if (GOOD != (err = DisplayModules(PUBLIC_DISPLAY)))
         return err;
   }
   return GOOD;
}


//--------------------------------------------------------------------------
// PrintBase
//
// For Moto, displays the name and base address of the base.
// For Intel, for real mode, displays the name, USER/SMM, segment number,
//            then base address.
//            For protected mode, displays the name, GDT selector, optional
//            LDT selector if non-zero, then base address.
//--------------------------------------------------------------------------
RETCODE PRIVATE PrintBase(TABLE_OFFSET baseOffset, BOOLEAN* printHeader) {
   S8           bufStr[MAX_SYMNAME_LENGTH];
   LPSTR        bufStrPtr;
   BaseSymbol   HUGE *basePtr;
   U16          len, column;
   U8           n;
   SYM_MODE     baseSymMode;
   RETCODE      err;
   
#define SYMCLI_MAX_COLUMN (16)
   basePtr = (BaseSymbol HUGE *)st.GetHugeDataPtr(baseOffset);
   // print the base header first.
   if ((*printHeader) && (basePtr->GetSymMode() == SYM_PROTECTED)) {
      *printHeader = FALSE;
      bufStr[0] = '\0'; bufStrPtr = bufStr;  // set to beginning of string
      // point to null string terminator
      while (*bufStrPtr != '\0') bufStrPtr++;  
      n = sprintf(bufStrPtr, "%- 16s %- 16s %- 16s %- 16s",
          "Base Name","LDT Selector","Seg/Selector", "Base Address");
      bufStrPtr += n; *bufStrPtr = '\0';
      if ((err = SendMessageToCli((U8 FAR *)bufStr)) != GOOD)
         return err;
      // print the heading ruler
      bufStr[0] = '\0'; bufStrPtr = bufStr;
      // point to null string terminator
      while (*bufStrPtr != '\0') bufStrPtr++;
      len = min(SYMCLI_MAX_COLUMN * 4, MAX_SYMNAME_LENGTH);
      for ( ; len > 0; len--) *bufStrPtr++ = '=';
      *bufStrPtr = '\0';
      if ((err = SendMessageToCli((U8 FAR *)bufStr)) != GOOD)
         return err;
   }

   // 11/03/94
   // print Base name for Intel real mode and Motorola 
   bufStr[0] = '\0';
   bufStrPtr = bufStr;  // set to beginning of string
   st.GetString(basePtr->GetBaseNameOffset(), (U8 FAR *)bufStr);   
   // point to null string terminator
   while (*bufStrPtr != '\0') bufStrPtr++;  
   len = (U16)(bufStrPtr - bufStr);
   if (SYMCLI_MAX_COLUMN <= len) {
      column = len + 1;
   } else {
     column = SYMCLI_MAX_COLUMN;
   }
   // move to next column
   while (len <= column) {
      *bufStrPtr = ' ';
      bufStrPtr++;
      len++;
   }
   *bufStrPtr = '\0';

   // check for Intel
   baseSymMode = basePtr->GetSymMode();
   if (baseSymMode == SYM_REAL) {
      // ***********************
      // fill in real mode info
      // ***********************
      // display "USER/SMM segment ="
      if (basePtr->GetSegAddrSpace() == SEG_SPACE_USER) {
         n = sprintf(bufStrPtr, "USER");
      } else {
         n = sprintf(bufStrPtr, "SMM");
      }
      bufStrPtr += n;

      // display segment value; show 4 hex digits
      n = sprintf(bufStrPtr, " segment = %4.4X  ", basePtr->GetSegOrLDTsel());
      bufStrPtr += n;
      // display "base address = xxxx" with leading 0's removed
      n = sprintf(bufStrPtr, "base address = %8.8lX",
                  basePtr->GetBaseAddress());
      bufStrPtr += n;
   } else if (baseSymMode == SYM_PROTECTED) {
      // ***************************
      // fill in protected mode info
      // ***************************
      // display LDT selector value; show 4 hex digits
      n = sprintf(bufStrPtr, "%- 16.4X ", basePtr->GetGDTsel());
      bufStrPtr += n;
      // display Segment|Selector
      if (0 != basePtr->GetSegOrLDTsel()) {
         // display LDT selector value; show 4 hex digits
         n = sprintf(bufStrPtr, "%- 16.4X ", basePtr->GetSegOrLDTsel());
         bufStrPtr += n;
      } else {
         // display LDT selector as blank space
         for (n = 0; n <= SYMCLI_MAX_COLUMN; n++)
            *bufStrPtr++ = ' ';
      }
      
      // display base address with leading 0's removed
      n = sprintf(bufStrPtr, "%8.8lX", basePtr->GetBaseAddress());
      bufStrPtr += n;
   } else {
      // Motorola symbols bases
      // display "base address = xxxx" with leading 0's removed
      n = sprintf(bufStrPtr, "base address = %8.8lX",
                  basePtr->GetBaseAddress());
      bufStrPtr += n;      
   }
   
   // output the string 
   return (SendMessageToCli((U8 FAR *)bufStr));

}  // end of PrintBase


//--------------------------------------------------------------------------
// GetBase
//--------------------------------------------------------------------------
RETCODE EXPORT
GetBase(LPSTR cmdString, U32 argc, U32 argv[]) {

   RETCODE      err;
   S8           baseName[MAX_SYMNAME_LENGTH];
   TABLE_OFFSET rootBaseOffset, baseOffset;
   BaseSymbol   HUGE *basePtr;
   BOOLEAN      noSymbolsLoaded;
   BOOLEAN      printHeader = TRUE;     

   if (argc > 2) return(ER_CLI_SYNTAX);
   if (GOOD != (err = SymCheckForNoSymbols(&noSymbolsLoaded)))
      return err;
   if (noSymbolsLoaded) {
      return ER_SYMBOL_NOT_A_MODULE;  // reports "no symbols are loaded"
   }
   
   if (argc == 2) {
      // get the base symbol that matches the name given by the user ;
      strcpy(baseName, &(cmdString[(U16)argv[1]]));
      if (GOOD != (err = GetBaseOffsetByName((LPSTR)baseName, baseOffset)))
         return err;
      if (GOOD != (err = PrintBase(baseOffset, &printHeader)))
         return err;
   } else {
      // 10/06/94 - Nghia
      // print all bases according to the BaseSymMode (SYM_REAL|SYM_PROTECTED).

      // get the offset of the first base symbol
      baseOffset = rootBaseOffset = bit.GetRootBaseSymbolOffset();
      if (!rootBaseOffset) return(ER_INDEX_NOT_IN_TABLE);      
      // print all real mode bases first           
      do {
         basePtr = (BaseSymbol HUGE *)st.GetHugeDataPtr(baseOffset);
         if (!basePtr) return ER_INVALID_SYM_DESCRIPTOR;
         // 11/03/94 - Support for both SYM_REAL & SYM_NONE
         // Intel real mode and Motorola base types      
         if ((basePtr->GetSymMode() != SYM_PROTECTED) &&
             (GOOD != (err = PrintBase(baseOffset, &printHeader))))
            return err;
         baseOffset = basePtr->GetNextBaseOffset();
      } while (baseOffset);
      
      // print all protected mode bases           
      baseOffset = rootBaseOffset = bit.GetRootBaseSymbolOffset();
      if (!rootBaseOffset) return(ER_INDEX_NOT_IN_TABLE);      
      do {
         basePtr = (BaseSymbol HUGE *)st.GetHugeDataPtr(baseOffset);
         if (!basePtr) return ER_INVALID_SYM_DESCRIPTOR;
         if ((basePtr->GetSymMode() == SYM_PROTECTED) &&
             (GOOD != (err = PrintBase(baseOffset, &printHeader))))
            return err;
         baseOffset = basePtr->GetNextBaseOffset();
      } while (baseOffset);      
   }
   return GOOD;
}  // end of GetBase


//--------------------------------------------------------------------------
// RemoveSymbols
//--------------------------------------------------------------------------
#pragma argsused
RETCODE EXPORT
RemoveSymbols(LPSTR cmdString, U32 argc, U32 argv[]) {
   RETCODE err;

   if (argc > 1)
      return(ER_CLI_SYNTAX);
   if ((err = SymRemoveSymbols()) != GOOD)
      return err;
   // notify interested parties
   return EnlEventNotify(EVENT_SYMBOL_DELETED);
}


//--------------------------------------------------------------------------
// SetBase
//--------------------------------------------------------------------------
RETCODE EXPORT
SetBase(LPSTR cmdString, U32 argc, U32 argv[]) {

   RETCODE         err;
   TABLE_OFFSET    baseOffset;
   BaseSymbol HUGE *basePtr;
   DESCRIPTOR      addrDesc;
   BASE_ADDRESS    baseAddr;
   BOOLEAN         noSymbolsLoaded;
   LPSTR           lpParam;
   
   if (argc != 3)
      return(ER_CLI_SYNTAX);
   if (GOOD != (err = SymCheckForNoSymbols(&noSymbolsLoaded)))
      return err;
   if (noSymbolsLoaded) {
      return ER_SYMBOL_NOT_A_MODULE;  // reports "no symbols are loaded"
   }

   if ((err = GetBaseOffsetByName((LPSTR) &cmdString[(U16)argv[1]],
      baseOffset)) != GOOD)
      return err;
   // 01/16/95 - Nghia
   // convert input address to address
   lpParam = &(cmdString[(U16)argv[2]]);
   if (GOOD != (err = AdrCreateAddressFromText(lpParam,NULL,&addrDesc)))
      return err;
   if (GOOD != (err = AdrGetAddrOffset(addrDesc, (U32 FAR *)&baseAddr)))
      return err;
   
   if ((basePtr = (BaseSymbol HUGE *)st.GetHugeDataPtr(baseOffset)) != NULL) {
      basePtr->SetBaseAddr(baseAddr);
      // notify interested parties
      return EnlEventNotify(EVENT_SYMBOL_BASE_CHANGED);
   }
   return GOOD;
}


//--------------------------------------------------------------------------
// Count
//
// Displays the number of symbols in the various tables
//--------------------------------------------------------------------------
#pragma argsused
RETCODE EXPORT
Count(LPSTR cmdString, U32 argc, U32 argv[]) {
   RETCODE    err, firstErr;
   S8         str[80];
   U32        count, memSize, tableSize;
   TYPE_INDEX typeIndexMax;
   BOOLEAN    noSymbolsLoaded;

   if (argc > 1)
      return ER_CLI_SYNTAX;
   if (GOOD != (err = SymCheckForNoSymbols(&noSymbolsLoaded)))
      return err;
   if (noSymbolsLoaded) {
      return ER_SYMBOL_NOT_A_MODULE;  // reports "no symbols are loaded"
   }

   // ORDINAL
   count = ot.GetOrdinalCount();
   memSize = ot.GetAvailMemOffset();
   tableSize = ot.GetTableSize();
   sprintf((LPSTR)str, "Ordinal count = %ld  (%ld) [%ld]",
                        count, memSize, tableSize);
   firstErr = SendMessageToCli((LPU8)str);


   // HASH TABLE
   count = ht.GetEntryCount();
   memSize = ht.GetHashTableSize();
   tableSize = ht.GetTableSize();
   sprintf((LPSTR)str, "Global symbol count = %ld (%ld) [%ld]",
                        count, memSize, tableSize);
   err = SendMessageToCli((LPU8)str);
   if (firstErr == GOOD)
      firstErr = err;

   // LINENUMS
   count = lt.GetLinenumCount();
   memSize = lt.GetAvailMemOffset();
   tableSize = lt.GetTableSize();
   sprintf((LPSTR)str, "Line number count = %ld (%ld) [%ld]",
                        count, memSize, tableSize);
   err = SendMessageToCli((LPU8)str);
   if (firstErr == GOOD)
      firstErr = err;

   // TYPES
   err = tt.GetMaxTypeIndex(typeIndexMax);
   memSize = tt.GetAvailMemOffset();
   tableSize = tt.GetTableSize();
   if (firstErr == GOOD)
      firstErr = err;
   sprintf((LPSTR)str, "Type count = %ld (%ld) [%ld]",
                        typeIndexMax, memSize, tableSize);
   err = SendMessageToCli((LPU8)str);
   if (firstErr == GOOD)
      firstErr = err;

   // SYMBOL TABLE SIZE
   memSize = st.GetAvailMemOffset();
   tableSize = st.GetTableSize();
   sprintf((LPSTR)str, "Symbol table size = (%ld) [%ld]",
                        memSize, tableSize);
   firstErr = SendMessageToCli((LPU8)str);


   // BASE TABLE COUNT
   count = bit.BaseGetBaseCount();
   memSize = bit.GetTableSize();
   sprintf((LPSTR)str, "Base count = %ld (%ld)", count, memSize);
   err = SendMessageToCli((LPU8)str);
   if (firstErr == GOOD)
      firstErr = err;

   // SYMBOLS STATISTICS OF EACH SYM_TYPE_TYPE
   U8 symType, nameIndex;
   for (symType = 0; symType < MAX_SYM_TYPE; symType++) {
       nameIndex = symTypeMap[symType];
       if (nameIndex < MAX_SYM_TYPE) {
          sprintf((LPSTR)str, "%12s = %6ld symbols",
                  (LPSTR) symTypeName[nameIndex],
                  symbolStat[symType]);
          err = SendMessageToCli((LPU8)str);
          if (firstErr == GOOD) firstErr = err;
       }
   }            

   // BY-ADDRESS TABLE WALK
   {
   TABLE_OFFSET loopPtr;  // pass by reference
   S8           baseName[100];
   U32          entryCount;  // pass by reference
   BOOLEAN      startLoop = TRUE;
   RETCODE      localErr;
      while (TRUE) {
         localErr = ByAddressTableGetNext(startLoop, loopPtr,
                                          (LPSTR)baseName,
                                          entryCount,  // by reference
                                          tableSize);  // by reference
         if (localErr != GOOD)
            break;
         if (0 == strlen(baseName))
            strcat(baseName, "NoNameBase");
         memSize = entryCount * (sizeof(TABLE_OFFSET));
         sprintf((LPSTR)str, "  %s contains %ld symbols (%ld) [%ld]",
                  baseName, entryCount, memSize, tableSize);
         err = SendMessageToCli((LPU8)str);
         if (GOOD == firstErr)
            firstErr = err;
         startLoop = FALSE;
      }
   }
   return firstErr;
}  // end of Count


//--------------------------------------------------------------------------
// NameOf
//
// Converts an address into a symbol and displays it
//    Address can be numeric or "pc" which returns present pc value
//
// Design:
//    convert address text into an address descriptor
//    set up descriptor with symbolic mode on
//    call AdrConvAddressToText
//    output text to CLI
//--------------------------------------------------------------------------
#pragma argsused
RETCODE EXPORT
NameOf(LPSTR cmdString, U32 argc, U32 argv[])  {

   RETCODE    err, firstErr;
   DESCRIPTOR desc;
   LPSTR      lpParam;
   S8         str[ADDR_BUFF_SZ_SYMBOLIC];
   BOOLEAN    noSymbolsLoaded;

   if (argc != 2)
      return ER_CLI_SYNTAX;
   if (GOOD != (err = SymCheckForNoSymbols(&noSymbolsLoaded)))
      return err;
   if (noSymbolsLoaded) {
      return ER_SYMBOL_NOT_A_MODULE;  // reports "no symbols are loaded"
   }

   lpParam = &(cmdString[(U16)argv[1]]);
   if (GOOD != (err = AdrCreateAddressFromText(lpParam,NULL,&desc)))
         return err;

   if (GOOD != (err = AdrSetAddrSymbolUsage(desc, TRUE)))
      goto CLEANUP;
   if (GOOD != (err = AdrConvAddressToTextWithParams(desc,
      with0X,
      (globalProcFamily == FAMILY_X86), /* leadZeroFill */
      str)))
      goto CLEANUP;
   err = SendMessageToCli((LPU8)str);

CLEANUP:
   firstErr = err;
   err = AdrDestroyAddress(desc);
   if (GOOD == firstErr)
      firstErr = err;
   return firstErr;
} // end of NameOf


//--------------------------------------------------------------------------
// AddressOf
//
// Converts a symbol path and name into an address; uses #mod#func#var
//   naming convention
//--------------------------------------------------------------------------
RETCODE EXPORT
AddressOf(LPSTR cmdString, U32 argc, U32 argv[])  {

   RETCODE           err, nextErr;
   DESCRIPTOR        addrDesc = 0L;
   SYM_DESCRIPTOR    symDesc = 0L;
   LINENUM_TYPE      actualLinenum;
   COLUMN_RANGE_TYPE actualColumnRange;
   LPSTR             lpParam;
   S8                str[SYMCLIPR_ADDR_TEXT_WIDTH*10];
   BOOLEAN           noSymbolsLoaded;
   SYM_TYPE_TYPE     symType;

   if (argc != 2)
      return ER_CLI_SYNTAX;
   if (GOOD != (err = SymCheckForNoSymbols(&noSymbolsLoaded)))
      return err;
   if (noSymbolsLoaded) {
      return ER_SYMBOL_NOT_A_MODULE;  // reports "no symbols are loaded"
   }

   lpParam = &(cmdString[(U16)argv[1]]);
   while (isspace((S16)*lpParam)) {  /* skip over spaces; requires int */
      lpParam++;
   }
   err = SymGetAddrFromName(lpParam,
                            SYM_UNKNOWN_ADDR,
                            &symDesc,
                            &addrDesc,
                            &actualLinenum,
			    &actualColumnRange,
			    &symType);
   /* NOTES: 09/22/93 - Nghia
   ** Filter out ER_NO_LINENUMS_ADDED to support ASM module which does not
   ** have any line number infomation, but still has a valid address range
   */
   if ((err != GOOD) && (err != ER_NO_LINENUMS_ADDED) &&
       (err != ER_ADR_END_ADDR_TOO_SMALL))
      return err;    // addrDesc not alloc'ed when error occurs

   if (actualLinenum == 0) { // indicates not a linenum lookup
      err = SymConvSymAddrToText(symDesc, str);
      // NOTES: 09/21/93 - Nghia
      // Only destroy addrDesc if it's valid
      if (addrDesc)
         goto CLEANUP1;
      // addrDesc is already destroyed, so do not destroying it
      goto CLEANUP2;
   } else {
      // 01/10/95 - Nghia
      // Fixed PPR 9763 - Intel virtual address is zeroFill
      BOOLEAN zeroFill = FALSE;
      ADDR_TYPE addrType;
      if ((globalProcFamily == FAMILY_X86) &&
          (AdrGetAddrType(addrDesc, &addrType) == GOOD)) {
         zeroFill = (addrType == ADDR_VIRTUAL);
      }
      if (symType == SYM_MODULE) {
         if (GOOD != (err = AdrConvAddrRangeToText1(addrDesc,
                                                    with0X,
                                                    zeroFill,
                                                    RANGE_BOTH,
                                                    (LPSTR)str)))
	    goto CLEANUP1;
      }
      else{
	 if (GOOD != (err = AdrConvAddrRangeToText(addrDesc,
                                                  with0X,
                                                  zeroFill,
                                                  RANGE_BOTH,
                                                 (LPSTR)str)))
	    goto CLEANUP1;
      }
   }
CLEANUP1:
   nextErr = AdrDestroyAddress(addrDesc);
   err = (err != GOOD) ? err : nextErr;
   
CLEANUP2:  
   nextErr = SendMessageToCli((LPU8)str);
   return((err != GOOD) ? err : nextErr);

} // end of AddressOf


//--------------------------------------------------------------------------
// SymbolOpenFile
//
// Sets symbol output to go to <file>
//--------------------------------------------------------------------------
#pragma argsused
RETCODE EXPORT
SymbolOpenFile(LPSTR cmdString, U32 argc, U32 argv[])  {

   RETCODE err;
   LPSTR   tmpPtr;

// create file for read/write (page 4-271)
#define NORMAL 0
   
   if (argc != 2)
      return ER_CLI_SYNTAX;

   if (sendToFile == TRUE) {
      // close current file
      if (GOOD != (err = SymbolCloseFile("", 1L, 0)))  // ignores params
         return err;
   }
   // process input file
   if ((hFile = _lcreat((LPSTR)&cmdString[(U16)argv[1]], NORMAL)) == -1) {
      return ER_CANNOT_OPEN;
   }
   // no file errors
   err = SendMessageToCli((U8 FAR *)
                          "Sending all symbol output to specified file...");

   sendToFile = TRUE;  // must be after message to Shell

   // save file name for closing
   fileNamePtr = (LPSTR)TMalloc(100);
   tmpPtr = stpcpy(fileNamePtr, "Closing file ");
   tmpPtr = stpcpy(tmpPtr, (LPSTR)&cmdString[(U16)argv[1]]);
   if (!(fileNamePtr))
      return ER_OUT_OF_MEMORY;
   return GOOD;
} // end of SymbolOpenFile


//--------------------------------------------------------------------------
// SymbolCloseFile
//
// Closes file opened by SymbolOpenFile
//--------------------------------------------------------------------------
#pragma argsused
RETCODE EXPORT
SymbolCloseFile(LPSTR cmdString, U32 argc, U32 argv[])  {

   RETCODE err=0, err2;
   
   if (argc != 1)
      return ER_CLI_SYNTAX;

   if (sendToFile == TRUE) {
      // close file
      if (_lclose(hFile) == -1) {
         err = ER_CANT_CLOSE_FILE;
         goto CLEANUP;
      }
   }
   sendToFile = FALSE;

   err = SendMessageToCli((U8 FAR *)fileNamePtr);

CLEANUP:
   err2 = TFree(fileNamePtr);
   if (err)
      return err;
   return err2;
} // end of SymbolCloseFile


//--------------------------------------------------------------------------
// DisplayTypes
//
// Displays all the types loaded.
//--------------------------------------------------------------------------
PRIVATE S8 str[80];
PRIVATE S8 typeName[MAX_SYMNAME_LENGTH];
PRIVATE S8 typeNameTmpBuff[MAX_SYMNAME_LENGTH];

#pragma argsused
RETCODE EXPORT DisplayTypes(LPSTR cmdString, U32 argc, U32 argv[]) {
   S8                     command[(MAX_SYMNAME_LENGTH/4)];
   CHAR                   *endPtr;
   U32                    memSize, tableSize;
   TYPE_INDEX             typeIndexMax, typeIndex;
   TYPE_INDEX             startIndex, endIndex;  
   BOOLEAN                noSymbolsLoaded, abortFromEsc, outputTotal;
   RETCODE                err = GOOD;
   TYPE_HEADER_TYPE2 HUGE *typeHdr;
   TYPE_HEADER_TYPE       typeHeader;
   TABLE_OFFSET           offset;
   
   if ((argc > 2) || (argc < 1))
      return ER_CLI_SYNTAX;
   if (GOOD != (err = SymCheckForNoSymbols(&noSymbolsLoaded)))
      return err;
   if (noSymbolsLoaded) {
      return ER_SYMBOL_NOT_A_MODULE;  // reports "no symbols are loaded"
   }
   // clears keyboard of any residual escape key hit
   if ((err = TskCheckAbort(&abortFromEsc)) != GOOD)
      return err;

   // TYPES TABLE INFORMATION
   err       = tt.GetMaxTypeIndex(typeIndexMax);
   memSize   = tt.GetAvailMemOffset();
   tableSize = tt.GetTableSize();
   // Set default endIndex = maxTypeIndex
   startIndex = 0L;
   endIndex = typeIndexMax;
   outputTotal = TRUE;
   
   if (argc == 2) {
      strcpy(command, &cmdString[(U16)argv[1]]);
      if (!strcmpi(command, "built-in")) {
         endIndex = 255L;  // Actual last built-in type is 57
      } else if (!strcmpi(command, "user")) {
         startIndex = 256L;
      } else if ((startIndex = strtoul(command, &endPtr, 0)) > 0) {
         outputTotal = FALSE;
         endIndex = startIndex;
      } else {
         return ER_CLI_SYNTAX;
      }
   }
   
   if (outputTotal) {   
      sprintf((LPSTR)str,
           "Max Type Index = %ld, MemSize = (%ld) TableSize = [%ld]",
           typeIndexMax, memSize, tableSize);
      SendMessageToCli((LPU8)str);
   }
   typeHeader.typeName = (LPSTR) typeName;
   
   // Loop over all type and print the type out
   for (typeIndex = startIndex; typeIndex <= endIndex; typeIndex++) {
      // Use SymGetTypeHeader() to resolve any indirect reference type
      if ((err = SymGetTypeHeader(typeIndex, &typeHeader)) == GOOD) {
         sprintf((LPSTR)str,
         "-- TYPE INDEX: %ld (%#04X) --------------------------------------",
                 typeIndex, typeIndex);
         SendMessageToCli((LPU8)str);
         // Get more information about the type
         if ((err = typit.GetOffset(typeIndex, offset)) != GOOD)
            return(err);
         typeHdr = (TYPE_HEADER_TYPE2 HUGE *)tt.GetHugeDataPtr(offset);
         
         switch (typeHeader.typeChoice) {
            case SIMPLE_TYPE_CLASS:
               sprintf((LPSTR)str,
                       "Name = %s, Type Value = %#04X, SizeInMAUs = %ld",
                       (LPSTR)typeHeader.typeName,
                       (U8)typeHeader.t.simpleType,
                       (U32)typeHeader.sizeInMAUs);
               SendMessageToCli((LPU8)str);
               sprintf((LPSTR)str,
                       "Member = %d, Record size = %ld bytes",
                       (U16)typeHdr->memberCount,
                       (U32)typeHdr->recordSize);
               SendMessageToCli((LPU8)str);
               break;
               
            case COMPLEX_TYPE_CLASS:
               sprintf((LPSTR)str,
                       "Name = %s, Type Value = %#04X, SizeInMAUs = %ld",
                       (LPSTR)typeHeader.typeName,
                       (COMPLEX_TYPE)typeHeader.t.complexType,
                       (U32)typeHeader.sizeInMAUs);
               SendMessageToCli((LPU8)str);
               sprintf((LPSTR)str,
                       "Member = %d, Record size = %ld bytes",
                       (U16)typeHdr->memberCount,
                       (U32)typeHdr->recordSize);
               SendMessageToCli((LPU8)str);
               // Get information about the complex type
               switch(typeHeader.t.complexType) {
                  case TY_UNKNOWN :       // = 0x21  !
                     sprintf((LPSTR) str, "-- TY_UNKNOWN");
                     break;
                  case TY_ENUM_PASCAL :   // = 0x45  E
                     sprintf((LPSTR) str, "-- TY_ENUM_PASCAL");
                     break;
                  case TY_GENERAL :       // = 0x47  G
                     sprintf((LPSTR) str, "-- TY_GENERAL");
                     break;
                  case TY_ENUM_C:         // = 0x4E,  // N
                     sprintf((LPSTR) str, "-- TY_ENUM_C");
                     break;
                  case TY_SMALL_PTR :     // = 0x4F,  // O
                  {
                     TYPE_INDEX baseTypeIndex;
                     if (SymGetTypePointerTypeIndex(typeIndex, &baseTypeIndex)
                         == GOOD) {
                        sprintf((LPSTR)str,"BASE TYPE INDEX = %ld",
                                (TYPE_INDEX)baseTypeIndex);
                        SendMessageToCli((LPU8)str);
                     }
                     sprintf((LPSTR) str, "-- TY_SMALL_PTR");
                     break;
                  }

                  case TY_LARGE_PTR :     // = 0x50,  // P
                  {
                     TYPE_INDEX baseTypeIndex;
                     if (SymGetTypePointerTypeIndex(typeIndex, &baseTypeIndex)
                         == GOOD) {
                        sprintf((LPSTR)str,"BASE TYPE INDEX = %ld",
                                (TYPE_INDEX)baseTypeIndex);
                        SendMessageToCli((LPU8)str);
                     }
                     sprintf((LPSTR) str, "-- TY_LARGE_PTR");
                     break;
                  }

                  case TY_16_16_PTR :     // = 0x00,
                  {
                     TYPE_INDEX baseTypeIndex;
                     if (SymGetTypePointerTypeIndex(typeIndex, &baseTypeIndex)
                         == GOOD) {
                        sprintf((LPSTR)str,"BASE TYPE INDEX = %ld",
                                (TYPE_INDEX)baseTypeIndex);
                        SendMessageToCli((LPU8)str);
                     }
                     sprintf((LPSTR) str, "-- TY_16_16_PTR");
                     break;
                  }

                  case TY_16_32_PTR :     // = 0x01,
                  {
                     TYPE_INDEX baseTypeIndex;
                     if (SymGetTypePointerTypeIndex(typeIndex, &baseTypeIndex)
                         == GOOD) {
                        sprintf((LPSTR)str,"BASE TYPE INDEX = %ld",
                                (TYPE_INDEX)baseTypeIndex);
                        SendMessageToCli((LPU8)str);
                     }
                     sprintf((LPSTR) str, "-- TY_16_32_PTR");
                     break;
                  }

                  case TY_RANGE :         // = 0x52,  // R
                     sprintf((LPSTR) str, "-- TY_RANGE");
                     break;
                     
                  case TY_STRUCT :        // = 0x53,  // S
                  case TY_UNION :         // = 0x55,  // U
                     TYPE_S_U_STRUCT typeSU;
                     U16 i;
                     // 05/11/95 - Nghia
                     // Print out struct/union member as well.
                     for (i = 0; typeHdr && (i < typeHdr->memberCount); i++) {
                        memset(&typeSU, 0, sizeof(typeSU));
                        typeSU.name = typeNameTmpBuff;
                        if (SymGetTypeStructUnionNth(typeIndex, i, &typeSU)
                                                    == GOOD) {
                           sprintf((LPSTR)str,
                           "Member: %-24s - Index: %#04X - Offset: %u",
                           (LPSTR)typeSU.name,
                           (TYPE_INDEX) typeSU.typeIndex,
                           (U16)typeSU.offset);
                           SendMessageToCli((LPU8)str);
                        }                        
                     }
                     // Now print the parent type
                     if (typeHeader.t.complexType == TY_STRUCT) 
                        sprintf((LPSTR) str, "-- TY_UNION");
                     else
                        sprintf((LPSTR) str, "-- TY_STRUCT");
                     break;
                     
                  case TY_TYPE :          // = 0x54,  // T
                  {
                     TYPE_INDEX baseTypeIndex;
                     if (SymGetTypeTypeIndex(typeIndex, &baseTypeIndex)
                         == GOOD) {
                        sprintf((LPSTR)str,"BASE TYPE INDEX = %ld",
                                (TYPE_INDEX)baseTypeIndex);
                        SendMessageToCli((LPU8)str);
                     }
                     sprintf((LPSTR) str, "-- TY_TYPE");
                     break;
                  }
                  case TY_VOID :          // = 0x56,  // V
                     sprintf((LPSTR) str, "-- TY_VOID");
                     break;
                  case TY_FUNC_NODEP :    // = 0x58,  // X
                     sprintf((LPSTR) str, "-- TY_FUNC_NODEP");
                     break;
                  case TY_C_ARRAY :       // = 0x5A,  // Z
                  {
                     TYPE_Z_STRUCT arrStruct;
                     if (SymGetTypeCArray(typeIndex, &arrStruct) == GOOD) {
                        if (arrStruct.highBound < 0)
                           sprintf((LPSTR)str,
                                   "external");
                        else
                           sprintf((LPSTR)str,
                                   "HighBound = %ld",
                                   (S32)arrStruct.highBound);
                        SendMessageToCli((LPU8)str);
                        sprintf((LPSTR)str,"BASE TYPE INDEX = %ld",
                                (TYPE_INDEX)arrStruct.typeIndex);
                        SendMessageToCli((LPU8)str);
                     }
                     sprintf((LPSTR) str, "-- TY_C_ARRAY");
                     break;
                  }
                  
                  case TY_BITFIELD :      // = 0x67,  // g
                  {
                     TYPE_BITFIELD_STRUCT bfStruct;
                     if (SymGetTypeBitfield(typeIndex, &bfStruct) == GOOD) {
                        sprintf((LPSTR) str,
                          "bitfieldSigned = %d, sizeInBits = %d",
                          (U8)bfStruct.bitfieldSigned,
                          (U16)bfStruct.size);
                        SendMessageToCli((LPU8)str);
                        sprintf((LPSTR)str,"BASE TYPE INDEX = %ld",
                                (TYPE_INDEX)bfStruct.baseTypeIndex);
                        SendMessageToCli((LPU8)str);
                     }
                     sprintf((LPSTR) str, "-- TY_BITFIELD");
                     break;
                  }
                  case TY_FUNC_DEP :      // = 0x78,  // x   
                     sprintf((LPSTR) str, "-- TY_FUNC_DEP");
                     break;
                  default :
                     sprintf((LPSTR)str, "Not supported type");
                     break;
               }
               SendMessageToCli((LPU8)str);  
               break;

            default :
               sprintf((LPSTR)str, "Unknown");
               SendMessageToCli((LPU8)str);
               
         } // end of switch
      }
      // escape when key pressed
      if ((TskCheckAbort(&abortFromEsc) != GOOD) || abortFromEsc) 
         return ER_ABORT_FROM_ESC;
   }
   return(err);
}

//--------------------------------------------------------------------------
// CreateLabelRanges
//
// Create public label address ranges
//--------------------------------------------------------------------------
#pragma argsused
RETCODE EXPORT CreateLabelRanges(LPSTR cmdString, U32 argc, U32 argv[])  {
   RETCODE err;
   U8     tmpStr[80];
   BOOLEAN noSymbolsLoaded;

   // Syntax:
   // :>createLabelRanges on|off
   if (argc < 2) {
      tmpStr[0] = (CHAR) '\0'; // init tmpStr
      lstrcat((LPSTR)tmpStr, (LPSTR) &cmdString[(U16)argv[0]]);
      lstrcat((LPSTR)tmpStr, "=");
      if (createLabelRanges)
         lstrcat((LPSTR)tmpStr, (LPSTR) "on");
      else
         lstrcat((LPSTR)tmpStr, (LPSTR) "off");
      SendMessageToCli(tmpStr);
      return(GOOD);
   }
   
   // Save the specified value to PWRVIEWS.INI 
   if (lstrcmpi((LPSTR)"on", &cmdString[(U16)argv[1]]) == 0) {
      if ((err = IniSetNumber((LPSTR) SAPP_NAME, (LPSTR) SAPP_LABEL,
         (LPSTR)PWRVIEWS_INI_DEFAULT, 1L)) != GOOD)
         return err;
      createLabelRanges = TRUE;
      if (GOOD != (err = SymCheckForNoSymbols(&noSymbolsLoaded)))
         return err;
      // if symbols loaded - do it
      if (noSymbolsLoaded == FALSE) 
         return CreateAllAddrRanges(SYM_PUBLIC_LABEL);      
   }
   else if (lstrcmpi((LPSTR)"off", &cmdString[(U16)argv[1]]) == 0) {
      if ((err = IniSetNumber((LPSTR) SAPP_NAME, (LPSTR) SAPP_LABEL,
         (LPSTR)PWRVIEWS_INI_DEFAULT, 0L)) != GOOD)
         return err;
      createLabelRanges = FALSE;
   }
   else {
      return(ER_CLI_SYNTAX);
   }
   /* "CreateLabelRanges" has been defined and saved into the PWRVIEWS.INI */
   return(GOOD);
}

//--------------------------------------------------------------------------
// ConfigSymbols
//
// Configure symbol bases
//--------------------------------------------------------------------------
#pragma argsused
RETCODE EXPORT ConfigSymbols(LPSTR cmdString, U32 argc, U32 argv[])  {
   RETCODE err;
   CHAR    baseName[MAX_SYMNAME_LENGTH];
   U16     dontCare;
   BOOLEAN noSymbolsLoaded;

   // Syntax:
   // :>configSymbols ["baseName"]
   if (argc > 2) return ER_CLI_SYNTAX;
   if (GOOD != (err = SymCheckForNoSymbols(&noSymbolsLoaded)))
      return err;
   if (noSymbolsLoaded) {
      return ER_SYMBOL_NOT_A_MODULE;  // reports "no symbols are loaded"
   }
   if (argc == 2) {
      TABLE_OFFSET tmpBaseOffset;
      BaseSymbol   HUGE* basePtr;
      DESCRIPTOR   symAddrDesc = 0L;
      U16          gdtSel, segOrldtSel;
      U32          base;
      BOOLEAN      found = FALSE;

      strcpy(baseName, &cmdString[(U16)argv[1]]);
      if (!(tmpBaseOffset = bit.GetRootBaseSymbolOffset()))
         return ER_SYMBOL_NOT_A_MODULE;  // report no selectors
      if (GOOD != (err = AdrCreateAddress(&symAddrDesc)))
         return err;
      while (tmpBaseOffset) {
         CHAR bufStr[MAX_SYMNAME_LENGTH];
         basePtr = (BaseSymbol HUGE*) st.GetHugeDataPtr(tmpBaseOffset);
         if (!basePtr) return ER_INVALID_SYM_DESCRIPTOR;
         st.GetString(basePtr->GetBaseNameOffset(), (U8 FAR *)bufStr);
          // Find the base - protected mode base
         found = !(strcmpi(baseName, bufStr));
         if (found && (SYM_PROTECTED == basePtr->GetSymMode())) {
            // set the segsel type and enter the selector and ldt value
            // In protected mode the GetGDTsel returns GDT selector
            // and GetSegOrLDTsel returns LDT selector.  
            // protected mode address format is gdt:ldt:offset
            gdtSel = basePtr->GetGDTsel();
            segOrldtSel = basePtr->GetSegOrLDTsel();
            // now get the base of the GDT/LDT selectors from main memory
            // tables
            if ((GOOD != (err = AdrSetLdtSelector(symAddrDesc, gdtSel))) ||
                (GOOD != (err = AdrSetAddrSegmentSelector(symAddrDesc,
                                                          ADDR_USE_VALUE,
                                                          &segOrldtSel))) ||
                (GOOD != (err = AdrGetSegmentSelectorBase(symAddrDesc,
                                                          &base)))) {
               ErrDisplayError(err, CHECK_MODE);
            } else {
               // set the base address
               basePtr->SetBaseAddr((BASE_ADDRESS)base);
               // Notify interest parties
               EnlEventNotify(EVENT_SYMBOL_BASE_CHANGED);               
            }
            break; // exit the while loop
         }
         tmpBaseOffset = basePtr->GetNextBaseOffset();
      }  // end of while
      err = AdrDestroyAddress(symAddrDesc);
      return (found ? err : ER_SYMBOL_NOT_FOUND); 
   } 
   // Update all symbols bases
   return SymUpdateSymbolBases(&dontCare);
}

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