Properly implement tinc.texi's dependency on tincinclude.texi.
[tinc] / src / list.c
1 /*
2     list.c -- functions to deal with double linked lists
3     Copyright (C) 2000-2005 Ivo Timmermans
4                   2000-2006 Guus Sliepen <guus@tinc-vpn.org>
5
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License along
17     with this program; if not, write to the Free Software Foundation, Inc.,
18     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21 #include "system.h"
22
23 #include "list.h"
24 #include "xalloc.h"
25
26 /* (De)constructors */
27
28 list_t *list_alloc(list_action_t delete) {
29         list_t *list;
30
31         list = xmalloc_and_zero(sizeof(list_t));
32         list->delete = delete;
33
34         return list;
35 }
36
37 void list_free(list_t *list) {
38         free(list);
39 }
40
41 list_node_t *list_alloc_node(void) {
42         return xmalloc_and_zero(sizeof(list_node_t));
43 }
44
45 void list_free_node(list_t *list, list_node_t *node) {
46         if(node->data && list->delete) {
47                 list->delete(node->data);
48         }
49
50         free(node);
51 }
52
53 /* Insertion and deletion */
54
55 list_node_t *list_insert_head(list_t *list, void *data) {
56         list_node_t *node;
57
58         node = list_alloc_node();
59
60         node->data = data;
61         node->prev = NULL;
62         node->next = list->head;
63         list->head = node;
64
65         if(node->next) {
66                 node->next->prev = node;
67         } else {
68                 list->tail = node;
69         }
70
71         list->count++;
72
73         return node;
74 }
75
76 list_node_t *list_insert_tail(list_t *list, void *data) {
77         list_node_t *node;
78
79         node = list_alloc_node();
80
81         node->data = data;
82         node->next = NULL;
83         node->prev = list->tail;
84         list->tail = node;
85
86         if(node->prev) {
87                 node->prev->next = node;
88         } else {
89                 list->head = node;
90         }
91
92         list->count++;
93
94         return node;
95 }
96
97 void list_unlink_node(list_t *list, list_node_t *node) {
98         if(node->prev) {
99                 node->prev->next = node->next;
100         } else {
101                 list->head = node->next;
102         }
103
104         if(node->next) {
105                 node->next->prev = node->prev;
106         } else {
107                 list->tail = node->prev;
108         }
109
110         list->count--;
111 }
112
113 void list_delete_node(list_t *list, list_node_t *node) {
114         list_unlink_node(list, node);
115         list_free_node(list, node);
116 }
117
118 void list_delete_head(list_t *list) {
119         list_delete_node(list, list->head);
120 }
121
122 void list_delete_tail(list_t *list) {
123         list_delete_node(list, list->tail);
124 }
125
126 /* Head/tail lookup */
127
128 void *list_get_head(list_t *list) {
129         if(list->head) {
130                 return list->head->data;
131         } else {
132                 return NULL;
133         }
134 }
135
136 void *list_get_tail(list_t *list) {
137         if(list->tail) {
138                 return list->tail->data;
139         } else {
140                 return NULL;
141         }
142 }
143
144 /* Fast list deletion */
145
146 void list_delete_list(list_t *list) {
147         list_node_t *node, *next;
148
149         for(node = list->head; node; node = next) {
150                 next = node->next;
151                 list_free_node(list, node);
152         }
153
154         list_free(list);
155 }
156
157 /* Traversing */
158
159 void list_foreach_node(list_t *list, list_action_node_t action) {
160         list_node_t *node, *next;
161
162         for(node = list->head; node; node = next) {
163                 next = node->next;
164                 action(node);
165         }
166 }
167
168 void list_foreach(list_t *list, list_action_t action) {
169         list_node_t *node, *next;
170
171         for(node = list->head; node; node = next) {
172                 next = node->next;
173
174                 if(node->data) {
175                         action(node->data);
176                 }
177         }
178 }