/****************************************************************************
**
**  Name:  stkcli.c
**
**  Description:
**     Entry points for CLI commands of the stack server.
**
**  Status:  PRELIMINARY | CODED | REVIEWED | TESTED
**
**  $Log:   S:/tbird/mt2_186/stkservr/stkcli.c_v  $
** 
**    Rev 1.1   01 Dec 1997 16:11:40   Winky
** remove "high water mark" feature
** 
**    Rev 1.0   16 Dec 1996 14:44:54   Judy
** Initial revision.
** 
**    Rev 1.28   28 Sep 1994 13:33:22   matthew
** Support 386EX
** 
**    Rev 1.27   06 Apr 1994 17:04:28   nghia
** - Replaced the AdrCreateAddress() with CpuGetSP to create Shell address 
** descriptor.  This to ensure that the address descriptor created are 
** compatible.
** 
**    Rev 1.26   29 Jul 1993 19:48:16   marilyn
** Fixed memory leaks in StackInfo routine.  
** 
**    Rev 1.25   16 Jul 1993 12:02:26   nghia
** PIP for Stack:
** - Added new command setStackArea.
** - Revised StackInfo to print out a consistent output.
** - Made RecalcAlarmLimit became public routine.
** - Made CLI routine to generate event notification only.
** - Only use one stack session for both the CLI and presenter.
** 
**    Rev 1.23   01 Jul 1993 17:15:28   doug
** Use general syntax error.
** 
**    Rev 1.22   28 Jun 1993 08:56:18   paul
** Change CHECK_ABORT to TskCheckAbort
** 
**    Rev 1.21   15 Jun 1993 11:11:00   mindy
** StkFrameCount is replaced by STkAnyFrames and is no longer called.
** Other changes.
** 
**    Rev 1.20   16 Dec 1992 11:21:30   marilyn
** 
** Fixed bug in stackInfo, ppr7814.
** 
**    Rev 1.19   02 Dec 1992 13:42:26   marilyn
** Added check abort.
** 
**    Rev 1.18   03 Nov 1992 10:41:06   marilyn
** The unused stackName parameter was confusing the cli commands.  For
** now we are not implementing the stackName convention. Fixed a UAE for
** commands that take no parameters.
** 
**    Rev 1.17   22 Oct 1992 20:27:06   marilyn
** Alarm limits now set by percentage.
** 
**    Rev 1.16   21 Oct 1992 17:18:52   marilyn
** Removed compiler warnings.
** 
**    Rev 1.15   08 Sep 1992 11:31:38   marilyn
** Added include for new events.h.
** 
**    Rev 1.14   19 Aug 1992 09:08:44   marilyn
** Adjusted interface for FillStackToPattern call.
** 
**    Rev 1.13   08 Aug 1992 11:50:32   tom
** New CLI registration.
** 
**    Rev 1.12   02 Jun 1992 16:19:36   marilyn
** Fixed bug in FreeStkBuf.
** 
**    Rev 1.11   24 Apr 1992 15:47:38   marilyn
** Fine tuning for new stack events.
** 
**    Rev 1.10   20 Mar 1992 08:47:54   marilyn
** Added event notification from the cli interface.
** 
**    Rev 1.9   16 Mar 1992 09:27:32   marilyn
** Fixed type-o in SetStackAlarm which caused UAE.
** 
**    Rev 1.8   12 Mar 1992 17:26:34   marilyn
** Added call for stackinfo to get the HWM.
** 
**    Rev 1.7   11 Mar 1992 10:46:08   marilyn
** Fixed bugs. Converted use of sscanf to strtoul. 
** 
**    Rev 1.6   02 Mar 1992 16:23:38   marilyn
** Added VOID parameter to some of the prototypes.
** 
**    Rev 1.5   27 Feb 1992 15:40:32   marilyn
** Minor bug fixes.
** 
**    Rev 1.4   14 Feb 1992 17:17:00   marilyn
** Changed interface for StkGetAlarmLimit.
** 
**    Rev 1.3   14 Feb 1992 12:08:12   marilyn
** Changed memoryReference variable to stackSex variable.
**
**    Rev 1.2   14 Feb 1992 11:38:54   marilyn
** Moved processor stack dependencies from stkwalk.c
**
**    Rev 1.1   12 Feb 1992 10:08:56   marilyn
** Changed StkGetSessionIdFromStackName to StkGetDescFromName.
**
**    Rev 1.0   11 Feb 1992 16:01:58   marilyn
** Initial revision.
**
**  $Header:   S:/tbird/mt2_186/stkservr/stkcli.c_v   1.1   01 Dec 1997 16:11:40   Winky  $
**
**  Copyright (C) 1992 Microtek International.  All rights reserved.
**
*****************************************************************************/

                       /****************************
                        *                          *
                        *       INCLUDE FILES      *
                        *                          *
                        ****************************/
#ifndef _BASEWIND_
#include "basewind.h"
#endif

#ifndef _HOSTERRS_
#include "hosterrs.h"
#endif

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

#ifndef _STKCLI_
#include "stkcli.h"
#endif

#ifndef _STKERRS_
#include "stkerrs.h"
#endif

#ifndef _STKWALK_
#include "stkwalk.h"
#endif

#ifndef _STKCNTXT_
#include "stkcntxt.h"
#endif

#ifndef _STKUTIL_
#include "stkutil.h"
#endif

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

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

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

#ifndef __STRING_H
#include "string.h"     /* required for strcmpi calls */
#endif

#ifndef __STDLIB_H
#include <stdlib.h>
#endif

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

/*
**  these variables are global for the stack server
**  and eventually will be set by some type of
**  read in parameter file.
*/
STACK_TYPE stackSex = HI_TO_LOW;
U8 stackUnitSize = 2;                 /* word boundaries */
/*
**  the offset of the return PC from the
**  frame pointer
*/
U32 retPCOffset = 4;       /* 4 byte offset */


#define MAX_FRAMES 0xFF

typedef enum {
   STK_DISPLAY_HEX,
   STK_DISPLAY_FUNC_SYMBOLICS,
   STK_DISPLAY_LOCAL_SYMBOLICS
} STK_DISPLAY_FORMAT;

                       /****************************
                        *                          *
                        *     LOCAL VARIABLES      *
                        *                          *
                        ****************************/

HANDLE cliServerHandle;

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

extern STACK_TYPE stackSex;
extern DESCRIPTOR defaultSessionId;

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

BOOLEAN PRIVATE AbortOperation(VOID);

RETCODE PRIVATE FreeStkBuf(STK_DISPLAY_PTR displayBufPtr);

RETCODE PRIVATE SendCliResults(LPSTR results, HANDLE server);

                       /****************************
                        *                          *
                        *      EXECUTABLE CODE     *
                        *                          *
                        ****************************/
/**********************************************************************
**
**   AbortOperation
**
**   Purpose : To check for feedback from the CLI to abort the operation
**   started by the user.  Currently not supported by the CLI.
**
***********************************************************************/
BOOLEAN PRIVATE AbortOperation() {

   return FALSE;
}

/******************************************************************************
**
**   DisableAlarmLimit
**
**   Purpose:
**      To disable the alarm limit which can generate an alarm condition.
**
**   Input parameters:
**      cmdString : the CLI command string
**      argc : number of arguments in command string
**      argv : array of pointers to the arguments
**
**   Output parameters:
**      none
**
**   Error:
**
******************************************************************************/
RETCODE EXPORT  DisableAlarmLimit(LPSTR cmdString, U32 argc, U32 argv[]) {

   RETCODE error;
   DESCRIPTOR sessionId;

   if (argc > 1)
      return ER_CLI_SYNTAX;
   if (argc == 2) {
      if ((error = StkGetDescFromName(&cmdString[(U16)argv[(U16)(argc-1)]],
            &sessionId)) != GOOD)
         return error;
   }
   else {
      if ((error = InitSessionForCli(&sessionId)) != GOOD)
         return error;
   }

   if ((error = StkDisableAlarmLimit(sessionId)) != GOOD)
      return error;

   /* Notify clients */
   if ((error = EnlEventNotify(EVENT_STK_ALARM_DISABLED)) != GOOD)
      return error;

   return GOOD;
}

/******************************************************************************
**
**   DisableHighWaterMark
**
**   Purpose:
**      To disable the high water mark which can generate an alarm condition.
**
**   Input parameters:
**      cmdString : the CLI command string
**      argc : number of arguments in command string
**      argv : array of pointers to the arguments
**
**   Output parameters:
**      none
**
**   Error:
**
******************************************************************************/
RETCODE EXPORT  DisableHighWaterMark(LPSTR cmdString, U32 argc, U32 argv[]) {

   RETCODE error;
   DESCRIPTOR sessionId;

   if (argc > 1)
      return ER_CLI_SYNTAX;
   if (argc == 2) {
      if ((error = StkGetDescFromName(&cmdString[(U16)argv[(U16)argc-1]],
            &sessionId)) != GOOD)
         return error;
   }
   else {
      if ((error = InitSessionForCli(&sessionId)) != GOOD)
         return error;
   }

   if ((error = StkDisableHighWaterMark(sessionId)) != GOOD)
      return error;
   /* Notify clients */
   if ((error = EnlEventNotify(EVENT_STK_HWM_DISABLED)) != GOOD)
      return error;

   return GOOD;
}

/******************************************************************************
**
**   DisplayStack
**
**   Purpose:
**      To display the stack frames in user comprehensible format.
**      Defaults to address and funcion names.  Locals options includes local
**      symbols.  Hex option displays in hex format using 16 bytes per line.
**      Defaults to hex format if no symbolic information is available.
**
**   Input parameters:
**      cmdString : the CLI command string
**      argc : number of arguments in command string
**      argv : array of pointers to the arguments
**
**   Output parameters:
**      none
**
**   Error:
**
******************************************************************************/
RETCODE EXPORT  DisplayStack(LPSTR cmdString, U32 argc, U32 argv[]) {

   RETCODE error;
   DESCRIPTOR sessionId;
   STK_DISPLAY_FORMAT stackFormat;
   U8 numOfFrames = MAX_FRAMES;
   U8 framesDisplayed = 0;
   U8 endFrameOffset = 0;
   STK_DISPLAY_PTR bufPtr;

   if (argc > 3)
      return ER_CLI_SYNTAX;
   if (argc == 3) {
      /*
      **  compare the last parameter to keywords
      */
      if (strcmpi(&cmdString[(U16)argv[(U16)argc-1]],"locals") == GOOD) {
         stackFormat = STK_DISPLAY_LOCAL_SYMBOLICS;
         if ((error = InitSessionForCli(&sessionId)) != GOOD)
            return error;
      }
      else {
         if (strcmpi(&cmdString[(U16)argv[(U16)argc-1]],"hex") == GOOD) {
            stackFormat = STK_DISPLAY_HEX;
            if ((error = InitSessionForCli(&sessionId)) != GOOD)
               return error;
         }
      }
      if ((error = StkGetDescFromName(&cmdString[(U16)argv[1]],
            &sessionId)) == GOOD)
         stackFormat = STK_DISPLAY_FUNC_SYMBOLICS;
      else
         return error;
   }
   if (argc == 2) {
      /*
      **  compare the last parameter to keywords
      */
      if (strcmpi(&cmdString[(U16)argv[(U16)argc-1]],"locals") == GOOD) {
         stackFormat = STK_DISPLAY_LOCAL_SYMBOLICS;
         if ((error = InitSessionForCli(&sessionId)) != GOOD)
            return error;
      }
      else {
         if (strcmpi(&cmdString[(U16)argv[(U16)argc-1]],"hex") == GOOD) {
            stackFormat = STK_DISPLAY_HEX;
            if ((error = InitSessionForCli(&sessionId)) != GOOD)
               return error;
         }
         else {
            if ((error = StkGetDescFromName(&cmdString[(U16)argv[
                  (U16)argc-1]],&sessionId)) == GOOD)
               stackFormat = STK_DISPLAY_FUNC_SYMBOLICS;
            else
               return error;
         }
      }
   }
   else if (argc == 1) {
      if ((error = InitSessionForCli(&sessionId)) != GOOD)
         return error;
      stackFormat = STK_DISPLAY_FUNC_SYMBOLICS;
   }
   if ((error = StkOpenStack(&numOfFrames,sessionId)) != GOOD)
      return error;
   while ((framesDisplayed < numOfFrames) && (!AbortOperation())) {
      if ((numOfFrames - framesDisplayed) < STK_MAX_FRAMES_PER_BUF)
          endFrameOffset = framesDisplayed + (numOfFrames -
                 framesDisplayed) - 1;
      else
         endFrameOffset = framesDisplayed + STK_MAX_FRAMES_PER_BUF - 1;
      switch (stackFormat) {
         case STK_DISPLAY_FUNC_SYMBOLICS :
            if ((error = StkReadFrameN(sessionId,framesDisplayed,
                  endFrameOffset,FALSE,&bufPtr))
                  != GOOD)
               return error;
            break;
         case STK_DISPLAY_LOCAL_SYMBOLICS :
            if ((error = StkReadFrameNAndLocals(sessionId,framesDisplayed,
                  endFrameOffset,FALSE,&bufPtr)) != GOOD)
               return error;
            break;
         case STK_DISPLAY_HEX :
            if ((error = StkReadFrameHex(sessionId,framesDisplayed,
                  endFrameOffset,&bufPtr)) != GOOD)
               return error;
            break;
      }
      framesDisplayed += STK_MAX_FRAMES_PER_BUF;
      if ((error = SendCliResults((LPSTR)bufPtr->text,cliServerHandle)) != GOOD) {
         FreeStkBuf(bufPtr);
         return error;
      }
      if ((error = FreeStkBuf(bufPtr)) != GOOD)
         return error;
   }
   return GOOD;
}

/******************************************************************************
**
**   EnableAlarmLimit
**
**   Purpose:
**      To enable the alarm limit which can generate an alarm condition.
**
**   Input parameters:
**      cmdString : the CLI command string
**      argc : number of arguments in command string
**      argv : array of pointers to the arguments
**
**   Output parameters:
**      none
**
**   Error:
**
******************************************************************************/
RETCODE EXPORT  EnableAlarmLimit(LPSTR cmdString, U32 argc, U32 argv[]) {
   RETCODE error;
   DESCRIPTOR sessionId;

   if (argc > 1)
      return ER_CLI_SYNTAX;
   if (argc == 2) {
      if ((error = StkGetDescFromName(&cmdString[(U16)argv[(U16)argc-1]],
            &sessionId)) != GOOD)
         return error;
   }
   else {
      if ((error = InitSessionForCli(&sessionId)) != GOOD)
         return error;
   }
   if ((error = StkEnableAlarmLimit(sessionId)) != GOOD)
      return error;
   /* Notify clients */
   if ((error = EnlEventNotify(EVENT_STK_ALARM_ENABLED)) != GOOD)
      return error;
   return GOOD;
}


/******************************************************************************
**
**   EnableHighWaterMark
**
**   Purpose:
**      To enable the high water mark which can generate an alarm condition.
**
**   Input parameters:
**      cmdString : the CLI command string
**      argc : number of arguments in command string
**      argv : array of pointers to the arguments
**
**   Output parameters:
**      none
**
**   Error:
**
******************************************************************************/
RETCODE EXPORT  EnableHighWaterMark(LPSTR cmdString, U32 argc, U32 argv[]) {

   RETCODE error;
   DESCRIPTOR sessionId;

   if (argc > 1)
      return ER_CLI_SYNTAX;
   if (argc == 2) {
      if ((error = StkGetDescFromName(&cmdString[(U16)argv[(U16)argc-1]],
            &sessionId)) != GOOD)
         return error;
   }
   else {
      if ((error = InitSessionForCli(&sessionId)) != GOOD)
         return error;
   }
   /* Enable HWM also cause the stack to fill before it can be calculated */
   if ((error = StkEnableHighWaterMark(sessionId)) != GOOD)
      return error;
   /* Notify clients */
   if ((error = EnlEventNotify(EVENT_STK_HWM_ENABLED)) != GOOD)
      return error;
   return GOOD;
}


/******************************************************************************
**
**   FillStackPattern
**
**   Purpose:
**      To initialize the stack area to a special pattern such as 55AA.
**
**   Input parameters:
**      cmdString : the CLI command string
**      argc : number of arguments in command string
**      argv : array of pointers to the arguments
**
**   Output parameters:
**      none
**
**   Error:
**      Returns ER_CLI_SYNTAX.
**      Returns ER_STK_INIT_STK_FAIL if the initialization fails due
**      to unknown stack base or size, or failure to write memory.
**
******************************************************************************/
RETCODE EXPORT  FillStackPattern(LPSTR cmdString, U32 argc, U32 argv[]) {

   RETCODE error;
   DESCRIPTOR sessionId;
   DESCRIPTOR baseAddr;
   U32 stackSize;
   BOOLEAN isValid;


   if (argc > 1)
      return ER_CLI_SYNTAX;
   if (argc == 2) {
      if ((error = StkGetDescFromName(&cmdString[(U16)argv[(U16)argc-1]],
            &sessionId)) != GOOD)
         return error;
   }
   else {
      if ((error = InitSessionForCli(&sessionId)) != GOOD)
         return error;
   }
   if ((error = StkGetStackBase(sessionId,&baseAddr,&isValid)) != GOOD)
      return error;
   if (!isValid) {
      return ER_STK_STK_BASE_INVALID;
   }
   if ((error = StkGetStackSize(sessionId,&stackSize)) != GOOD)
      return error;
   if ((error = StkSetStackToPattern(baseAddr,stackSize))
         != GOOD)
      return error;

   /* notify interested parties that the stack has changed */
   if ((error = EnlEventNotify(EVENT_STK_STACK_CHANGED)) != GOOD)
      return error;

   return GOOD;
}

/***********************************************************************
**
** FreeStkBuf
**
*************************************************************************/
RETCODE PRIVATE FreeStkBuf(STK_DISPLAY_PTR displayBufPtr) {

   LPWORD bufptr;
   RETCODE error;

   bufptr = (LPWORD)displayBufPtr;
   if (*bufptr == STK_TMALLOC) {
      if ((error = TFree((LPSTR)(LPSTR)displayBufPtr)) != GOOD)
         return error;
   }
   else
      GlobalFree(*bufptr);

   return GOOD;
}

/************************************************************************
**
**   InitSessionForCli
**
**   Get the default stack's session id or create a new stack context
**   for the CLI in the stack server.
**
*************************************************************************/
RETCODE InitSessionForCli(DESCRIPTOR *sessionId) {
   RETCODE retcode;

   if ((*sessionId = StkGetDefaultSessionId()) == NULL) {
      if (defaultSessionId == NULL) {
       /* Create a new session will set the defaultSessionId */
       if ((retcode = StkStartSession(cliServerHandle, sessionId))
               != GOOD)  return retcode;
      }
      else 
         *sessionId = defaultSessionId;
   }
   return GOOD;
}


/************************************************************************
**
**   InitCServer :
**   Register stack server with CLI.
**
*************************************************************************/
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 = 30;
   msgBufPtr->dllNameIndex = 31;
   msgBufPtr->numberOfCommandsIndex = 32;
   msgBufPtr->commandStartIndex = 33;
   SendMessage(cliHandle, CLI_NEW_SVR_REGISTRATION, CLI_NEW_SVR_REGISTRATION,
      (DWORD)msgBufPtr);
   return(GOOD);
}  /* InitCServer */


/***************************************************************************
**
**   SendCliResults :
**
**************************************************************************/
RETCODE PRIVATE SendCliResults(LPSTR results, HANDLE server) {
   CSERVER_RESULTS FAR * msgBufPtr;
   DESCRIPTOR msgBufHandle;
   U16 msgTextSize;

   msgTextSize = lstrlen(results);
   if ((msgBufHandle = GlobalAlloc(STACK_WFLAGS,(sizeof(CSERVER_RESULTS) +
         msgTextSize + 2))) == NULL)
      return(ER_OUT_OF_MEMORY);
   if((msgBufPtr=(CSERVER_RESULTS FAR *)GlobalLock((HANDLE) msgBufHandle)) 
                  == NULL) return(ER_WINDOWS_MEMLOCK);
   msgBufPtr->target = 0;
   msgBufPtr->variantCode = 0x401;
   msgBufPtr->resultTextLength = msgTextSize;
   lstrcpy(msgBufPtr->messageText,results);
   if( SendMessage(server, 0x401, (S16)msgBufHandle, 0x401L) )
      return(GOOD);
   return(ER_STK_SEND_MESSAGE_FAILED);
}

/******************************************************************************
**
**   SetStackAlarm
**
**   Purpose:
**      To set the stack alarm limit(must be between stackbase +/- stacksize).
**
**   Inpput parameters:
**      cmdString : the CLI command string
**      argc : number of arguments in command string
**      argv : array of pointers to the arguments
**
**   Output parameters:
**      none
**
**   Error:
**
******************************************************************************/
RETCODE EXPORT  SetStackAlarm(LPSTR cmdString, U32 argc, U32 argv[]) {

   RETCODE error;
   DESCRIPTOR sessionId;
   S8 *endptr;
   U32 percent;

   if (argc != 2)
      return ER_CLI_SYNTAX;
   if (argc == 3) {
      if ((error = StkGetDescFromName(&cmdString[(U16)argv[1]],
            &sessionId)) != GOOD)
         return error;
   }
   if (argc == 2) {
      if ((error = InitSessionForCli(&sessionId)) != GOOD)
         return error;
   }
   percent = strtoul(&cmdString[(U16)argv[(U16)argc-1]],&endptr,0);
   /* percent must be from 1 to 100 */
   if ((percent < 1L) && (percent > 100))
      return(ER_STACK_ALARM_RANGE);
   
   if ((error = StkSetAlarmLimitPercent(sessionId, percent)) != GOOD)
      return error;

   /* Notify clients */
   if ((error = EnlEventNotify(EVENT_STK_ALARM_CHANGE)) != GOOD)
      return error;
   return GOOD;
}

/******************************************************************************
**
**   SetStackBase
**
**   Purpose:
**      To set the stack base pointer.
**
**   Input parameters:
**      cmdString : the CLI command string
**      argc : number of arguments in command string
**      argv : array of pointers to the arguments
**
**   Output parameters:
**      none
**
**   Error:
**
******************************************************************************/
RETCODE EXPORT SetStackBase(LPSTR cmdString, U32 argc, U32 argv[]) {
   RETCODE error;
   DESCRIPTOR tmpAddr;
   DESCRIPTOR sessionId;

   if (argc < 2)
      return ER_CLI_SYNTAX;
   if (argc == 3) {
      if ((error = StkGetDescFromName(&cmdString[(U16)argv[1]],
         &sessionId)) != GOOD)  return error;
   }
   if (argc == 2)
      if ((error = InitSessionForCli(&sessionId)) != GOOD)
         return error;
   if ((error = CpuGetSP(&tmpAddr)) != GOOD)
      return error;
   if ((error = AdrSetAddrSymbolUsage(tmpAddr,FALSE)) != GOOD)
      return error;
   if ((error = AdrConvTextToAddress(tmpAddr,&cmdString[(U16)argv[
                (U16)argc-1]])) != GOOD) {
      AdrDestroyAddress(tmpAddr);
      return error;
   }
	/* StkSetStackBase also recalculate the AlarmLimit */
	if ((error = StkSetStackBase(sessionId,tmpAddr)) != GOOD) {
      AdrDestroyAddress(tmpAddr);
      return error;
   }
   /* notify interested parties that the stack has changed */
   if ((error = EnlEventNotify(EVENT_STK_BASE_SIZE_AVAIL)) != GOOD)
      return error;

   return GOOD;
}

/******************************************************************************
**
**   SetStackSize
**
**   Purpose:
**      To set the stack size.
**
**   Input parameters:
**      cmdString : the CLI command string
**      argc : number of arguments in command string
**      argv : array of pointers to the arguments
**
**   Output parameters:
**      none
**
**   Error:
**      ER_CLI_SYNTAX or
**      ER_CLI_SYNTAX or
**      ER_STK_INVALID_STK_SIZE
**
******************************************************************************/
RETCODE EXPORT  SetStackSize(LPSTR cmdString, U32 argc, U32 argv[]) {
   RETCODE error;
   U32 stackSize;
   DESCRIPTOR sessionId;
   STRING tempStr;
   S8 *endPtr;
 
   if (argc != 2)
      return ER_CLI_SYNTAX;
   if (argc == 3) {
      if ((error = StkGetDescFromName(&cmdString[(U16)argv[1]],
            &sessionId)) != GOOD)
         return error;
   }
   if (argc == 2)
      if ((error = InitSessionForCli(&sessionId)) != GOOD)
         return error;
   tempStr = (STRING)&cmdString[(U16)argv[(U16)argc-1]];

   if ((stackSize = strtoul((LPSTR)tempStr,&endPtr,0)) == 0)
      return ER_STK_INVALID_STK_SIZE;

	/* StkSetStackSize() also recalculate the alarm limit */
   if ((error = StkSetStackSize(sessionId,stackSize)) != GOOD)
      return error;

   /* notify interested parties that the stack has changed */
   if ((error = EnlEventNotify(EVENT_STK_BASE_SIZE_AVAIL)) != GOOD)
      return error;

   return GOOD;
}

/******************************************************************************
**
**   SetStackBaseAndSize
**
**   Purpose:
**      To set the stack base pointer and size.
**
**   Input parameters:
**      cmdString : the CLI command string
**      argc : number of arguments in command string
**      argv : array of pointers to the arguments
**
**   Output parameters:
**      none
**
**   Error:
**
******************************************************************************/
RETCODE EXPORT  SetStackArea(LPSTR cmdString, U32 argc, U32 argv[]) {
   RETCODE err;
   DESCRIPTOR sessionId;
   DESCRIPTOR stkAddr;
   U32 stkSize;
   U16 optIdx = 0;
   STK_CONTEXT *contextPtr;
   BOOLEAN isEnabled = TRUE, fillArea = FALSE;
   STRING tempStr;
   S8 *endPtr;

   if (argc > 5)
      return(ER_CLI_SYNTAX);

   /* Parsing the command */
   switch (argc) {
      /* Both stack session name and "fillArea" present */
      case 5:
         if (strcmpi(&cmdString[(U16)argv[(U16)argc-1]],"fillArea") != GOOD)
            return(ER_CLI_SYNTAX);
         if ((err = StkGetDescFromName(&cmdString[(U16)argv[1]], &sessionId))
            != GOOD)
            return err;
         break;
	   
      /* Atleast one of the stack session name or "fillArea" presents */
      case 4 :
         if (strcmpi(&cmdString[(U16)argv[(U16)argc-1]],"fillArea") != GOOD) {
            /* It must be stack session name or else it's syntax error */
            if ((err = StkGetDescFromName(&cmdString[(U16)argv[1]], 
                       &sessionId)) != GOOD) return err;
         } else {
            fillArea = TRUE;
            optIdx = 1;
            /* Let get the default session or create one if none available */
            if ((err = InitSessionForCli(&sessionId)) != GOOD) return(err);
         }
         break;
      /* Only <command> <addr> <size> */
      case 3 :
         if ((err = InitSessionForCli(&sessionId)) != GOOD)
            return err;
         break;
      /* Dump the stack area info -  use the stackInfo command */
      case 1 :
         return(StackInfo((LPSTR)NULL, 1, 0L));
	}
	/* Get the base address and size and do the real work here */
   if ((err = CpuGetSP(&stkAddr)) != GOOD)
      return err;
   if ((err = AdrSetAddrSymbolUsage(stkAddr, FALSE)) != GOOD)
      return err;
   if ((err = AdrConvTextToAddress(stkAddr, &cmdString[(U16)argv[
              (U16)argc-2-optIdx]])) != GOOD) {
      AdrDestroyAddress(stkAddr);
      return err;
   }
    /* Stack Size */
   tempStr = (STRING)&cmdString[(U16)argv[(U16)argc-1-optIdx]];
   if ((stkSize = strtoul((LPSTR)tempStr, &endPtr,0)) == 0)
      return(ER_STK_INVALID_STK_SIZE);		
	/* Fill the stack area as user requested, even HWM is not enabled */
	contextPtr = (STK_CONTEXT *)sessionId;
	if ((fillArea) && (!contextPtr->isHighWaterMarkEnabled)) {
		/* Change the HWM enable flag to do the fill */
        isEnabled = FALSE;
		contextPtr->isHighWaterMarkEnabled = TRUE;
	}
	/* Set new base and size and fill the area if needed */
   err = StkSetStackBaseAndSize(sessionId, stkAddr, stkSize);
  
   /* Restore the HWM flag if it's previously disabled else don't need to */
    if ((fillArea) && (!isEnabled))
		contextPtr->isHighWaterMarkEnabled = FALSE;
   if (err != GOOD)
	   return(err);
	
   /* notify interested parties that the stack has changed */
   if ((err = EnlEventNotify(EVENT_STK_BASE_SIZE_AVAIL)) != GOOD)
      return(err);
   return(GOOD);
}

/******************************************************************************
**
**   StackInfo
**
**   Purpose:
**      To display general stack information: stack base, stack size, current
**      stack pointer, number of frames, alarm limit, high water mark, and
**      growth direction of the stack.
**
**   Input parameters:
**      cmdString : the CLI command string
**      argc : number of arguments in command string
**      argv : array of pointers to the arguments
**
**   Output parameters:
**      none
**
**   Error:
**
******************************************************************************/
RETCODE EXPORT  StackInfo(LPSTR cmdString, U32 argc, U32 argv[]) {

   RETCODE error;
   STRING string,textPtr;
   DESCRIPTOR stkAddr;
   DESCRIPTOR sessionId;
   BOOLEAN isValid,isEnabled,
           stackBaseValid,activated;
   U8 tmpBuf[MAX_CHARS_PER_LINE];
   U32 stackSize;
   U32 percent;

   if (argc > 2) 
      return ER_CLI_SYNTAX;
   if (argc == 2) {
      if ((error = StkGetDescFromName(&cmdString[(U16)argv[(U16)argc-1]],
            &sessionId)) != GOOD)
         return error;
   }
   if (argc == 1)
      if ((error = InitSessionForCli(&sessionId)) != GOOD)
         return error;
   if ((string = (STRING)TMalloc(MAX_CHARS_PER_LINE *
         LINES_FOR_STACK_INFO)) == NULL)
      return ER_OUT_OF_MEMORY;
   textPtr = string;
   memset(textPtr,'\0',MAX_CHARS_PER_LINE * LINES_FOR_STACK_INFO);
   lstrcat((LPSTR)textPtr,"stack base = ");
   if ((error = StkGetStackBase(sessionId,&stkAddr,&isValid)) != GOOD) {
      TFree((LPSTR)string);
      return error;
   }
   if (isValid) {
      stackBaseValid = TRUE;
      if ((error = AdrConvAddressToText(stkAddr,(LPSTR)tmpBuf)) != GOOD) {
         AdrDestroyAddress(stkAddr);
         TFree((LPSTR)string);
         return error;
      }
      lstrcat((LPSTR)textPtr,(LPSTR)tmpBuf);
      if ((error = AdrDestroyAddress(stkAddr)) != GOOD)
         return error;
   }
   else {
      stackBaseValid = FALSE;
      lstrcat((LPSTR)textPtr,"unknown");
   }
   GetEndOfLine(&textPtr);
   lstrcat((LPSTR)textPtr,"size = ");
   textPtr += strlen((LPSTR)textPtr);
   if ((error = StkGetStackSize(sessionId,&stackSize)) != GOOD) {
      TFree((LPSTR)string);
      return error;
   }
   /* Print out size in decimal */
   wsprintf((LPSTR)textPtr,"%lu",stackSize);
   GetEndOfLine(&textPtr);
   lstrcat((LPSTR)textPtr,"current stack pointer = ");
   if ((error = CpuGetSP(&stkAddr)) != GOOD)  {
      TFree((LPSTR)string);
      return error;
   }
   if ((error = AdrConvAddressToText(stkAddr,(LPSTR)tmpBuf)) != GOOD) {
      AdrDestroyAddress(stkAddr);
      TFree((LPSTR)string);
      return error;
   }
   lstrcat((LPSTR)textPtr,(LPSTR)tmpBuf);
   GetEndOfLine(&textPtr);
   if ((error = AdrDestroyAddress(stkAddr)) != GOOD)
      return error;
   lstrcat((LPSTR)textPtr,"alarm limit = ");
   if ((error = StkGetAlarmLimit(sessionId,&stkAddr,&percent,
         &isValid,&isEnabled)) != GOOD) {
      TFree((LPSTR)string);
      return error;
   }
   itoa((S16)percent,(LPSTR)tmpBuf,10);
   lstrcat((LPSTR)textPtr,(LPSTR)tmpBuf);
   lstrcat((LPSTR)textPtr,"%");
   if (isEnabled)  {
      lstrcat((LPSTR)textPtr,", ENABLED");
      if ((error = StkGetAlarmState(sessionId,&activated)) != GOOD)
         return error;
      if (activated)
         lstrcat((LPSTR)textPtr,"  *** WARNING *** STACK ALARM ACTIVATED!!!");
   }
   else
      lstrcat((LPSTR)textPtr,", DISABLED");

/* Winky 11/20/97 : remove "high water mark" message */
/*
   GetEndOfLine(&textPtr);
   if ((error = AdrDestroyAddress(stkAddr)) != GOOD)
      return error;
   lstrcat((LPSTR)textPtr,"high water mark = ");
   if (stackBaseValid) {
      if ((error = StkGetHighWaterMark(sessionId,&stkAddr,&isEnabled))
             != GOOD) {
         TFree((LPSTR)string);
         return error;
      }
      if (isEnabled) {
         if ((error = AdrSetAddrSymbolUsage(stkAddr,FALSE)) != GOOD)
            return error;
         if ((error = AdrConvAddressToText(stkAddr,(LPSTR)tmpBuf)) != GOOD) {
            AdrDestroyAddress(stkAddr);
            TFree((LPSTR)string);
            return error;
         }
         lstrcat((LPSTR)textPtr,(LPSTR)tmpBuf);
         lstrcat((LPSTR)textPtr,", ENABLED");         
      }
      else
         lstrcat((LPSTR)textPtr,"DISABLED");
      if ((error = AdrDestroyAddress(stkAddr)) != GOOD)
         return error;
   }
   else
      lstrcat((LPSTR)textPtr,"unknown");
*/
 /*  EOF Winky 11/20/97     */

   GetEndOfLine(&textPtr);
   lstrcat((LPSTR)textPtr,"stack type = ");
   if (stackSex == HI_TO_LOW)
      lstrcat((LPSTR)textPtr,"high to low");
   else
      lstrcat((LPSTR)textPtr,"low to high");
   GetEndOfBuffer(&textPtr);

   if ((error = SendCliResults((LPSTR)string,cliServerHandle)) != GOOD) {
      FreeStkBuf((STK_DISPLAY_PTR)string);
      return error;
   }

   return(FreeStkBuf((STK_DISPLAY_PTR)string));
}

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