{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} { GENERIC NUMERICS ````````````````````````````` A Generic Utilities unit, for use by any program. Copyright İ by David Sinclair, 1990 ­ 2001. I am releasing these units to the Pascal community. Feel free to use them in whole or part in your Pascal programs. You are also welcome to modify these units to suit your needs. If you wish to re-distribute the sources with your changes, please clearly indicate that you have changed them. In all cases, you must leave these comments and the copyright notice intact. If you use a significant portion of these units, I would appreciate acknowledgement in your About dialog and/or documentation, e.g. ³Dejal Generic Utilities copyright İ by David Sinclair, 1990 - 2001.² Iıd appreciate it if you also e-mail me at if you find these units useful. If you have any questions about these units, you can e-mail me at that address and I will do my best to help, time permitting. However, these units are provided ³as is² and I do not guarantee their reliablity or suitability for any particular purpose. These units have been used extensively in my Dejal shareware and freeware products over the years. Most of the code was written many years ago, and the code and style may not be optimal in all cases, but unless otherwise noted all routines have been used in released software, so should work as described. Please visit and try out Dejal QuickEncrypt and/or my other shareware products. If you want to show your appreciation for these units financially, registrations for my shareware are always welcome! Or you can make a donation to me via my online order form: . I hope you find these units useful, and good luck in your Pascal endeavors! - David Sinclair, Dejal * * * UNIT HISTORY: (Reverse chronology) Start ­ finish dates: Comments / changes: 27 October 2001 Public release as source code. 15 July 1997 Added the NumRndRange routine. 13 July 1997 Renamed the old NumRnd function as NumNonGlobalRnd, and added new NumRnd routine that is much more random. 28 June 1997 Added the TestBit, SetBit, TestBitNum, and SetBitNum routines. 27 January 1997 Added the OSTypeHandle type. 26 February 1996 Added the numGetLineFromHandle routine. 26 January 1996 Added the numZeroBlock routine. * * * } { OLD UNIT HISTORY: } { } { Version: Start - finish dates: Comments / changes: } { } { 1.0: 22 Sept 1990 Copied the integerPtr type and the rnd } { function from old programs. } { 1.0.1: 26 October 1990 Unit name to Œgenı prefix & routines to } { Œnumı prefix. } { 1.1: 11 April 1991 Added the numSwap procedure. } { 1.2: 15 Nov 1991 Added the longAs2Ints type for coercion } { purposes. } { 1.3: 19 Nov 1991 Added numGetWordAtOffset & long equiv. } { 1.3.1: 21 Nov 1991 Locked & restored the handles in } { numGetXAtOffset. } { 1.4: 21 Nov 1991 Added the numOffsetPtrInHandle function. } { 2.0: 20 December 1991 First public release, in library form. } { 2.1: 28 January 1992 Added the numPtrOffsetInHandle function. } { 2.1.1: 20 April 1992 If the offset for numGet__AtOffset is odd, 1 } { is now added to it, to prevent an address } { error. } { 2.1.2: 20 February 1993 Changed offset parameters from integer } { values to longints, to allow a greater range. } { 2.2: 25 May 1994 Added numBiggest and numSmallest. } { 2.3: 9 July 1994 Added the numBitSetInMask function. } { 2.4: 4­5 October 1994 Added the numBlocksEqual function and } { the a few types, and changed handles and } { pointers passed to routines in this unit to } { use the univ identifier. } { 2.5: 6 October 1994 Improved the numRnd function, and added } { the longAs4Bytes and longAs4Chars types. } { 2.6: 21 November 94 Added the numPortionSize function. } { 2.7: 22 November 94 Added the numOffsetPtrInPtr function. } { 2.8: 29 November 94 Added the numNewHandle function. } { 2.9: 1 December 1994 Added numSign and numPreserveSign. } { 2.10: 30 December 1994 Added the numLockHandle, } { numUnlockHandle, numReleaseHandle, } { and numReleaseResource routines. } { 2.11: 4 January 1995 Added the numGetResource function. } { 2.12: 9 January 1995 Added the numBlindLockHandle, } { numBlindUnlockHandle, and } { numGetIndResource routines. } { 2.13: 12 January 1995 Added the numGet1Resource and } { numGet1IndResource routines. } { 2.14: 24 Sep 1995 Added the numReadScrap and } { numWriteScrap routines. } { 2.15: 1 October 1995 Added the numAppendToHandle routine. } { 2.16: 26 Nov 1995 Added the numUnsignedInt routine. } { * * * } { N.B: Most of my units require the compile-time variables Œapplicationı } { and Œdebugı, both of which are booleans. } {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} UNIT genNumerics; INTERFACE USES genToolbox; CONST textKind = 'TEXT'; stylKind = 'styl'; pictKind = 'PICT'; TYPE integerPtr = ^integer; integerHandle = ^integerPtr; longPtr = ^Longint; longHandle = ^longPtr; CharArray = PACKED ARRAY[1..1] OF Char; CharArrayPtr = ^CharArray; CharArrayHandle = ^CharArrayPtr; byteArray = PACKED ARRAY[1..1] OF signedByte; byteArrayPtr = ^byteArray; byteArrayHandle = ^byteArrayPtr; integerArray = PACKED ARRAY[1..1] OF integer; integerArrayPtr = ^integerArray; integerArrayHandle = ^integerArrayPtr; longArray = ARRAY[1..1] OF Longint; longArrayPtr = ^longArray; longArrayHandle = ^longArrayPtr; OSTypeArray = ARRAY[1..1] OF OSType; OSTypePtr = ^OSTypeArray; OSTypeHandle = ^OSTypePtr; intAs2Bytes = RECORD hiByte, loByte: signedByte END; longAs2Ints = RECORD hiWord, loWord: integer END; longAs4Bytes = RECORD hiByte, medHiByte, medLoByte, loByte: signedByte END; longAs4Chars = RECORD char1, char2, char3, char4: char END; strAs64Longs = PACKED ARRAY[1..64] OF Longint; strAs128Ints = PACKED ARRAY[1..128] OF integer; strAs256Bytes = PACKED ARRAY[0..255] OF signedByte; {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} FUNCTION NumNonGlobalRnd (range: Longint): Longint; FUNCTION NumRnd (range: Longint): Longint; FUNCTION NumRndRange (first, last: Longint): Longint; PROCEDURE numSwap (VAR firstNumber, secondNumber: Longint); FUNCTION numBiggest (firstNumber, secondNumber: Longint): Longint; FUNCTION numSmallest (firstNumber, secondNumber: Longint): Longint; FUNCTION numSign (number: Longint): Longint; FUNCTION numPreserveSign (preserveSign, newNumber: Longint): Longint; FUNCTION numUnsignedInt (theNumber: Integer): Longint; FUNCTION TestBit(flag, mask: Integer): Boolean; PROCEDURE SetBit(VAR flag: Integer; mask: Integer; value: Boolean); FUNCTION TestBitLong(flag, mask: Longint): Boolean; PROCEDURE SetBitLong(VAR flag: Longint; mask: Longint; value: Boolean); FUNCTION TestBitNum(flag: Longint; bitNumber: Integer): Boolean; PROCEDURE SetBitNum(VAR flag: Longint; bitNumber: Integer; value: Boolean); FUNCTION numNewHandle (VAR theHandle: UNIV handle; theSize: size): osErr; FUNCTION NumResizeHandle(theHandle: UNIV Handle; theSize: Size): OSErr; PROCEDURE numLockHandle (theHandle: UNIV handle; VAR hndlState: signedByte); PROCEDURE numUnlockHandle (theHandle: UNIV handle; hndlState: signedByte); PROCEDURE numBlindLockHandle (theHandle: UNIV handle); PROCEDURE numBlindUnlockHandle (theHandle: UNIV handle); PROCEDURE numDisposeHandle (VAR theHandle: UNIV handle); FUNCTION numGetResource (VAR theHandle: UNIV handle; resourceType: resType; resourceID: integer): osErr; FUNCTION numGet1Resource (VAR theHandle: UNIV handle; resourceType: resType; resourceID: integer): osErr; FUNCTION numGetIndResource (VAR theHandle: UNIV handle; resourceType: resType; resourceIndex: integer): osErr; FUNCTION numGet1IndResource (VAR theHandle: UNIV handle; resourceType: resType; resourceIndex: integer): osErr; PROCEDURE numReleaseResource (VAR theHandle: UNIV handle); FUNCTION numGetWordAtOffset (theHandle: UNIV handle; offset: Longint): integer; FUNCTION numGetLongAtOffset (theHandle: UNIV handle; offset: Longint): Longint; FUNCTION numOffsetPtrInHandle (theHandle: UNIV handle; offset: Longint): ptr; FUNCTION numPtrOffsetInHandle (theHandle: UNIV handle; thePtr: UNIV ptr): Longint; FUNCTION numOffsetPtrInPtr (thePtr: UNIV ptr; offset: Longint): ptr; FUNCTION numBitSetInMask (value, mask: Longint): boolean; FUNCTION numBlocksEqual (firstPtr, secondPtr: UNIV ptr; blockSize: Longint): boolean; FUNCTION numPortionSize (startPtr, endPtr: UNIV ptr): Longint; PROCEDURE numZeroBlock (theBlockPtr: UNIV Ptr; blockSize: Longint); PROCEDURE numAppendToHandle (theHandle: UNIV Handle; VAR handleSize: Longint; preStr, dataStr, postStr: Str255); FUNCTION numGetLineFromHandle (theHandle: UNIV CharArrayHandle; handleSize: Longint; VAR fromPos: Longint): Str255; PROCEDURE numReadScrap (scrapKind: osType; VAR scrapHndl: UNIV handle; VAR scrapLen: Longint); PROCEDURE numWriteScrap (scrapKind: osType; scrapHndl: UNIV handle; scrapLen: Longint); {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} IMPLEMENTATION TYPE getResOpType = (getAny, getCurrent, getIndAny, getIndCurrent); {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} FUNCTION NumNonGlobalRnd (range: Longint): Longint; { Returns a random number between 1 and the specified range. This should work } { even when Random might not be available. Note, however, that it is very bad when } { called several times in quick succession. } { Written by David Sinclair, 10 November 1989; changed to allow generating } { numbers up to maxLongint, and improve the randomness via TickCount, } { 6 October 1994; renamed from NumRnd, 13 July 1997. } CONST halfMaxRange = (maxLongint DIV 2) - 1; VAR rndNumber: Longint; BEGIN GetDateTime(rndNumber); rndNumber:= abs(rndNumber MOD halfMaxRange); NumNonGlobalRnd:= ((rndNumber + abs(tickCount MOD halfMaxRange)) MOD range) + 1 END; {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} FUNCTION NumRnd (range: Longint): Longint; {Returns a random number between 1 and the specified range.} {Written by David Sinclair, 13 July 1997.} VAR long: Longint; BEGIN long:= 0; IF range>=1 THEN long:= ((Abs(Random) + Abs(TickCount)) MOD range) + 1; NumRnd:= long END; {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} FUNCTION NumRndRange (first, last: Longint): Longint; {Returns a random number between first and last, inclusive.} {Written by David Sinclair, 15 July 1997.} VAR range: Longint; long: Longint; BEGIN long:= 0; range:= last-first+1; IF range>=1 THEN long:= ((Abs(Random) + Abs(TickCount)) MOD range) + first; NumRndRange:= long END; {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} PROCEDURE numSwap (VAR firstNumber, secondNumber: Longint); { Simply swaps the two numbers over, so if you passed 10 in firstNumber and 50 in } { secondNumber, it would return 50 in firstNumber and 10 in secondNumber. } { Written by David Sinclair, 11 April 1991. } VAR tempNumber: integer; BEGIN tempNumber:= firstNumber; firstNumber:= secondNumber; secondNumber:= tempNumber END; {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} FUNCTION numBiggest (firstNumber, secondNumber: Longint): Longint; { Returns whichever of the numbers is the larger. Integers work fine too. } { Written by David Sinclair, 25 May 1994. } BEGIN IF firstNumber > secondNumber THEN numBiggest:= firstNumber ELSE numBiggest:= secondNumber END; {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} FUNCTION numSmallest (firstNumber, secondNumber: Longint): Longint; { Returns whichever of the numbers is the smaller. Integers work fine too. } { Written by David Sinclair, 25 May 1994. } BEGIN IF firstNumber < secondNumber THEN numSmallest:= firstNumber ELSE numSmallest:= secondNumber END; {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} FUNCTION numSign (number: Longint): Longint; { Returns the sign of the number; -1 if the number is negative, 0 if zero, or 1 if positive. I canıt } { believe there isnıt a sgn function built-in, but I canıt find it! } { Written by David Sinclair, 1 December 1994. } BEGIN IF number < 0 THEN numSign:= -1 ELSE IF number > 0 THEN numSign:= 1 ELSE numSign:= 0 END; {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} FUNCTION numPreserveSign (preserveSign, newNumber: Longint): Longint; { Returns the newNumber value, but with the sign adjusted so that it is the same as that of the } { preserveSign value, unless that is zero, then newNumberıs sign is unchanged. Useful if the sign } { of a number carries information that is independent of itıs value (which is a bad practice, but } { sometimes convenient or even necessary). } { Written by David Sinclair, 1 December 1994. } BEGIN IF preserveSign < 0 THEN numPreserveSign:= -abs(newNumber) ELSE IF preserveSign > 0 THEN numPreserveSign:= abs(newNumber) ELSE numPreserveSign:= newNumber END; {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} FUNCTION numUnsignedInt (theNumber: Integer): Longint; { Given an Integer, returns it as a Longint without sign-extending (i.e treating bit 15 as a sign bit). } { Useful when a word-sized value is to be interpreted as unsigned. } { Written by David Sinclair, 26 November 1995. } BEGIN numUnsignedInt:= BAND(theNumber, $FFFF) END; {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} FUNCTION TestBit(flag, mask: Integer): Boolean; {Given a flag, returns true if the bit specified by the mask is set, otherwise false.} BEGIN TestBit:= BAND(flag,mask) = mask; END; {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} PROCEDURE SetBit(VAR flag: Integer; mask: Integer; value: Boolean); {Sets the bit specified by the mask of the flag to the value.} BEGIN flag:= flag - BAND(flag,mask); flag:= flag + (ORD(value)*mask); END; {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} FUNCTION TestBitLong(flag, mask: Longint): Boolean; {Given a flag, returns true if the bit specified by the mask is set, otherwise false.} BEGIN TestBitLong:= BAND(flag,mask) = mask; END; {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} PROCEDURE SetBitLong(VAR flag: Longint; mask: Longint; value: Boolean); {Sets the bit specified by the mask of the flag to the value.} BEGIN flag:= flag - BAND(flag,mask); flag:= flag + (ORD(value)*mask); END; {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} FUNCTION TestBitNum(flag: Longint; bitNumber: Integer): Boolean; {Given flag, tests whether the bitNumber bit is set or not, and returns appropiate response. (Bit zero is the low-order bit.)} BEGIN TestBitNum:= BTST(flag,bitNumber); END; {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} PROCEDURE SetBitNum(VAR flag: Longint; bitNumber: Integer; value: Boolean); {Forces the bit specified by bitNumber to the value. (Bit zero is the low-order bit.)} BEGIN IF value THEN BSET(flag,bitNumber) ELSE BCLR(flag,bitNumber); END; {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} { M E M O R Y R O U T I N E S } {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} FUNCTION numNewHandle (VAR theHandle: UNIV handle; theSize: size): osErr; { Creates a new handle in the app heap if possible, otherwise using temporary memory (if } { available). If unable to allocate the requested size in either location (allowing a reasonable safety } { margin), it returns a Memory Manager error and theHandle will be nil, otherwise it returns the } { new handle in theHandle. Note that you can pass any type of handle. Use this in place of a } { NewHandle call for extra safety and convenience. } { Written by David Sinclair, 11 May 1993; made into a generic routine, 29 November 1994. } CONST safety = 5120; VAR response: Longint; hasTempMem: boolean; err: osErr; BEGIN theHandle:= newHandle(theSize + safety); { Allow a safety margin } err:= memError; IF (theHandle = NIL) | (err <> noErr) THEN IF gestalt(gestaltOSAttr, response) = noErr THEN BEGIN hasTempMem:= bitTst(@response, 31 - gestaltTempMemSupport); hasTempMem:= hasTempMem & bitTst(@response, 31 - gestaltRealTempMemory); hasTempMem:= hasTempMem & bitTst(@response, 31 - gestaltTempMemTracked); IF hasTempMem THEN theHandle:= tempNewHandle(theSize + safety, err); END; IF (theHandle = NIL) & (err = noErr) THEN { Nil handle but no error code reported, } err:= memFullErr; { so we assign one ourselves } IF err = noErr THEN BEGIN setHandleSize(theHandle, theSize); { Set to requested size } err:= memError END; IF err <> noErr THEN theHandle:= NIL; numNewHandle:= err END; {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} FUNCTION NumResizeHandle(theHandle: UNIV Handle; theSize: Size): OSErr; {Resizes the handle to the requested size, if possible. Returns True if there is enough memory available (including a safety margin), otherwise False. Note that you can pass any type of handle. Use this in place of a SetHandleSize call for extra safety and convenience.} CONST SafetyMargin = 5120; VAR err: OSErr; BEGIN IF theHandle=Nil THEN err:= NilHandleErr ELSE BEGIN SetHandleSize(theHandle,theSize+SafetyMargin); {Allow a reasonable safety margin} err:= MemError; IF err = NoErr THEN BEGIN SetHandleSize(theHandle,theSize); {Set to requested size} err:= MemError; END; END; NumResizeHandle:= err END; {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} PROCEDURE numLockHandle (theHandle: UNIV handle; VAR hndlState: signedByte); { Locks the specified handle safely, by first moving it into high memory (to prevent heap } { fragmentation) and noting its existing state for later restoring via numUnlockHandle, } { below. Note, an advantage of using this routine is that you donıt need to coerce the handle } { if it isnıt a plain handle, thanks to the univ parameter. Use this in place of a HLock call for extra } { safety and convenience. } { Written by David Sinclair, 30 December 1994. } BEGIN IF theHandle<>nil THEN BEGIN MoveHHi(theHandle); hndlState:= HGetState(theHandle); HLock(theHandle); END; END; {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} PROCEDURE numUnlockHandle (theHandle: UNIV handle; hndlState: signedByte); { Restores the state of the handle before it was locked by numLockHandle, above. Note, the } { handle only ends up unlocked if it was previously unlocked, which is what youıd normally } { want, but if you need it unlocked, call HUnlock or numBlindUnlockHandle instead. If you just } { want to dispose of it, simply call numDisposeHandle, below. Use this in place of a HUnlock call } { for extra safety and convenience. } { Written by David Sinclair, 30 December 1994. } BEGIN IF theHandle<>nil THEN HSetState(theHandle, hndlState) END; {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} PROCEDURE numBlindLockHandle (theHandle: UNIV handle); { Locks the specified handle, first moving it into high memory (to prevent heap fragmentation). } { Itıs existing state is not noted; use numLockHandle, above, for that. Note, an advantage of using } { this routine is that you donıt need to coerce the handle if it isnıt a plain handle, thanks to the } { univ parameter. Use this in place of a HLock call for extra safety and convenience. } { Written by David Sinclair, 9 January 1995. } BEGIN IF theHandle<>nil THEN BEGIN MoveHHi(theHandle); HLock(theHandle); END; END; {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} PROCEDURE numBlindUnlockHandle (theHandle: UNIV handle); { Unlocks the handle. If you just want to dispose of it, simply call numDisposeHandle, below. } { You could use this in place of a HUnlock call to save having to do a type coercion, though realise } { that it will add extra overhead. } { Written by David Sinclair, 9 January 1995. } BEGIN IF theHandle<>nil THEN HUnlock(theHandle) END; {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} PROCEDURE numDisposeHandle (VAR theHandle: UNIV handle); { Safely disposes of the handle, if it isnıt nil. After calling this routine, the handle will be nil. } { Use this in place of a DisposeHandle call for extra safety and convenience. } { Written by David Sinclair, 30 December 1994. } BEGIN IF theHandle <> NIL THEN BEGIN HUnlock(theHandle); DisposeHandle(theHandle); theHandle:= NIL END; END; {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} FUNCTION getTheResource (operation: getResOpType; VAR theHandle: UNIV handle; {} resourceType: resType; idOrIndex: integer): osErr; { Gets and returns a handle to the specified resource from the requested resource file. If the } { resource is too large to fit in the application heap, it is loaded into temporary memory, if } { possible. Called by one of the following ³pretty interface² routines. } { NOTE: the resource will be detached, so use numDisposeHandle instead of numReleaseResource } { (or Toolbox equivalents) when finished with the handle. } { Written by David Sinclair, 4 January 1995; split routine into core and pretty parts, 12 January 1995. } VAR resMasterPtr: handle; theSize, response: Longint; hndlState: signedByte; err: osErr; BEGIN SetResLoad(true); CASE operation OF getAny: theHandle:= GetResource(resourceType, idOrIndex); getCurrent: theHandle:= Get1Resource(resourceType, idOrIndex); getIndAny: theHandle:= GetIndResource(resourceType, idOrIndex); OTHERWISE theHandle:= Get1IndResource(resourceType, idOrIndex); END; err:= ResError; IF ((theHandle = NIL) & (err = noErr)) | ((theHandle <> NIL) & (theHandle^ = NIL)) THEN err:= resNotFound; IF err = noErr THEN BEGIN DetachResource(theHandle); err:= ResError; END; IF err = memFullErr THEN IF (gestalt(gestaltResourceMgrAttr, response) = noErr) & bitTst(@response, 31 - gestaltPartialRsrcs) THEN BEGIN { Read the resource into temporary memory } SetResLoad(false); CASE operation OF getAny: resMasterPtr:= GetResource(resourceType, idOrIndex); getCurrent: resMasterPtr:= Get1Resource(resourceType, idOrIndex); getIndAny: resMasterPtr:= GetIndResource(resourceType, idOrIndex); OTHERWISE resMasterPtr:= Get1IndResource(resourceType, idOrIndex); END; err:= ResError; SetResLoad(true); IF err = noErr THEN BEGIN theSize:= GetResourceSizeOnDisk(resMasterPtr); err:= ResError; IF err = noErr THEN err:= numNewHandle(theHandle, theSize); IF err = noErr THEN BEGIN numLockHandle(theHandle, hndlState); ReadPartialResource(resMasterPtr, 0, theHandle^, theSize); err:= ResError; numUnlockHandle(theHandle, hndlState); IF err <> noErr THEN numDisposeHandle(theHandle) END; ReleaseResource(resMasterPtr); IF err = noErr THEN err:= ResError END END; getTheResource:= err END; {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} FUNCTION numGetResource (VAR theHandle: UNIV handle; resourceType: resType; {} resourceID: integer): osErr; { Gets and returns a handle to the specified resource from any resource file. If the resource } { is too large to fit in the application heap, it is loaded into temporary memory, if possible. } { NOTE: the resource will be detached, so use numDisposeHandle instead of numReleaseResource } { (or Toolbox equivalents) when finished with the handle. } { Written by David Sinclair, 4 January 1995. } BEGIN numGetResource:= getTheResource(getAny, theHandle, resourceType, resourceID) END; {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} FUNCTION numGet1Resource (VAR theHandle: UNIV handle; resourceType: resType; {} resourceID: integer): osErr; { Gets and returns a handle to the specified resource from the current resource file. If the resource } { is too large to fit in the application heap, it is loaded into temporary memory, if possible. } { NOTE: the resource will be detached, so use numDisposeHandle instead of numReleaseResource } { (or Toolbox equivalents) when finished with the handle. } { Written by David Sinclair, 4 January 1995. } BEGIN numGet1Resource:= getTheResource(getCurrent, theHandle, resourceType, resourceID) END; {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} FUNCTION numGetIndResource (VAR theHandle: UNIV handle; resourceType: resType; {} resourceIndex: integer): osErr; { Gets and returns a handle to the indexth occurance of the specified resource in any resource file. } { If the resource is too large to fit in the application heap, it is loaded into temporary memory, if } { possible. } { NOTE: the resource will be detached, so use numDisposeHandle instead of numReleaseResource } { (or Toolbox equivalents) when finished with the handle. } { Written by David Sinclair, 9 January 1995. } BEGIN numGetIndResource:= getTheResource(getIndAny, theHandle, resourceType, resourceIndex) END; {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} FUNCTION numGet1IndResource (VAR theHandle: UNIV handle; resourceType: resType; {} resourceIndex: integer): osErr; { Gets and returns a handle to the indexth occurance of the specified resource in the current } { resource file. If the resource is too large to fit in the application heap, it is loaded into temporary } { memory, if possible. } { NOTE: the resource will be detached, so use numDisposeHandle instead of numReleaseResource } { (or Toolbox equivalents) when finished with the handle. } { Written by David Sinclair, 9 January 1995. } BEGIN numGet1IndResource:= getTheResource(getIndCurrent, theHandle, resourceType, resourceIndex) END; {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} PROCEDURE numReleaseResource (VAR theHandle: UNIV handle); { Safely releases the resource, if the handle isnıt nil. After calling this routine, the handle will be } { nil. Use this in place of a ReleaseResource call for extra safety and convenience. } { Written by David Sinclair, 30 December 1994. } BEGIN IF theHandle <> NIL THEN BEGIN hUnlock(theHandle); releaseResource(theHandle); IF resError = resNotFound THEN DisposeHandle(theHandle); theHandle:= NIL END END; {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} FUNCTION numGetWordAtOffset (theHandle: UNIV handle; offset: Longint): integer; { Returns the word (integer) at the specified offset from the start of the handle, or 0 if } { the handle is nil or the offset is out of range. If the offset is odd, it is incremented by 1. } { Written by David Sinclair, 17 November 1991. } VAR ptrToData: integerPtr; hndlState: signedByte; BEGIN numGetWordAtOffset:= 0; IF odd(offset) THEN offset:= offset + 1; IF theHandle <> NIL THEN IF offset < getHandleSize(theHandle) THEN BEGIN numLockHandle(theHandle, hndlState); ptrToData:= integerPtr(pointer(ord4(@theHandle^^) + offset)); numGetWordAtOffset:= ptrToData^; numUnlockHandle(theHandle, hndlState); END END; {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} FUNCTION numGetLongAtOffset (theHandle: UNIV handle; offset: Longint): Longint; { Returns the long (Longint) at the specified offset from the start of the handle, or 0 if } { the handle is nil or the offset is out of range. If the offset is odd, it is incremented } { by 1. } { Written by David Sinclair, 18 November 1991. } VAR ptrToData: longPtr; hndlState: signedByte; BEGIN numGetLongAtOffset:= 0; IF odd(offset) THEN offset:= offset + 1; IF theHandle <> NIL THEN IF offset < getHandleSize(theHandle) THEN BEGIN numLockHandle(theHandle, hndlState); ptrToData:= longPtr(pointer(ord4(@theHandle^^) + offset)); numGetLongAtOffset:= ptrToData^; numUnlockHandle(theHandle, hndlState); END END; {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} FUNCTION numOffsetPtrInHandle (theHandle: UNIV handle; offset: Longint): ptr; { Returns a pointer to the specified offset from the start of the handle, or nil if the } { handle is nil or the offset is out of range. N.B: you MUST lock the handle before } { calling this routine and keep it locked until you have finished with the pointer it } { returns, otherwise the pointer may become invalid if the handleıs memory is } { moved. Note also that the pointer returned is a ³fake² one, so you must NOT call } { DisposePtr with it. Since that would dispose of a chunk of the handle, even if it } { would work, this would not be something you would want to do anyway. } { Written by David Sinclair, 21 November 1991. } BEGIN numOffsetPtrInHandle:= NIL; IF theHandle <> NIL THEN IF offset < getHandleSize(theHandle) THEN numOffsetPtrInHandle:= pointer(ord4(@theHandle^^) + offset) END; {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} FUNCTION numPtrOffsetInHandle (theHandle: UNIV handle; thePtr: UNIV ptr): Longint; { Returns the offset to the specified pointer from the start of the handle, or 0 if the } { handle or the pointer is nil. Performs the opposate of the previous routine. N.B: } { you MUST lock the handle before calling this routine. } { Written by David Sinclair, 28 January 1992. } BEGIN numPtrOffsetInHandle:= 0; IF (theHandle <> NIL) & (thePtr <> NIL) THEN numPtrOffsetInHandle:= ord4(@thePtr^) - ord4(@theHandle^^) END; {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} FUNCTION numOffsetPtrInPtr (thePtr: UNIV ptr; offset: Longint): ptr; { Returns a pointer to the specified offset from the start of the pointer, or nil if the } { pointer is nil. Note that you may pass a ³fake² pointer to this routine, and also note } { that the pointer returned is a ³fake² one, so you must NOT call DisposePtr with it. } { Written by David Sinclair, 22 November 1994. } BEGIN IF thePtr <> NIL THEN numOffsetPtrInPtr:= pointer(ord4(thePtr) + offset) ELSE numOffsetPtrInPtr:= NIL END; {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} FUNCTION numBitSetInMask (value, mask: Longint): boolean; { Returns true if the bit(s) set in the mask are also set in the value. Either parameter } { can be a byte, integer, or Longint. Note: in processor-intensive or time-critical } { situations, youıd save some time by using ³BitAnd (value, mask) <> 0² instead } { (which is all this routine does). } { Written by David Sinclair, 9 July 1994. } BEGIN numBitSetInMask:= bitAnd(value, mask) <> 0 END; {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} {$PUSH} {$R-} FUNCTION numBlocksEqual (firstPtr, secondPtr: UNIV ptr; blockSize: Longint): boolean; { Compares the two blocks of memory (both of which are assumed to be the same } { size), and returns true if the contents are the same. } { Written by David Sinclair, 4 October 1994; originally from my high-level } { preferences units. } VAR index: Longint; equal: boolean; BEGIN index:= 1; REPEAT equal:= integerArrayPtr(firstPtr)^[index] = integerArrayPtr(secondPtr)^[index]; index:= index + 1 UNTIL NOT equal | (index > (blockSize DIV 2)); numBlocksEqual:= equal END; {$POP} {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} FUNCTION numPortionSize (startPtr, endPtr: UNIV ptr): Longint; { Returns the size of the block of memory between the two specified pointers. } { The pointers can be fake or real pointers. } { Written by David Sinclair, 21 November 1994. } VAR diff: Longint; BEGIN IF (startPtr <> NIL) & (endPtr <> NIL) THEN diff:= abs(ord4(endPtr) - ord4(startPtr)) ELSE diff:= 0; numPortionSize:= diff END; {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} {$PUSH} {$R-} PROCEDURE numZeroBlock (theBlockPtr: UNIV Ptr; blockSize: Longint); { Zeroes the contents of an arbitary block of memory; pass @theBlock and its length in bytes. } VAR index: Longint; BEGIN FOR index:= 1 TO blockSize DIV 2 DO IntegerArrayPtr(theBlockPtr)^[index]:= 0; {Clear the block of data} IF Odd(blockSize) THEN ByteArrayPtr(theBlockPtr)^[blockSize]:= 0; {Also clear any odd byte on the end} END; {$POP} {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} PROCEDURE numAppendToHandle (theHandle: UNIV Handle; VAR handleSize: Longint; {} preStr, dataStr, postStr: Str255); { Appends the specified text to the handle, if dataStr isnıt null. Pass the current size of the text } { already in the handle in handleSize ‹ the actual handle size can be larger than that value. The } { handle will be expanded if there isnıt enough room for the text. } { Written by David Sinclair, 1 October 1995. } VAR oldHandleSize: Longint; hndlState: SignedByte; BEGIN IF (theHandle <> NIL) & (handleSize >= 0) & (dataStr <> '') THEN BEGIN dataStr:= Concat(preStr, dataStr, postStr); oldHandleSize:= GetHandleSize(theHandle); IF (handleSize + Length(dataStr)) > oldHandleSize THEN SetHandleSize(theHandle, oldHandleSize + 512); IF MemError = noErr THEN BEGIN numLockHandle(theHandle, hndlState); BlockMove(@dataStr[1], Pointer(Ord4(theHandle^) + handleSize), Length(dataStr)); numUnlockHandle(theHandle, hndlState); handleSize:= handleSize + Length(dataStr); END; END; END; {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} FUNCTION numGetLineFromHandle (theHandle: UNIV CharArrayHandle; handleSize: Longint; {} VAR fromPos: Longint): Str255; { Given a handle containing text and the length of that text, returns a string containing the text from } { the specified position (1-based) to the end of line, file, or string. The fromPos value is updated so } { you can call this routine again to read the next line. } { Written by David Sinclair, 26 February 1996. } VAR theStr: Str255; foundReturn: Boolean; hndlState: SignedByte; BEGIN theStr:= ''; IF (theHandle <> NIL) & (handleSize > 0) & (fromPos >= 1) & (fromPos <= handleSize) THEN BEGIN { Note: canıt do fromPos IN [1..handleSize] as handleSize is a Longint } numLockHandle(theHandle, hndlState); REPEAT foundReturn:= (theHandle^^[fromPos] = Chr(13)); IF NOT foundReturn THEN theStr:= Concat(theStr, theHandle^^[fromPos]); fromPos:= fromPos + 1; UNTIL foundReturn | (fromPos > handleSize) | (Length(theStr) >= 255); numUnlockHandle(theHandle, hndlState); END; numGetLineFromHandle:= theStr END; {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} PROCEDURE numReadScrap (scrapKind: osType; VAR scrapHndl: UNIV handle; {} VAR scrapLen: Longint); { Reads the specified kind of scrap data, returning the contents in the new scrapHndl handle, and } { the length in scrapLen. If the scrap couldnıt be read (or there is nothing of the specified kind), } { scrapHndl is nil and scrapLen is zero or an OS error code. The constants textKind, stylKind and } { pictKind are available. } { Written by David Sinclair, 24 September 1995. } VAR offset: Longint; BEGIN scrapHndl:= NewHandle(0); scrapLen:= MemError; IF scrapHndl <> NIL THEN BEGIN scrapLen:= GetScrap(scrapHndl, scrapKind, offset); IF scrapLen <= 0 THEN BEGIN DisposeHandle(scrapHndl); scrapHndl:= NIL; END; END; END; {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} PROCEDURE numWriteScrap (scrapKind: osType; scrapHndl: UNIV handle; scrapLen: Longint); { Writes out the specified kind of scrap data. The constants textKind, stylKind and pictKind } { are available. } { Written by David Sinclair, 24 September 1995. } VAR hndlState: signedByte; err: Longint; BEGIN err:= ZeroScrap; numLockHandle(scrapHndl, hndlState); err:= PutScrap(scrapLen, scrapKind, scrapHndl^); numUnlockHandle(scrapHndl, hndlState); END; {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} END.