1 /*+++++++++++++++++
2   linklist.c - implements some functions for linked lists
3   markus@mhoenicka.de 7-11-00
4 
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 2 of the License, or
8    (at your option) any later version.
9 
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14 
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software
17    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 
19   ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
20 
21 #include <stdio.h> /* for a definition of NULL */
22 #include <stdlib.h> /* for malloc */
23 #include <string.h>
24 
25 #include "linklist.h"
26 
27 /*********************************************************************
28  linked list for file descriptors
29  This is an ordered linked list. The highest fd will always be the
30  first member of the list.
31 ********************************************************************/
32 
33 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
34   insert_olili(): inserts a new item into an ordered linked list. The
35                   list will be in descending order, so the first item
36                   after the sentinel is the item with the highest
37                   value
38 
39   int insert_olili returns 0 if ok, 1 if error
40 
41   struct olili *ptr_first pointer to sentinel
42 
43   int value the value to be inserted into the list (value >= 0)
44 
45   ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
insert_olili(Olili * ptr_first,int value)46 int insert_olili(Olili *ptr_first, int value) {
47   Olili *ptr_before; /* item before insertion point */
48   Olili *ptr_after; /* item after insertion point */
49   Olili *ptr_new_olili; /* new item */
50 
51   ptr_before = ptr_first; /* start search at the beginning */
52   ptr_after = ptr_before->ptr_next;
53 
54   while (ptr_after != NULL) {
55     if (ptr_after->fd <= value) { /* sort in descending order */
56       break;
57     }
58     ptr_after = ptr_after->ptr_next;
59     ptr_before = ptr_before->ptr_next;
60   }
61 
62   ptr_new_olili = malloc(sizeof(Olili));
63   if (ptr_new_olili == NULL) {
64     return 1;
65   }
66   ptr_new_olili->fd = value;
67   ptr_before->ptr_next = ptr_new_olili;
68   ptr_new_olili->ptr_next = ptr_after;
69 
70   return 0;
71 }
72 
73 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
74   delete_olili(): deletes an item from an ordered linked list.
75 
76   int delete_olili returns 0 if ok, 1 if error
77 
78   Olili *ptr_first pointer to sentinel
79 
80   int value the value to be inserted into the list
81 
82   ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
delete_olili(Olili * ptr_first,int value)83 int delete_olili(Olili *ptr_first, int value) {
84   Olili *ptr_before; /* item before deletion point */
85   Olili *ptr_curr; /* item at deletion point */
86 
87   ptr_before = ptr_first; /* start search at the beginning */
88   ptr_curr = ptr_before->ptr_next;
89 
90   while (ptr_curr != NULL) {
91     if (ptr_curr->fd == value) { /* got it */
92       break;
93     }
94     ptr_curr = ptr_curr->ptr_next;
95     ptr_before = ptr_before->ptr_next;
96   }
97 
98   if (ptr_curr == NULL) {
99     return 1;
100   }
101 
102   ptr_before->ptr_next = ptr_curr->ptr_next;
103   free(ptr_curr);
104   return 0;
105 }
106 
107 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
108   max_olili(): returns the item with the highest value from an ordered
109                linked list.
110 
111   int max_olili returns the maximum value, or -1 if an error occurred
112 
113   Olili *ptr_first pointer to sentinel
114 
115   ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
max_olili(Olili * ptr_first)116 int max_olili(Olili *ptr_first) {
117   if (ptr_first != NULL && ptr_first->ptr_next != NULL) {
118     return ptr_first->ptr_next->fd;
119   }
120   else if (ptr_first != NULL) {
121     return ptr_first->fd;
122   }
123   else {
124     return -1;
125   }
126 }
127 
128 
129 /*********************************************************************
130  linked list for allocated memory
131  This is an unsorted linked list. The first list member is a sentinel
132  which is not automatically deallocated by the lilimem functions.
133  The calling fn has to explicitly declare, initialize, and destruct
134  a lilimem struct for this purpose.
135 ********************************************************************/
136 
137 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
138   insert_lilimem(): inserts a new member into the list
139 
140   int insert_lilimem returns 0 if ok, or 1 if an error occurred
141                  if an error occurs, the memory pointed to by ptr_mem
142 		 will be freed
143 
144   Lilimem *ptr_first pointer to sentinel
145 
146   void** ptr_mem ptr to ptr to allocated memory
147 
148   char* varname ptr to string with the name of the variable used for
149                 that memory location. This name is used to find the
150 		correct list member if you want to delete a specific
151 		entry with the delete_lilimem() function. This can in
152 		fact be any unique string other than the variable name.
153 		You may pass NULL here if you don't use
154 		delete_lilimem(), but only delete_all_lilimem()
155 
156   ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
insert_lilimem(Lilimem * ptr_first,void ** ptr_mem,char * varname)157 int insert_lilimem(Lilimem *ptr_first, void** ptr_mem, char* varname) {
158   Lilimem* ptr_new_item;
159 
160   if (varname && strlen(varname) > 32) { /* string too long to fit into struct */
161     return 1;
162   }
163 
164   ptr_new_item = malloc(sizeof(Lilimem));
165 
166   if (ptr_new_item == NULL) { /* malloc failed */
167     free(*ptr_mem);
168     return 1;
169   }
170 
171   if (varname) {
172     strcpy(ptr_new_item->varname, varname);
173   }
174   else {
175     (ptr_new_item->varname)[0] = '\0';
176   }
177   ptr_new_item->ptr_mem = ptr_mem;
178   ptr_new_item->ptr_next = ptr_first->ptr_next;
179   ptr_first->ptr_next = ptr_new_item;
180 
181   return 0;
182 }
183 
184 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
185   delete_lilimem(): deletes a member from the list by the varname
186 
187   int delete_lilimem returns 0 if ok, or 1 if an error occurred
188 
189   Lilimem *ptr_first pointer to sentinel
190 
191   char* varname ptr to string with the name of the variable used for
192                 that memory location
193 
194   ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
delete_lilimem(Lilimem * ptr_first,char * varname)195 int delete_lilimem(Lilimem *ptr_first, char* varname) {
196   Lilimem* ptr_curr_item;
197   Lilimem* ptr_prev_item;
198   int gotit = 0;
199 
200   ptr_prev_item = ptr_first;
201   ptr_curr_item = ptr_first->ptr_next;
202 
203   while (ptr_curr_item) {
204     if (ptr_curr_item->varname && strcmp(ptr_curr_item->varname, varname) == 0) {
205       gotit = 1;
206       break;
207     }
208     /* else: silently ignore if item has no varname */
209     ptr_prev_item = ptr_curr_item;
210     ptr_curr_item = ptr_curr_item->ptr_next;
211   }
212 
213   if (gotit) {
214     free(*(ptr_curr_item->ptr_mem)); /* free the memory referenced by the list
215 					member */
216 /*      fprintf(stderr, "freeing %s\n", ptr_curr_item->varname); */
217     *(ptr_curr_item->ptr_mem) = NULL; /* set the memory ptr to NULL to avoid
218 				      problems with erroneous subsequent
219 				      free() calls */
220     ptr_prev_item->ptr_next = ptr_curr_item->ptr_next;
221     free(ptr_curr_item); /* free the memory allocated for the list member */
222     return 0;
223   }
224   else {
225     return 1;
226   }
227 }
228 
229 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
230   delete_all_lilimem(): deletes all members from the list
231 
232   int delete_all_lilimem returns 0 if ok, or 1 if an error occurred
233 
234   Lilimem *ptr_first pointer to sentinel
235 
236   ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
delete_all_lilimem(Lilimem * ptr_first)237 int delete_all_lilimem(Lilimem *ptr_first) {
238   Lilimem* ptr_curr_item;
239   Lilimem* ptr_next_item;
240 
241   ptr_curr_item = ptr_first->ptr_next;
242   ptr_first->ptr_next = NULL;
243 
244   while (ptr_curr_item) {
245     ptr_next_item = ptr_curr_item->ptr_next;
246 /*      fprintf(stderr, "freeing %s\n", ptr_curr_item->varname); */
247     free(*(ptr_curr_item->ptr_mem)); /* free the memory referenced by the list
248 					member */
249     *(ptr_curr_item->ptr_mem) = NULL; /* set the memory ptr to NULL to avoid
250 				      problems with erroneous subsequent
251 				      free() calls */
252     free(ptr_curr_item); /* free the memory allocated for the list member */
253 
254     ptr_curr_item = ptr_next_item;
255   }
256   return 0;
257 }
258 
259 /*********************************************************************
260  linked list for decoding cgi data
261  This is an unsorted linked list. The first list member is a sentinel
262  which is not automatically deallocated by the lilimem functions.
263  The calling fn has to explicitly declare, initialize, and destruct
264  a lilimem struct for this purpose.
265 ********************************************************************/
266 
267 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
268   insert_liliform(): inserts a new member into the list
269 
270   int insert_liliform returns 0 if ok, or 1 if an error occurred
271                  if an error occurs, the memory pointed to by ptr_mem
272 		 will be freed
273 
274   Liliform *ptr_first pointer to sentinel
275 
276   char* name ptr to string with the name of the variable used for
277                 that memory location.
278 
279   char* value ptr to allocated memory
280 
281   ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
insert_liliform(Liliform * ptr_first,char * name,char * value)282 int insert_liliform(Liliform *ptr_first, char* name, char* value) {
283   Liliform* ptr_new_item;
284   char* my_value;
285 
286   if (name == NULL) {
287     return 0; /* do nothing, no error */
288   }
289 
290   if (strlen(name) > 32) { /* string too long to fit into struct */
291     return 1;
292   }
293 
294   ptr_new_item = malloc(sizeof(Liliform));
295 
296   if (!ptr_new_item) { /* malloc failed */
297     return 1;
298   }
299 
300   strcpy(ptr_new_item->name, name);
301 
302   if (value && strlen(value)) {
303     my_value = malloc(strlen(value)+1);
304     if (!my_value) {
305       free(ptr_new_item);
306       return 1;
307     }
308     strcpy(my_value, value);
309     ptr_new_item->value = my_value;
310   }
311   else {
312     ptr_new_item->value = NULL;
313   }
314 
315   ptr_new_item->ptr_next = ptr_first->ptr_next;
316   ptr_first->ptr_next = ptr_new_item;
317 
318   return 0;
319 }
320 
321 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
322   append_liliform(): appends a new member into the list. The
323                        implementation is not very efficient but is ok
324 		       for a low number of entries
325 
326   int append_liliform returns 0 if ok, or 1 if an error occurred
327                  if an error occurs
328 
329   Liliform *ptr_first pointer to sentinel
330 
331   char* name ptr to string with the name of the variable used for
332                 that memory location.
333 
334   char* value ptr to allocated memory
335 
336   ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
append_liliform(Liliform * ptr_first,char * name,char * value)337 int append_liliform(Liliform *ptr_first, char* name, char* value) {
338   char* my_value;
339   Liliform* ptr_new_item;
340   Liliform* ptr_last_item;
341 
342   ptr_new_item = malloc(sizeof(Liliform));
343 
344   if (!ptr_new_item) { /* malloc failed */
345     return 1;
346   }
347 
348   strcpy(ptr_new_item->name, name);
349 
350   if (value && *value) {
351     my_value = malloc(strlen(value)+1);
352     if (!my_value) {
353       free(ptr_new_item);
354       return 1;
355     }
356     strcpy(my_value, value);
357     ptr_new_item->value = my_value;
358   }
359   else {
360     ptr_new_item->value = NULL;
361   }
362 
363   ptr_new_item->ptr_next = NULL;
364 
365   ptr_last_item = ptr_first;
366 
367   /* this is going to be inefficient for a large number of entries */
368   while (ptr_last_item->ptr_next) {
369     ptr_last_item = ptr_last_item->ptr_next;
370   }
371   ptr_last_item->ptr_next = ptr_new_item;
372 
373   return 0;
374 }
375 
376 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
377   get_liliform(): retrieves a member of the list by name
378 
379   Liliform* get_liliform returns a ptr to the first member
380                    whose name matches as specified and whose value is
381 		   not NULL, otherwise it returns NULL
382 
383   Liliform *ptr_first pointer to sentinel
384 
385   char* name ptr to string with the name of the variable
386 
387   ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
get_liliform(Liliform * ptr_first,char * name)388 Liliform* get_liliform(Liliform* ptr_first, char* name) {
389   Liliform* ptr_curr_item;
390   Liliform* ptr_result = NULL;
391 
392   ptr_curr_item = ptr_first->ptr_next;
393 
394   while (ptr_curr_item) {
395     if (!strcmp(ptr_curr_item->name, name)) {
396       if (ptr_curr_item->value) {
397 	ptr_result = ptr_curr_item;
398       }
399       break;
400     }
401     ptr_curr_item = ptr_curr_item->ptr_next;
402   }
403   return ptr_result;
404 }
405 
406 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
407   get_nliliform(): retrieves a member of the list by partial name match
408 
409   Liliform* get_nliliform returns a ptr to the first member
410                    whose name matches as specified and whose value is
411 		   not NULL, otherwise it returns NULL
412 
413   Liliform *ptr_first pointer to sentinel
414 
415   char* name ptr to string with the name of the variable
416 
417   size_t n the number of characters to compare, starting at name[0]
418 
419   ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
get_nliliform(Liliform * ptr_first,char * name,size_t n)420 Liliform* get_nliliform(Liliform* ptr_first, char* name, size_t n) {
421   Liliform* ptr_curr_item;
422   Liliform* ptr_result = NULL;
423 
424   ptr_curr_item = ptr_first->ptr_next;
425 
426   while (ptr_curr_item) {
427     if (!strncmp(ptr_curr_item->name, name, n)) {
428       if (ptr_curr_item->value) {
429 	ptr_result = ptr_curr_item;
430       }
431       break;
432     }
433     ptr_curr_item = ptr_curr_item->ptr_next;
434   }
435   return ptr_result;
436 }
437 
438 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
439   get_next_liliform(): retrieves next member of the list
440 
441   Liliform* get_next_liliform returns a ptr to the next member or NULL
442                       if we're at the end of the list. Use this fn
443 		      to loop over all list entries. In the first
444 		      iteration, pass a ptr to the sentinel. In
445 		      subsequent iterations, pass the ptr that the
446 		      previous iteration returns.
447 
448 
449   Liliform *ptr_first pointer to sentinel
450 
451   ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
get_next_liliform(Liliform * ptr_first)452 Liliform* get_next_liliform(Liliform* ptr_first) {
453   return ptr_first->ptr_next;
454 }
455 
456 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
457   delete_all_liliform(): deletes all members from the list
458 
459   int delete_all_liliform returns 0 if ok, or 1 if an error occurred
460 
461   Liliform *ptr_first pointer to sentinel
462 
463   ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
delete_all_liliform(Liliform * ptr_first)464 int delete_all_liliform(Liliform *ptr_first) {
465   Liliform* ptr_curr_item;
466   Liliform* ptr_next_item;
467 
468   ptr_curr_item = ptr_first->ptr_next;
469   ptr_first->ptr_next = NULL;
470 
471   while (ptr_curr_item) {
472     ptr_next_item = ptr_curr_item->ptr_next;
473 /*      fprintf(stderr, "freeing %s\n", ptr_curr_item->varname); */
474     free(ptr_curr_item->value); /* free the memory allocated for the value */
475     free(ptr_curr_item); /* free the memory allocated for the list member */
476 
477     ptr_curr_item = ptr_next_item;
478   }
479   return 0;
480 }
481 
482 /*********************************************************************
483  linked list for reading non-standard field mapping for BibTeX data
484  This is an unsorted linked list. The first list member is a sentinel
485  which is not automatically deallocated by the lilimem functions.
486  The calling fn has to explicitly declare, initialize, and destruct
487  a lilimem struct for this purpose.
488 ********************************************************************/
489 
490 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
491   insert_lilibib(): inserts a new member into the list
492 
493   int insert_lilibib returns 0 if ok, or 1 if an error occurred
494                  if an error occurs, the memory pointed to by ptr_mem
495 		 will be freed
496 
497   Lilibib *ptr_first pointer to sentinel
498 
499   char* name ptr to string with the name of the variable used for
500                 that memory location. May be NULL if retrieval by name
501 		is not necessary
502 
503   char* value ptr to allocated memory
504 
505   ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
insert_lilibib(Lilibib * ptr_first,char * name,char * value)506 int insert_lilibib(Lilibib *ptr_first, char* name, char* value) {
507   Lilibib* ptr_new_item;
508   char* my_value;
509   char* my_name;
510 
511   ptr_new_item = malloc(sizeof(Lilibib));
512 
513   if (!ptr_new_item) { /* malloc failed */
514     return 1;
515   }
516 
517   if (name && *name) {
518     my_name = malloc(strlen(name)+1);
519     if (!my_name) {
520       free(ptr_new_item);
521       return 1;
522     }
523     strcpy(my_name, name);
524     ptr_new_item->name = my_name;
525   }
526   else {
527     ptr_new_item->name = NULL;
528   }
529 
530   if (value && *value) {
531     my_value = malloc(strlen(value)+1);
532     if (!my_value) {
533       free(ptr_new_item);
534       return 1;
535     }
536     strcpy(my_value, value);
537     ptr_new_item->value = my_value;
538   }
539   else {
540     ptr_new_item->value = NULL;
541   }
542 
543   ptr_new_item->ptr_next = ptr_first->ptr_next;
544   ptr_first->ptr_next = ptr_new_item;
545 
546   return 0;
547 }
548 
549 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
550   get_next_lilibib(): retrieves next member of the list
551 
552   Lilibib* get_next_lilibib returns a ptr to the next member or NULL
553                       if we're at the end of the list. Use this fn
554 		      to loop over all list entries. In the first
555 		      iteration, pass a ptr to the sentinel. In
556 		      subsequent iterations, pass the ptr that the
557 		      previous iteration returns.
558 
559 
560   Lilibib *ptr_first pointer to sentinel
561 
562   ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
get_next_lilibib(Lilibib * ptr_first)563 Lilibib* get_next_lilibib(Lilibib* ptr_first) {
564   return ptr_first->ptr_next;
565 }
566 
567 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
568   get_lilibib(): retrieves a member of the list by name
569 
570   Lilibib* get_next_lilibib returns a ptr to the list member with
571                  the given name or NULL if none such exists.
572 
573 
574   Lilibib *ptr_first pointer to sentinel
575 
576   char* name name of the list member to return
577 
578   ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
get_lilibib(Lilibib * ptr_first,char * name)579 Lilibib* get_lilibib(Lilibib* ptr_first, char* name) {
580   Lilibib* ptr_curr_item;
581   Lilibib* ptr_result = NULL;
582 
583   ptr_curr_item = ptr_first->ptr_next;
584 
585   while (ptr_curr_item) {
586     if (!strcmp(ptr_curr_item->name, name)) {
587       if (ptr_curr_item->value) {
588 	ptr_result = ptr_curr_item;
589       }
590       break;
591     }
592     ptr_curr_item = ptr_curr_item->ptr_next;
593   }
594   return ptr_result;
595 }
596 
597 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
598   delete_all_lilibib(): deletes all members from the list
599 
600   int delete_all_lilibib returns 0 if ok, or 1 if an error occurred
601 
602   Lilibib *ptr_first pointer to sentinel
603 
604   ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
delete_all_lilibib(Lilibib * ptr_first)605 int delete_all_lilibib(Lilibib *ptr_first) {
606   Lilibib* ptr_curr_item;
607   Lilibib* ptr_next_item;
608 
609   ptr_curr_item = ptr_first->ptr_next;
610   ptr_first->ptr_next = NULL;
611 
612   while (ptr_curr_item) {
613     ptr_next_item = ptr_curr_item->ptr_next;
614 /*      fprintf(stderr, "freeing %s\n", ptr_curr_item->varname); */
615     if (ptr_curr_item->name) {
616       free(ptr_curr_item->name); /* free the memory allocated for the name */
617     }
618     if (ptr_curr_item->value) {
619       free(ptr_curr_item->value); /* free the memory allocated for the value */
620     }
621     free(ptr_curr_item); /* free the memory allocated for the list member */
622 
623     ptr_curr_item = ptr_next_item;
624   }
625   return 0;
626 }
627 
628 /*********************************************************************
629  linked list for reading id lists
630  This is a sorted linked list. The first list member is a sentinel
631  which is not automatically deallocated by the lilimem functions.
632  The calling fn has to explicitly declare, initialize, and destruct
633  a lilid struct for this purpose.
634  The payload of a member is an id value and two ints used as booleans
635 ********************************************************************/
636 
637 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
638   insert_lilid(): inserts a new member into the list
639 
640   int insert_lilid returns 0 if ok, or 1 if an error occurred
641 
642   Lilid *ptr_first pointer to sentinel
643 
644   unsigned long long value the value to store
645 
646   ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
insert_lilid(Lilid * ptr_first,unsigned long long value)647 int insert_lilid(Lilid *ptr_first, unsigned long long value) {
648   Lilid* ptr_new_item; /* ptr to new list member */
649   Lilid* ptr_before; /* ptr to member before insertion point */
650   Lilid* ptr_after; /* ptr to member after insertion point */
651 
652   ptr_new_item = malloc(sizeof(Lilid));
653 
654   if (!ptr_new_item) { /* malloc failed */
655     return 1;
656   }
657 
658   /* set requested value */
659   ptr_new_item->value = value;
660 
661   /* set default values */
662   ptr_new_item->is_duplicate = 0;
663   ptr_new_item->is_existent = 0;
664 
665   /* find insertion point */
666   ptr_before = ptr_first; /* start search at the beginning */
667   ptr_after = ptr_before->ptr_next;
668 
669   while (ptr_after != NULL) {
670     if (ptr_after->value >= value) { /* sort in ascending order */
671       break;
672     }
673     ptr_after = ptr_after->ptr_next;
674     ptr_before = ptr_before->ptr_next;
675   }
676 
677   /* insert new item into list */
678   ptr_before->ptr_next = ptr_new_item;
679   ptr_new_item->ptr_next = ptr_after;
680 
681   return 0;
682 }
683 
684 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
685   get_next_lilid(): retrieves next member of the list in ascending order
686 
687   Lilid* get_next_lilid returns a ptr to the next member or NULL
688                       if we're at the end of the list. Use this fn
689 		      to loop over all list entries. In the first
690 		      iteration, pass a ptr to the sentinel. In
691 		      subsequent iterations, pass the ptr that the
692 		      previous iteration returns.
693 
694 
695   struct lilid *ptr_first pointer to sentinel
696 
697   ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
get_next_lilid(Lilid * ptr_first)698 Lilid* get_next_lilid(Lilid* ptr_first) {
699   return ptr_first->ptr_next;
700 }
701 
702 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
703   count_lilid(): counts all members in the list
704 
705   unsigned long long count_lilid returns the number of list members
706 
707   Lilid *ptr_first pointer to sentinel
708 
709   ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
count_lilid(Lilid * ptr_first)710 unsigned long long count_lilid(Lilid* ptr_first) {
711   unsigned long long ull_counter = 0;
712   Lilid *ptr_curr;
713 
714   /* start at the beginning */
715   ptr_curr = ptr_first;
716 
717   /* loop over all list elements */
718   while ((ptr_curr = get_next_lilid(ptr_curr)) != NULL) {
719     ull_counter++;
720   }
721 
722   return ull_counter;
723 }
724 
725 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
726   delete_all_lilid(): deletes all members from the list
727 
728   int delete_all_lilid returns 0 if ok, or 1 if an error occurred
729 
730   Lilid *ptr_first pointer to sentinel
731 
732   ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
delete_all_lilid(Lilid * ptr_first)733 int delete_all_lilid(Lilid *ptr_first) {
734   Lilid* ptr_curr_item;
735   Lilid* ptr_next_item;
736 
737   /* skip the sentinel when freeing memory */
738   ptr_curr_item = ptr_first->ptr_next;
739   ptr_first->ptr_next = NULL;
740 
741   /* loop over all list members after the sentinel */
742   while (ptr_curr_item) {
743     /* save a pointer to the next member, if any */
744     ptr_next_item = ptr_curr_item->ptr_next;
745 
746     /* free the memory allocated for the list member */
747     free(ptr_curr_item);
748 
749     ptr_curr_item = ptr_next_item;
750   }
751   return 0;
752 }
753 
754 /*********************************************************************
755  linked list for tokenizing strings. The list stores pointers to
756  the individual tokens. The calling function should terminate the tokens
757  by inserting \0 between the tokens.
758  This is an unsorted linked list. The first list member is a sentinel
759  which is not automatically deallocated by the lilimem functions.
760  The calling fn has to explicitly declare, initialize, and destruct
761  a lilimem struct for this purpose.
762 ********************************************************************/
763 
764 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
765   insert_lilistring(): inserts a new member into the list
766 
767   int insert_lilistring returns 0 if ok, or 1 if an error occurred
768                  if an error occurs
769 
770   Lilistring *ptr_first pointer to sentinel
771 
772   char* token ptr to token
773 
774   ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
insert_lilistring(Lilistring * ptr_first,char * token)775 int insert_lilistring(Lilistring *ptr_first, char* token) {
776   Lilistring* ptr_new_item;
777 
778   ptr_new_item = malloc(sizeof(Lilistring));
779 
780   if (!ptr_new_item) { /* malloc failed */
781     return 1;
782   }
783 
784   if (token) {
785     ptr_new_item->token = token;
786   }
787   else {
788     ptr_new_item->token = NULL;
789   }
790 
791   ptr_new_item->ptr_next = ptr_first->ptr_next;
792   ptr_first->ptr_next = ptr_new_item;
793 
794   return 0;
795 }
796 
797 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
798   append_lilistring(): appends a new member into the list. The
799                        implementation is not very efficient but is ok
800 		       for a low number of entries
801 
802   int append_lilistring returns 0 if ok, or 1 if an error occurred
803                  if an error occurs
804 
805   Lilistring *ptr_first pointer to sentinel
806 
807   char* token ptr to token
808 
809   ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
append_lilistring(Lilistring * ptr_first,char * token)810 int append_lilistring(Lilistring *ptr_first, char* token) {
811   Lilistring* ptr_new_item;
812   Lilistring* ptr_last_item;
813 
814   ptr_new_item = malloc(sizeof(Lilistring));
815 
816   if (!ptr_new_item) { /* malloc failed */
817     return 1;
818   }
819 
820   if (token) {
821     ptr_new_item->token = token;
822   }
823   else {
824     ptr_new_item->token = NULL;
825   }
826 
827   ptr_new_item->ptr_next = NULL;
828 
829   ptr_last_item = ptr_first;
830 
831   /* this is going to be inefficient for a large number of entries */
832   while (ptr_last_item->ptr_next) {
833     ptr_last_item = ptr_last_item->ptr_next;
834   }
835   ptr_last_item->ptr_next = ptr_new_item;
836 
837   return 0;
838 }
839 
840 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
841   get_next_lilistring(): retrieves next member of the list
842 
843   Lilistring* get_next_lilistring returns a ptr to the next member or NULL
844                       if we're at the end of the list. Use this fn
845 		      to loop over all list entries. In the first
846 		      iteration, pass a ptr to the sentinel. In
847 		      subsequent iterations, pass the ptr that the
848 		      previous iteration returns.
849 
850 
851   Lilistring *ptr_first pointer to sentinel
852 
853   ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
get_next_lilistring(Lilistring * ptr_first)854 Lilistring* get_next_lilistring(Lilistring* ptr_first) {
855   return ptr_first->ptr_next;
856 }
857 
858 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
859   delete_all_lilistring(): deletes all members from the list
860 
861   int delete_all_lilistring returns 0 if ok, or 1 if an error occurred
862 
863   Lilistring *ptr_first pointer to sentinel
864 
865   ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
delete_all_lilistring(Lilistring * ptr_first)866 int delete_all_lilistring(Lilistring *ptr_first) {
867   Lilistring* ptr_curr_item;
868   Lilistring* ptr_next_item;
869 
870   ptr_curr_item = ptr_first->ptr_next;
871   ptr_first->ptr_next = NULL;
872 
873   while (ptr_curr_item) {
874     ptr_next_item = ptr_curr_item->ptr_next;
875 /*      fprintf(stderr, "freeing %s\n", ptr_curr_item->varname); */
876     free(ptr_curr_item); /* free the memory allocated for the list member */
877 
878     ptr_curr_item = ptr_next_item;
879   }
880   return 0;
881 }
882 
883 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
884   count_lilistring(): counts all members in the list
885 
886   int count_lilistring returns the number of list members
887 
888   Lilistring *ptr_first pointer to sentinel
889 
890   ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
count_lilistring(Lilistring * ptr_first)891 int count_lilistring(Lilistring* ptr_first) {
892   int counter = 0;
893   Lilistring *ptr_curr;
894 
895   /* start at the beginning */
896   ptr_curr = ptr_first;
897 
898   /* loop over all list elements */
899   while ((ptr_curr = get_next_lilistring(ptr_curr)) != NULL) {
900     counter++;
901   }
902 
903   return counter;
904 }
905 
906 /*********************************************************************
907  linked list for fixed-size strings. The list keeps the original order
908  of items
909 ********************************************************************/
910 
911 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
912   append_lilifstring(): appends a new member into the list. The
913                        implementation is not very efficient but is ok
914 		       for a low number of entries
915 
916   int append_lilifstring returns 0 if ok, or 1 if an error occurred
917                  if an error occurs
918 
919   Lilifstring *ptr_first pointer to sentinel
920 
921   char* token ptr to token
922 
923   ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
append_lilifstring(Lilifstring * ptr_first,char * token)924 int append_lilifstring(Lilifstring *ptr_first, char* token) {
925   Lilifstring* ptr_new_item;
926   Lilifstring* ptr_last_item;
927 
928   ptr_new_item = malloc(sizeof(Lilifstring));
929 
930   if (!ptr_new_item) { /* malloc failed */
931     return 1;
932   }
933 
934   if (token) {
935     strncpy(ptr_new_item->token, token, LILIFSTRING_SIZE);
936     (ptr_new_item->token)[LILIFSTRING_SIZE-1] = '\0';
937   }
938   else {
939     (ptr_new_item->token)[0] = '\0';
940   }
941 
942   ptr_new_item->ptr_next = NULL;
943 
944   ptr_last_item = ptr_first;
945 
946   /* this is going to be inefficient for a large number of entries */
947   while (ptr_last_item->ptr_next) {
948     ptr_last_item = ptr_last_item->ptr_next;
949   }
950   ptr_last_item->ptr_next = ptr_new_item;
951 
952   return 0;
953 }
954 
955 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
956   get_next_lilifstring(): retrieves next member of the list
957 
958   Lilifstring* get_next_lilifstring returns a ptr to the next member or NULL
959                       if we're at the end of the list. Use this fn
960 		      to loop over all list entries. In the first
961 		      iteration, pass a ptr to the sentinel. In
962 		      subsequent iterations, pass the ptr that the
963 		      previous iteration returns.
964 
965 
966   Lilifstring *ptr_first pointer to sentinel
967 
968   ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
get_next_lilifstring(Lilifstring * ptr_first)969 Lilifstring* get_next_lilifstring(Lilifstring* ptr_first) {
970   return ptr_first->ptr_next;
971 }
972 
973 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
974   delete_all_lilifstring(): deletes all members from the list
975 
976   int delete_all_lilifstring returns 0 if ok, or 1 if an error occurred
977 
978   Lilifstring *ptr_first pointer to sentinel
979 
980   ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
delete_all_lilifstring(Lilifstring * ptr_first)981 int delete_all_lilifstring(Lilifstring *ptr_first) {
982   Lilifstring* ptr_curr_item;
983   Lilifstring* ptr_next_item;
984 
985   ptr_curr_item = ptr_first->ptr_next;
986   ptr_first->ptr_next = NULL;
987 
988   while (ptr_curr_item) {
989     ptr_next_item = ptr_curr_item->ptr_next;
990 /*      fprintf(stderr, "freeing %s\n", ptr_curr_item->varname); */
991     free(ptr_curr_item); /* free the memory allocated for the list member */
992 
993     ptr_curr_item = ptr_next_item;
994   }
995   return 0;
996 }
997 
998 
999 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1000   find_lilifstring(): checks whether token is already stored in the list
1001 
1002   int find_lilifstring returns 1 if token is part of the list. or
1003                  0 if not
1004 
1005   Lilifstring *ptr_first pointer to sentinel
1006 
1007   char* token ptr to token
1008 
1009   ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
find_lilifstring(Lilifstring * ptr_first,char * token)1010 char* find_lilifstring(Lilifstring* ptr_first, char* token) {
1011   Lilifstring* ptr_curr_item;
1012 
1013   ptr_curr_item = ptr_first;
1014 
1015   while ((ptr_curr_item = get_next_lilifstring(ptr_curr_item)) != NULL) {
1016     if (!strcmp(ptr_curr_item->token, token)) {
1017       return token;
1018     }
1019   }
1020 
1021   return NULL;
1022 }
1023