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