Coverage Report

Created: 2025-12-03 07:02

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/curl/lib/llist.c
Line
Count
Source
1
/***************************************************************************
2
 *                                  _   _ ____  _
3
 *  Project                     ___| | | |  _ \| |
4
 *                             / __| | | | |_) | |
5
 *                            | (__| |_| |  _ <| |___
6
 *                             \___|\___/|_| \_\_____|
7
 *
8
 * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
9
 *
10
 * This software is licensed as described in the file COPYING, which
11
 * you should have received as part of this distribution. The terms
12
 * are also available at https://curl.se/docs/copyright.html.
13
 *
14
 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15
 * copies of the Software, and permit persons to whom the Software is
16
 * furnished to do so, under the terms of the COPYING file.
17
 *
18
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19
 * KIND, either express or implied.
20
 *
21
 * SPDX-License-Identifier: curl
22
 *
23
 ***************************************************************************/
24
25
#include "curl_setup.h"
26
27
#include <curl/curl.h>
28
29
#include "llist.h"
30
31
#ifdef DEBUGBUILD
32
0
#define LLISTINIT 0x100cc001 /* random pattern */
33
0
#define NODEINIT  0x12344321 /* random pattern */
34
0
#define NODEREM   0x54321012 /* random pattern */
35
36
0
#define VERIFYNODE(x) verifynode(x)
37
static struct Curl_llist_node *verifynode(struct Curl_llist_node *n)
38
0
{
39
0
  DEBUGASSERT(!n || (n->_init == NODEINIT));
40
0
  return n;
41
0
}
42
#else
43
#define VERIFYNODE(x) x
44
#endif
45
/*
46
 * @unittest: 1300
47
 */
48
void
49
Curl_llist_init(struct Curl_llist *l, Curl_llist_dtor dtor)
50
0
{
51
0
  l->_size = 0;
52
0
  l->_dtor = dtor;
53
0
  l->_head = NULL;
54
0
  l->_tail = NULL;
55
0
#ifdef DEBUGBUILD
56
0
  l->_init = LLISTINIT;
57
0
#endif
58
0
}
59
60
/*
61
 * Curl_llist_insert_next()
62
 *
63
 * Inserts a new list element after the given one 'e'. If the given existing
64
 * entry is NULL and the list already has elements, the new one will be
65
 * inserted first in the list.
66
 *
67
 * The 'ne' argument should be a pointer into the object to store.
68
 *
69
 * @unittest: 1300
70
 */
71
void
72
Curl_llist_insert_next(struct Curl_llist *list,
73
                       struct Curl_llist_node *e, /* may be NULL */
74
                       const void *p,
75
                       struct Curl_llist_node *ne)
76
0
{
77
0
  DEBUGASSERT(list);
78
0
  DEBUGASSERT(list->_init == LLISTINIT);
79
0
  DEBUGASSERT(ne);
80
81
0
#ifdef DEBUGBUILD
82
0
  ne->_init = NODEINIT;
83
0
#endif
84
0
  ne->_ptr = CURL_UNCONST(p);
85
0
  ne->_list = list;
86
0
  if(list->_size == 0) {
87
0
    list->_head = ne;
88
0
    list->_head->_prev = NULL;
89
0
    list->_head->_next = NULL;
90
0
    list->_tail = ne;
91
0
  }
92
0
  else {
93
    /* if 'e' is NULL here, we insert the new element first in the list */
94
0
    ne->_next = e ? e->_next : list->_head;
95
0
    ne->_prev = e;
96
0
    if(!e) {
97
0
      list->_head->_prev = ne;
98
0
      list->_head = ne;
99
0
    }
100
0
    else if(e->_next) {
101
0
      e->_next->_prev = ne;
102
0
    }
103
0
    else {
104
0
      list->_tail = ne;
105
0
    }
106
0
    if(e)
107
0
      e->_next = ne;
108
0
  }
109
110
0
  ++list->_size;
111
0
}
112
113
/*
114
 * Curl_llist_append()
115
 *
116
 * Adds a new list element to the end of the list.
117
 *
118
 * The 'ne' argument should be a pointer into the object to store.
119
 *
120
 * @unittest: 1300
121
 */
122
void
123
Curl_llist_append(struct Curl_llist *list, const void *p,
124
                  struct Curl_llist_node *ne)
125
0
{
126
0
  DEBUGASSERT(list);
127
0
  DEBUGASSERT(list->_init == LLISTINIT);
128
0
  DEBUGASSERT(ne);
129
0
  Curl_llist_insert_next(list, list->_tail, p, ne);
130
0
}
131
132
void *Curl_node_take_elem(struct Curl_llist_node *e)
133
0
{
134
0
  void *ptr;
135
0
  struct Curl_llist *list;
136
0
  if(!e)
137
0
    return NULL;
138
139
0
  list = e->_list;
140
0
  DEBUGASSERT(list);
141
0
  DEBUGASSERT(list->_init == LLISTINIT);
142
0
  DEBUGASSERT(list->_size);
143
0
  DEBUGASSERT(e->_init == NODEINIT);
144
0
  if(list) {
145
0
    if(e == list->_head) {
146
0
      list->_head = e->_next;
147
148
0
      if(!list->_head)
149
0
        list->_tail = NULL;
150
0
      else
151
0
        e->_next->_prev = NULL;
152
0
    }
153
0
    else {
154
0
      if(e->_prev)
155
0
        e->_prev->_next = e->_next;
156
157
0
      if(!e->_next)
158
0
        list->_tail = e->_prev;
159
0
      else
160
0
        e->_next->_prev = e->_prev;
161
0
    }
162
0
    --list->_size;
163
0
  }
164
0
  ptr = e->_ptr;
165
166
0
  e->_list = NULL;
167
0
  e->_ptr  = NULL;
168
0
  e->_prev = NULL;
169
0
  e->_next = NULL;
170
0
#ifdef DEBUGBUILD
171
0
  e->_init = NODEREM; /* specific pattern on remove - not zero */
172
0
#endif
173
174
0
  return ptr;
175
0
}
176
177
/*
178
 * @unittest: 1300
179
 */
180
UNITTEST void Curl_node_uremove(struct Curl_llist_node *, void *);
181
UNITTEST void
182
Curl_node_uremove(struct Curl_llist_node *e, void *user)
183
0
{
184
0
  struct Curl_llist *list;
185
0
  void *ptr;
186
0
  if(!e)
187
0
    return;
188
189
0
  list = e->_list;
190
0
  DEBUGASSERT(list);
191
0
  if(list) {
192
0
    ptr = Curl_node_take_elem(e);
193
0
    if(list->_dtor)
194
0
      list->_dtor(user, ptr);
195
0
  }
196
0
}
197
198
void Curl_node_remove(struct Curl_llist_node *e)
199
0
{
200
0
  Curl_node_uremove(e, NULL);
201
0
}
202
203
void
204
Curl_llist_destroy(struct Curl_llist *list, void *user)
205
0
{
206
0
  if(list) {
207
0
    DEBUGASSERT(list->_init == LLISTINIT);
208
0
    while(list->_size > 0)
209
0
      Curl_node_uremove(list->_tail, user);
210
0
  }
211
0
}
212
213
/* Curl_llist_head() returns the first 'struct Curl_llist_node *', which
214
   might be NULL */
215
struct Curl_llist_node *Curl_llist_head(struct Curl_llist *list)
216
0
{
217
0
  DEBUGASSERT(list);
218
0
  DEBUGASSERT(list->_init == LLISTINIT);
219
0
  return VERIFYNODE(list->_head);
220
0
}
221
222
#ifdef UNITTESTS
223
/* Curl_llist_tail() returns the last 'struct Curl_llist_node *', which
224
   might be NULL */
225
struct Curl_llist_node *Curl_llist_tail(struct Curl_llist *list)
226
{
227
  DEBUGASSERT(list);
228
  DEBUGASSERT(list->_init == LLISTINIT);
229
  return VERIFYNODE(list->_tail);
230
}
231
#endif
232
233
/* Curl_llist_count() returns a size_t the number of nodes in the list */
234
size_t Curl_llist_count(struct Curl_llist *list)
235
0
{
236
0
  DEBUGASSERT(list);
237
0
  DEBUGASSERT(list->_init == LLISTINIT);
238
0
  return list->_size;
239
0
}
240
241
/* Curl_node_elem() returns the custom data from a Curl_llist_node */
242
void *Curl_node_elem(struct Curl_llist_node *n)
243
0
{
244
0
  DEBUGASSERT(n);
245
0
  DEBUGASSERT(n->_init == NODEINIT);
246
0
  return n->_ptr;
247
0
}
248
249
/* Curl_node_next() returns the next element in a list from a given
250
   Curl_llist_node */
251
struct Curl_llist_node *Curl_node_next(struct Curl_llist_node *n)
252
0
{
253
0
  DEBUGASSERT(n);
254
0
  DEBUGASSERT(n->_init == NODEINIT);
255
0
  return VERIFYNODE(n->_next);
256
0
}
257
258
#ifdef UNITTESTS
259
260
/* Curl_node_prev() returns the previous element in a list from a given
261
   Curl_llist_node */
262
struct Curl_llist_node *Curl_node_prev(struct Curl_llist_node *n)
263
{
264
  DEBUGASSERT(n);
265
  DEBUGASSERT(n->_init == NODEINIT);
266
  return VERIFYNODE(n->_prev);
267
}
268
269
#endif
270
271
struct Curl_llist *Curl_node_llist(struct Curl_llist_node *n)
272
0
{
273
0
  DEBUGASSERT(n);
274
0
  DEBUGASSERT(!n->_list || n->_init == NODEINIT);
275
0
  return n->_list;
276
0
}