Fix reading configuration files that do not end with a newline.
[tinc] / lib / 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
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19
20     $Id$
21 */
22
23 #include "system.h"
24
25 #include "list.h"
26 #include "xalloc.h"
27
28 /* (De)constructors */
29
30 list_t *list_alloc(list_action_t delete)
31 {
32         list_t *list;
33
34         list = xmalloc_and_zero(sizeof(list_t));
35         list->delete = delete;
36
37         return list;
38 }
39
40 void list_free(list_t *list)
41 {
42         free(list);
43 }
44
45 list_node_t *list_alloc_node(void)
46 {
47         return xmalloc_and_zero(sizeof(list_node_t));
48 }
49
50 void list_free_node(list_t *list, list_node_t *node)
51 {
52         if(node->data && list->delete)
53                 list->delete(node->data);
54
55         free(node);
56 }
57
58 /* Insertion and deletion */
59
60 list_node_t *list_insert_head(list_t *list, void *data)
61 {
62         list_node_t *node;
63
64         node = list_alloc_node();
65
66         node->data = data;
67         node->prev = NULL;
68         node->next = list->head;
69         list->head = node;
70
71         if(node->next)
72                 node->next->prev = node;
73         else
74                 list->tail = node;
75
76         list->count++;
77
78         return node;
79 }
80
81 list_node_t *list_insert_tail(list_t *list, void *data)
82 {
83         list_node_t *node;
84
85         node = list_alloc_node();
86
87         node->data = data;
88         node->next = NULL;
89         node->prev = list->tail;
90         list->tail = node;
91
92         if(node->prev)
93                 node->prev->next = node;
94         else
95                 list->head = node;
96
97         list->count++;
98
99         return node;
100 }
101
102 void list_unlink_node(list_t *list, list_node_t *node)
103 {
104         if(node->prev)
105                 node->prev->next = node->next;
106         else
107                 list->head = node->next;
108
109         if(node->next)
110                 node->next->prev = node->prev;
111         else
112                 list->tail = node->prev;
113
114         list->count--;
115 }
116
117 void list_delete_node(list_t *list, list_node_t *node)
118 {
119         list_unlink_node(list, node);
120         list_free_node(list, node);
121 }
122
123 void list_delete_head(list_t *list)
124 {
125         list_delete_node(list, list->head);
126 }
127
128 void list_delete_tail(list_t *list)
129 {
130         list_delete_node(list, list->tail);
131 }
132
133 /* Head/tail lookup */
134
135 void *list_get_head(list_t *list)
136 {
137         if(list->head)
138                 return list->head->data;
139         else
140                 return NULL;
141 }
142
143 void *list_get_tail(list_t *list)
144 {
145         if(list->tail)
146                 return list->tail->data;
147         else
148                 return NULL;
149 }
150
151 /* Fast list deletion */
152
153 void list_delete_list(list_t *list)
154 {
155         list_node_t *node, *next;
156
157         for(node = list->head; node; node = next) {
158                 next = node->next;
159                 list_free_node(list, node);
160         }
161
162         list_free(list);
163 }
164
165 /* Traversing */
166
167 void list_foreach_node(list_t *list, list_action_node_t action)
168 {
169         list_node_t *node, *next;
170
171         for(node = list->head; node; node = next) {
172                 next = node->next;
173                 action(node);
174         }
175 }
176
177 void list_foreach(list_t *list, list_action_t action)
178 {
179         list_node_t *node, *next;
180
181         for(node = list->head; node; node = next) {
182                 next = node->next;
183                 if(node->data)
184                         action(node->data);
185         }
186 }