#include <stdio.h>
#include <stdlib.h>

typedef struct Item_ {
  unsigned id;
  void *data;               // Pointer to custom data container.
  void (*deleter)(void *);  // Custom deleter for `data`, defaults to `free()`.
  struct Item_ *next;
} Item;


Item **endOfList_(Item **const begin) {
  Item **item = begin;
  for (; *item; item = &(*item)->next);
  return item;
}

Item **findItem_(Item **const begin, unsigned const id) {
  Item **item = begin;
  for (; *item && (*item)->id != id; item = &(*item)->next);
  return item;
}

void spliceItem_(Item **const reference, Item *const item) {
  Item *next = *reference;
  *reference = item;
  (*reference)->next = next;
}


Item *newItem(
    unsigned const id, void *const data, void (*const deleter)(void *)) {
  Item *item = malloc(sizeof(Item));
  item->id = id;
  item->data = data;
  item->deleter = deleter;
  item->next = NULL;
  return item;
}

void deleteItem(Item *const item) {
  if (item->deleter) {
    item->deleter(item->data);
  }
  else {
    free(item->data);
  }
  free(item);
}

void appendItem(Item **const begin, Item *const item) {
  Item **reference = endOfList_(begin);
  *reference = item;
}

void prependItem(Item **const begin, Item *const item) {
  spliceItem_(begin, item);
}

Item *findItem(Item **const begin, unsigned const id) {
  return *findItem_(begin, id);
}

void insertAfter(Item **const begin, unsigned const id, Item *const item) {
  Item **reference = findItem_(begin, id);
  if (!*reference) {
    return;
  }

  spliceItem_(&(*reference)->next, item);
}

void insertBefore(Item **const begin, unsigned const id, Item *const item) {
  Item **reference = findItem_(begin, id);
  if (!*reference) {
    return;
  }

  spliceItem_(reference, item);
}

void removeItem(Item **const begin, unsigned const id) {
  Item **item = findItem_(begin, id);
  if (!*item) {
    return;
  }

  Item *item_ = *item;
  (*item) = (*item)->next;
  deleteItem(item_);
}

void destroyList(Item **const begin) {
  for (Item *item = *begin; item;) {
    Item *item_ = item;
    item = item->next;
    deleteItem(item_);
  }
}

void printList(Item **const begin) {
  for (Item *item = *begin; item; item = item->next) {
    printf("%i ", item->id);
  }
  printf("\n");
}


/* Usage example. */

typedef struct {
  int x;
  int y;
} Data;


Data *newData(int const x, int const y) {
  Data *data = malloc(sizeof(Data));
  data->x = x;
  data->y = y;
  return data;
}

void deleteData(void *data) {
  printf("Custom deleter called.\n");
  free(data);
}

void printItem(Item *const item) {
  printf("item: %u, ", item->id);

  Data *data = item->data;
  if (data) {
    printf("data: (x: %i, y: %i)\n", data->x, data->y);
  }
  else {
    printf("no data\n");
  }
}


int main(void) {
  Item *list = {NULL};

  Data *data = newData(10, 20);
  appendItem(&list, newItem(1, data, NULL));
  appendItem(&list, newItem(2, NULL, deleteData));
  printList(&list);                                  // 1, 2

  prependItem(&list, newItem(0, NULL, deleteData));
  printList(&list);                                  // 0, 1, 2

  insertAfter(&list, 0, newItem(4, NULL, NULL));
  printList(&list);                                  // 0, 4, 1, 2

  insertBefore(&list, 0, newItem(5, NULL, NULL));
  printList(&list);                                  // 5, 0, 4, 1, 2

  insertBefore(&list, 4, newItem(6, NULL, NULL));
  printList(&list);                                  // 5, 0, 6, 4, 1, 2

  removeItem(&list, 4);
  printList(&list);                                  // 5, 0, 6, 1, 2

  removeItem(&list, 2);
  printList(&list);                                  // 5, 0, 6, 1

  printItem(findItem(&list, 1));
  printItem(findItem(&list, 6));

  destroyList(&list);
}

Add a code snippet to your website: www.paste.org