/* CLASS: ADDRESSLIB
   Address Server
*/!!

inherit(ProvidedLibs, #AddressLib, nil, 2, nil)!!

now(class(AddressLib))!!

/* semiPRIVATE -- should only be called via require(AddressLib)
   Define entry points and load library.  Define any structs required.
*/
Def provide(self, path)
{
  ^initialise( new(self:ancestor), path )
}
!!

now(AddressLib)!!

/* 3/13/1995 21:13 */
Def physicalRangeOfAddresses(self, addrDesc1, addrDesc2 | numBytesRef)
{  
  numBytesRef := new(Struct, 4);
  if pcallLock(self) then
    lastError := pcall( procs[#ADRPHYSICALRANGEOFADDRESSES], 
                        asLong(addrDesc1), 
                        asLong(addrDesc2), 
                        numBytesRef);
    pcallUNLock(self);
  else
    lastError := ERR_PCALL_RECURSION;
  endif;

  if (lastError <> GOOD) then
    displayFormattedError(ErrorTextLibClass$Inst, 
       lastError, CHECK_MODE, nil, nil, nil);
    ^nil;
  endif;
  /* Return the number of bytes */ 
  ^longAt(numBytesRef, 0);    
}!!

/* 6/16/1994 10:31 - PUBLIC
  Return the tuple(minOffset, maxOffset) for the address descriptor. */
Def getAddressLimitsNoError(self, addrDesc | minBuf, maxBuf, minVal, maxVal)
{ 
  minBuf := new(Struct, 4);
  maxBuf := new(Struct, 4);
  if pcallLock(self)
    lastError := pcall(procs[#ADRGETADDRESSLIMITS], addrDesc, minBuf, maxBuf);
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION;
  endif;

  if (lastError <> GOOD)
    ^nil
  endif;
  
  /* Turn the returned offsets into a tuple */
  minVal := longAt(minBuf, 0); 
  maxVal := longAt(maxBuf, 0); 
  
  ^tuple(minVal, maxVal);
}
!!

/* Set the specified address type for the input address Descriptor. */
Def setAddrMode(self, addrDesc, addrMode)
{ 
  if pcallLock(self)
    lastError := pcall(procs[#ADRSETADDRMODE], 
      asLong(addrDesc), asInt(addrMode));
    pcallUNLock(self);
  else
    lastError := ERR_PCALL_RECURSION;
  endif;
  
  if lastError <> GOOD
    displayFormattedError(ErrorTextLibClass$Inst, 
       lastError, CHECK_MODE, nil, nil, nil);
    ^nil;
  endif;
  ^addrDesc;  
}
!!

/* Set the specified address type for the input address Descriptor. */
Def setAddrType(self, addrDesc, addrType)
{ 
  if pcallLock(self)
    lastError := pcall(procs[#ADRSETADDRTYPE], 
      asLong(addrDesc), asInt(addrType));
    pcallUNLock(self);
  else
    lastError := ERR_PCALL_RECURSION;
  endif;
  
  if lastError <> GOOD
    displayFormattedError(ErrorTextLibClass$Inst, 
       lastError, CHECK_MODE, nil, nil, nil);
    ^nil;
  endif;
  ^addrDesc;  
}
!!

/* Set the segment type for the address descriptor. */
Def setAddressSegmentSelector(self, addrDesc, segmentType |
  typeBuf, typeVal, selectorBuf, selectorVal)
{
  if pcallLock(self)
    lastError := pcall(procs[#ADRSETADDRSEGMENTSELECTOR],
      addrDesc, segmentType, 0);
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION;
  endif;

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

/* Debug: print out info on address. */
Def printAddress(self, addr | temp)
{
  temp := getAddressSegmentSelector(self, addr);
  printLine("segment type: " + asString(temp[0]) +", selector: " + asString(temp[1]));
  printLine("offset: " + asString(getOffset(self, addr)));
  printLine("mode: " + asString(getAddressMode(self, addr)));
  printLine("type: " + asString(getAddressType(self, addr)));
  printLine("space: " + asString(getAddressSpace(self, addr)));
  printLine("text: " + asString(getAddressText(self, addr)));
}
!!

/* Get the pmode value, text */
Def getPmode(self | pmodeVal pmodeStruct t1 t2)
{
  pmodeVal := new(Struct, 2);
  pmodeStruct := new(Struct, 40);
  if pcallLock(self) then
    lastError := pcall(procs[#ADRGETPMODE], pmodeVal, pmodeStruct);
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION;
  endif;

  if (lastError <> GOOD) then
    displayFormattedError(ErrorTextLibClass$Inst, 
       lastError, CHECK_MODE, nil, nil, nil);
    ^nil;
  endif;
  t1 := wordAt(pmodeVal, 0);
  t2 := removeNulls(physicalString(pmodeStruct));
  ^tuple(t1, t2);
}
!!

/* PUBLIC -- compare offsets, use address descriptor template to set
   all address fields except offset.
   Return value as compareAddresses. */
Def compareOffsetsUsingTemplate(self, offset1, offset2, template |
      addr1 addr2 status)
{
  if not(offset1) cor not(offset2)
    ^nil;
  endif;
  
  if not(addr1 := createAddress(self))
    ^nil;
  endif;
  
  if not(copyAddress(self, template, addr1))
    destroyAddress(self, addr1);
    ^nil;
  endif;
  
  if not(setOffset(self, addr1, offset1))
    destroyAddress(self, addr1);
    ^nil;
  endif;
  
  if not(addr2 := createAddress(self))
    destroyAddress(self, addr1);
    ^nil;
  endif;
  
  if not(copyAddress(self, template, addr2))
    destroyAddress(self, addr1);
    destroyAddress(self, addr2);
    ^nil;
  endif;
  
  if not(setOffset(self, addr2, offset2))
    destroyAddress(self, addr1);
    destroyAddress(self, addr2);
    ^nil;
  endif;
  
  status := compareAddresses(self, addr1, addr2);
  
  destroyAddress(self, addr1);
  destroyAddress(self, addr2);
  
  ^status;
}
!!

/* 6/17/1994 - PUBLIC  Copy from addr1 to addr2  
  NOTE: does not destroy input descriptors. */
Def copyAddress(self, addrDesc1, addrDesc2 | result)
{ 
  if pcallLock(self) then
    lastError := pcall(procs[#ADRCOPYADDRESS],
      asLong(addrDesc1), asLong(addrDesc2));
    pcallUNLock(self);
  else
    lastError := ERR_PCALL_RECURSION;
  endif;
  if (lastError <> GOOD) then
    ^nil;
  endif;
  ^GOOD;
}
!!

/* 6/16/1994 - PUBLIC
  Return the tuple(segmentType, segmentSelector) for the address descriptor. */
Def getAddressSegmentSelector(self, addrDesc |
  typeBuf, typeVal, selectorBuf, selectorVal)
{
  typeBuf := new(Struct, 4);
  selectorBuf := new(Struct, 4);
  if pcallLock(self)
    lastError := pcall(procs[#ADRGETADDRSEGMENTSELECTOR],
      addrDesc, typeBuf, selectorBuf);
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION;
  endif;

  if (lastError <> GOOD)
    displayFormattedError(ErrorTextLibClass$Inst, 
       lastError, CHECK_MODE, nil, nil, nil);
    ^nil
  endif;
  
  /* Turn the returned offsets into a tuple */
  typeVal := wordAt(typeBuf, 0); 
  selectorVal := wordAt(selectorBuf, 0); 
  
  ^tuple(typeVal, selectorVal);
}
!!

/* 6/16/1994 - PUBLIC  Return the address mode. */
Def getAddressMode(self, addrDesc | modeBuf)
{ 
  modeBuf := new(Struct, 4);
  if pcallLock(self)
    lastError := pcall( procs[#ADRGETADDRMODE], asLong(addrDesc), modeBuf);
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION;
  endif;

  if (lastError <> GOOD)
    displayFormattedError(ErrorTextLibClass$Inst, 
       lastError, CHECK_MODE, nil, nil, nil);
    ^nil;
  endif;
  
  /* return the mode */
  ^wordAt(modeBuf, 0);
}
!!

/* 6/16/1994 10:31 - PUBLIC
  Return the tuple(minOffset, maxOffset) for the address descriptor. */
Def getAddressLimits(self, addrDesc | temp)
{ 
  if not(temp := getAddressLimitsNoError(self, addrDesc))
    displayFormattedError(ErrorTextLibClass$Inst, 
       lastError, CHECK_MODE, nil, nil, nil);
    ^nil;
  endif;
  
  ^temp;
}
!!

/* 5/15/1992 14:26 - PUBLIC 
  Return #true 
  if the input address >= startOffset and < endOffset of range, 
  else nil.
  NOTES:
    - This method does not destroy the input descriptor.
    - No error will be reported.
*/
Def isAddrInDasmRangeNoError(self, inAddrDesc, rangeAddrDesc | inRangeRef)
{
  /* DEBUG 
  printLine("inRange: "+asAddr(self, inAddrDesc)+" - "+
    asAddrRange(self, rangeAddrDesc));
  */  
  inRangeRef := new(Struct, 4);
  if pcallLock(self) then
    lastError := pcall( procs[#ADRISADDRINDASMRANGE], 
      asLong(inAddrDesc), asLong(rangeAddrDesc), inRangeRef);
    pcallUNLock(self);
  else
    lastError := ERR_PCALL_RECURSION;
  endif;
  if (lastError <> GOOD) then
    ^nil;
  endif;
  /* Return nil if the C's boolean value is 0 */ 
  ^(atLSB(inRangeRef, 0) <> BOOL_FALSE);    
}
!!

/* 5/15/1992 14:26 - PUBLIC 
  Return #true if the input address in range, else nil.
  NOTES:
    - This method does not destroy the input descriptor.
*/
Def isPhysicalAddrInRange(self, inAddrDesc, rangeAddrDesc | result)
{
  /* call the isPhysicalAddrInRangeNoError() */
  if not(result := isPhysicalAddrInRangeNoError(self, inAddrDesc, rangeAddrDesc)) then
    if (lastError <> GOOD) then
      displayFormattedError(ErrorTextLibClass$Inst, 
                            lastError, CHECK_MODE, nil, nil, nil);
    endif;                        
  endif;
  /* Return nil if byte is 0 - C's boolean type */ 
  ^result;    
}
!!

/* 6/8/1994 14:26 - PUBLIC 
  Return #true if the input address in range, else nil.
  NOTES:
    - This method does not destroy the input descriptor.
    - No error will be reported.
*/
Def isPhysicalAddrInRangeNoError(self, inAddrDesc, rangeAddrDesc | inRangeRef)
{
  inRangeRef := new(Struct, 4);
  if pcallLock(self) then
    lastError := pcall( procs[#ADRISPHYSICALADDRINRANGE], 
      asLong(inAddrDesc), asLong(rangeAddrDesc), inRangeRef);
    pcallUNLock(self);
  else
    lastError := ERR_PCALL_RECURSION;
  endif;
  if (lastError <> GOOD) then
    ^nil;
  endif;
  /* Return nil if byte is 0 - C's boolean type */ 
  ^(atLSB(inRangeRef, 0) <> BOOL_FALSE)    
}
!!

/* 6/8/1994 - PUBLIC
  Adds the input offset to the address descriptor. If
  address addition overflow occurs, set to maxOutputOffset and 
  return the errcode.  Other error return nil.
*/
Def addToAddressOverFlow(self, addrDesc, offset | maxOffset)
{ 
  if pcallLock(self) then
    lastError := pcall(procs[#ADRADDTOADDRESSOVERFLOW], 
      asLong(addrDesc), asLong(offset));
    pcallUNLock(self);
  else
    lastError := ERR_PCALL_RECURSION;
  endif;

  if (lastError <> GOOD) cand 
     (asLong(lastError) <> ER_ADR_RESULT_OVERFLOW) then
    displayFormattedError(ErrorTextLibClass$Inst, 
       lastError, CHECK_MODE, nil, nil, nil);
    ^nil;
  endif;

  if (lastError = ER_ADR_RESULT_OVERFLOW) 
    ^ER_ADR_RESULT_OVERFLOW;
  endif; 
  ^GOOD;
}
!!

/* 6/7/1994 16:45 - DEBUG 
  Return the string of the Address Range Offset in hex format
*/
Def asAddrRange(self, addrRangeDesc | withZeroX)
{ 
  withZeroX := 0;
  /* Do not put 0x for Intel format */
  if (TheProcFamily <> PROC_FAMILY_X86) then
    withZeroX := 1;  
  endif;  
  ^convertAddrRangeToText(self, addrRangeDesc, withZeroX, 1,RANGE_BOTH);
}
!!

/* 6/7/1994 16:45 - DEBUG 
  Return the string format of the input Address Descriptor 
*/
Def asAddr(self, addrDesc | withZeroX)
{ 
  withZeroX := 0;
  /* Do not put 0x for Intel format */
  if (TheProcFamily <> PROC_FAMILY_X86) then
    withZeroX := 1;  
  endif;  
  ^getAddressTextParam(self, addrDesc, withZeroX, 1);
}
!!

/* 7/7/1994 9:35 - PUBLIC
  This method returns the number of bytes remaining in from the maxInputAddress
  to the input address. Return the number of bytes if successful, else nil.
      
                +
                |
                |   
                |  <-+ inAddrDesc
                |    |      (number of bytes) 
                +  <-+ maxInputAddressOffset                      
            
  NOTES:
    - Caller has the sole ownership of the input address.
*/
Def remainingBytes(self, addrDesc | numBytesRef)
{  
  numBytesRef := new(Struct, 4);
  if pcallLock(self) then
    lastError := pcall( procs[#ADRREMAININGBYTES], 
                        asLong(addrDesc), 
                        numBytesRef);
    pcallUNLock(self);
  else
    lastError := ERR_PCALL_RECURSION;
  endif;

  if (lastError <> GOOD) then
    displayFormattedError(ErrorTextLibClass$Inst, 
       lastError, CHECK_MODE, nil, nil, nil);
    ^nil;
  endif;
  /* Return the number of bytes */ 
  ^longAt(numBytesRef, 0);    
}

!!

/* 6/3/1994 11:16 - PUBLIC
  This method returns the number of bytes between the 2 input addresses
  Return the number of bytes if successful, else nil.
                |
      Addr1 +-> +  
            |   |        
            |   |  (number of bytes) 
      Addr2 +-> +        
                | 
            
  NOTES:
    - id Addr1 == Addr2 the number of bytes is 1
    - Both addresses must be the same type, space and mode.
    - Caller has the sole ownership of the two addresses.
*/
Def rangeOfAddresses(self, addrDesc1, addrDesc2 | numBytesRef)
{  
  numBytesRef := new(Struct, 4);
  if pcallLock(self) then
    lastError := pcall( procs[#ADRRANGEOFADDRESSES], 
                        asLong(addrDesc1), 
                        asLong(addrDesc2), 
                        numBytesRef);
    pcallUNLock(self);
  else
    lastError := ERR_PCALL_RECURSION;
  endif;

  if (lastError <> GOOD) then
    displayFormattedError(ErrorTextLibClass$Inst, 
       lastError, CHECK_MODE, nil, nil, nil);
    ^nil;
  endif;
  /* Return the number of bytes */ 
  ^longAt(numBytesRef, 0);    
}!!

/* 3/17/1994 01:20  - PUBLIC 
  Subtracts the addrDesc2 from the addrDesc1 - result => addrDesc1 
  without checking for underflow errors.  */
Def subtractAddresses(self, addrDesc1, addrDesc2)
{ 
  if pcallLock(self) then
    lastError := pcall(procs[#ADRSUBTRACTADDRESSES], addrDesc1, addrDesc2);
    pcallUNLock(self);
  else
    lastError := ERR_PCALL_RECURSION;
  endif;

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

/* 3/17/1994 10:49 - PUBLIC
  Translate the specified address space enumeration to its text form.
  Return the translated text string if successful, else nil.
*/
Def getAddrSpaceText(self, spaceId | spaceTxtBuf)
{ 
  spaceTxtBuf := new(Struct, 10);  /* each space text is around 5 char long */
  if pcallLock(self) then
    lastError := pcall(procs[#ADRGETSPACESTR], spaceId, spaceTxtBuf);
    pcallUNLock(self);
  else
    lastError := ERR_PCALL_RECURSION;
  endif;
  
  if lastError <> GOOD then
    displayFormattedError(ErrorTextLibClass$Inst, 
       lastError, CHECK_MODE, nil, nil, nil);
    ^nil;
  endif;
  ^removeNulls(physicalString(spaceTxtBuf));  
}
!!

/* 03/17/94 - PUBLIC 
  Convert an address range to its text format.
  when <comp> is RANGE_BOTH, the text string in this format:
     <startOffset>..<endOffset> 
  Return nil if error, the addrRange is not destroyed in any case.   
  Ex: convertAddrRangeToText(AddressLibClass$Inst, addrRange, 1, 0, RANGE_BOTH);
  
  NOTES: 
    Component = RANGE_START, RANGE_END, RANGE_BOTH.
    hexFormat and zeroFill = C's boolean value.
*/
Def convertAddrRangeToText(self, addrRange, hexFormat, zeroFill, component | bufStruct)
{
  bufStruct := new( Struct, 40 ) ; /* BUF_ADDR_SIZ is 20 */
  if pcallLock(self) then
    lastError := pcall( procs[#ADRCONVADDRRANGETOTEXT], 
                      asLong(addrRange), 
                      hexFormat,
                      zeroFill,
                      component,
                      bufStruct);
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION ;
  endif ;

  if (lastError <> GOOD) then
    displayFormattedError(ErrorTextLibClass$Inst, 
       lastError, CHECK_MODE, nil, nil, nil);
    ^nil
  endif ;
  ^removeNulls(physicalString(bufStruct));
}
!!

/*Hera 5/22/97*/
Def convertAddrRangeToText1(self, addrRange, hexFormat, zeroFill, component | bufStruct)
{
  bufStruct := new( Struct, 400 ) ; /* BUF_ADDR_SIZ is 200 */
  if pcallLock(self) then
    lastError := pcall( procs[#ADRCONVADDRRANGETOTEXT1], 
                      asLong(addrRange), 
                      hexFormat,
                      zeroFill,
                      component,
                      bufStruct);
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION ;
  endif ;

  if (lastError <> GOOD) then
    displayFormattedError(ErrorTextLibClass$Inst, 
       lastError, CHECK_MODE, nil, nil, nil);
    ^nil
  endif ;
  ^removeNulls(physicalString(bufStruct));
}
!!
/* 3/17/1994 9:35 - PUBLIC
  This method returns the number of bytes remaining in the specified
  addressRange from the Input addrDesc.  
  Return the number of bytes if successful, else nil.
                |
      Range +-> +
            |   |        
            |   |  <-+ inAddrDesc
            |   |    |      (number of bytes) 
            +-> +  <-+      
                | 
            
  NOTES:
    - Both addresses must be the same type, space and mode.
    - Caller has the sole ownership of the two addresses.
*/
Def remainingBytesInRange(self, rangeAddrDesc, inAddrDesc | numBytesRef)
{  
  numBytesRef := new(Struct, 4);
  if pcallLock(self) then
    lastError := pcall( procs[#ADRREMAININGBYTESINRANGE], 
                        asLong(rangeAddrDesc), 
                        asLong(inAddrDesc), 
                        numBytesRef);
    pcallUNLock(self);
  else
    lastError := ERR_PCALL_RECURSION;
  endif;

  if (lastError <> GOOD) then
    displayFormattedError(ErrorTextLibClass$Inst, 
       lastError, CHECK_MODE, nil, nil, nil);
    ^nil;
  endif;
  /* Return the number of bytes */ 
  ^longAt(numBytesRef, 0);    
}

!!

/* 3/17/1994 01:20  - PUBLIC 
  Subtracts the addrDesc2 from the addrDesc1 - result => addrDesc1 
  without checking for underflow errors.  */
Def subtractAddressesUnderflow(self, addrDesc1, addrDesc2)
{ 
  if pcallLock(self) then
    lastError := pcall(procs[#ADRSUBTRACTADDRESSESUNDERFLOW], 
      asLong(addrDesc1), asLong(addrDesc2));
    pcallUNLock(self);
  else
    lastError := ERR_PCALL_RECURSION;
  endif;

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

/* 3/16/1994 10:49 - PUBLIC
  Translate the specified address space text to the address space
  value.
  Return the translated address space if successful, else nil.
*/
Def translateAddrSpace(self, spaceTxt | spaceValRef)
{ 
  spaceValRef := new(Struct, 4);
  if pcallLock(self) then
    lastError := pcall(procs[#ADRTRANSLATESPACE], asciiz(spaceTxt), spaceValRef);
    pcallUNLock(self);
  else
    lastError := ERR_PCALL_RECURSION;
  endif;
  
  if lastError <> GOOD then
    displayFormattedError(ErrorTextLibClass$Inst, 
       lastError, CHECK_MODE, nil, nil, nil);
    ^nil;
  endif;
  ^wordAt(spaceValRef, 0);  
}
!!

/* 3/16/1994 10:49 - PUBLIC
  Set the specified address space for the input address Descriptor.
*/
Def setAddrSpace(self, addrDesc, addrSpace)
{ 
  if pcallLock(self) then
    lastError := pcall(procs[#ADRSETADDRSPACE], 
      asLong(addrDesc), asInt(addrSpace));
    pcallUNLock(self);
  else
    lastError := ERR_PCALL_RECURSION;
  endif;
  
  if lastError <> GOOD then
    displayFormattedError(ErrorTextLibClass$Inst, 
       lastError, CHECK_MODE, nil, nil, nil);
    ^nil;
  endif;
  ^addrDesc;  
}
!!

/* 3/15/1994 14:27 - PUBLIC
  Convert the input address descriptor to the specified type.
  Modified the input <addrDesc>.
  NOTES:
    - Caller is responsible for allocate and destroy the input <addrDesc>.
*/
Def convertAddressToType(self, addrDesc, type | rangeRef)
{ 
  rangeRef := new(Struct, 4);
  if pcallLock(self) then
    lastError := pcall(procs[#ADRCONVERTADDRESS], 
      asLong(addrDesc), asInt(type), rangeRef);
    pcallUNLock(self);
  else
    lastError := ERR_PCALL_RECURSION;
  endif;

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

  ^addrDesc; 
}
!!

/* 3/8/1994 10:31 - PUBLIC
  Convert an ASCII text string to the input address descriptor.  
  Caller supplies the address descriptor <addrDesc>.
  Return GOOD if successful, else return nil.
  NOTES: 
    - This method will not destroy the input <addrDesc> in any case.
    - The error will be reported.
*/
Def convertTextToAddrDesc(self, addrText, addrDesc | result)
{ 
  if not(result := convertTextToAddressWithAddrDesc(self, addrText, addrDesc)) then
    if (lastError <> GOOD) then
      displayFormattedError(ErrorTextLibClass$Inst, 
            lastError, CHECK_MODE, nil, nil, nil);    
    endif; 
  endif;
  ^result;
}
!!

/* 3/15/1994 14:05 - PUBLIC
  Return the current space of the input <addrDesc>.
  Return nil if error occurred.
*/
Def getAddressSpace(self, addrDesc | spaceRef)
{ 
  spaceRef := new(Struct, 4);
  if pcallLock(self) then
    lastError := pcall( procs[#ADRGETADDRSPACE], 
      asLong(addrDesc), spaceRef);
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION ;
  endif ;

  if (lastError <> GOOD) then
    displayFormattedError(ErrorTextLibClass$Inst, 
       lastError, CHECK_MODE, nil, nil, nil);
    ^nil;
  endif ;
  /* return the SPACE of <addrDesc> */
  ^wordAt(spaceRef, 0);
}
!!

/* 3/15/1994 14:05 - PUBLIC
  Return the current type of the input <addrDesc>.
  Notes: type is ADDR_PHYSICAL, ADDR_LINEAR, and ADDR_VIRTUAL.
  Return nil if error occurred.
*/
Def getAddressType(self, addrDesc | typeRef)
{ 
  typeRef := new(Struct, 4);
  if pcallLock(self) then
    lastError := pcall( procs[#ADRGETADDRTYPE], 
      asLong(addrDesc), typeRef);
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION ;
  endif ;

  if (lastError <> GOOD) then
    displayFormattedError(ErrorTextLibClass$Inst, 
       lastError, CHECK_MODE, nil, nil, nil);
    ^nil;
  endif ;
  /* return the TYPE of <addrDesc> */
  ^wordAt(typeRef, 0);
}
!!

/* 3/15/1994 10:31 - PUBLIC
  Return the OrderedCollection of all Address Spaces string of the 
  current processor. If failed, return nil.
*/
Def getAddressSpaces(self | bufRef, countRef, count, 
  bufLenRef, len, spacesColl, str, loc, loc2, item)
{ 
  bufRef := new(Struct, 4);
  bufLenRef := new(Struct, 4);
  countRef := new(Struct, 4);
  if pcallLock(self) then
    lastError := pcall( procs[#ADRRETURNSPACES], bufRef, countRef, bufLenRef);
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION ;
  endif ;

  if (lastError <> GOOD) then
    displayFormattedError(ErrorTextLibClass$Inst, 
       lastError, CHECK_MODE, nil, nil, nil);
    ^nil
  endif;  
  /* Turn the returned buffer into a text collection */
  len := longAt(bufLenRef, 0); 
  count := longAt(countRef, 0); 
  str := physicalString(copyFromLong(new(Struct, len), 
                                     longAt(bufRef, 0)));
  /* Break spaces string into an Collection of strings */
  spacesColl := new(TextCollection, count);
  loc := item := 0;
  loop
  while (item < count) 
  begin
     /* Find the null character index to extract the substring */  
     if (loc2 := indexOf(str, asChar(0), loc))   
       add(spacesColl, subString(str, loc, loc2));
     endif; 
     item := item+1; /* next item */ 
     loc := loc2+1;  /* advanced to next character after the null character */
  endLoop;
  /* return the Collection */
  ^spacesColl; 
}
!!

/* 3/14/1994 9:51 - PUBLIC 
  This method adjusts the range of the input address uisng the specified
  arguments. Limits and boundary checking is done for caller.
  Where the direction code are
   { MOVE_RANGE_TO_LOW_ADDR, MOVE_RANGE_TO_HI_ADDR, 
     EXPAND_RANGE_LOW_ADDR, EXPAND_RANGE_HI_ADDR,
     EXPAND_RANGE_BOTH }
  Return GOOD if successful, else nil.   
     
  NOTES: 
    - Caller is responsible for allocate and free addrRangeDesc.    
*/
Def adjustRange(self, addrRangeDesc, numBytes, length, direction)
{ 
  if pcallLock(self) then
    lastError := pcall(procs[#ADRADJUSTRANGE], 
      asLong(addrRangeDesc), asLong(numBytes), asLong(length), direction);
    pcallUNLock(self);
  else
    lastError := ERR_PCALL_RECURSION;
  endif;
  
  if lastError <> GOOD then
    displayFormattedError(ErrorTextLibClass$Inst, 
       lastError, CHECK_MODE, nil, nil, nil);
    ^nil;
  endif;
  ^GOOD;  
}
!!

/* 5/15/1992 14:26 - PUBLIC 
  Return #true if the input address in range, else nil.
  NOTES:
    - This method does not destroy the input descriptor.
    - No error will be reported.
*/

/*Hera 5/21/97*/
Def isAddrInAddressRangeNoError1(self, inAddrDesc, rangeAddrDesc | inRangeRef)
{
  /* DEBUG 
  printLine("inRange: "+asAddr(self, inAddrDesc)+" - "+
    asAddrRange(self, rangeAddrDesc));
  */  
  inRangeRef := new(Struct, 4);
  if pcallLock(self) then
    lastError := pcall( procs[#ADRISADDRINRANGE1], 
      asLong(inAddrDesc), asLong(rangeAddrDesc), inRangeRef);
    pcallUNLock(self);
  else
    lastError := ERR_PCALL_RECURSION;
  endif;
  if (lastError <> GOOD) then
    ^nil;
  endif;
  /* Return nil if the C's boolean value is 0 */ 
  ^(atLSB(inRangeRef, 0) <> BOOL_FALSE);    
}
!!
Def isAddrInAddressRangeNoError(self, inAddrDesc, rangeAddrDesc | inRangeRef)
{
  /* DEBUG 
  printLine("inRange: "+asAddr(self, inAddrDesc)+" - "+
    asAddrRange(self, rangeAddrDesc));
  */  
  inRangeRef := new(Struct, 4);
  if pcallLock(self) then
    lastError := pcall( procs[#ADRISADDRINRANGE], 
      asLong(inAddrDesc), asLong(rangeAddrDesc), inRangeRef);
    pcallUNLock(self);
  else
    lastError := ERR_PCALL_RECURSION;
  endif;
  if (lastError <> GOOD) then
    ^nil;
  endif;
  /* Return nil if the C's boolean value is 0 */ 
  ^(atLSB(inRangeRef, 0) <> BOOL_FALSE);    
}
!!

/* 5/15/1992 14:26 - PUBLIC 
  Return #true if the input address in range, else nil.
  NOTES:
    - This method does not destroy the input descriptor.
    - No error will be reported.
*/
Def isAddrInAddressRange(self, inAddrDesc, rangeAddrDesc | result)
{
  if not(result :=  isAddrInAddressRangeNoError(self, inAddrDesc, rangeAddrDesc)) then
    if (lastError <> GOOD) then
       displayFormattedError(ErrorTextLibClass$Inst, 
           lastError, CHECK_MODE, nil, nil, nil);
    endif;
  endif;
  /* Return nil if byte is 0 - C's boolean type */ 
  ^result;   
}
!!

/* 3/11/1994 9:38 - PUBLIC 
  Compare the two input addresses, return {0 : addr1 > addr2, 1 : addr2 > addr1, 2 : addr1 = addr2 } = ADDR_COMPARE type
  return 0 = ADRLIB_ADDR_GREATER_THAN, 1 = ADRLIB_ADDR_LESS_THAN, 2 = ADRLIB_ADDR_EQUAL
  or nil.  
  NOTES: 
    - Do not destroy input descriptors.
    - No Error will be reported.
*/
Def comparePhysicalAddressesNoError(self, addrDesc1, addrDesc2 | resultRef)
{ 
  resultRef := new(Struct, 4);
  if pcallLock(self) then
    lastError := pcall(procs[#ADRCOMPAREPHYSICALADDRESSES], 
      asLong(addrDesc1), asLong(addrDesc2), resultRef);
    pcallUNLock(self);
  else
    lastError := ERR_PCALL_RECURSION;
  endif;
  
  if (lastError <> GOOD) then
    ^nil;
  endif;
  /* {0 : addr1 > addr2, 1 : addr2 > addr1, 2 : addr1 = addr2 } = ADDR_COMPARE type */ 
  ^wordAt(resultRef, 0);        
}


!!

/* 10/15/1992 10:17 - PUBLIC
  Compare the two input addresses, return {0 : addr1 > addr2, 1 : addr2 > addr1, 2 : addr1 = addr2 } = ADDR_COMPARE type
  return 0 = ADRLIB_ADDR_GREATER_THAN, 1 = ADRLIB_ADDR_LESS_THAN, 2 = ADRLIB_ADDR_EQUAL
  or nil. 
  
  NOTES: do not destroy input descriptors.
*/
Def compareAddressesNoError(self, addrDesc1, addrDesc2 | resultRef)
{ 
  resultRef := new(Struct, 4);
  if pcallLock(self) then
    lastError := pcall(procs[#ADRCOMPAREADDRESSES], 
      asLong(addrDesc1), asLong(addrDesc2), resultRef);
    pcallUNLock(self);
  else
    lastError := ERR_PCALL_RECURSION;
  endif;
  if (lastError <> GOOD) then
    ^nil;
  endif;
  /* {0 : addr1 > addr2, 1 : addr2 > addr1, 2 : addr1 = addr2 } = ADDR_COMPARE type */ 
  /* DEBUG 
  printLine("addr: "+asHex(getOffset(AddressLibClass$Inst, addrDesc1))+
     " == "+ asHex(getOffset(AddressLibClass$Inst, addrDesc2)));
  printLine("compare result: "+asString(wordAt(resultRef, 0))); 
  */
  ^wordAt(resultRef, 0);        
}
!!

/* 3/11/1994 9:38 - PUBLIC 
  Compare the two input addresses, return {0 : addr1 > addr2, 1 : addr2 > addr1, 2 : addr1 = addr2 } = ADDR_COMPARE type
  return 0 = ADRLIB_ADDR_GREATER_THAN, 1 = ADRLIB_ADDR_LESS_THAN, 2 = ADRLIB_ADDR_EQUAL
  or nil.  
  NOTES: do not destroy input descriptors.
*/
Def comparePhysicalAddresses(self, addrDesc1, addrDesc2 | result)
{ 
  if not(result := comparePhysicalAddressesNoError(self, addrDesc1, addrDesc2)) then
    if (lastError <> GOOD) then
      displayFormattedError(ErrorTextLibClass$Inst, 
            lastError, CHECK_MODE, nil, nil, nil);
    endif;        
  endif;
  /* {0 : addr1 > addr2, 1 : addr2 > addr1, 2 : addr1 = addr2 } = ADDR_COMPARE type */ 
  ^result;        
}

!!

/* 3/8/1994 10:31 - PUBLIC
  Convert an ASCII text string to an address descriptor.  Caller
  supplies the address descriptor <addrDesc>.
  Return GOOD if successful, else return error.
  NOTES: 
    - This method will not destroyed the input <addrDesc> in any case.
    - When error occurred, this method will not report the error.
*/
Def convertTextToAddressWithAddrDesc(self, addrText, addrDesc)
{ 
  /* Make sure the input is valid */
  if not(addrText) cor not(addrDesc)
     ^nil;
  endif;
  
  if pcallLock(self) then
     lastError := pcall(procs[#ADRCONVTEXTTOADDRESS], 
      asLong(addrDesc), asciiz(addrText));
     pcallUNLock(self);
  else
     lastError := ERR_PCALL_RECURSION;
  endif;                  

  if (lastError <> GOOD) then
     ^nil;
  endif;
  ^GOOD;
}
!!

/* 08/13/1993 17:23 -PUBLIC
  Symbolically convert an input string to address and get its offset.
  Clean up after itself - No Error will be reported.
*/
Def getSymbolicOffsetNoError(self, symbolStr | addrDesc, addrOffset)
{ 
  if not(addrDesc := convertTextToAddressNoError(self, symbolStr)) then
    ^nil;
  endif;
  addrOffset := getOffsetNoError(self, addrDesc);
  destroyAddress(self, addrDesc); /* Get rid ot the unused addrDesc */
  ^addrOffset;
}
!!

/* 2/17/1993 11:20  - PUBLIC 
  Subtracts the supplied offset from the address descriptor 
  without checking for underflow errors.  */
Def subtractFromAddressUnderflow(self, addrDesc, offset)
{ 
  if pcallLock(self) then
    lastError := pcall(procs[#ADRSUBTRACTFROMADDRESSUNDERFLOW], 
      asLong(addrDesc), offset);
    pcallUNLock(self);
  else
    lastError := ERR_PCALL_RECURSION;
  endif;

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

  ^GOOD;  
}
!!

/* 6/7/1994 12:12 - PUBLIC
  Set the input addressDesc to a valid input offset, if it's an address
  range then the range is modified.  Return GOOD if successful or nil if error.
*/
Def maskAddressMSB(self, addrDesc | offset)
{ 
  if pcallLock(self) then
    lastError := pcall(procs[#ADRMASKADDRMSB], asLong(addrDesc));
    pcallUNLock(self);
  else
    lastError := ERR_PCALL_RECURSION;
  endif;
  
  if lastError <> GOOD then
    displayFormattedError(ErrorTextLibClass$Inst, 
       lastError, CHECK_MODE, nil, nil, nil);
    ^nil;
  endif;
  ^GOOD;
}
!!

/* 2/17/1993 11:20  - PUBLIC
   Subtracts the supplied offset from the address descriptor 
*/
Def subtractFromAddress(self, addrDesc, offset)
{ 
  if pcallLock(self) then
    lastError := pcall(procs[#ADRSUBTRACTFROMADDRESS], 
      asLong(addrDesc), offset);
    pcallUNLock(self);
  else
    lastError := ERR_PCALL_RECURSION;
  endif;

  if (lastError <> GOOD) cand (lastError <> ER_ADDRESS_UNDERFLOW) then
    displayFormattedError(ErrorTextLibClass$Inst, 
       lastError, CHECK_MODE, nil, nil, nil);
    ^nil;
  endif;

  if (lastError = ER_ADDRESS_UNDERFLOW) 
    ^setOffset(self,addrDesc, offset := 0L);
  endif;

  ^GOOD;  
}
!!

/* 2/17/1993 11:20 - PUBLIC
  Adds the supplied offset to the address descriptor 
  Check for Overflow and set to maxOutputOffset
*/
Def addToAddress(self, addrDesc, offset | maxOffset)
{ 
  if pcallLock(self) then
    lastError := pcall(procs[#ADRADDTOADDRESS], 
      asLong(addrDesc), offset);
    pcallUNLock(self);
  else
    lastError := ERR_PCALL_RECURSION;
  endif;

  if (lastError <> GOOD) cand (asLong(lastError) <> ER_ADR_RESULT_OVERFLOW) then
    displayFormattedError(ErrorTextLibClass$Inst, 
       lastError, CHECK_MODE, nil, nil, nil);
    ^nil;
  endif;

  if (lastError = ER_ADR_RESULT_OVERFLOW) cand 
     (maxOffset := maxOutputOffset(self, addrDesc)) then
    ^setOffset(self, addrDesc, maxOffset);
  endif; 
  ^GOOD;
}
!!

/* 3/5/1992 14:18 - PUBLIC
   Get an address end offset 
*/
Def getFullEndOffset(self, addressDescriptor | offsetPtr)
{
  offsetPtr := new(Struct, 4);
  if pcallLock(self)
  then
    lastError := pcall( procs[#ADRGETENDADDROFFSET], 
                      asLong(addressDescriptor), offsetPtr) ;
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION ;
  endif ;

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

/* PRIVATE: Define all entry points for library as prototypes.  */
Def addImportProcs(self)
{
  add(self, #INITCSERVER,                    1, #(0, 0));
  add(self, #ADRADDTOADDRESS,                1, #(1, 1));
  add(self, #ADRADDTOADDRESSOVERFLOW,        1, #(1, 1));
  add(self, #ADRADJUSTRANGE,                 1, #(1, 1, 1, 0));
  add(self, #ADRCOPYADDRESS,                 1, #(1, 1));
  add(self, #ADRCOMPAREADDRESSES,            1, #(1, 1, 1));
  add(self, #ADRCOMPAREPHYSICALADDRESSES,    1, #(1, 1, 1));
  add(self, #ADRCONVADDRESSTOTEXT,           1, #(1, 1));
  add(self, #ADRCONVADDRESSTOTEXTNOFILL,     1, #(1, 1));
  add(self, #ADRCONVADDRESSTOTEXTWITHPARAMS, 1, #(1, 0, 0, 1));
  add(self, #ADRCONVADDRRANGETOTEXT,         1, #(1, 0, 0, 0, 1));
  add(self, #ADRCONVADDRRANGETOTEXT1,        1, #(1, 0, 0, 0, 1));
  add(self, #ADRCONVERTADDRESS,              1, #(1, 0, 1));
  add(self, #ADRCONVTEXTTOADDRESS,           1, #(1, 1));
  add(self, #ADRCREATEADDRESS,               1, #(1));
  add(self, #ADRDESTROYADDRESS,              1, #(1));
  add(self, #ADRDUPLICATEADDRESS,            1, #(1, 1));
  add(self, #ADRGETADDRESSLIMITS,            1, #(1, 1, 1));
  add(self, #ADRGETADDRMODE,                 1, #(1, 1));
  add(self, #ADRGETADDROFFSET,               1, #(1, 1));
  add(self, #ADRGETADDRRANGELENGTH,          1, #(1, 1));
  add(self, #ADRGETADDRSEGMENTSELECTOR,      1, #(1, 1, 1));
  add(self, #ADRGETADDRSPACE,                1, #(1, 1));
  add(self, #ADRGETADDRTYPE,                 1, #(1, 1));
  add(self, #ADRGETALLOCCOUNTS,              1, #(1, 1, 1));
  add(self, #ADRGETENDADDROFFSET,            1, #(1, 1));
  add(self, #ADRGETMAXINPUTADDRDIGITS,       1, #(1, 1));
  add(self, #ADRGETMAXINPUTADDROFFSET,       1, #(1, 1));
  add(self, #ADRGETMAXOUTPUTADDRDIGITS,      1, #(1, 1));
  add(self, #ADRGETMAXOUTPUTADDROFFSET,      1, #(1, 1));
  add(self, #ADRGETPMODE,                    1, #(1, 1));
  add(self, #ADRGETRANGEACTIVE,              1, #(1, 1));
  add(self, #ADRGETSPACESTR,                 1, #(0, 1));
  add(self, #ADRISADDRINRANGE,               1, #(1, 1, 1));
  add(self, #ADRISADDRINRANGE1,              1, #(1, 1, 1));
  add(self, #ADRISADDRINDASMRANGE,           1, #(1, 1, 1));
  add(self, #ADRISPHYSICALADDRINRANGE,       1, #(1, 1, 1));
  add(self, #ADRISADDRRANGEEQUAL,            1, #(1, 1, 1));
  add(self, #ADRMASKADDRMSB,                 1, #(1));
  add(self, #ADRPHYSICALRANGEOFADDRESSES,    1, #(1, 1, 1));
  add(self, #ADRRANGEOFADDRESSES,            1, #(1, 1, 1));
  add(self, #ADRREMAININGBYTES,              1, #(1, 1));
  add(self, #ADRREMAININGBYTESINRANGE,       1, #(1, 1, 1));
  add(self, #ADRRETURNSPACES,                1, #(1, 1, 1));
  add(self, #ADRSETADDROFFSET,               1, #(1, 1));
  add(self, #ADRSETADDRRANGELENGTH,          1, #(1, 1));
  add(self, #ADRSETADDRSEGMENTSELECTOR,      1, #(1, 0, 1));
  add(self, #ADRSETADDRSPACE,                1, #(1, 0));
  add(self, #ADRSETENDADDROFFSET,            1, #(1, 1));
  add(self, #ADRSUBTRACTADDRESSES,           1, #(1, 1));
  add(self, #ADRSUBTRACTFROMADDRESS,         1, #(1, 1));
  add(self, #ADRSUBTRACTFROMADDRESSUNDERFLOW,1, #(1, 1));
  add(self, #ADRTRANSLATESPACE,              1, #(1, 1));
  add(self, #ADRSETADDRTYPE,                 1, #(1, 0));
  add(self, #ADRSETADDRMODE,                 1, #(1, 0));
}!!

/* 10/15/1992 10:17 - PUBLIC
  Compare the two input addresses, return {0 : addr1 > addr2, 1 : addr2 > addr1, 2 : addr1 = addr2 } = ADDR_COMPARE type
  return 0 = ADRLIB_ADDR_GREATER_THAN, 1 = ADRLIB_ADDR_LESS_THAN, 2 = ADRLIB_ADDR_EQUAL
  or nil. 
  
  NOTES: do not destroy input descriptors.
*/
Def compareAddresses(self, addrDesc1, addrDesc2 | result)
{ 
  if not(result := compareAddressesNoError(self, addrDesc1, addrDesc2)) then
    if (lastError <> GOOD) then
       displayFormattedError(ErrorTextLibClass$Inst, 
           lastError, CHECK_MODE, nil, nil, nil);
    endif;
  endif;
  /* {0 : addr1 > addr2, 1 : addr2 > addr1, 2 : addr1 = addr2 } = ADDR_COMPARE type */ 
  ^result;        
}
!!

/* 6/17/1992 11:24 - PUBLIC
  Convert an ASCII text string to an address descriptor.
  return an addressDescriptor or nil.
*/
Def convertTextToAddress(self, addrText | ret)
{ 
  /* Call the prime interface to do the work */
  if not(ret := convertTextToAddressNoError(self, addrText)) then
    displayFormattedError(ErrorTextLibClass$Inst, 
       lastError, CHECK_MODE, nil, nil, nil);
    ^nil;
  endif; 
  ^ret; /* AddressDesc */
}   
!!

/* 6/17/1992 11:24 - PUBLIC
  Convert an ASCII text string to an address descriptor.
  return an addressDescriptor or nil.
  NOTES: It does not report error. Caller needs to extract error code if interest.
*/
Def convertTextToAddressNoError(self, addrText | addrDesc, saveErr)
{ 
  if pcallLock(self) then
    if not(addrDesc := createAddressNoError(AddressLibClass$Inst)) then
      ^nil;
    endif;
    lastError := pcall(procs[#ADRCONVTEXTTOADDRESS], 
      asLong(addrDesc), asciiz(addrText));
    pcallUNLock(self);
  else
    lastError := ERR_PCALL_RECURSION;
  endif;
  if (lastError <> GOOD) then
    /* Save the lastError so the destroyAddress() cannot clear it */
    saveErr := lastError;  
    destroyAddress(AddressLibClass$Inst, addrDesc);
    lastError := saveErr;
    ^nil;
  endif;          
  ^addrDesc;   
}
!!

/* PUBLIC -- create a symbolic address descriptor */
Def createAddress(self | ret )
{
  /* Call the prime interface to do the work */
  if not(ret := createAddressNoError(self)) then
    displayFormattedError(ErrorTextLibClass$Inst, 
       lastError, CHECK_MODE, nil, nil, nil);
    ^nil;
  endif; 
  ^ret; /* AddressDesc */
}
!!

/* PUBLIC -- create a symbolic address descriptor 
  Return the newly create address descriptor or nil.
  NOTES: It does not report error. Caller needs to extract error code if interest.
*/
Def createAddressNoError(self | descriptorRef)
{
  descriptorRef := new( Struct, 4 ) ;
  if pcallLock(self) then
    lastError := pcall( procs[#ADRCREATEADDRESS], descriptorRef ) ;
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION ;
  endif ;

  if (lastError <> GOOD) then
    ^nil
  endif ;
  ^longAt(descriptorRef, 0);
}
!!

/* PUBLIC -- create a symbolic address descriptor */
Def createAndSetAddress(self, offset | addr status)
{
  /* create address */
  if not(addr := createAddress(self)) cor
     not(status := setOffset(self, addr, offset)) then
    ^nil;
  endif;
  ^addr;
}
!!

/* 8/31/1992 9:14 - PUBLIC
  Return the Number of active address descriptor in the server.
  If convertToStr = #true then ouput is a string, else it's a number.
*/
Def debugAddrDescActive(self, convertToStr | allocDescPtr, deallocDescPtr, activeDesc)
{
  allocDescPtr := new(Struct, 4);
  deallocDescPtr := new(Struct, 4);
   
  if pcallLock(self)
  then
    lastError := pcall( procs[#ADRGETALLOCCOUNTS], 
                      allocDescPtr, deallocDescPtr) ;
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION ;
  endif ;

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

  /* Number of active descriptor in the server */
  activeDesc := (longAt(allocDescPtr, 0) - longAt(deallocDescPtr, 0));
  if convertToStr then
    ^"Active Desc: "+asString(activeDesc);  
  endif;
  ^activeDesc;
}
!!

/* PUBLIC -- destroy address descriptor */
Def destroyAddress(self, addressDescriptor)
{
  /* Make sure addressDescriptor is valid */
  if not(addressDescriptor) 
    displayFormattedError(ErrorTextLibClass$Inst, 
    ER_ADR_INVALID_DESCRIPTOR, CHECK_MODE, nil, nil, nil);
    ^nil
  endif;
  
  if pcallLock(self)
  then
    lastError := pcall( procs[#ADRDESTROYADDRESS], 
      asLong(addressDescriptor));
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION ;
  endif ;

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

/* 3/5/1992 14:22 - PUBLIC 
  Create a duplicate symbolic address descriptor */
Def duplicateAddress(self, addrDesc | descriptorRef)
{
  if not(addrDesc)
    ^nil;
  endif;
  
  descriptorRef := new(Struct, 4);
 
  if pcallLock(self)
    lastError := pcall(procs[#ADRDUPLICATEADDRESS], 
      asLong(addrDesc), descriptorRef);
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION;
  endif;

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

/* PUBLIC -- Convert an address to its text format */
Def getAddressText(self, addressDescriptor | bufStruct)
{
  bufStruct := new( Struct, 40 ) ; /* BUF_ADDR_SIZ is 20 */
  if pcallLock(self)
  then
    lastError := pcall( procs[#ADRCONVADDRESSTOTEXT], 
                      asLong(addressDescriptor), bufStruct ) ;
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION ;
  endif ;

  if (lastError <> GOOD) then
    displayFormattedError(ErrorTextLibClass$Inst, 
       lastError, CHECK_MODE, nil, nil, nil);
    ^nil
  endif ;
  ^removeNulls(physicalString(bufStruct));
}
!!

/* 5/14/1992 11:54 - PUBLIC
 Convert an address descriptor to its text with no leading 0 fill.
*/
Def getAddressTextNoFill(self, addressDescriptor | bufStruct)
{
  bufStruct := new( Struct, 40); /* BUF_ADDR_SIZ is 20 */
  if pcallLock(self) then
    lastError := pcall( procs[#ADRCONVADDRESSTOTEXTNOFILL], 
                      asLong(addressDescriptor), bufStruct ) ;
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION ;
  endif ;

  if (lastError <> GOOD) then
    displayFormattedError(ErrorTextLibClass$Inst, 
       lastError, CHECK_MODE, nil, nil, nil);
    ^nil
  endif;  
  ^removeNulls(physicalString(bufStruct));
}
!!

/* PUBLIC -- Convert an address to its text format 
  Ex: getAddressTextParams(AddressLibClass$Inst, addrDesc, 1, 0);
  hexFormat and zeroFill are C's boolean values.
*/
Def getAddressTextParam(self, addressDescriptor, hexFormat, zeroFill | bufStruct)
{
  bufStruct := new( Struct, 40 ) ; /* BUF_ADDR_SIZ is 20 */
  if pcallLock(self)
  then
    lastError := pcall( procs[#ADRCONVADDRESSTOTEXTWITHPARAMS], 
                      asLong(addressDescriptor), 
                      hexFormat,
                      zeroFill,
                      bufStruct ) ;
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION ;
  endif ;

  if (lastError <> GOOD) then
    displayFormattedError(ErrorTextLibClass$Inst, 
       lastError, CHECK_MODE, nil, nil, nil);
    ^nil
  endif ;
  ^removeNulls(physicalString(bufStruct));
}
!!

/* 7/8/1992 16:28 - PUBLIC
  Return the length of an address range.
*/
Def getAddrRangeLength(self, addrDesc | rangeLengthRef)
{ 
  rangeLengthRef := new(Struct, 4);
  if pcallLock(self) then
    lastError := pcall( procs[#ADRGETADDRRANGELENGTH], 
                      asLong(addrDesc), rangeLengthRef) ;
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION ;
  endif ;

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

/* 3/5/1992 14:18 - PUBLIC -- 
  Get an address offset preMask to maxOutputAddress
*/
Def getEndOffset(self, addrDesc | ret)
{
  /* Get the full 32bits offset the mask the upper bits as necessary */
  if (ret := getFullEndOffset(self, addrDesc)) then
    ^(ret bitAnd maxOutputOffset(self, addrDesc));
  endif;
  ^nil;   
}
!!

/* 3/5/1992 14:18 - PUBLIC -- get an address offset */
Def getOffset(self, addressDescriptor | ret)
{
  /* Call the prime interface to do the work */
  if not(ret := getOffsetNoError(self, addressDescriptor)) then
    displayFormattedError(ErrorTextLibClass$Inst, 
       lastError, CHECK_MODE, nil, nil, nil);
    ^nil;
  endif; 
  ^ret;
}
!!

/* 3/5/1992 14:18 - PUBLIC -- get an address offset 
  NOTES: It does not report error.
*/
Def getOffsetNoError(self, addressDescriptor | offsetPtr value)
{
  offsetPtr := new(Struct, 4);
  if pcallLock(self)
    lastError := pcall( procs[#ADRGETADDROFFSET], 
                      asLong(addressDescriptor), offsetPtr);
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION;
  endif;

  if (lastError <> GOOD)
    ^nil;
  endif;
  
  value := longAt(offsetPtr, 0);
  
  if (TheProcFamily = PROC_FAMILY_X86)
    ^value;
  endif;
  
  ^(value bitAnd maxOutputOffset(self, addressDescriptor));
}
!!

/* 3/5/1992 14:18 - PUBLIC -- get an address offset 
  NOTES: It does not report error.
*/
Def getFullOffsetNoError(self, addressDescriptor | offsetPtr)
{
  offsetPtr := new(Struct, 4);
  if pcallLock(self)
  then
    lastError := pcall( procs[#ADRGETADDROFFSET], 
                      asLong(addressDescriptor), offsetPtr) ;
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION ;
  endif ;

  if (lastError <> GOOD) then
    ^nil;
  endif ;
  ^longAt(offsetPtr, 0);
}
!!

/* 10/15/1992 17:23 -PUBLIC
  Symbolically convert an input string to address and get its offset.
  Clean up after itself.
*/
Def getSymbolicOffset(self, symbolStr | addrDesc, addrOffset)
{ 
  if not(addrDesc := convertTextToAddress(self, symbolStr)) then
    ^nil;
  endif;
  addrOffset := getOffset(self, addrDesc);
  destroyAddress(self, addrDesc); /* Get rid ot the unused addrDesc */
  ^addrOffset;
}
!!

/* 7/13/1992 10:17 - PUBLIC
  Compare the two input address ranges, return #true if they are equaled, else
  return nil. 
  NOTES: do not destroy input descriptors.
*/
Def isAddressRangesEqual?(self, addrDesc1, addrDesc2 | rangeEqualRef)
{ 
  rangeEqualRef := new(Struct, 4);
  if pcallLock(self) then
    lastError := pcall(procs[#ADRISADDRRANGEEQUAL], 
      asLong(addrDesc1), asLong(addrDesc2), rangeEqualRef);
    pcallUNLock(self);
  else
    lastError := ERR_PCALL_RECURSION;
  endif;

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

  /* Return nil if byte is 0 (FALSE) - C's boolean type */ 
  ^(atLSB(rangeEqualRef, 0) <> BOOL_FALSE)        
}
!!

/* 7/10/1992 11:07 - PUBLIC
  Determine a specified address descriptor is an address range descriptor or not.
*/
Def isAnAddrRangeDesc?(self, addrDesc | rangeRef)
{ 
  rangeRef := new(Struct, 4);
  if pcallLock(self) then
    lastError := pcall( procs[#ADRGETRANGEACTIVE], 
      asLong(addrDesc), rangeRef);
    pcallUNLock(self);
  else
    lastError := ERR_PCALL_RECURSION;
  endif;
  if (lastError <> GOOD) then
    displayFormattedError(ErrorTextLibClass$Inst, 
       lastError, CHECK_MODE, nil, nil, nil);
    ^nil;
  endif;
  /* Return nil if byte is 0 - C's boolean type = FALSE */ 
  ^(atLSB(rangeRef, 0) <> BOOL_FALSE)    

}
!!

/* 6/29/1992 16:08 - PUBLIC
  Set the offset of end address using the rangeLength.
  Return the input addrDesc or nil.
    NOTES: Caller is responsible for allocate and free addrDesc.
*/
Def setAddrRangeLength(self, addrDesc, rangeLength)
{ 
  if pcallLock(self) then
    lastError := pcall(procs[#ADRSETADDRRANGELENGTH], 
      asLong(addrDesc), asLong(rangeLength));
    pcallUNLock(self);
  else
    lastError := ERR_PCALL_RECURSION;
  endif;
  
  if lastError <> GOOD then
    displayFormattedError(ErrorTextLibClass$Inst, 
       lastError, CHECK_MODE, nil, nil, nil);
    ^nil;
  endif;
  ^addrDesc;  
}
!!

/* 6/29/1992 16:08 - PUBLIC
  Set the offset of end address for an addressRange.
  Return the addrDesc.
*/
Def setEndAddrOffset(self, addrDesc, endOffset)
{ 
  if pcallLock(self) then
    lastError := pcall(procs[#ADRSETENDADDROFFSET], 
      asLong(addrDesc), asLong(endOffset));
    pcallUNLock(self);
  else
    lastError := ERR_PCALL_RECURSION;
  endif;
  
  if lastError <> GOOD then
    displayFormattedError(ErrorTextLibClass$Inst, 
       lastError, CHECK_MODE, nil, nil, nil);
    ^nil;
  endif;
  ^addrDesc;  
}
!!

/* PUBLIC -- set an address offset */
Def setOffset(self, addressDescriptor, offset)
{
  if pcallLock(self)
  then
    lastError := pcall( procs[#ADRSETADDROFFSET], 
                      asLong(addressDescriptor), asLong(offset) ) ;
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION ;
  endif ;

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

/* PUBLIC -- set an address offset */
Def setOffsetText(self, addressDescriptor, text)
{
  if pcallLock(self)
  then
    lastError := pcall(procs[#ADRCONVTEXTTOADDRESS], 
                      asLong(addressDescriptor), asciiz(text));
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION ;
  endif ;

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

/* PUBLIC */
Def maxInputOffset(self, addrDesc | offsetStruct)
{
  offsetStruct := new(Struct, 4);
  if pcallLock(self)
  then
    lastError := pcall(procs[#ADRGETMAXINPUTADDROFFSET], 
                                   asLong(addrDesc), offsetStruct);
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION;
  endif ;

  if (lastError = 0)
  then
    ^longAt(offsetStruct, 0);
  else
    displayError(ErrorTextLibClass$Inst,lastError, CHECK_MODE);
    ^nil
  endif ;
}
!!

/* 8/19/1992 16:31 - PUBLIC
  Format a integer number into its equivalent HEX format with maxdigit guard.
*/
Def format(self, longNum | tmpDesc temp)
{ 
  tmpDesc := createAndSetAddress(self, longNum);
  temp := getAddressTextParam(self, tmpDesc, 0, 1);
  destroyAddress(self, tmpDesc);
  ^temp;
}
!!

/* PUBLIC */
Def maxOutputAddrDigits(self, addrDesc | offsetStruct)
{
  offsetStruct := new(Struct, 4);
  if pcallLock(self)
  then
    lastError := pcall(procs[#ADRGETMAXOUTPUTADDRDIGITS], 
                               asLong(addrDesc), offsetStruct);
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION;
  endif ;

  if (lastError = 0)
  then
    ^longAt(offsetStruct, 0);
  else
    displayError(ErrorTextLibClass$Inst,lastError, CHECK_MODE);
    ^nil
  endif ;
}
!!

/* PUBLIC */
Def maxOutputOffset(self, addrDesc | offsetStruct)
{
  offsetStruct := new(Struct, 4);
  if pcallLock(self)
  then
    lastError := pcall(procs[#ADRGETMAXOUTPUTADDROFFSET], 
                              asLong(addrDesc), offsetStruct);
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION;
  endif ;

  if (lastError = 0)
  then
    ^longAt(offsetStruct, 0);
  else
    displayError(ErrorTextLibClass$Inst,lastError, CHECK_MODE);
    ^nil
  endif ;
}
!!
