/*************************************************************************** * * 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 */