-
Notifications
You must be signed in to change notification settings - Fork 13
/
u_list.c
271 lines (224 loc) · 7.75 KB
/
u_list.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
/*
* FCRON - periodic command scheduler
*
* Copyright 2000-2021 Thibault Godouet <fcron@free.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* The GNU General Public License can also be found in the file
* `LICENSE' that comes with the fcron source distribution.
*/
/*
* Unordered list of generic items
*/
#include "global.h"
#include "mem.h"
#include "log.h"
#include "u_list.h"
/* private functions: */
int u_list_resize_array(u_list_t * l);
u_list_entry_t *u_list_last(u_list_t * l);
u_list_t *
u_list_init(size_t entry_size, int init_size, int grow_size)
/* Create a new unordered list
* Returns the newly created unorderd list
* Enough memory to hold init_size entries will initially be allocated,
* and it will grow by grow_size entries when more space is needed.
* Dies on error. */
{
u_list_t *l = NULL;
/* sanity check */
if (entry_size < 1 || init_size < 1 || grow_size < 1)
die("Invalid arguments for u_list_init(): entry_size=%d, init_size=%d, "
"grow_size=%d", entry_size, init_size, grow_size);
/* Allocate the list structure: */
l = alloc_safe(sizeof(struct u_list_t), "new u_list_t");
/* Initialize the structure and allocate the array: */
l->array_size = init_size;
l->entry_size = entry_size;
l->grow_size = grow_size;
l->cur_entry = NULL;
l->cur_removed = 0;
l->entries_array = alloc_safe(init_size * entry_size, "new u_list_t array");
return l;
}
u_list_t *
u_list_copy(u_list_t * list)
{
u_list_t *new_list = NULL;
if (list == NULL)
return NULL;
new_list = alloc_safe(sizeof(struct u_list_t), "u_list_t copy");
memcpy(new_list, list, sizeof(struct u_list_t));
new_list->cur_entry = NULL;
new_list->entries_array = alloc_safe(list->array_size * list->entry_size,
"u_list_t copy (array)");
memcpy(new_list->entries_array, list->entries_array,
(list->array_size * list->entry_size));
return new_list;
}
int
u_list_resize_array(u_list_t * l)
/* Resize l's entries_array up to l->max_entries
* Returns OK on success, ERR if the array is already at maximum size */
{
int offset = 0;
int old_size = l->array_size;
/* sanity check */
if (l == NULL)
die("Invalid argument for u_list_resize_array(): list=%d", l);
if (l->max_entries > 0 && l->array_size >= l->max_entries) {
debug
("Resizing u_list_t failed because it is already at max size (size: %d)",
l->array_size);
return ERR;
}
if (l->cur_entry != NULL)
/* Compute cur_entry's offset so as we can set cur_entry to the right place
* after we have allocated a new chunk of memory for the entries_array */
offset = (char *)l->cur_entry - (char *)l->entries_array;
l->array_size = (l->array_size + l->grow_size);
if (l->max_entries > 0 && l->array_size > l->max_entries)
l->array_size = l->max_entries;
debug("Resizing u_list_t (old size: %d, new size: %d)...", old_size,
l->array_size);
l->entries_array =
realloc_safe(l->entries_array, (l->array_size * l->entry_size),
"larger u_list_t array");
/* allocate newly allocated memory */
memset((char *)l->entries_array + (old_size * l->entry_size), '\0',
(l->array_size - old_size) * l->entry_size);
if (l->cur_entry != NULL)
l->cur_entry = (u_list_entry_t *) ((char *)l->entries_array + offset);
return OK;
}
u_list_entry_t *
u_list_last(u_list_t * l)
/* Returns the pointer of the last entry in the list, or NULL if l is empty */
{
if (l->num_entries <= 0)
return NULL;
else
return (u_list_entry_t *)
((char *)l->entries_array + l->entry_size * (l->num_entries - 1));
}
u_list_entry_t *
u_list_add(u_list_t * l, u_list_entry_t * e)
/* Add one entry to the list
* Returns a pointer to the added element, or NULL if list is already at max size */
{
u_list_entry_t *new = NULL;
/* sanity check */
if (l == NULL || e == NULL)
die("Invalid arguments for u_list_add(): list=%d, entry=%d", l, e);
/* Check there is some space left, or resize the array */
if (l->num_entries >= l->array_size) {
/* no more space: attempt to grow (the following function dies on error: */
if (u_list_resize_array(l) != OK)
return NULL;
}
l->num_entries++;
new = u_list_last(l);
memcpy(new, e, l->entry_size);
return new;
}
int
u_list_is_iterating(u_list_t * l)
{
/* sanity check */
if (l == NULL)
die("Invalid argument for u_list_iterating(): list=%d", l);
return (l->cur_entry != NULL);
}
u_list_entry_t *
u_list_first(u_list_t * l)
/* Return the first entry of the list (then u_list_next() can be used) */
{
/* sanity check */
if (l == NULL)
die("Invalid argument for u_list_first(): list=%d", l);
if (l->cur_entry != NULL)
die("u_list_first() called but there is already an iteration");
if (l->num_entries > 0) {
l->cur_entry = l->entries_array;
}
return l->cur_entry;
}
u_list_entry_t *
u_list_next(u_list_t * l)
/* Return the entry after e */
{
/* sanity checks */
if (l == NULL)
die("Invalid arguments for u_list_next(): list=%d", l);
if (l->cur_entry == NULL)
die("u_list_next() called outside an iteration: l->cur_entry=%d",
l->cur_entry);
if (l->cur_removed > 0) {
l->cur_removed = 0;
/* the current entry has just been removed and replaced by another one:
* we can return the same pointer again.
* However if the removed entry was the last one then we reached the end
* of the list */
if (l->cur_entry > u_list_last(l))
l->cur_entry = NULL;
}
else {
/* cur_entry *not* removed (standard behavior) */
if (l->cur_entry < u_list_last(l))
l->cur_entry =
(u_list_entry_t *) ((char *)l->cur_entry + l->entry_size);
else
/* reached the end of the list */
l->cur_entry = NULL;
}
return l->cur_entry;
}
void
u_list_end_iteration(u_list_t * list)
/* Stop an iteration before _next() reached the end of the list by itself */
{
list->cur_entry = NULL;
list->cur_removed = 0;
}
void
u_list_remove_cur(u_list_t * l)
{
u_list_entry_t *last = NULL;
/* sanity checks */
if (l == NULL)
die("Invalid arguments for u_list_remove(): list=%d", l);
if (l->cur_entry == NULL)
die("u_list_remove_cur() called outside of an iteration");
last = u_list_last(l);
if (l->cur_entry < last) {
/* Override e with the last entry */
memcpy(l->cur_entry, last, l->entry_size);
}
/* erase the last entry and update the number of entries */
memset(last, 0, l->entry_size);
l->num_entries--;
l->cur_removed = 1;
}
u_list_t *
u_list_destroy(u_list_t * list)
/* free() the memory allocated for list and returns NULL */
{
if (list == NULL)
die("Invalid argument for u_list_destroy(): list=%d", list);
Free_safe(list->entries_array);
Free_safe(list);
return NULL;
}