#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_ */