view lib/llist.c @ 1604:f057223498e4 draft

Remove more strncpy() calls. The semantics of strncat() and strncpy() are non-obvious, so let's not use 'em. Both zero all their remaining buffer space, and with strncat() the size is the space left at the _end_ of the string (not the size of the buffer) so it's way too easy to stomp memory you don't own. As long as we have to measure stuff ourselves to get it right, just use memcpy().
author Rob Landley <rob@landley.net>
date Sat, 13 Dec 2014 11:56:41 -0600
parents 4d898affda0c
children
line wrap: on
line source

/* llist.c - Linked list functions
 *
 * Linked list structures have a next pointer as their first element.
 */

#include "toys.h"

// Callback function to free data pointer of double_list or arg_list

void llist_free_arg(void *node)
{
  struct arg_list *d = node;

  free(d->arg);
  free(d);
}

void llist_free_double(void *node)
{
  struct double_list *d = node;

  free(d->data);
  free(d);
}

// Call a function (such as free()) on each element of a linked list.
void llist_traverse(void *list, void (*using)(void *node))
{
  void *old = list;

  while (list) {
    void *pop = llist_pop(&list);
    using(pop);

    // End doubly linked list too.
    if (old == list) break;
  }
}

// Return the first item from the list, advancing the list (which must be called
// as &list)
void *llist_pop(void *list)
{
  // I'd use a void ** for the argument, and even accept the typecast in all
  // callers as documentation you need the &, except the stupid compiler
  // would then scream about type-punned pointers.  Screw it.
  void **llist = (void **)list;
  void **next = (void **)*llist;
  *llist = *next;

  return (void *)next;
}

void *dlist_pop(void *list)
{
  struct double_list **pdlist = (struct double_list **)list, *dlist = *pdlist;

  if (dlist->next == dlist) *pdlist = 0;
  else {
    dlist->next->prev = dlist->prev;
    dlist->prev->next = *pdlist = dlist->next;
  }

  return dlist;
}

void dlist_add_nomalloc(struct double_list **list, struct double_list *new)
{
  if (*list) {
    new->next = *list;
    new->prev = (*list)->prev;
    (*list)->prev->next = new;
    (*list)->prev = new;
  } else *list = new->next = new->prev = new;
}


// Add an entry to the end of a doubly linked list
struct double_list *dlist_add(struct double_list **list, char *data)
{
  struct double_list *new = xmalloc(sizeof(struct double_list));

  new->data = data;
  dlist_add_nomalloc(list, new);

  return new;
}

// Terminate circular list for traversal in either direction. Returns end *.
void *dlist_terminate(void *list)
{
  struct double_list *end = list;

  if (!list) return 0;

  end = end->prev;
  end->next->prev = 0;
  end->next = 0;

  return end;
}