Blame dynamic_array.c

Packit 7dae13
/*
Packit 7dae13
 *      Dynamic array, to store all your flims in Includes macros required
Packit 7dae13
 *      to create an array of strings but as the primitive type for the
Packit 7dae13
 *      array is void * providing your own duplicate_primitive and
Packit 7dae13
 *      destroy_primitive functions will allow you to use the dynamic_array
Packit 7dae13
 *      API to have a dynamic array containing any primitive
Packit 7dae13
 *
Packit 7dae13
 *      Authors: Horms <horms@vergenet.net>
Packit 7dae13
 *
Packit 7dae13
 *      Released under the terms of the GNU GPL
Packit 7dae13
 *
Packit 7dae13
 */
Packit 7dae13
Packit 7dae13
#include "dynamic_array.h"
Packit 7dae13
Packit 7dae13
Packit 7dae13
/**********************************************************************
Packit 7dae13
 * dynamic_array_create
Packit 7dae13
 * Create a dynamic array
Packit 7dae13
 * pre: block_size: blocking size to use.
Packit 7dae13
 *                  DEFAULT_DYNAMIC_ARRAY_BLOCK_SIZE is used if block_size is 0
Packit 7dae13
 *                  Block size refers to how many elements are prealocated
Packit 7dae13
 *                  each time the array is grown.
Packit 7dae13
 * return: An empty dynamic array
Packit 7dae13
 *         NULL on error
Packit 7dae13
 **********************************************************************/
Packit 7dae13
Packit 7dae13
dynamic_array_t *
Packit 7dae13
dynamic_array_create(size_t block_size)
Packit 7dae13
{
Packit 7dae13
  dynamic_array_t *a;
Packit 7dae13
Packit 7dae13
  if ((a = (dynamic_array_t *) malloc(sizeof(dynamic_array_t))) == NULL) {
Packit 7dae13
    return (NULL);
Packit 7dae13
  }
Packit 7dae13
Packit 7dae13
  a->vector = NULL;
Packit 7dae13
  a->count = 0;
Packit 7dae13
  a->allocated_size = 0;
Packit 7dae13
  a->block_size =
Packit 7dae13
      block_size ? block_size : DEFAULT_DYNAMIC_ARRAY_BLOCK_SIZE;
Packit 7dae13
Packit 7dae13
  return (a);
Packit 7dae13
}
Packit 7dae13
Packit 7dae13
Packit 7dae13
/**********************************************************************
Packit 7dae13
 * dynamic_array_destroy
Packit 7dae13
 * Free an array an all the elements held within
Packit 7dae13
 * pre: a: array to destroy
Packit 7dae13
 *      destroy_element: pointer to funtion to destroy array elements
Packit 7dae13
 *                       Function should take an argument of a pointer
Packit 7dae13
 *                       and free the memory allocated to the structure
Packit 7dae13
 *                       pointed to.
Packit 7dae13
 * post: array is freed and destroy_element is called for all elements
Packit 7dae13
 *       of the array.
Packit 7dae13
 *       Nothing if a is NULL
Packit 7dae13
 **********************************************************************/
Packit 7dae13
Packit 7dae13
void
Packit 7dae13
dynamic_array_destroy(dynamic_array_t * a,
Packit 7dae13
		      void (*destroy_element) (void *))
Packit 7dae13
{
Packit 7dae13
  if (a == NULL)
Packit 7dae13
    return;
Packit 7dae13
  while (a->count-- > 0) {
Packit 7dae13
    destroy_element(*(a->vector + a->count));
Packit 7dae13
  }
Packit 7dae13
  if (a->allocated_size > 0) {
Packit 7dae13
    free(a->vector);
Packit 7dae13
  }
Packit 7dae13
}
Packit 7dae13
Packit 7dae13
Packit 7dae13
/**********************************************************************
Packit 7dae13
 * dynamic_array_add_element
Packit 7dae13
 * Add an element to a dynamic array
Packit 7dae13
 * pre: a: dynamic array to add element to
Packit 7dae13
 *      e: element to add
Packit 7dae13
 *      destroy_element: pointer to a function to destroy an element
Packit 7dae13
 *                       passed to dynamic_array_destroy on error
Packit 7dae13
 *      duplicate_element: pointer to a function to duplicate an
Packit 7dae13
 *                         element should take a pointer to an element
Packit 7dae13
 *                         to duplicate as the only element and return
Packit 7dae13
 *                         a copy of the element Any memory allocation
Packit 7dae13
 *                         required should be done by this function.
Packit 7dae13
 * post: element in inserted in the first unused position in the array
Packit 7dae13
 *       array size is increased by a->block_size if there is
Packit 7dae13
 *       insufficient room in the array to add the element.
Packit 7dae13
 *       Nothing is done if e is NULL
Packit 7dae13
 * return: a on success
Packit 7dae13
 *         NULL if a is NULL or an error occurs
Packit 7dae13
 **********************************************************************/
Packit 7dae13
Packit 7dae13
dynamic_array_t *
Packit 7dae13
dynamic_array_add_element(dynamic_array_t * a,
Packit 7dae13
			  const void *e, void (*destroy_element) (void *s), void
Packit 7dae13
			  *(*duplicate_element) (const void *s))
Packit 7dae13
{
Packit 7dae13
  if (a == NULL)
Packit 7dae13
    return (NULL);
Packit 7dae13
  if (e == NULL)
Packit 7dae13
    return (a);
Packit 7dae13
  if (a->count == a->allocated_size) {
Packit 7dae13
    a->allocated_size += a->block_size;
Packit 7dae13
    if (
Packit 7dae13
	(a->vector =
Packit 7dae13
	 (void **) realloc(a->vector,
Packit 7dae13
			   a->allocated_size * sizeof(void *))) == NULL) {
Packit 7dae13
      dynamic_array_destroy(a, destroy_element);
Packit 7dae13
      return (NULL);
Packit 7dae13
    }
Packit 7dae13
  }
Packit 7dae13
  if ((*(a->vector + a->count) = (void *) duplicate_element(e)) == NULL) {
Packit 7dae13
    return (NULL);
Packit 7dae13
  }
Packit 7dae13
  a->count++;
Packit 7dae13
Packit 7dae13
  return (a);
Packit 7dae13
}
Packit 7dae13
Packit 7dae13
Packit 7dae13
/**********************************************************************
Packit 7dae13
 * dynamic_array_display
Packit 7dae13
 * Print the contents of a dynamic array to a string
Packit 7dae13
 * pre: a: dynamic array to display
Packit 7dae13
 *      delimiter: character to place between elements of the array
Packit 7dae13
 *      display_element: pointer to a function to display an element
Packit 7dae13
 *      element_length:  pointer to a function to return the
Packit 7dae13
 *                       length of an element
Packit 7dae13
 * post: If a is NULL or there are no elements in a then nothing is done
Packit 7dae13
 *       Else a character buffer is alocated and the contents
Packit 7dae13
 *       of each array element, separated by delimiter is placed
Packit 7dae13
 *       in the '\0' termintated buffer returned. It is up to the
Packit 7dae13
 *       user to free this buffer.
Packit 7dae13
 * return: Allocated buffer as above
Packit 7dae13
 *         NULL on error, NULL a or empty a
Packit 7dae13
 **********************************************************************/
Packit 7dae13
Packit 7dae13
char *
Packit 7dae13
dynamic_array_display(dynamic_array_t * a,
Packit 7dae13
		      char delimiter,
Packit 7dae13
		      void (*display_element) (char *, void *),
Packit 7dae13
		      size_t(*element_length) (void *))
Packit 7dae13
{
Packit 7dae13
  void **a_current;
Packit 7dae13
  void **a_top;
Packit 7dae13
  char *buffer;
Packit 7dae13
  char *buffer_current;
Packit 7dae13
  size_t nochar;
Packit 7dae13
  size_t len = 0;
Packit 7dae13
Packit 7dae13
  if (a == NULL || a->count == 0) {
Packit 7dae13
    return (NULL);
Packit 7dae13
  }
Packit 7dae13
  a_top = a->vector + a->count;
Packit 7dae13
  nochar = a->count;
Packit 7dae13
  for (a_current = a->vector; a_current < a_top; a_current++) {
Packit 7dae13
    nochar += (len = element_length(*a_current));
Packit 7dae13
    if (!len) {
Packit 7dae13
      nochar--;
Packit 7dae13
    }
Packit 7dae13
  }
Packit 7dae13
  if ((buffer = (char *) malloc(nochar)) == NULL) {
Packit 7dae13
    return (NULL);
Packit 7dae13
  }
Packit 7dae13
  buffer_current = buffer;
Packit 7dae13
  for (a_current = a->vector; a_current < a_top; a_current++) {
Packit 7dae13
    if ((len = element_length(*a_current))) {
Packit 7dae13
      display_element(buffer_current, *a_current);
Packit 7dae13
      buffer_current += element_length(*a_current);
Packit 7dae13
      *buffer_current++ = delimiter;
Packit 7dae13
    }
Packit 7dae13
  }
Packit 7dae13
  if (len) {
Packit 7dae13
    buffer_current--;
Packit 7dae13
  }
Packit 7dae13
  *buffer_current = '\0';
Packit 7dae13
  return (buffer);
Packit 7dae13
}
Packit 7dae13
Packit 7dae13
Packit 7dae13
/**********************************************************************
Packit 7dae13
 * dynamic_array_get_element
Packit 7dae13
 * Get an element from an array
Packit 7dae13
 * pre: a: array to retrieve element from
Packit 7dae13
 *      elementno: index element in array to retrieve
Packit 7dae13
 * post: no change is made to a
Packit 7dae13
 * return: element requested
Packit 7dae13
 *         NULL if element is beyond the number of elements in the arary
Packit 7dae13
 **********************************************************************/
Packit 7dae13
Packit 7dae13
void *
Packit 7dae13
dynamic_array_get_element(dynamic_array_t * a, size_t elementno)
Packit 7dae13
{
Packit 7dae13
  if (elementno > a->count)
Packit 7dae13
    return (NULL);
Packit 7dae13
  return (*((a->vector) + elementno));
Packit 7dae13
}
Packit 7dae13
Packit 7dae13
Packit 7dae13
/**********************************************************************
Packit 7dae13
 * dynamic_array_get_count
Packit 7dae13
 * Get the number of elements in the array
Packit 7dae13
 * pre: array to find the number of elements in
Packit 7dae13
 * return: number of elements in the array
Packit 7dae13
 *         -1 if a is NULL
Packit 7dae13
 **********************************************************************/
Packit 7dae13
Packit 7dae13
size_t
Packit 7dae13
dynamic_array_get_count(dynamic_array_t * a)
Packit 7dae13
{
Packit 7dae13
  if (a == NULL)
Packit 7dae13
    return (-1);
Packit 7dae13
  return (a->count);
Packit 7dae13
}
Packit 7dae13
Packit 7dae13
Packit 7dae13
/**********************************************************************
Packit 7dae13
 * dynamic_array_get_vector
Packit 7dae13
 * Get the array contained in the dynamic array
Packit 7dae13
 * pre: array to find the vector of
Packit 7dae13
 * return: vector
Packit 7dae13
 *         NULL if a is NULL
Packit 7dae13
 **********************************************************************/
Packit 7dae13
Packit 7dae13
void *
Packit 7dae13
dynamic_array_get_vector(dynamic_array_t * a)
Packit 7dae13
{
Packit 7dae13
  if (a == NULL)
Packit 7dae13
    return (NULL);
Packit 7dae13
  return (a->vector);
Packit 7dae13
}
Packit 7dae13
Packit 7dae13
Packit 7dae13
/**********************************************************************
Packit 7dae13
 * dynamic_array_split_str
Packit 7dae13
 * Split a string into substrings on a delimiter
Packit 7dae13
 * pre: str: string to split
Packit 7dae13
 *      delimiter: character to split string on
Packit 7dae13
 * post: string is split.
Packit 7dae13
 *       Note: The string is modified.
Packit 7dae13
 * return: dynamic array containing sub_strings
Packit 7dae13
 *         NULL on error
Packit 7dae13
 *         string being NULL is an error state
Packit 7dae13
 **********************************************************************/
Packit 7dae13
Packit 7dae13
dynamic_array_t *
Packit 7dae13
dynamic_array_split_str(char *string, const char delimiter)
Packit 7dae13
{
Packit 7dae13
  dynamic_array_t *a;
Packit 7dae13
  char *sub_string;
Packit 7dae13
Packit 7dae13
  if (string == NULL) {
Packit 7dae13
    return (NULL);
Packit 7dae13
  }
Packit 7dae13
  if ((a = dynamic_array_create(0)) == NULL) {
Packit 7dae13
    return (NULL);
Packit 7dae13
  }
Packit 7dae13
  while ((sub_string = strchr(string, delimiter)) != NULL) {
Packit 7dae13
    *sub_string = '\0';
Packit 7dae13
    if (dynamic_array_add_element(a, string, DESTROY_STR, DUP_STR) == NULL) {
Packit 7dae13
      return (NULL);
Packit 7dae13
    }
Packit 7dae13
    string = sub_string + 1;
Packit 7dae13
  }
Packit 7dae13
  if (*string != '\0' &&
Packit 7dae13
      dynamic_array_add_element(a, string, DESTROY_STR, DUP_STR) == NULL) {
Packit 7dae13
    return (NULL);
Packit 7dae13
  }
Packit 7dae13
  return (a);
Packit 7dae13
}