How do I implement a generic linked list?
/* BEGIN string_sort_2.c */
/*
** Demonstration of use of generic list functions
** to sort a list of strings.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct list_node {
struct list_node *next;
void *data;
};
typedef struct list_node list_type;
#define NUMBERS \
{"one","two","three","four","five",\
"six","seven","eight","nine","ten"}
#define NMEMB(A) (sizeof (A) / sizeof *(A))
int lencomp(const list_type *a, const list_type *b);
list_type *list_append
(list_type **head, list_type *tail, void *data, size_t size);
void list_free(list_type *node, void (*free_data)(void *));
int list_fputs(const list_type *node, FILE *stream);
list_type *list_sort(list_type *head,
int (*compar)(const list_type *, const list_type *));
static list_type *sort_node (list_type *head,
int (*compar)(const list_type *, const list_type *));
static list_type *split_list(list_type *head);
static list_type *merge_lists(list_type *head, list_type *tail,
int (*compar)(const list_type *, const list_type *));
int main(void)
{
list_type *head;
list_type *tail;
char *numbers[] = NUMBERS;
char **const after = numbers + NMEMB(numbers);
char **ptr;
puts("/* BEGIN string_sort_2.c output */");
puts("\nOriginal order of list of pointers to strings:");
tail = head = NULL;
for (ptr = numbers; ptr != after; ++ptr) {
tail = list_append(&head, tail, *ptr, strlen(*ptr) + 1);
if (tail == NULL) {
puts("malloc trouble!");
break;
}
}
list_fputs(head, stdout);
puts("\nList after stable mergesort by string length:");
head = list_sort(head, lencomp);
list_fputs(head, stdout);
list_free(head, free);
puts("\n/* END string_sort_2.c output */");
return 0;
}
int lencomp(const list_type *a, const list_type *b)
{
const size_t a_len = strlen(a -> data);
const size_t b_len = strlen(b -> data);
return b_len > a_len ? -1 : b_len != a_len;
}
list_type *list_append
(list_type **head, list_type *tail, void *data, size_t size)
{
list_type *node;
node = malloc(sizeof *node);
if (node != NULL) {
node -> next = NULL;
node -> data = malloc(size);
if (node -> data != NULL) {
memcpy(node -> data, data, size);
if (*head != NULL) {
tail -> next = node;
} else {
*head = node;
}
} else {
free(node);
node = NULL;
}
}
return node;
}
void list_free(list_type *node, void (*free_data)(void *))
{
list_type *next_node;
while (node != NULL) {
next_node = node -> next;
free_data(node -> data);
free(node);
node = next_node;
}
}
int list_fputs(const list_type *node, FILE *stream)
{
int rc = 0;
while (node != NULL
&& (rc = fputs(node -> data, stream)) != EOF
&& (rc = putc('\n', stream)) != EOF)
{
node = node -> next;
}
return rc;
}
list_type *list_sort(list_type *head,
int (*compar)(const list_type *, const list_type *))
{
return head != NULL ? sort_node(head, compar) : head;
}
static list_type *sort_node(list_type *head,
int (*compar)(const list_type *, const list_type *))
{
list_type *tail;
if (head -> next != NULL) {
tail = split_list(head);
tail = sort_node(tail, compar);
head = sort_node(head, compar);
head = merge_lists(head, tail, compar);
}
return head;
}
static list_type *split_list(list_type *head)
{
list_type *tail;
tail = head -> next;
while ((tail = tail -> next) != NULL
&& (tail = tail -> next) != NULL)
{
head = head -> next;
}
tail = head -> next;
head -> next = NULL;
return tail;
}
static list_type *merge_lists(list_type *head, list_type *tail,
int (*compar)(const list_type *, const list_type *))
{
list_type *list, *sorted, **node;
node = compar(head, tail) > 0 ? &tail : &head;
list = sorted = *node;
*node = sorted -> next;
while (*node != NULL) {
node = compar(head, tail) > 0 ? &tail : &head;
sorted -> next = *node;
sorted = *node;
*node = sorted -> next;
}
sorted -> next = tail != NULL ? tail : head;
return list;
}
/* END string_sort_2.c */