/
list.c
356 lines (338 loc) · 11.1 KB
/
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
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
/* jpnevulator - serial reader/writer
* Copyright (C) 2006-2020 Freddy Spierenburg
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdlib.h>
#include "list.h"
/* This routine initializes our list meta data. */
enum listRtrn listInitialize(list_t *list) {
list->first=list->last=list->current=NULL;
list->elements=0;
return(listRtrnOk);
}
/* This routine appends one element to the list. It will
* be appended just after the current element. */
enum listRtrn listAppend(list_t *list,void *data) {
struct listElement *p;
/* Allocate memory for the new element. */
p=(struct listElement *)malloc(sizeof(p[0]));
if(p!=NULL) {
/* Assign the data to the element. */
p->data=data;
/* Do any elements exist already in the list? */
if(list->current!=NULL) {
/* Yes, we will append this one after the current one. */
/* Is the current one the last one in the list? */
if(list->current->next!=NULL) {
/* No, so we have to let the one after the current know
* that we will be the previous element from now on. */
list->current->next->previous=p;
} else {
/* Yes, so we tell the meta data that we are the last in the
* list right now. */
list->last=p;
}
/* Our next one will be the next one of the current element. */
p->next=list->current->next;
/* Our previous one will be the current element. */
p->previous=list->current;
/* And of course we should let the current element know that
* we come next in the list. */
list->current->next=p;
} else {
/* No, there do not exist any elements in the list yet so we
* are the first, last and current. */
p->previous=p->next=NULL;
list->first=list->last=list->current=p;
}
/* Increase the amount of elements known to the list. */
list->elements++;
return(listRtrnOk);
} else {
return(listRtrnMemory);
}
}
/* This routine insert one element to the list. It will
* be inserted just before the current element. */
enum listRtrn listInsert(list_t *list,void *data) {
struct listElement *p;
/* Allocate memory for the new element. */
p=(struct listElement *)malloc(sizeof(p[0]));
if(p!=NULL) {
/* Assign the data to the element. */
p->data=data;
/* Do any elements exist already in the list? */
if(list->current!=NULL) {
/* Yes, we will insert this one before the current one. */
/* Our previous one will be the one before the current element. */
p->previous=list->current->previous;
/* We will be the previous one for the current element. */
list->current->previous=p;
/* Our next one will be the current element. */
p->next=list->current;
/* Are we now the first one in the list? */
if(p->previous!=NULL) {
/* No, so we have to let the one before us know that we
* will be the next element from now on. */
p->previous->next=p;
} else {
/* Yes, so we tell the meta data that we are the first in the
* list right now. */
list->first=p;
}
} else {
/* No, there do not exist any elements in the list yet so we
* are the first, last and current. */
p->previous=p->next=NULL;
list->first=list->last=list->current=p;
}
/* Increase the amount of elements known to the list. */
list->elements++;
return(listRtrnOk);
} else {
return(listRtrnMemory);
}
}
/* This routine removes the current element from the list. If none available
* it does nothing. */
void listRemove(list_t *list,void (*garbageCollect)(void *)) {
/* Any elements in the list available? */
if(list->current!=NULL) {
struct listElement *p;
/* Yes, let's remove the current one. */
p=list->current;
/* Is it the first element in the list? */
if(p->previous!=NULL) {
/* No, so let the element before know what the new element after
* it will be. */
list->current->previous->next=p->next;
} else {
/* Yes, so update the first meta data. */
list->first=p->next;
}
/* Is it the last element in the list? */
if(p->next!=NULL) {
/* No, so let the element after it know what the new element
* before it will be. */
p->next->previous=p->previous;
} else {
/* Yes, so update the last meta data. */
list->last=p->previous;
}
/* Now we need to update the current meta data. Does an element
* after this element exist? */
if(p->next!=NULL) {
/* Yes, this next element will be the new current element. */
list->current=p->next;
} else {
/* No, the element before this one will be the new current element. */
list->current=p->previous;
}
/* Run the garbage collector for this item if required. */
if(garbageCollect!=NULL) {
garbageCollect(p->data);
}
/* Return system resources. */
free(p);
/* Decrease the amount of elements known to the list. */
list->elements--;
}
}
/* This routine returns the data of the current element or NULL if
* none is available. */
void *listCurrent(list_t *list) {
return(list->current!=NULL?list->current->data:NULL);
}
/* This routine returns the first element in the list or NULL if
* none is available. It also sets the current meta data to be the
* first element in the list. */
void *listFirst(list_t *list) {
list->current=list->first;
return(listCurrent(list));
}
/* This routine returns the next element in the list or NULL if
* none is available. It also advances the current meta data to the
* next element. */
void *listNext(list_t *list) {
if((list->current!=NULL)&&(list->current->next!=NULL)) {
list->current=list->current->next;
return(listCurrent(list));
} else {
return(NULL);
}
}
/* This routine returns the previous element in the list or NULL if
* none is available. It also sets the current meta data to the
* previous element. */
void *listPrevious(list_t *list) {
if((list->current!=NULL)&&(list->current->previous!=NULL)) {
list->current=list->current->previous;
return(listCurrent(list));
} else {
return(NULL);
}
}
/* This routine returns the last element in the list or NULL if
* none is available. It also sets the current meta data to be the
* last element in the list. */
void *listLast(list_t *list) {
list->current=list->last;
return(listCurrent(list));
}
/* This routine search the list for a specific element given by needle and
* returns that element or NULL if it's not found. */
void *listSearch(list_t *list,int (*compare)(void *,void *),void *needle) {
void *data;
int found;
/* At first we of course didn't find anything and especially when
we do not receive a list we make sure we did not found anything
as of yet. */
found=0;
/* Does any element exist in the list? */
if((data=listFirst(list))!=NULL) {
do {
/* Yes, so search for our element... */
if((found=compare(data,needle))) break;
/* ...untill none left. */
} while((data=listNext(list))!=NULL);
}
/* If we found our data return it, otherwise return NULL. */
return(found?data:NULL);
}
/* This routine gracefully returns all system resources and empty the
* list. */
void listDestroy(list_t *list,void (*garbageCollect)(void *)) {
struct listElement *p;
/* Search untill no elements are left... */
while(list->first!=NULL) {
/* First save a reference to our next element. */
p=list->first->next;
/* Run the garbage collector for this item if required. */
if(garbageCollect!=NULL) {
garbageCollect(list->first->data);
}
/* Then return resources for the current one. */
free(list->first);
/* And at last advance to our next element. */
list->first=p;
}
/* Reset all our meta data. */
list->first=list->last=list->current=NULL;
list->elements=0;
}
#if 0
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
int cmpr(void *p,void *q) {
return(!strcmp((char *)p,(char *)q));
}
void garbageCollect(void *data) {
printf("Taking down: %s\n",(char *)data);
}
int main(int argc,char **argv) {
list_t list;
int index;
char *arg;
int elements;
/* Initialize our list. */
listInitialize(&list);
/* Fill our list with all command line arguments given, but skip the
* first argument since that's our needle (see below -> listSearch()). */
for(index=2;index<argc;index++) {
/* Append the argument to our list. */
if(listAppend(&list,(void *)argv[index])!=listRtrnOk) {
fprintf(stderr,"Can't create item!\n");
break;
}
/* Advance to this next position. By default listAppend() does not
* advance our current pointer to the appended element. */
listNext(&list);
}
/* Print all our arguments from the first to the last. */
printf("First to last:\n");
/* Does any argument exist? */
if((arg=(char *)listFirst(&list))!=NULL) {
/* Yes, we print it and... */
do {
printf("[%s]\n",arg);
/* ...advance to the next argument, untill none left. */
} while((arg=(char *)listNext(&list))!=NULL);
} else {
printf("empty list\n");
}
/* Print all our arguments from the last to the first. */
printf("Last to first:\n");
/* Does any argument exist? */
if((arg=(char *)listLast(&list))!=NULL) {
/* Yes, we print it and... */
do {
printf("[%s]\n",arg);
/* ...advance to the next argument, untill none left. */
} while((arg=(char *)listPrevious(&list))!=NULL);
} else {
printf("empty list\n");
}
/* If there do exist enough arguments... */
if(argc>=2) {
/* ...search for the first one given... */
arg=listSearch(&list,cmpr,(void *)argv[1]);
/* ...and tell if it's found. */
printf("searching for [%s]... %sfound\n",argv[1],arg!=NULL?"":"not ");
}
/* Randomly remove half of the arguments. */
srandom(getpid());
for(elements=listElements(&list)/2;elements>0;elements--) {
int element=(random()%(argc-2))+2;
arg=listSearch(&list,cmpr,(void *)argv[element]);
printf("Removing [%s]... ",argv[element]);
if(arg!=NULL) {
listRemove(&list,NULL);
printf("ok\n");
} else {
printf("not in the list!\n");
}
}
/* Print all our arguments from the first to the last. */
printf("First to last:\n");
/* Does any argument exist? */
if((arg=(char *)listFirst(&list))!=NULL) {
/* Yes, we print it and... */
do {
printf("[%s]\n",arg);
/* ...advance to the next argument, untill none left. */
} while((arg=(char *)listNext(&list))!=NULL);
} else {
printf("empty list\n");
}
/* Print all our arguments from the last to the first. */
printf("Last to first:\n");
/* Does any argument exist? */
if((arg=(char *)listLast(&list))!=NULL) {
/* Yes, we print it and... */
do {
printf("[%s]\n",arg);
/* ...advance to the next argument, untill none left. */
} while((arg=(char *)listPrevious(&list))!=NULL);
} else {
printf("empty list\n");
}
/* Destroy the list and all its elements. */
listDestroy(&list,garbageCollect);
return(0);
}
#endif