/* 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/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));
}
!!

/* 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>.
  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 TextCollection of all Address Spaces of the current processor.
  If failed, return nil.
*/
Def getAddressSpaces(self | bufRef, countRef, count, bufLenRef, len, spacesColl, str)
{ 
  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 text collection */
  add(spacesColl := new(TextCollection, count), "");
  insertText(spacesColl, removeNulls(str), 0, 0);
  ^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 resposible 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.
*/
Def isPhysicalAddrInAddressRangeNoError(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)    
}
!!

/* 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 isPhysicalAddrInAddressRange(self, inAddrDesc, rangeAddrDesc | result)
{
  /* call the isPhysicalAddrInAddressRangeNoError?() */
  if not(result := isPhysicalAddrInAddressRangeNoError?(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;    
}
!!

/* 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 isAddrInAddressRangeNoError(self, inAddrDesc, rangeAddrDesc | inRangeRef)
{
  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, addrDesc1)));
  */ 
  /* DEBUG - 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;  
}
!!

/* 2/23/1993 14:23 */ /* PRIVATE */
Def minAddressOffset(self, offset1, offset2 | temp)
{ 
  if not(temp := compareOffsets(self, offset1, offset2))
    ^nil;
  endif;
  
  /* determine the smallest address range to use */
  if (temp = ADRLIB_ADDR_GREATER_THAN) then /* offset1 > offset2 */
    ^offset2;
  else
    ^offset1;
  endif;

}
!!

/* 1/8/1993 12:12 - PUBLIC
  Set the input addressDesc to a valid input offset, if it's an address
  range then the range is modified.  Return the inputAddrDesc or nil if 
  error.
*/
Def maskAddressMSB(self, inputAddrDesc | offset)
{ 
  if not(inputAddrDesc) cor 
    not(offset := getOffset(self, inputAddrDesc)) then
    ^nil;
  endif;
  /* Check for odd address boundary */
  if (offset mod 2) <> 0 then
    displayFormattedError(ErrorTextLibClass$Inst, 
       ER_ADDR_ODD_ADDRESS, FORCE_POPUP, nil, nil, nil);
    ^nil;       
  endif; 
  /* Mask off the upper bits */
  setOffset(self, inputAddrDesc, 
           (offset bitAnd maxInputOffset(self, inputAddrDesc)));
  if isAnAddrRangeDesc?(self, inputAddrDesc) then
    if not(offset := getFullEndOffset(self, inputAddrDesc)) then
      ^nil;
    endif;
    setEndAddrOffset(self, inputAddrDesc,
                    (offset bitAnd maxInputOffset(self, inputAddrDesc)));       
  endif;  
  ^inputAddrDesc;
}
!!

/* 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 (lastError <> ER_ADDRESS_OVERFLOW) then
    displayFormattedError(ErrorTextLibClass$Inst, 
       lastError, CHECK_MODE, nil, nil, nil);
    ^nil;
  endif;

  if (lastError = ER_ADDRESS_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, #ADRADJUSTRANGE,                 1, #(1, 1, 1, 0)    );
  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, #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, #ADRGETADDROFFSET,               1, #(1, 1)          );
  add( self, #ADRGETADDRRANGELENGTH,          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, #ADRGETRANGEACTIVE,              1, #(1, 1)          );   
  add( self, #ADRGETSPACESTR,                 1, #(0, 1)          );   
  add( self, #ADRISADDRINRANGE,               1, #(1, 1, 1)       );
  add( self, #ADRISPHYSICALADDRINRANGE,       1, #(1, 1, 1)       );
  add( self, #ADRISADDRRANGEEQUAL,            1, #(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, #ADRSETADDRSPACE,                1, #(1, 0)          ); 
  add( self, #ADRSETENDADDROFFSET,            1, #(1, 1)          ); 
  add( self, #ADRSUBTRACTFROMADDRESS,         1, #(1, 1)          );
  add( self, #ADRSUBTRACTFROMADDRESSUNDERFLOW,1, #(1, 1)          );
  add( self, #ADRTRANSLATESPACE,              1, #(1, 1)          );
}!!

/* 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;        
}
!!

/* PUBLIC -- compare offsets; same return value as compareAddresses */
Def compareOffsets(self, offset1, offset2 | addr1 addr2 status)
{
  if not(offset1) cor not(offset2)
    ^nil;
  endif;
  
  addr1 := createAndSetAddress(self, offset1);
  if not(addr1)
    ^nil;
  endif;
  
  addr2 := createAndSetAddress(self, offset2);
  if not(addr2)
    destroyAddress(self, addr1);
    ^nil;
  endif;
  
  status := compareAddresses(self, addr1, addr2);
  
  destroyAddress(self, addr1);
  destroyAddress(self, addr2);
  
  ^status;
}
!!

/* 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 -- create a symbolic address descriptor */
Def destroyAddress(self, addressDescriptor)
{
  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)
{
  descriptorRef := new( Struct, 4 ) ;
 
  if pcallLock(self)
  then
    lastError := pcall( procs[#ADRDUPLICATEADDRESS], 
      asLong(addrDesc), descriptorRef);
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION ;
  endif ;

  if (lastError <> GOOD) then
    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)
{
  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)  
           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 resposible 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 ;
}
!!
