1 /*
2  * Copyright 2006, 2007 Daniel Silverstone <dsilvers@digital-scurf.org>
3  *
4  * This file is part of NetSurf, http://www.netsurf-browser.org/
5  *
6  * NetSurf is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; version 2 of the License.
9  *
10  * NetSurf 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, see <http://www.gnu.org/licenses/>.
17  */
18 
19 /** \file
20  * Ring list structure.
21  *
22  * Rings are structures which have an r_next pointer and an r_prev
23  * pointer which are always initialised and always point at the next
24  * or previous element respectively.
25  *
26  * The degenerate case of a single element in the ring simply points
27  * at itself in both directions. A zero element ring is NULL.
28  *
29  * Some of the ring functions are specific to the fetcher but may be
30  * of use to others and are thus included here.
31  */
32 
33 #ifndef _NETSURF_UTILS_RING_H_
34 #define _NETSURF_UTILS_RING_H_
35 
36 
37 /** Insert the given item into the specified ring.
38  * Assumes that the element is zeroed as appropriate.
39  */
40 #define RING_INSERT(ring,element) \
41 	/*LOG("RING_INSERT(%s, %p(%s))", #ring, element, element->host);*/ \
42 	if (ring) { \
43 		element->r_next = ring; \
44 		element->r_prev = ring->r_prev; \
45 		ring->r_prev = element; \
46 		element->r_prev->r_next = element; \
47 	} else \
48 		ring = element->r_prev = element->r_next = element
49 
50 /** Remove the given element from the specified ring.
51  * Will zero the element as needed
52  */
53 #define RING_REMOVE(ring, element) \
54 	/*LOG("RING_REMOVE(%s, %p(%s)", #ring, element, element->host);*/ \
55 	if (element->r_next != element ) { \
56 		/* Not the only thing in the ring */ \
57 		element->r_next->r_prev = element->r_prev; \
58 		element->r_prev->r_next = element->r_next; \
59 		if (ring == element) ring = element->r_next; \
60 	} else { \
61 		/* Only thing in the ring */ \
62 		ring = 0; \
63 	} \
64 	element->r_next = element->r_prev = 0
65 
66 /** Find the element (by hostname) in the given ring, leave it in the
67  * provided element variable
68  */
69 #define RING_FINDBYLWCHOST(ring, element, lwc_hostname) \
70 	/*LOG("RING_FINDBYHOST(%s, %s)", #ring, hostname);*/ \
71 	if (ring) { \
72 		bool found = false; \
73 		element = ring; \
74 		do { \
75 			if (lwc_string_isequal(element->host, lwc_hostname, \
76 					&found) == lwc_error_ok && \
77 					found == true) { \
78 				break; \
79 			} \
80 			element = element->r_next; \
81 		} while (element != ring); \
82 		if (!found) element = 0; \
83 	} else element = 0
84 
85 /** Measure the size of a ring and put it in the supplied variable */
86 #define RING_GETSIZE(ringtype, ring, sizevar) \
87 	/*LOG("RING_GETSIZE(%s)", #ring);*/ \
88 	if (ring) { \
89 		ringtype *p = ring; \
90 		sizevar = 0; \
91 		do { \
92 			sizevar++; \
93 			p = p->r_next; \
94 		} while (p != ring); \
95 	} else sizevar = 0
96 
97 /** Count the number of elements in the ring which match the provided lwc_hostname */
98 #define RING_COUNTBYLWCHOST(ringtype, ring, sizevar, lwc_hostname) \
99 	/*LOG("RING_COUNTBYHOST(%s, %s)", #ring, hostname);*/ \
100 	if (ring) { \
101 		ringtype *p = ring; \
102 		sizevar = 0; \
103 		do { \
104 			bool matches = false; \
105 			/* nsurl guarantees lowercase host */ \
106 			if (lwc_string_isequal(p->host, lwc_hostname, \
107 					&matches) == lwc_error_ok) \
108 				if (matches) \
109 					sizevar++; \
110 			p = p->r_next; \
111 		} while (p != ring); \
112 	} else sizevar = 0
113 
114 /*
115  * Ring iteration works as follows:
116  *
117  * RING_ITERATE_START(ringtype, ring, iteratorptr) {
118  *    code_using(iteratorptr);
119  * } RING_ITERATE_END(ring, iteratorptr);
120  *
121  * If you want to stop iterating (e.g. you found your answer)
122  * RING_ITERATE_STOP(ring, iteratorptr);
123  * You *MUST* abort the iteration if you do something to modify
124  * the ring such as deleting or adding an element.
125  */
126 
127 #define RING_ITERATE_START(ringtype, ring, iteratorptr) \
128 	if (ring != NULL) {				\
129 		ringtype *iteratorptr = ring;		\
130 		do {					\
131 			do {				\
132 
133 #define RING_ITERATE_STOP(ring, iteratorptr)	\
134 	goto iteration_end_ring##_##iteratorptr
135 
136 #define RING_ITERATE_END(ring, iteratorptr)		\
137 			} while (false);		\
138 			iteratorptr = iteratorptr->r_next;	\
139 		} while (iteratorptr != ring);		\
140 	}						\
141 	iteration_end_ring##_##iteratorptr:
142 
143 #endif
144