llwfp

Documentation
Login

Documentation

#ifdef _LLWFP_H_
#error Mixing 'llwfp' and 'llwfp-min' in the same code is probably not a good a idea!
#endif

#ifndef _LLWFP_MIN_H_
#define _LLWFP_MIN_H_

#include <errno.h>
#include <string.h> /* strerror() */
#include <stdio.h>  /* fprintf() */
#include <stdlib.h> /* malloc(), calloc(), free() */


/* Status flags */
typedef enum
{
  LL_ERROR = -1,
  LL_OK    = 0,
  LL_END   = 1, /* EndOfLinkedList (current node is the last in list having data */
  LL_EMPTY = 2  /* EmptyLinkedList (head node is NULL) */
} ll_status_t;


/* Node definition, generic data type (void *) */
typedef struct node_t
{
  struct node_t *next;
  void *data;
} node_t;


/* Struct of function pointers to handle node data */
typedef size_t (*data_size_t)(void *data);
typedef ll_status_t (*data_add_t)(void *input_data, void **data);
typedef void *(*data_get_t)(void *data);
typedef void (*data_cleanup_t)(void *data);
typedef struct node_data_fp_t
{
  data_size_t size;
  data_add_t add;
  data_get_t get;
  data_cleanup_t cleanup;
} node_data_fp_t;

/* Generic init function definition for the function pointers */
typedef void (*data_init_t)(node_data_fp_t *ndfp);


/* Typedef for the main list object */
typedef struct nodewfp_t
{
  node_t *head;       /* First node in list */
  node_t *current;    /* Current node in list */
  node_data_fp_t *df; /* Struct of function pointers to handle node data */
} nodewfp_t;

/*
  ---------------
  The minimal API
  ---------------
 */
void node_init(nodewfp_t *nwfp, data_init_t init_function)
{
  if ((nwfp->df = malloc(sizeof(*nwfp->df))) != NULL)
  {
    init_function(nwfp->df);
  }
  nwfp->head = NULL;
  nwfp->current = NULL;
}

/* malloc() node - generic */
static ll_status_t node_malloc(nodewfp_t *nwfp)
{
  node_t *node = calloc(1, sizeof(*node));
  if (node == NULL)
  {
    fprintf(stderr, "node_init(): malloc() failed: %s\n", strerror(errno));
    return LL_ERROR;
  }
  else
  {
    node->next = NULL;
    /* First node? */
    if (!nwfp->head)
    {
      nwfp->head = node;
      nwfp->current = nwfp->head;
    }
    else
    {
      nwfp->current->next = node;
      nwfp->current = nwfp->current->next;
    }
  }
  return 0;
}

/* Add node and assign data - generic */
int node_add(nodewfp_t *nwfp, void *data)
{
  int rc = LL_ERROR;
  if (!nwfp) {return LL_ERROR;}
  if (node_malloc(nwfp) == LL_ERROR) {return LL_ERROR;}
  if (nwfp->df->add)
  {
    /* If an 'add' function is defined, let that function add the data (may include data malloc()). */
    /* Any user defined method should set rc to non-zero to indicate error, zero for success */
    rc = nwfp->df->add(data, &nwfp->current->data);
  }
  else if (nwfp->df->size)
  {
    /* If no 'add', but a 'size' function is defined, let that function decide how much data to allocate here. */
    /* Any user defined method should set rc to negative to indicate error, zero for NOP (no allocation occurs), positive for success */
    size_t alloc_size = nwfp->df->size(data);
    nwfp->current->data = calloc(1, alloc_size);
    if (!nwfp->current->data)
    {
      rc = LL_ERROR;
    }
    else
    {
      /* copy data with memcpy() */
      memcpy(nwfp->current->data, data, alloc_size);
      rc = LL_OK;
    }
  }
  else
  {
    /* If there no user defined functions, just copy data pointers here */
    nwfp->current->data = data;
    rc = LL_OK;
  }
  return rc;
}

/* Get data for first node - generic */
void *node_get_first(nodewfp_t *nwfp, int *rc)
{
  if (nwfp == NULL)
  {
    *rc = LL_ERROR;
    return NULL;
  }
  /* Reset current to point to head */
  nwfp->current = nwfp->head;
  /* If head is NULL, list is empty, return EmptyLinkedList */
  if (nwfp->current == NULL)
  {
    *rc = 2;
    return NULL;
  }
  /* If current node the last in list having data, set status flag to EndOfLinkedList */
  *rc = (nwfp->current->next) ? 0 : 1;
  return nwfp->head->data;
}
/* Get data for consequent nodes - generic */
void *node_get_next(nodewfp_t *nwfp, int *rc)
{
  /* If the current node is NULL, this is considered an error */
  if ((nwfp == NULL) || (nwfp->current == NULL))
  {
    *rc = LL_ERROR;
    return NULL;
  }
  /* This is a repeated call to get data for the next node. */
  nwfp->current = nwfp->current->next;
  /* Catch unexpected error (may occur when called using the wrong list object)  */
  if (nwfp->current == NULL)
  {
    *rc = LL_ERROR;
    return NULL;
  }
  /* If this is the last node, set status flag to EndOfLinkedList */
  *rc = (nwfp->current->next) ? LL_OK : LL_END;
  return nwfp->current->data;
}


/* Get number of nodes */
int node_count(nodewfp_t *nwfp)
{
  int count = 0;
  if (nwfp != NULL)
  {
    nwfp->current = nwfp->head;
    while (nwfp->current)
    {
      count++;
      nwfp->current = nwfp->current->next;
    }
  }
  return count;
}

/* Delete all nodes - generic */
void node_cleanup(nodewfp_t *nwfp, node_t *node)
{
  if ((nwfp == NULL) || (node == NULL)) return;
  /* Goto to last node */
  node_cleanup(nwfp, node->next);
  /* Cleanup user data */
  if (nwfp->df->cleanup) nwfp->df->cleanup(node->data);
  /* Cleanup node */
  free(node);
  if (nwfp->head == NULL) free(nwfp->df);
}

#endif /* _LLWFP_MIN_H_ */