llist.c 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. /* llist.c - Linked list functions
  2. *
  3. * Linked list structures have a next pointer as their first element.
  4. */
  5. #include "toys.h"
  6. // Callback function to free data pointer of double_list or arg_list
  7. void llist_free_arg(void *node)
  8. {
  9. struct arg_list *d = node;
  10. free(d->arg);
  11. free(d);
  12. }
  13. void llist_free_double(void *node)
  14. {
  15. struct double_list *d = node;
  16. free(d->data);
  17. free(d);
  18. }
  19. // Call a function (such as free()) on each element of a linked list.
  20. void llist_traverse(void *list, void (*using)(void *node))
  21. {
  22. void *old = list;
  23. while (list) {
  24. void *pop = llist_pop(&list);
  25. using(pop);
  26. // End doubly linked list too.
  27. if (old == list) break;
  28. }
  29. }
  30. // Return the first item from the list, advancing the list (which must be called
  31. // as &list)
  32. void *llist_pop(void *list)
  33. {
  34. void **llist = list, **next;
  35. if (!list || !*llist) return 0;
  36. next = (void **)*llist;
  37. *llist = *next;
  38. return next;
  39. }
  40. // Remove first item from &list and return it
  41. void *dlist_pop(void *list)
  42. {
  43. struct double_list **pdlist = (struct double_list **)list, *dlist = *pdlist;
  44. if (!dlist) return 0;
  45. if (dlist->next == dlist) *pdlist = 0;
  46. else {
  47. if (dlist->next) dlist->next->prev = dlist->prev;
  48. if (dlist->prev) dlist->prev->next = dlist->next;
  49. *pdlist = dlist->next;
  50. }
  51. return dlist;
  52. }
  53. // remove last item from &list and return it (stack pop)
  54. void *dlist_lpop(void *list)
  55. {
  56. struct double_list *dl = *(struct double_list **)list;
  57. void *v = 0;
  58. if (dl) {
  59. dl = dl->prev;
  60. v = dlist_pop(&dl);
  61. if (!dl) *(void **)list = 0;
  62. }
  63. return v;
  64. }
  65. // Append to list in-order (*list unchanged unless empty, ->prev is new node)
  66. void dlist_add_nomalloc(struct double_list **list, struct double_list *new)
  67. {
  68. if (*list) {
  69. new->next = *list;
  70. new->prev = (*list)->prev;
  71. (*list)->prev->next = new;
  72. (*list)->prev = new;
  73. } else *list = new->next = new->prev = new;
  74. }
  75. // Add an entry to the end of a doubly linked list
  76. struct double_list *dlist_add(struct double_list **list, char *data)
  77. {
  78. struct double_list *new = xmalloc(sizeof(struct double_list));
  79. new->data = data;
  80. dlist_add_nomalloc(list, new);
  81. return new;
  82. }
  83. // Terminate circular list for traversal in either direction. Returns end *.
  84. void *dlist_terminate(void *list)
  85. {
  86. struct double_list *end = list;
  87. if (!end || !end->prev) return 0;
  88. end = end->prev;
  89. end->next->prev = 0;
  90. end->next = 0;
  91. return end;
  92. }