{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
{
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: 45 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.