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