/* CLASS: StkLibInst   StkLibinst
   Provide multiple instances of the StackLib
   All instance address variables are addressDescriptor or nil. 
*/!!

inherit(StackLib, #StkLibInst, #(sessionID /* id of stack session */
), 2, nil)!!

now(class(StkLibInst))!!

/* 3/2/1992 17:06 - semiPRIVATE 
  called by StackLib:openSession() only */
Def new(self, hWnd)
{
  ^initialize( new(self:ancestor), hWnd )
}

!!

now(StkLibInst)!!

/* 3/17/1994 11:19 - PUBLIC
  Destroy the input stack's address descriptor if not nil.
*/
Def destroy(self, addrDesc)
{ 
  if addrDesc then
    ^destroyAddress(AddressLibClass$Inst, addrDesc);
  endif;
  ^GOOD;
}
!!

/* 07/14/93 - 08:30 - PUBLIC 
  Set the current stack context alarm percent.
*/
Def setAlarmLimitPercent(self, setAlarmPercent)
{ 
  if pcallLock(self)
  then
    lastError = pcall( procs[#STKSETALARMLIMITPERCENT], sessionID, setAlarmPercent);
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION ;
  endif ;

  if (lastError <> GOOD) then
    displayError(ErrorTextLibClass$Inst,lastError, CHECK_MODE);
    ^nil;
  endif;
  ^GOOD;
}
!!

/* 3/3/1992 15:14 - PUBLIC 
  Set stack base address and stack size, destroy the input addrDesc.
  NOTES: stkBaseDesc is consumed by Stack Server.
*/
Def setStackBaseAndSize(self, stkBaseDesc, stkSize )
{   
  /* Set stack base for server */    
  if pcallLock(self)
  then
    lastError = pcall( procs[#STKSETSTACKBASEANDSIZE], sessionID, stkBaseDesc, 
                       stkSize);
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION ;
  endif ;
  if (lastError <> GOOD) then
    displayError(ErrorTextLibClass$Inst,lastError, CHECK_MODE);
    ^nil;
  endif; 
  ^GOOD;
}
!!

/* 7/1/1993 14:07 - PUBLIC
  Get all stack session information in one shot.
  if success return tuple of stack info else return nil; 
  NOTES: #(currentSP, baseAddr, stackSize, alarmPercent, alarmLimit, 
    enableStkAlarm, hwMarkAddr, enableStkHWMark, validBaseAddr, lowToHigh); 
*/
Def getStackInfo(self | 
  stkBasePtr, isBaseValidPtr, stkSizePtr, alarmLimitPtr,
  alarmPercentPtr, isAlarmValidPtr, isAlarmEnabledPtr,
  hwmPtr, isHWMEnabledPtr, directionPtr, currentSP,
  alarmAddr, hwMarkAddr)
{ 
  if not(currentSP := getStackPointer(CpuLibClass$Inst)) 
    ^nil;
  endif;
  stkBasePtr        := new(Struct, 4);
  isBaseValidPtr    := new(Struct, 2);
  stkSizePtr        := new(Struct, 4);
  alarmLimitPtr     := new(Struct, 4);
  alarmPercentPtr   := new(Struct, 4);
  isAlarmValidPtr   := new(Struct, 2);
  isAlarmEnabledPtr := new(Struct, 2);
  hwmPtr            := new(Struct, 4);
  isHWMEnabledPtr   := new(Struct, 2);
  directionPtr      := new(Struct, 4);

  if pcallLock(self)
  then
    lastError := pcall(procs[#STKGETSTACKINFO], sessionID, 
        stkBasePtr, isBaseValidPtr, stkSizePtr,
        alarmLimitPtr, alarmPercentPtr, isAlarmValidPtr, 
        isAlarmEnabledPtr, hwmPtr, isHWMEnabledPtr,
        directionPtr);
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION ;
  endif ;
  /* Error if base is not valid */
  if (lastError <> GOOD) then 
    displayError(ErrorTextLibClass$Inst,lastError, CHECK_MODE);
    ^nil;
  endif;
  
  alarmAddr := longAt(alarmLimitPtr,0);
  if (wordAt(isAlarmValidPtr, 0) = BOOL_FALSE) then
    destroyAddress(AddressLibClass$Inst, alarmAddr);
    alarmAddr := nil;  
  endif;  

  hwMarkAddr := longAt(hwmPtr,0);
  if (wordAt(isHWMEnabledPtr, 0) = BOOL_TRUE) then
    destroyAddress(AddressLibClass$Inst, hwMarkAddr);
    hwMarkAddr := nil;
  endif;  
  /* return tuple of information */
  ^tuple(currentSP,
         longAt(stkBasePtr,0),          /* stack Base addrDesc */
         longAt(stkSizePtr, 0),         /* stack size */
         longAt(alarmPercentPtr, 0),    /* Alarm stuffs */
         alarmAddr,
         wordAt(isAlarmEnabledPtr, 0),
         hwMarkAddr,                    /* HighWaterMark stuffs */
         wordAt(isHWMEnabledPtr, 0),  
         wordAt(isBaseValidPtr, 0),  
         byteAt(directionPtr, 0));      /* stack direction */
}
!!

/* 3/2/1992 17:07 - PUBLIC
  opensesion() is defined in StackLib
 */
Def closeSession(self)
{
  if open?(self) then
    if pcallLock(self) then
      lastError := pcall(procs[#STKENDSESSION], sessionID) ;
      pcallUNLock(self);
    else 
      lastError := ERR_PCALL_RECURSION ;
    endif ; 
  else
    ^nil
  endif;

  if (lastError <> GOOD) then
    displayError(ErrorTextLibClass$Inst,lastError,FORCE_POPUP);
    ^nil;
  endif;
  sessionID := nil;
  ^GOOD;    
}
!!

/* 3/3/1992 11:21 - PUBLIC */
Def disableAlarmLimit(self)
{ 
  if pcallLock(self)
  then
    lastError := pcall(procs[#STKDISABLEALARMLIMIT], sessionID) ;
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION ;
  endif ;

  if (lastError <> GOOD) then
     displayError(ErrorTextLibClass$Inst,lastError,FORCE_POPUP);
     ^nil;
  endif;
  ^GOOD;    
}
!!

/* 3/3/1992 12:14 - PUBLIC*/
Def disableHighWaterMark(self)
{ 
  if pcallLock(self)
  then
    lastError := pcall(procs[#STKDISABLEHIGHWATERMARK], sessionID);
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION ;
  endif ;

  if (lastError <> GOOD) then
     displayError(ErrorTextLibClass$Inst,lastError, CHECK_MODE);
     ^nil;
  endif;    
  ^GOOD;    
}


!!

/* 3/3/1992 12:14 - PUBLIC*/
Def enableAlarmLimit(self)
{ 
  if pcallLock(self)
  then
    lastError := pcall(procs[#STKENABLEALARMLIMIT], sessionID);
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION ;
  endif ;

  if (lastError <> GOOD) then
    displayError(ErrorTextLibClass$Inst,lastError, CHECK_MODE);
    ^nil;
  endif;
  ^GOOD;
}


!!

/* 3/3/1992 12:14 - PUBLIC*/
Def enableHighWaterMark(self)
{ 
  if pcallLock(self)
  then
    lastError := pcall(procs[#STKENABLEHIGHWATERMARK], sessionID);
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION ;
  endif ;

  if (lastError <> GOOD) then
    if (lastError <> ER_STK_FILL_STACK_AREA) then
      displayError(ErrorTextLibClass$Inst,lastError, CHECK_MODE);
    endif;  
    ^nil;
  endif;
  ^GOOD;    
}


!!

/* 3/3/1992 13:31 - PUBLIC 
  Return nil or tuple = #(alarmEnableState, alarmLimit, alarmPrecent).
  NOTES:
    - alarmLimit is an address descriptor - Caller need to destroy it when done.
*/
Def getAlarmLimit(self | alarmLimitPtr, alarmPercentPtr, isValid, isEnabled)
{ 
  /* Stack Alarm enable, so get new value - else return old value */
  alarmLimitPtr   := new(Struct, 4);
  alarmPercentPtr := new(Struct, 4);
  isValid         := new(Struct, 2);
  isEnabled       := new(Struct, 2);

  if pcallLock(self) then
    lastError := pcall( procs[#STKGETALARMLIMIT], sessionID, 
                       alarmLimitPtr, alarmPercentPtr, isValid, isEnabled);
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION ;
  endif ;
  if (lastError <> GOOD) then
    displayError(ErrorTextLibClass$Inst,lastError, CHECK_MODE);
    destroyAddress(AddressLibClass$Inst, longAt(alarmLimitPtr,0)); 
    ^nil;
  endif;
  if (byteAt(isValid, 0) = BOOL_FALSE) 
    ^nil;
  endif;   
  ^tuple(byteAt(isEnabled, 0), longAt(alarmLimitPtr,0), longAt(alarmPercentPtr, 0)); 
}
!!

/* 3/3/1992 16:20 - PUBLIC 
  Return a #true or nil value for Alarm enable or disable.
*/
Def getAlarmState(self | alarmStatePtr)
{ 
  alarmStatePtr := new( Struct, 2 );
  if pcallLock(self) then
    lastError := pcall( procs[#STKGETALARMSTATE], sessionID, 
                          alarmStatePtr);
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION ;
  endif ;

  if (lastError <> GOOD) then
     displayError(ErrorTextLibClass$Inst,lastError, CHECK_MODE);
     ^nil;
  endif; 
  /* Boolean value */ 
  ^(wordAt(alarmStatePtr, 0));
}
!!

/* 3/3/1992 13:31 - PUBLIC 
  Return a TextCollection of stack frame start from startF to endF.
  Text format from the displayBufPtr is:
    [<Stack Addr:8><Code Addr:8><FuncName:{max:256}>+CR+LF]...
 */
Def getFrame(self, startF, endF | displayBufPtr)
{ 
  displayBufPtr := new(Struct, 4);
  if pcallLock(self) then
    lastError := pcall( procs[#STKREADFRAMEN], sessionID, startF, endF,
                        0 /* Batch Mode */, displayBufPtr);
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION ;
  endif ;

  if (lastError <> GOOD) then
    displayError(ErrorTextLibClass$Inst,lastError, CHECK_MODE);
    ^nil;
  endif;
  /* Get the text into a TextCollection for the caller */
  ^getTextFromAddr(self,longAt(displayBufPtr, 0));
}
!!

/* 3/9/1992 13:05 - PUBLIC 
  Return the BOOL_TRUE if stack frames exist or nil */
Def anyFrames(self | frameNumPtr )
{ 
  /* Default to get all frame - eventhough, some do not have symbol */
  frameNumPtr := new(Struct, 2);
  if pcallLock(self) then
    lastError := pcall(procs[#STKANYFRAMES], sessionID, frameNumPtr);
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION ;
  endif;
  if (lastError <> GOOD) then
    displayError(ErrorTextLibClass$Inst,lastError, CHECK_MODE);
    ^nil;
  endif;
  ^wordAt(frameNumPtr, 0);  
}
!!

/* 3/6/1992 13:27 - PUBLIC 
  Return a tupple of information of the specified stack frame number.
  RETURN: #(symDesc, moduleDesc, addrDesc) 
*/
Def getFrameInfo(self, frameNum | symDescPtr, moduleDescPtr, addrDescPtr)
{ 
  symDescPtr := new(Struct, 4);
  moduleDescPtr := new(Struct, 4);
  addrDescPtr := new(Struct, 4);
  if pcallLock(self) then
    lastError := pcall( procs[#STKGETFRAMESYMBOL], sessionID, 
                     asInt(frameNum), symDescPtr, moduleDescPtr, addrDescPtr);
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION ;
  endif ;

  if (lastError <> GOOD) then  
    displayError(ErrorTextLibClass$Inst,lastError, CHECK_MODE);
    ^nil;
  endif;
  /* RETURN: #(symDesc, moduleDesc, addrDesc) */
  ^tuple(longAt(symDescPtr, 0), longAt(moduleDescPtr, 0), longAt(addrDescPtr, 0));   
}
!!

/* 3/3/1992 13:31 - PUBLIC 
  Return a SYM_DESCRIPTOR of the first local symbol. Use getSymbolSibling()
  of the SymbolLib Class to extract all the symbol, go until NULL_SYMBOL
  is returned.  
 */
Def getFrameLocals(self, frameId | numParamPtr, firstLocalPtr)
{ 
  numParamPtr := new(Struct, 2);
  firstLocalPtr := new(Struct, 4);
  if pcallLock(self) then
    lastError := pcall( procs[#STKREADFRAMELOCALS], sessionID, 
                        asInt(frameId), numParamPtr, firstLocalPtr);
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION ;
  endif ;

  if (lastError <> GOOD) then
    displayError(ErrorTextLibClass$Inst,lastError, CHECK_MODE);
    ^nil;
  endif;
  /* RETURN: #(SYM_DESC, numParam) */
  ^tuple(longAt(firstLocalPtr, 0), byteAt(numParamPtr,0)); 
}
!!

/* 3/3/1992 13:31 - PUBLIC 
  Return the stack HWM address descriptor or nil.
  NOTES:
    Caller must destroy the returned descriptor when done.
*/
Def getHighWaterMark(self | hwMarkPtr, enablePtr)
{ 
  hwMarkPtr := new( Struct, 4 );
  enablePtr := new( Struct, 2 );
  if pcallLock(self) then
    lastError := pcall( procs[#STKGETHIGHWATERMARK], sessionID, 
                          hwMarkPtr, enablePtr);
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION ;
  endif ;

  if  (lastError <> GOOD) then
    displayError(ErrorTextLibClass$Inst,lastError, CHECK_MODE);    
    ^nil;
  endif;
  
  /* if highwater mark is enabled */
  if (byteAt(enablePtr, 0) = BOOL_FALSE) then
    displayFormattedError(ErrorTextLibClass$Inst, 
       ER_STACK_HW_DISABLED, FORCE_POPUP, nil, nil, nil);
    destroyAddress(AddressLibClass$Inst, longAt(hwMarkPtr, 0)); 
    ^nil;
  endif;  
  ^longAt(hwMarkPtr,0);
}
!!

/* 3/3/1992 13:31 - PUBLIC 
  Return stack base address descriptor or nil.
  NOTES:
    Caller must destroy the returned descriptor when done.
 */
Def getStackBase(self | stkBasePtr, isValidPtr)
{ 
  stkBasePtr := new( Struct, 4 );
  isValidPtr := new( Struct, 2 );
  if pcallLock(self) then
    lastError := pcall( procs[#STKGETSTACKBASE], sessionID, 
                        stkBasePtr, isValidPtr);
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION ;
  endif ;

  if ((lastError <> GOOD) cand (wordAt(isValidPtr, 0) = BOOL_FALSE)) then
    displayError(ErrorTextLibClass$Inst,lastError, CHECK_MODE);
    destroyAddress(AddressLibClass$Inst, longAt(stkBasePtr, 0));
    ^nil;
  endif;
  /* stack Base is valid */
  ^longAt(stkBasePtr,0); 
}
!!

/* 3/11/1992 10:13 - PUBLIC 
  If dirPrt is 1 if stack direction is high->low, else 0 is lowToHigh.
  return nil if error.
*/
Def getStackDirection(self | directionRef)
{ 
  directionRef := new(Struct, 4);
   
  if pcallLock(self) then
    lastError := pcall( procs[#STKGETSTACKDIRECTION], sessionID, directionRef);
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION ;
  endif ;

  if (lastError <> GOOD) then
    displayError(ErrorTextLibClass$Inst,lastError, CHECK_MODE);
    ^nil;
  endif;
  ^byteAt(directionRef, 0); 
}
!!

/* 3/3/1992 13:31 - PUBLIC 
  Return a U32 stack size value
*/
Def getStackSize(self | stkSizePtr)
{ 
  stkSizePtr := new( Struct, 4 );
  if pcallLock(self) then
    lastError := pcall( procs[#STKGETSTACKSIZE], sessionID, stkSizePtr);
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION ;
  endif ;

  if (lastError <> GOOD) then
    displayError(ErrorTextLibClass$Inst,lastError,CHECK_MODE);  
    ^nil;
  endif;
  ^longAt(stkSizePtr, 0);
}
!!

/* 3/6/1992 15:14 - PRIVATE 
  Take a "STK_DISPLAY_PTR *" and convert its text into a collection.
  Free the C storage upon completion. Return nil if failed. 
  */
Def getTextFromAddr(self, longCAddress | txtColl, txtLen, aStruct, handle, numF)
{ 
  /* Check if address is not nil nor NULL */
  if not(longCAddress) cor (longCAddress = 0L) then
    ^nil;
  endif;
  
  /* Get the struct less the text[] */
  aStruct := copyFromLong( new(Struct, 8), longCAddress);
  /* Get number of frame in text[] */
  numF := wordAt(aStruct, 2);    /* keep it */
  /* Get textLength of text[] */
  txtLen := longAt(aStruct, 4);
  /* Get the allocationIndicator - STK_TMALLOC or GlobalAlloc handle */
  handle := wordAt(aStruct, 0);
  
  /* Create a new TextCollection and convert the string into it */
  add((txtColl := new(TextCollection, 1)), "");
  insertText(txtColl, physicalString(copyFromLong(new(Struct, txtLen),
    (longCAddress + 8) )), 0 , 0);
  /* Free the storage */
  if (handle <> 0) then    
    Call GlobalFree(handle);
  else
    cFree( MallocLibClass$Inst, longCAddress);
  endif;
  ^txtColl;
}
!!

/* 3/2/1992 17:12 - PRIVATE */
Def initialize(self, hWnd | sesPtr, bufPtr)
{
  sesPtr := new( Struct, 4 ) ; 
  if pcallLock(self) then
    lastError := pcall( procs(StackLibClass$Inst)
                [#STKSTARTSESSION], hWnd, sesPtr);
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION ;
  endif ;

  if (lastError <> GOOD) 
     displayError(ErrorTextLibClass$Inst,lastError, CHECK_MODE);
     ^nil; 
  endif;
  /* init session variables */
  sessionID       := longAt(sesPtr,0); 
  ^self
}
!!

/* 3/2/1992 17:17 - PUBLIC */
Def open?(self)
{
  ^sessionID  /* session id is nil if not a valid session */
}
 
!!

/* 3/3/1992 13:31 - PUBLIC */
Def openStack(self, frameCount | numFramePtr)
{ 
  numFramePtr := new( Struct, 2 );
  putByte(numFramePtr, frameCount, 0 ) ;
  if pcallLock(self) then
    lastError := pcall( procs[#STKOPENSTACK], numFramePtr, sessionID);
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION ;
  endif ;

  if (lastError <> GOOD) then
    displayError(ErrorTextLibClass$Inst,lastError, CHECK_MODE);
    ^nil;
  endif;
  ^wordAt(numFramePtr,0);
}
!!

/* 3/2/1992 17:12 - PRIVATE */
Def setIVars(self, hL, n, o, p, gNS)
{
  hLib     := hL ;
  name     := n  ;
  ordinals := o  ;
  procs    := p  ;
  globalNameSymbol := gNS ;
}

!!
