// safelib.cpp
 
 
 
#include "common.h"
 
 
 
 
 
// prototypes
 
void *SAFE_malloc (int count, size_t element_size, bool cleanup);
 
void *SAFE_realloc (void *allocation, int old_count, int new_count, size_t element_size, bool cleanup);
 
void SAFE_free (void **address_of_pointer_to_allocation);
 
char *SAFE_strncpy (char *destination, const char *source, size_t buffer_size);
 
int SAFE_snprintf (char *destination, size_t buffer_size, const char *fmt, ...);
 
int SAFE_vsnprintf (char *destination, size_t buffer_size, const char *fmt, va_list argptr);
 
char *SAFE_strncatf (char *destination, size_t buffer_size, const char *fmt, ...);
 
 
 
 
 
void *SAFE_malloc (int count, size_t element_size, bool cleanup)
 
{
 
   // handy wrapper for things we always forget, like checking malloc's returned pointer and
 
   // ensuring the allocated space is zeroed out.
 
 
 
   // here we are guaranteed to have some correctly allocated space
 
   return (SAFE_realloc (NULL, 0, count, element_size, cleanup));
 
}
 
 
 
 
 
//#pragma warning(disable: 4723) // for zero divide
 
void *SAFE_realloc (void *allocation, int old_count, int new_count, size_t element_size, bool cleanup)
 
{
 
   // handy wrapper for things we always forget, like checking malloc's returned pointer and
 
   // ensuring the extra allocated space is zeroed out if necessary.
 
 
 
   void *new_allocation;
 
 
 
   // do we want to reallocate a void space ?
 
   if (new_count == 0)
 
   {
 
      SAFE_free (&allocation); // free it if needed
 
      return (NULL); // and return an empty pointer
 
   }
 
 
 
   // do we NOT actually need to reallocate ?
 
   if (old_count == new_count)
 
      return (allocation); // allocation is well-suited for the purpose already
 
 
 
   // try re allocating the requested size
 
   if (allocation == NULL)
 
      new_allocation = malloc (new_count * element_size);
 
   else
 
      new_allocation = realloc (allocation, new_count * element_size);
 
   if (new_allocation == NULL)
 
      (void *) (1 / (new_count - new_count)); // divide by zero so that the program crashes here
 
 
 
   // zero out extra allocated content if necessary
 
   if (cleanup && (new_count > old_count))
 
      memset ((void *) ((unsigned char *) new_allocation + (old_count * element_size)), 0, (new_count - old_count) * element_size);
 
 
 
   return (new_allocation); // here we are guaranteed to have some correctly reallocated space
 
}
 
//#pragma warning(default: 4723)
 
 
 
 
 
void SAFE_free (void **address_of_pointer_to_allocation)
 
{
 
   // handy wrapper for things we always forget, like checking the buffer pointer's validity
 
   // before freeing it and nulling it out after it has been freed.
 
 
 
   if (address_of_pointer_to_allocation == NULL)
 
      return; // consistency check
 
 
 
   // is it a valid block pointer ?
 
   if (*address_of_pointer_to_allocation != NULL)
 
      free (*address_of_pointer_to_allocation); // only free valid block pointers
 
   *address_of_pointer_to_allocation = NULL; // reset the pointer (ensures it won't get freed twice)
 
 
 
   return; // finished
 
}
 
 
 
 
 
char *SAFE_strncpy (char *destination, const char *source, size_t buffer_size)
 
{
 
   // handy wrapper for operations we always forget, like checking for string terminations
 
 
 
   unsigned int buffer_index;
 
 
 
   if ((buffer_size <= 0) || (destination == NULL))
 
      return (destination); // consistency checks
 
 
 
   // for each character we find up to buffer_size...
 
   for (buffer_index = 0; buffer_index < buffer_size; buffer_index++)
 
   {
 
      destination[buffer_index] = source[buffer_index]; // copy everything
 
      if (destination[buffer_index] == 0)
 
         return (destination); // finished, string is copied AND terminated (and it fits)
 
   }
 
 
 
   destination[buffer_size - 1] = 0; // string overflown, let us set the terminator zero ourselves
 
   return (destination); // finished, string is copied AND terminated (even if it overflown)
 
}
 
 
 
 
 
int SAFE_snprintf (char *destination, size_t buffer_size, const char *fmt, ...)
 
{
 
   // handy wrapper for operations we always forget, like checking for string terminations.
 
   // This function should return the number of characters that would be written if there had
 
   // been enough buffer space to be C99 compatible.
 
 
 
   va_list argptr;
 
   int result;
 
 
 
   if ((buffer_size <= 0) || (destination == NULL))
 
      return (0); // consistency checks
 
 
 
   // concatenate all the arguments in the destination string...
 
   va_start (argptr, fmt);
 
   result = vsnprintf_s (destination, buffer_size, _TRUNCATE, fmt, argptr);
 
   va_end (argptr);
 
 
 
   if (result < 0)
 
      destination[buffer_size - 1] = 0; // ...but let us set the terminator zero ourselves
 
 
 
   return (result); // finished
 
}
 
 
 
 
 
int SAFE_vsnprintf (char *destination, size_t buffer_size, const char *fmt, va_list argptr)
 
{
 
   // handy wrapper for operations we always forget, like checking for string terminations.
 
   // This function should return the number of characters that would be written if there had
 
   // been enough buffer space to be C99 compatible.
 
 
 
   int result;
 
 
 
   if ((buffer_size <= 0) || (destination == NULL))
 
      return (0); // consistency checks
 
 
 
   // concatenate all the arguments in the destination string...
 
   result = vsnprintf_s (destination, buffer_size, _TRUNCATE, fmt, argptr);
 
   if (result < 0)
 
      destination[buffer_size - 1] = 0; // ...but let us set the terminator zero ourselves
 
 
 
   return (result); // finished
 
}
 
 
 
 
 
char *SAFE_strncatf (char *destination, size_t buffer_size, const char *fmt, ...)
 
{
 
   // handy wrapper for operations we always forget, like checking for string terminations.
 
   // This function adds variable arguments to strcat(), printf()-style.
 
 
 
   va_list argptr;
 
   char *message; // mallocated, can't be larger than buffer_size
 
   int start_index;
 
   int result;
 
   unsigned int pos;
 
   unsigned int amount_to_copy;
 
 
 
   if ((buffer_size <= 0) || (destination == NULL))
 
      return (destination); // consistency checks
 
 
 
   // allocate a buffer large enough for the formatted string
 
   message = (char *) malloc (buffer_size);
 
   if (message == NULL)
 
      return (NULL); // out of memory ?
 
 
 
   // concatenate all the arguments in one string
 
   va_start (argptr, fmt);
 
   result = vsnprintf_s (message, buffer_size, _TRUNCATE, fmt, argptr);
 
   va_end (argptr);
 
   if (result < 0)
 
      message[buffer_size - 1] = 0; // ...but let us set the terminator zero ourselves
 
 
 
   // get the destination string end position
 
   start_index = strlen (destination);
 
 
 
   // see how much data we can copy
 
   amount_to_copy = strlen (message);
 
   if (amount_to_copy > buffer_size - start_index)
 
      amount_to_copy = buffer_size - start_index; // don't copy more than the space left
 
 
 
   // and finally append ourselves the right number of characters, not to overflow
 
   for (pos = 0; pos < amount_to_copy; pos++)
 
   {
 
      destination[start_index + pos] = message[pos]; // append message to destination string
 
      if (destination[start_index + pos] == 0)
 
      {
 
         free (message); // free the mallocated memory
 
         return (destination); // don't copy beyond the end of source
 
      }
 
   }
 
   destination[start_index + amount_to_copy] = 0; // ...but let us set the terminator zero ourselves
 
   free (message); // free the mallocated memory
 
   return (destination); // finished
 
}