/***************************************************************************
* * Copyright (c) 1998, Decision Systems Group * * Permission is hereby
granted, free of charge, to any person obtaining * a copy of this software
and associated documentation files (the * "Software"), to deal in the
Software without restriction, including * without limitation the rights to
use, copy, modify, merge, publish, * distribute, sublicense, and/or sell
copies of the Software, and to * permit persons to whom the Software is
furnished to do so, subject to * the following conditions: * * The above
copyright notice and this permission notice shall be * included in all
copies or substantial portions of the Software. * * THE SOFTWARE IS
PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE. * *
==========================================================================
* * FILE: CU_Basics.c * * AUTHOR: * * Stephan R.A. Deibel * YongJoon Lee *
Jonathan H. Traum * Edward Pattison-Gordon * * CREATION DATE: * * 8/15/93 *
* VERSION: * * 8/8/94 * * DESCRIPTION: * * Basic utilities for code
portability and testing. * * NOTES: * * * MODIFICATIONS: * ----------
---------------------------------------------------------------- * Date
Name Description of modification * ----------
---------------------------------------------------------------- * *
2/23/95 YJoon Got rid of the _DB and _CU memory functions and put *
them into CU_ functions. * 8/15/93 Stephan Created with initial set of
functions. * ?/??/93 Joon? Added basic CUt_Text support functions *
8/8/94 Stephan Cleaned up mess in CUt_Text support functions, added *
missing comments, etc. Made some changes in parameters *
of text functions as well for consistency. Added *
ASSERTS. Filled in skeletons for functions previously *
only in the header file ??!?! What a mess! * Also
added support for CU_MallocSet(). * 8/12/94 YJLee Uhm... I didn't get
around to finishing them?... :} * 8/12/94 YJLee Removed ASSERT in
CU_Realloc requiring memory * pointer to be non-NULL;
functionality is well * defined for realloc(). * */
#ifdef __GNUC__ #define __USE_FIXED_PROTOTYPES__ #endif
#ifdef macintosh #include <Memory.h> #endif
#include <stddef.h> #include <stdlib.h> #include <stdio.h> #include
<string.h> #include <ctype.h>
#ifdef X_WIN #include <memory.h> #endif #ifdef dos #include "CUBasics.h"
#include "CUDebug.h" #include "CUTime.h" #else #include "CU_Failure.h"
#include "CU_Basics.h" #include "CU_Debug.h" #include "CU_Time.h" #endif /*
dos */
#ifdef MS_WIN #include <windows.h> #endif
/***************************************************************************
* * FUNCTION: * * CU_Initialize() * * DESCRIPTION: * * Initialize the CU
toolkit for use * * PARAMETERS: * * None * * RETURNS: * * tError --
Error if fails * * NOTES: * */
tError CU_Initialize() {
/* Initialize tick counter */
if (!CU_InitTicks())
return kInitFailure;
/* Redirect standard out and standard error based on platform */ #ifdef
MS_WIN
if (freopen("stderr", "w+", stderr) == NULL)
return kInitFailure;
if (freopen("stdout", "w+", stdout) == NULL)
return kInitFailure; #endif
/* Success */
return kNoError; }
/***************************************************************************
* * FUNCTION: * * CU_MemCpy() * * DESCRIPTION: * * CU memory copy function.
Use CU_MemCpy() instead of the c-library * memcpy() for better cross-
platform compatibility. * The funtion copies "count" bytes from "src" to
"dest". If the source and * destination overlap, these functions do not
ensure that the * overlapping region are copied before being overwritten
(use CU_MemMove()). * * PARAMETERS: * * void *dest -- The
destination memory * const void *src -- The source memory * tUInt4
count -- The number of bytes to copy * * RETURNS: * * void *
-- The destination pointer * * NOTES: * * Does not currently do any debug
memory checks. * */
void * CU_MemCpy( void *dest, const void *src, tUInt4 count ) {
tUInt4 offset;
tUInt4 bytes_left;
size_t copy_block;
tUInt4 max_block;
/* Error Check */
ASSERT( dest != NULL );
ASSERT( src != NULL );
/* Trivial case */
if ( count == 0 ) {
return( dest ); }
if ( sizeof(size_t) == 4 ) {
max_block = 0xFFFFFFFF;
} else if ( sizeof(size_t) == 2 ) {
max_block = 0xFFFF;
} else {
ASSERT(0);
}
offset = 0;
bytes_left = count;
while (bytes_left > 0) {
copy_block = (size_t) CU_MIN(max_block, bytes_left);
memcpy( (void *)((char *)dest + offset),
(void *)((char *)src + offset) , copy_block );
bytes_left -= copy_block;
offset += copy_block;
}
/* Done */
return( dest );
} /* MemCpy */
/***************************************************************************
* * FUNCTION: * * CU_MemMove() * * DESCRIPTION: * * CU memory move
function. Use CU_MemMove() instead of the c-library * function memmove()
for better cross-platform compatibility. * The function copies count bytes
of src to dest. The function properly * copies overlapping sections of
memory. * * PARAMETERS: * * void *dest -- The destination memory *
const void *src -- The source memory * tUInt4 count -- The number
of bytes to copy * * RETURNS: * * void * -- The destination
pointer * * NOTES: * * Does not currently do any debug memory checks. * */
void * CU_MemMove( void *dest, const void *src, tUInt4 count ) {
tUInt4 offset;
tUInt4 bytes_left;
size_t copy_block;
tUInt4 max_block;
/* Error Check */
ASSERT( dest != NULL );
ASSERT( src != NULL );
/* Trivial case */
if ( count == 0 )
return dest;
else if (dest == src)
return dest;
/* Check maximum copy size */
if ( sizeof(size_t) == 4 ) {
max_block = 0xFFFFFFFF;
} else if ( sizeof(size_t) == 2 ) {
max_block = 0xFFFF;
} else {
ASSERT(0);
return NULL;
}
/* Copy high to low */
if (dest < src) {
/* Set up for copy */
offset = 0;
bytes_left = count;
/* Do it */
while (bytes_left > 0) {
copy_block = (size_t) CU_MIN(max_block, bytes_left);
memmove( (void *)((char *)dest + offset),
(void *)((char *)src + offset) , copy_block );
bytes_left -= copy_block;
offset += copy_block;
}
}
/* Copy low to high */
else {
/* Set up for copy */
bytes_left = count;
offset = count - CU_MIN(count, max_block);
/* Do it */
while (bytes_left > 0) {
copy_block = (size_t) CU_MIN(max_block, bytes_left);
memmove( (void *)((char *)dest + offset),
(void *)((char *)src + offset) , copy_block );
bytes_left -= copy_block;
offset -= copy_block;
}
}
/* Done */
return( dest );
} /* MemMove */
/***************************************************************************
* * FUNCTION: * * CU_MemCmp() * * DESCRIPTION: * * CU memory compare
function. Use CU_MemCmp() instead of the c-library * function, memcmp()
for better cross-platform compatibility. * The CU_MemCmp() function
compares the first count bytes of buf1 and buf2 * and return a value
indicating their relationship. See below. * * PARAMETERS: * * const void
*buf1 -- The memory buffer 1 * const void *buf2 -- The memory
buffer 2 * tUInt4 count -- The number of bytes to compare * *
RETURNS: * * tInt4 -- < 0 : buf1 less than buf2 *
= 0 : buf1 identical to buf2 * > 0 : buf1 greater
than buf2 * * NOTES: * * */
tInt4 CU_MemCmp( const void *buf1, const void *buf2, tUInt4 count ) {
tUInt4 offset;
tUInt4 bytes_left;
size_t cmp_block;
tUInt4 max_block;
tUInt4 result;
/* Error Check */
ASSERT( buf1 != NULL );
ASSERT( buf2 != NULL );
/* Trivial case */
if ( count == 0 ) {
return( 0 ); }
if ( sizeof(size_t) == 4 ) {
max_block = 0xFFFFFFFF;
} else if ( sizeof(size_t) == 2 ) {
max_block = 0xFFFF;
} else {
ASSERT(0);
}
offset = 0;
result = 0;
bytes_left = count;
while ( result == 0 && bytes_left > 0 ) {
cmp_block = (size_t) CU_MIN(max_block, bytes_left);
result += memcmp( (void *)((char *)buf1 + offset),
(void *)((char *)buf2 + offset), cmp_block );
bytes_left -= cmp_block;
offset += cmp_block;
}
/* Done */
return( result );
} /* MemCmp */
/***************************************************************************
* * FUNCTION: * * CU_MemSet() * * DESCRIPTION: * * CU memory set function.
Use CU_MemSet() instead of the c-library * function memset() for better
cross-platform compatibility. * Sets the memory to the specified value. *
* PARAMETERS: * * void *dest -- The destination memory * char c
-- The char to fill with * tUInt4 count -- The number of bytes to set
* * RETURNS: * * void * -- The destination pointer * * NOTES: *
* Does not currently do any debug memory checks. * */
void * CU_MemSet( void *dest, char c, tUInt4 count ) {
tUInt4 offset;
tUInt4 bytes_left;
size_t set_block;
tUInt4 max_block;
/* Error Check */
ASSERT( dest != NULL );
/* Trivial case */
if ( count == 0 ) {
return( dest ); }
if ( sizeof(size_t) == 4 ) {
max_block = 0xFFFFFFFF;
} else if ( sizeof(size_t) == 2 ) {
max_block = 0xFFFF;
} else {
ASSERT(0);
}
offset = 0;
bytes_left = count;
while (bytes_left > 0) {
set_block = (size_t) CU_MIN(max_block, bytes_left);
memset( (void *)((char *)dest + offset), c, set_block );
bytes_left -= set_block;
offset += set_block;
}
/* Done */
return( dest );
} /* MemSet */
/***************************************************************************
* * FUNCTION: * * CU_MaxMem() * * DESCRIPTION: * * Returns maximum possible
size for a new memory allocation. On machines * with heap memory managers,
this returns the maximum available block * without doing heap compaction.
* * RETURNS: * * tUInt4 -- The maximum size of a new allocation * *
NOTES: * * On Mac: May want to change this to take possible heap compaction
into * account -- that is, IF allocating a pointer on Mac & PC will also *
do a heap compact if necessary. * */
tUInt4 CU_MaxMem(void) {
tUInt4 free_block;
#ifdef MAC_WIN
tUInt4 growBytes; #endif /* MAC_WIN */
/* Init to zero */
free_block = 0;
#ifdef MAC_WIN
/* MaxMem returns largest contiguous block without doing */
/* heap compaction. GrowBytes is set to the size available */
/* with heap compaction but we currently ignore this value. */
free_block = (tUInt4) MaxMem((Size*) &growBytes);
free_block += growBytes; #endif /* MAC_WIN */
#ifdef X_WIN
UNIMPLEMENTED; #endif /* X_WIN */
#ifdef MS_WIN
UNTESTED; #ifdef __GNUC__
UNIMPLEMENTED; #else
free_block = (tUInt4)GetFreeSpace(0); #endif /* __GNUC__ */ #endif /*
MS_WIN */
/*
* Done
*/
return (free_block);
} /* MaxMem */
/***************************************************************************
* * FUNCTION: * * CU_InvertMem() * * DESCRIPTION: * * Invert all the bits
in a buffer (0->1 and 1->0) * * PARAMETERS: * * void *
-- A pointer to the buffer * tUInt4 -- The size (in
bytes) of the buffer * * RETURNS: * * void * */
void CU_InvertMem(void* buff, tUInt4 buffsize) {
register tUInt4 * ptr = NULL;
tUInt4 iter;
GOODMEM(buff);
if (buffsize == 0)
return;
ptr = (tUInt4 *) buff;
for (iter = 0; iter < buffsize; iter += sizeof(tUInt4)) {
*ptr = ~(*ptr);
++ptr;
}
} /* CU_InvertMem */
/***************************************************************************
* * FUNCTION: * * CU_CreateUniqueID() * * DESCRIPTION: * * Create a
pseudo-globally unique ID by filling in the given structure. * *
PARAMETERS: * * CUt_UniqueID * -- Pointer to preallocated unique ID
structure. * * RETURNS: * * tBoolean -- TRUE if succeeded; FALSE
upon failure; * */
tBoolean CU_CreateUniqueID(CUt_UniqueID *id) {
GOODMEM(id);
/*
EVENTUALLY WANT TO MOVE CGg_HostID and CGg_ProcessID into CU and use
those
here!!!
id->HostID = CUg_HostID; id->ProcessID = CUg_ProcessID; */
id->HostID = rand();
id->ProcessID = rand();
id->Time = CU_CurrentTicks();
id->ID = rand();
return( TRUE );
} /* CreateUniqueID */
/***************************************************************************
* * FUNCTION: * * CU_InitUniqueID() * * DESCRIPTION: * * Init a unique ID
to blank / NULL state. * * PARAMETERS: * * CUt_UniqueID * -- Pointer
to preallocated unique ID structure. * * RETURNS: * * void * */
void CU_InitUniqueID(CUt_UniqueID *id) {
GOODMEM(id);
id->HostID = 0;
id->ProcessID = 0;
id->Time = 0;
id->ID = 0; }
/***************************************************************************
* * FUNCTION: * * CU_UniqueIDEqual() * * DESCRIPTION: * * Check whether two
unique IDs are equal. * * PARAMETERS: * * const CUt_UniqueID * --
First ID * const CUt_UniqueID * -- Second ID * * RETURNS: * * tBoolean
-- TRUE if succeeded; FALSE upon failure; * */
tBoolean CU_UniqueIDEqual(const CUt_UniqueID *id1, const CUt_UniqueID *id2)
{
GOODMEM(id1);
GOODMEM(id2);
if (id1->HostID == id2->HostID && id1->ProcessID == id2->ProcessID &&
id1->Time == id2->Time && id1->ID == id2->ID)
return TRUE;
else
return FALSE; }
/***************************************************************************
* * FUNCTION: * * CU_Malloc() * * DESCRIPTION: * * CU memory allocation
function, allocates a buffer of size "mem_size" and * returns a pointer to
the buffer. Use CU_Malloc() instead of malloc() for * better cross-
platform compatibility. * In debug mode, CU_Malloc() keeps memory
statistics used to detect memory * errors. * * PARAMETERS: * * tUInt4
-- The amount of memory to allocate. * * RETURNS: * * void * --
Pointer to the allocated memory; or NULL on failure. * * NOTES: * * Does
not currently do any debug memory checks. * */
#ifdef CU_Malloc #undef CU_Malloc #endif
void * CU_Malloc(tUInt4 mem_size) {
void *result; #ifdef MSVC
HGLOBAL wm_handle; #endif
/*
* Error check
*/
ASSERT(mem_size > 0);
/*
* Allocate memory
*/
#ifdef MSVC
wm_handle = GlobalAlloc(GMEM_FIXED,(mem_size));
if (wm_handle)
result = GlobalLock(wm_handle);
else
result = NULL; #else
result = (void *) malloc(mem_size); #endif /* MS_WIN */
#ifdef DEBUG
/*
* When debugging BARF if memory allocation fails
*/
if (result == NULL) {
BARF;
}
#endif /* DEBUG */
return( result );
} /* Malloc */
/***************************************************************************
* * FUNCTION: * * CU_Calloc() * * DESCRIPTION: * * Returns a pointer to
space for an array of "num" elements of size "size". * CU_calloc()
initializes the buffer to 0. Use CU_Calloc() instead of * the c-library
function, calloc() for better cross-platform compatibility. * In debug
mode, keeps memory statistics for checking for memory * errors. * *
PARAMETERS: * * tUInt4 -- The number of array elements to allocate.
* tUInt4 -- The size of each array element. * * Total space
allocated is the product of the above (possibly plus some * byte alignment
space??). * * RETURNS: * * void * -- The newly allocated pointer; or
NULL on failure. * * NOTES: * * Does not currently do any debug memory
checks. * */
#ifdef CU_Calloc #undef CU_Calloc #endif
void * CU_Calloc(tUInt4 num, tUInt4 size) {
void *result; #ifdef MSVC
HGLOBAL wm_handle; #endif
/*
* Error check
*/
ASSERT(size > 0);
ASSERT(num > 0);
/*
* Allocate memory
*/ #ifdef MSVC
wm_handle = GlobalAlloc(GPTR,(num * size));
if (wm_handle)
result = GlobalLock(wm_handle);
else
result = NULL; #else
result = (void *) calloc((size_t)num, (size_t)size); #endif /* MS_WIN */
#ifdef DEBUG
/*
* When debugging BARF if memory allocation fails
*/
if (result == NULL) {
BARF;
} #endif /* DEBUG */
/*
* Done
*/
return( result );
} /* Calloc */
/***************************************************************************
* * FUNCTION: * * CU_Realloc() * * DESCRIPTION: * * CU_Realloc() changes
the size of a block of memory to the new size, * "mem_size" while
preserving its contents. The "ptr" value must not be * NULL. Use
CU_Malloc() or CU_Calloc() to allocate new memory. Use * CU_Realloc()
instead of the c-library function realloc() for better * cross-platform
compatibility. * In debug mode, keeps memory statistics used to detect
memory * errors. * * PARAMETERS: * * void * -- The pointer to
reallocate. * tUInt4 -- The new size needed. * * RETURNS: * * void
* -- Pointer to new memory; or NULL on failure. * * NOTES: * Do not
use CU_Realloc() to free memory by setting the new size to 0, * as this
behavior is not defined and will ASSERT in debug mode. * Does not
currently do any debug memory checks. * */
#ifdef CU_Realloc #undef CU_Realloc #endif
void * CU_Realloc(void *ptr, tUInt4 mem_size) {
void *result; #ifdef MSVC
DWORD dw_handle;
HGLOBAL wm_handle; #endif /* MS_WIN */
/*
* Error check
*/
ASSERT(mem_size > 0);
ASSERT(ptr != NULL);
/*
* Allocate memory
*/ #ifdef MSVC
dw_handle = GlobalHandle(HIWORD(ptr));
wm_handle = LOWORD(dw_handle);
GlobalUnlock(wm_handle);
GlobalReAlloc(wm_handle, mem_size, GMEM_MOVEABLE);
if (wm_handle)
result = GlobalLock(wm_handle);
else
result = NULL; #else
result = (void *) realloc(ptr, (size_t)mem_size); #endif /* MS_WIN */
#ifdef DEBUG
/*
* When debugging BARF if memory allocation fails
*/
if (result == NULL) {
BARF;
} #endif /*DEBUG */
/*
* Done
*/
return( result );
} /* Realloc */
/***************************************************************************
* * FUNCTION: * * CU_MallocSet() * * DESCRIPTION: * * Equivalent to a call
to CU_Malloc() plus CU_MemSet() to initialize new * memory with given
character value (from 0 to 255). * In debug mode, keeps memory statistics
used to detect * memory errors. * * PARAMETERS: * * tUInt4 -- The
amount of memory to allocate. * tUInt1 -- The initialization / fill
character (usually 0) * * RETURNS: * * void * -- Pointer to the
allocated and blanked memory; or NULL on * failure. * *
NOTES: * * Does not currently do any debug memory checks. * */
#ifdef CU_MallocSet #undef CU_MallocSet #endif
void * CU_MallocSet(tUInt4 mem_size, tUInt1 fill) {
void *result; #ifdef MSVC
HGLOBAL wm_handle; #endif
/*
* Error check
*/
ASSERT(mem_size > 0);
/*
* Allocate memory
*/
#ifdef MSVC
wm_handle = GlobalAlloc(GHND, mem_size);
if (wm_handle)
result = GlobalLock(wm_handle);
else
result = NULL; #else
result = (void *) malloc(mem_size);
/*
* Init new memory (if malloc() succeeded)
*/
if (result != NULL)
memset(result, fill, (size_t)mem_size); #endif /* MS_WIN */
#ifdef DEBUG
/*
* When debugging BARF if memory allocation fails
*/
if (result == NULL) {
BARF;
} #endif /* DEBUG */
/*
* Done
*/
return( result );
} /* MallocSet */
/***************************************************************************
* * FUNCTION: * * CU_Free() * * DESCRIPTION: * * CU_Free() releases a block
of memory that was allocated by any CU_Calloc() * or CU_Malloc(). * In
debug mode, does memory diagnostics to check for memory errors. * *
PARAMETERS: * * void * -- The memory to free. * * NOTES: * * Will
ASSERT on a NULL "mem" value in debug mode. * Does not currently do any
debug memory checks. * */
#ifdef CU_Free #undef CU_Free #endif
void CU_Free(void *mem) { #ifdef MSVC
DWORD dw_handle;
HGLOBAL wm_handle; #endif /* MS_WIN */
/*
* Deallocate
*/
#ifdef MSVC
dw_handle = GlobalHandle(HIWORD(mem));
wm_handle = LOWORD(dw_handle);
GlobalUnlock(wm_handle);
GlobalFree(wm_handle); #else
free(mem); #endif
#ifdef DEBUG
/*
* Later -- may add code here to do certain things when
* DEBUG is defined
*/ #endif /* DEBUG */ } /* Free */
/* end of CG_Basics.c */