1 /*------------------------------------------------------------------------------
2  *
3  * Copyright (c) 2011-2021, EURid vzw. All rights reserved.
4  * The YADIFA TM software product is provided under the BSD 3-clause license:
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  *        * Redistributions of source code must retain the above copyright
11  *          notice, this list of conditions and the following disclaimer.
12  *        * Redistributions in binary form must reproduce the above copyright
13  *          notice, this list of conditions and the following disclaimer in the
14  *          documentation and/or other materials provided with the distribution.
15  *        * Neither the name of EURid nor the names of its contributors may be
16  *          used to endorse or promote products derived from this software
17  *          without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  *
31  *------------------------------------------------------------------------------
32  *
33  */
34 
35 /** @defgroup collections Generic collections functions
36  *  @ingroup dnscore
37  *  @brief A node-based single linked list
38  *
39  * A node-based single linked list
40  *
41  * @{
42  */
43 /*------------------------------------------------------------------------------
44  *
45  * USE INCLUDES */
46 
47 #include "dnscore/dnscore-config.h"
48 #include "dnscore/list-sl.h"
49 
50 #define LISTDATA_TAG 0x415441445453494c
51 
52 /*------------------------------------------------------------------------------
53  * FUNCTIONS */
54 
55 /**
56  * Remove the first item that points to data;
57  *
58  * @param list
59  * @param data
60  * @return TRUE if an item has been deleted
61  */
62 
63 bool
list_sl_remove(list_sl_s * list,void * data)64 list_sl_remove(list_sl_s *list, void *data)
65 {
66     list_sl_node_s **nodep = &list->first;
67     list_sl_node_s *node = list->first;
68 
69     while(node != (list_sl_node_s*)&list->sentinel)
70     {
71         if(data == node->data)
72         {
73             *nodep = node->next;
74             list->size--;
75             free(node);
76             return TRUE;
77         }
78 
79         nodep = &node->next;
80         node = node->next;
81     }
82 
83     return FALSE;
84 }
85 
86 /**
87  * Remove all items from the list.
88  * Deletes the nodes but not the data.
89  *
90  * @param list
91  */
92 
93 void
list_sl_clear(list_sl_s * list)94 list_sl_clear(list_sl_s *list)
95 {
96     list_sl_node_s *node = list->first;
97 
98     while(node != (list_sl_node_s*)&list->sentinel)
99     {
100         list_sl_node_s *tmp = node;
101 
102         node = node->next;
103 
104         free(tmp);
105     }
106 
107     list->first = (list_sl_node_s *)&list->sentinel;
108     list->size = 0;
109 }
110 
111 /**
112  * Iterates through the nodes of the function, calling the comparator.
113  *
114  * The comparator must return:
115  *
116  * COLLECTION_ITEM_SKIP                 : go to next item
117  * COLLECTION_ITEM_STOP                 : stop processing, return NULL
118  * COLLECTION_ITEM_PROCESS_THEN_STOP    : stop processing, return node data
119  *
120  * @param list
121  * @param comparator
122  *
123  * @return a matching node or NULL
124  */
125 
list_sl_search(list_sl_s * list,result_callback_function * comparator,void * parm)126 void *list_sl_search(list_sl_s *list, result_callback_function *comparator, void *parm)
127 {
128     list_sl_node_s *node = list->first;
129 
130     while(node != (list_sl_node_s*)&list->sentinel)
131     {
132         ya_result ret = comparator(node->data, parm);
133 
134         if((ret & COLLECTION_ITEM_STOP) != 0)
135         {
136             if((ret & COLLECTION_ITEM_PROCESS) != 0)
137             {
138                 return node->data;
139             }
140             else
141             {
142                 return NULL;
143             }
144         }
145 
146         node = node->next;
147     }
148 
149     return NULL;
150 }
151 
152 /**
153  * Iterates through the nodes of the function, calling the comparator.
154  *
155  * The comparator must return:
156  *
157  * < 0 : stop processing, return NULL
158  * = 0 : no match
159  * > 0 : stop processing, return node data
160  *
161  * @param list
162  * @param comparator
163  *
164  * @return a matching node or NULL
165  */
166 
167 bool
list_sl_remove_match(list_sl_s * list,result_callback_function * comparator,void * parm)168 list_sl_remove_match(list_sl_s *list, result_callback_function *comparator, void *parm)
169 {
170     list_sl_node_s **nodep = &list->first;
171     list_sl_node_s *node = list->first;
172     bool matched = FALSE;
173 
174     while(node != (list_sl_node_s*)&list->sentinel)
175     {
176         ya_result ret = comparator(node->data, parm);
177 
178         if((ret & COLLECTION_ITEM_PROCESS) != 0)
179         {
180             list_sl_node_s* next = node->next;
181             *nodep = node->next;
182             list->size--;
183             free(node);
184             matched = TRUE;
185 
186             if((ret & COLLECTION_ITEM_STOP) != 0)
187             {
188                 break;
189             }
190 
191             node = next; // node is assigned its next value (stored in *nodep), it's not using freed memory with this.
192             nodep = &node->next;
193             continue;
194         }
195 
196         if((ret & COLLECTION_ITEM_STOP) != 0)
197         {
198             break;
199         }
200 
201         node = *nodep; // node is assigned its next value (stored in *nodep), it's not using freed memory with this.
202         nodep = &node->next;
203     }
204 
205     return matched;
206 }
207 
208 
209 /** @} */
210 
211 /*----------------------------------------------------------------------------*/
212