1 /*
2  * Copyright (c) 2000, 2001 Peter Bozarov.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by Peter Bozarov.
16  * 4. The name of the author may not be used to endorse or promote products
17  *    derived from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
23  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 /*
33  * Note: this "queue" implementation is actually also a linked list. Why
34  * bother with making two things that are essentially the same as far as
35  * implementation is concerned?
36  *
37  * Last modified: Fri Dec  7 10:19:00 EST 2001
38  *		  Mon Dec 24 10:36:38 EST 2001
39  */
40 # include "local.h"
41 
42 # define QNULL		((Queue*) 0)
43 # define QELEMNULL	((QElem*) 0)
44 
45 struct QElem
46 {
47     void *	qeData;
48     QElem *	qePrev;
49     QElem *	qeNext;
50 };
51 
52 struct Queue
53 {
54     int		qTotal;
55     QElem *	qHead;
56     QElem *	qTail;
57     QElem * 	qCurr;		/* For currencies */
58 };
59 
60 # define TOTAL(q)	((Queue*)q)->qTotal
61 # define TAIL(q)	((Queue*)q)->qTail
62 # define HEAD(q)	((Queue*)q)->qHead
63 # define CURR(q)	((Queue*)q)->qCurr
64 
65 static QElem*
qelem_new(void * data)66 qelem_new(void *data)
67 {
68     QElem *qelem;
69 
70     STDMALLOC(qelem,sizeof(QElem),NULL);
71 
72     qelem->qeData = data;
73     qelem->qePrev = QELEMNULL;
74     qelem->qeNext = QELEMNULL;
75 
76     return qelem;
77 }
78 static int
qelem_enque(QUEUE q,QELEM elem)79 qelem_enque(QUEUE q,QELEM elem)
80 {
81     QElem *	qelem = (QElem*) elem;
82 
83     if (!HEAD(q))
84     {
85     	CURR(q) = TAIL(q) = HEAD(q) = qelem;
86     }
87     else
88     {
89 	qelem->qePrev   = TAIL(q);
90 	CURR(q) = TAIL(q)->qeNext = qelem;
91 	TAIL(q)		= TAIL(q)->qeNext;
92     }
93 
94     ++TOTAL(q);
95 
96     return 0;
97 }
98 /*----------------------------------------------------------------------*
99  * Exported 								*
100  *----------------------------------------------------------------------*/
101 /*
102  * Standard Queue functions
103  */
104 QUEUE
qMake(void)105 qMake(void)
106 {
107     Queue *	q;
108 
109     STDMALLOC(q,sizeof(Queue),QNULL);
110 
111     q->qHead = QELEMNULL;
112     q->qTail = QELEMNULL;
113     q->qCurr = QELEMNULL;
114     q->qTotal= 0;
115 
116     return q;
117 }
118 void
qClose(QUEUE q)119 qClose(QUEUE q)
120 {
121     qCloseWithFunction(q,NULL);
122 }
123 void
qCloseWithFunction(QUEUE queue,void (* f)(void *))124 qCloseWithFunction(QUEUE queue,void (*f)(void*))
125 {
126     if (queue)
127     {
128 	/* Loop through all elements and free them. */
129 	QElem * tmp = HEAD(queue);
130 
131 	while (tmp)
132 	{
133 	    QElem * t = tmp;
134 	    if (f)
135 	    	f(tmp->qeData);
136 	    tmp = tmp->qeNext;
137 	    STDFREE(t);
138 	}
139     }
140 
141     STDFREE(queue);
142 }
143 QELEM
qEnque(QUEUE q,void * data)144 qEnque(QUEUE q,void *data)
145 {
146     QElem *	qelem;
147 
148     if (!q)
149 	return NULL;
150 
151     /* Allocate a new QElement to put in the queue */
152 
153     if (!(qelem = qelem_new(data)))
154 	return NULL;
155 
156     qelem_enque(q,(QELEM)qelem);
157 
158     return (QELEM) qelem;
159 }
160 void*
qDeque(QUEUE q)161 qDeque(QUEUE q)
162 {
163     QElem *	first;
164     void *	data = NULL;
165 
166     if (!q)
167     	return NULL;
168 
169     if (HEAD(q))
170     {
171     	first = HEAD(q);
172 
173 	/* Last element found, set TAIL(q) to NIL */
174 
175 	if (TAIL(q) == HEAD(q))
176 	    TAIL(q) = QELEMNULL;
177 
178 	HEAD(q) = HEAD(q)->qeNext;
179 
180 	if (HEAD(q))
181 	    HEAD(q)->qePrev = QELEMNULL;
182 
183 	/* Remember the data  ... */
184 
185 	data = first->qeData;
186 
187 	/* ... and free the element */
188 
189 	first->qeNext = QELEMNULL;
190 	STDFREE(first);
191 
192 	--TOTAL(q);
193     }
194     return data;
195 }
196 
197 int
qWalk(QUEUE q,void (* fun)(void *))198 qWalk(QUEUE q,void (*fun)(void*))
199 {
200     QElem *	tmp;
201 
202     if (!q)
203 	return -1;
204 
205     tmp = HEAD(q);
206 
207     while (tmp)
208     {
209 	(void)fun(tmp->qeData);
210 	tmp = tmp->qeNext;
211     }
212 
213     return 0;
214 }
215 int
qWalkAscending(QUEUE q,void (* fun)(void *))216 qWalkAscending(QUEUE q,void (*fun)(void*))
217 {
218     return qWalk(q,fun);
219 }
220 int
qWalkDescending(QUEUE q,void (* fun)(void *))221 qWalkDescending(QUEUE q,void (*fun)(void*))
222 {
223     QElem *	tmp;
224 
225     if (!q)
226     	return -1;
227 
228     tmp = TAIL(q);
229 
230     while (tmp)
231     {
232 	fun(tmp->qeData);
233 	tmp = tmp->qePrev;
234     }
235     return 0;
236 }
qLength(QUEUE q)237 int qLength(QUEUE q) { return ((Queue*)q)->qTotal; }
qEmpty(QUEUE q)238 int qEmpty( QUEUE q) { return ! HEAD(q); }
239 
240 void*
qCurrent(QUEUE q)241 qCurrent(QUEUE q)
242 {
243     if (!q)
244 	return NULL;
245 
246     return CURR(q) ? CURR(q)->qeData : NULL;
247 }
248 void
qClearCurrent(QUEUE q)249 qClearCurrent(QUEUE q)
250 {
251     qSetCurrent(q,NULL);
252 }
253 void
qSetCurrent(QUEUE q,QELEM el)254 qSetCurrent(QUEUE q,QELEM el)
255 {
256     if (!q)
257 	return;
258     CURR(q) = el;
259 }
260 void*
qFirst(QUEUE q)261 qFirst(QUEUE q)
262 {
263     QElem * first;
264 
265     first = qElemFirst(q);
266     CURR(q) = first;
267     return first ? first->qeData : NULL;
268 }
269 void*
qLast(QUEUE q)270 qLast(QUEUE q)
271 {
272     QElem * last;
273 
274     last = qElemLast(q);
275     CURR(q) = last;
276     return last ? last->qeData : NULL;
277 }
278 void*
qNext(QUEUE q)279 qNext(QUEUE q)
280 {
281     QElem *next;
282 
283     if (!CURR(q))
284 	return qFirst(q);
285     next = qElemNext(CURR(q));
286 
287     CURR(q) = next;
288 
289     return next ? next->qeData : NULL;
290 }
291 void*
qPrev(QUEUE q)292 qPrev(QUEUE q)
293 {
294     QElem *prev;
295 
296     if (!CURR(q))
297 	return qLast(q);
298     prev = qElemPrev(CURR(q));
299     CURR(q) = prev;
300 
301     return prev ? prev->qeData : NULL;
302 }
303 /*----------------------------------------------------------------------*
304  * More sophisticated QELEM functionality 				*
305  *----------------------------------------------------------------------*/
306 void*
qElemData(QELEM qelem)307 qElemData(QELEM qelem)
308 {
309     if (!qelem)
310 	return NULL;
311     return ((QElem*)qelem)->qeData;
312 }
313 
314 /*
315  * Insert a QELEM in the queue. The new qelem is placed before the one
316  * given. If the given element is NULL, the qelem put at the end of the
317  * queue.
318  */
319 int
qElemInsert(QUEUE q,QELEM pBefore,QELEM pElem)320 qElemInsert(QUEUE q,QELEM pBefore,QELEM pElem)
321 {
322     QElem *	elem = (QElem*)pElem;
323     QElem *	before= (QElem*)pBefore;
324 
325     if (!before)
326 	return qelem_enque(q,elem);
327 
328     elem->qeNext = before;
329     elem->qePrev = before->qePrev;
330     if (before->qePrev)
331 	before->qePrev->qeNext = elem;
332     before->qePrev = elem;
333     return 0;
334 }
335 /*
336  * Attach an existing QELEM to the given QUEUE. This is the same
337  * as actually enqueing the element, but does not create a new
338  * QELEM.
339  */
340 int
qElemAttach(QUEUE q,QELEM elem)341 qElemAttach(QUEUE q,QELEM elem)
342 {
343     return qelem_enque(q,elem);
344 }
345 /*
346  * Detach the given queue element from the queue.
347  * It can now be added to another queue, or freed using qElemFree().
348  */
349 int
qElemDetach(QUEUE q,QELEM elem)350 qElemDetach(QUEUE q,QELEM elem)
351 {
352     QElem *curr = (QElem*)elem;
353     QElem *prev = curr->qePrev;
354     QElem *next = curr->qeNext;
355 
356     /* Detach curr from the queue */
357     if (prev)
358         prev->qeNext = next;
359     else /* This is the head */
360 	HEAD(q) = next;
361 
362     if (next)
363         next->qePrev = prev;
364     else /* This is the tail element */
365 	TAIL(q) = prev;
366 
367     curr->qePrev = curr->qeNext = NULL;
368 
369     if (CURR(q) == curr)
370 	CURR(q) = NULL;
371 
372     --TOTAL(q);
373     return 0;
374 }
375 
376 void
qElemFree(QELEM elem)377 qElemFree(QELEM elem)
378 {
379     STDFREE(elem);
380 }
381 
382 /*
383  * Returns a pointer to the first element in the queue. To get the
384  * actual data, call qElemData(QELEM qelem).
385  */
386 QELEM
qElemFirst(QUEUE q)387 qElemFirst(QUEUE q)
388 {
389     if (!q || !HEAD(q))
390     	return NULL;
391     return HEAD(q);
392 }
393 /*
394  * Returns a pointer to the last element of the queue.
395  */
396 QELEM
qElemLast(QUEUE q)397 qElemLast(QUEUE q)
398 {
399     if (!q || !TAIL(q))
400     	return NULL;
401     return TAIL(q);
402 }
403 /*
404  * Given a current qElem, return the next one.
405  */
406 QELEM
qElemNext(QELEM curr)407 qElemNext(QELEM curr)
408 {
409     if (!curr)
410 	return NULL;
411 
412     return ((QElem*)curr)->qeNext;
413 }
414 /*
415  * Given a current element, return the previous.
416  */
417 QELEM
qElemPrev(QELEM curr)418 qElemPrev(QELEM curr)
419 {
420     if (!curr)
421 	return NULL;
422 
423     return ((QElem*)curr)->qePrev;
424 }
425 QELEM
qElemCurr(QUEUE q)426 qElemCurr(QUEUE q)
427 {
428     return CURR(q);
429 }
430 /*
431  * Given a current qElem, remove it from the queue.
432  * The data stored with the element is returned.
433  * The element itself is free()'d.
434  *
435  * Returns NULL if it fails, or if you stored a NULL pointer with this
436  * element.
437  */
438 void*
qElemRemove(QUEUE q,QELEM elem)439 qElemRemove(QUEUE q,QELEM elem)
440 {
441     void * data;
442     if (!elem)
443 	return 0;
444 
445     /* Give the data back */
446     data = ((QElem*)elem)->qeData;
447 
448     qElemDetach(q,elem);
449     STDFREE(elem);
450     return data;
451 }
452