source: vis_dev/glu-2.3/src/list/list.c @ 104

Last change on this file since 104 was 13, checked in by cecile, 13 years ago

library glu 2.3

File size: 26.6 KB
Line 
1/*
2 * $Id: list.c,v 1.11 2009/04/11 02:02:54 fabio Exp $
3 *
4 */
5/*
6 * List Management Package
7 *
8 * David Harrison
9 * University of California, Berkeley, 1985
10 *
11 * This package implements a simple generic linked list data type.  It
12 * uses a doubly linked list structure and provides some standard operations
13 * for storing and retrieving data from the list.
14 */
15
16#include "util.h"
17#include "list.h"               /* Self declaration        */
18
19
20/*
21 * The list identifier is in reality a pointer to the following list
22 * descriptor structure.  Lists are doubly linked with both top and
23 * bottom pointers stored in the list descriptor.  The length
24 * of the list is also stored in the descriptor.
25 */
26
27typedef struct list_elem {      /* One list element  */
28    struct list_desc *mainList; /* List descriptor   */
29    struct list_elem *prevPtr;  /* Previous element  */
30    struct list_elem *nextPtr;  /* Next list element */
31    lsGeneric userData;         /* User pointer      */
32} lsElem;
33
34typedef struct list_desc {      /* List descriptor record            */
35    lsElem *topPtr, *botPtr;    /* Pointer to top and bottom of list */
36    int length;                 /* Length of list                    */
37} lsDesc;
38
39
40/*
41 * Generators are in reality pointers to the generation descriptor
42 * defined below.  A generator has a current spot which is *between*
43 * two items.  Thus,  a generator consists of two pointers:  record
44 * before spot and record after spot.  A pointer to the main list
45 * is included so the top and bottom pointers of the list can be
46 * modified if needed.
47 */
48
49typedef struct gen_desc {       /* Generator Descriptor */
50    lsDesc *mainList;           /* Pointer to list descriptor   */
51    lsElem *beforeSpot;         /* Item before the current spot */
52    lsElem *afterSpot;          /* Item after the current spot  */
53} lsGenInternal;
54
55/*
56 * Handles are in reality pointers to lsElem records.  They are
57 * cheap to generate and need not be disposed.
58 */
59
60
61
62/*
63 * List Creation and Deletion
64 */
65
66lsList lsCreate(void)
67/*
68 * Creates a new linked list and returns its handle.  The handle is used
69 * by all other list manipulation routines and should not be discarded.
70 */
71{
72    lsDesc *newList;
73
74    newList = ALLOC(lsDesc, 1);
75    newList->topPtr = newList->botPtr = NIL(lsElem);
76    newList->length = 0;
77    return( (lsList) newList );
78}
79
80lsStatus lsDestroy(
81  lsList list                   /* List to destroy              */,
82  void (*delFunc)(lsGeneric)    /* Routine to release user data */)
83/*
84 * Frees all resources associated with the specified list.  It frees memory
85 * associated with all elements of the list and then deletes the list.
86 * User data is released by calling 'delFunc' with the pointer as the
87 * argument.  Accessing a list after its destruction is a no-no.
88 */
89{
90    lsDesc *realList;
91    lsElem *index, *temp;
92
93    realList = (lsDesc *) list;
94    /* Get rid of elements */
95    index = realList->topPtr;
96    while (index != NIL(lsElem)) {
97        temp = index;  index = index->nextPtr;
98        if (delFunc)
99          (*delFunc)(temp->userData);
100        FREE(temp);
101    }
102    /* Get rid of descriptor */
103    FREE(realList);
104    return(LS_OK);
105}
106
107
108/*
109 * Copying lists
110 */
111
112static lsGeneric lsIdentity(lsGeneric data)
113/* Identity copy function */
114{
115    return data;
116}
117
118lsList lsCopy(
119  lsList list                           /* List to be copied         */,
120  lsGeneric (*copyFunc)(lsGeneric)      /* Routine to copy user data */)
121/*
122 * Returns a copy of list `list'.  If `copyFunc' is non-zero,
123 * it will be called for each item in `list' and the pointer it
124 * returns will be used in place of the original user data for the
125 * item in the newly created list.  The form of `copyFunc' should be:
126 *   lsGeneric copyFunc(data)
127 *   lsGeneric data;
128 * This is normally used to make copies of the user data in the new list.
129 * If no `copyFunc' is provided,  an identity function is used.
130 */
131{
132    lsList newList;
133    lsGen gen;
134    lsGeneric data;
135
136    if (!copyFunc) copyFunc = lsIdentity;
137    newList = lsCreate();
138    gen = lsStart(list);
139    while (lsNext(gen, &data, LS_NH) == LS_OK) {
140        (void) lsNewEnd(newList, (*copyFunc)(data), LS_NH);
141    }
142    lsFinish(gen);
143    return newList;
144}
145
146
147/*
148 * Adding New Elements to the Beginning and End of a List
149 */
150
151lsStatus lsNewBegin(
152  lsList list                   /* List to add element to    */,
153  lsGeneric data                /* Arbitrary pointer to data */,
154  lsHandle *itemHandle          /* Handle to data (returned) */)
155/*
156 * Adds a new item to the start of a previously created linked list.
157 * If 'itemHandle' is non-zero,  it will be filled with a handle
158 * which can be used to generate a generator positioned at the
159 * item without generating through the list.
160 */
161{
162    lsDesc *realList = (lsDesc *) list;
163    lsElem *newElem;
164
165    newElem = ALLOC(lsElem, 1);
166    newElem->userData = data;
167    newElem->nextPtr = realList->topPtr;
168    newElem->prevPtr = NIL(lsElem);
169    newElem->mainList = realList;
170    if (realList->topPtr == NIL(lsElem)) {
171        /* The new item is both the top and bottom element */
172        realList->botPtr = newElem;
173    } else {
174        /* There was a top element - make its prev correct */
175        realList->topPtr->prevPtr = newElem;
176    }
177    realList->topPtr = newElem;
178    realList->length += 1;
179    if (itemHandle) *itemHandle = (lsHandle) newElem;
180    return(LS_OK);
181}
182
183lsStatus lsNewEnd(
184  lsList list                   /* List to append element to */,
185  lsGeneric data                /* Arbitrary pointer to data */,
186  lsHandle *itemHandle          /* Handle to data (returned) */)
187/*
188 * Adds a new item to the end of a previously created linked list.
189 * This routine appends the item in constant time and
190 * can be used freely without guilt.
191 */
192{
193    lsDesc *realList = (lsDesc *) list;
194    lsElem *newElem;
195
196    newElem = ALLOC(lsElem, 1);
197    newElem->userData = data;
198    newElem->prevPtr = realList->botPtr;
199    newElem->nextPtr = NIL(lsElem);
200    newElem->mainList = realList;
201    if (realList->topPtr == NIL(lsElem))
202      realList->topPtr = newElem;
203    if (realList->botPtr != NIL(lsElem))
204      realList->botPtr->nextPtr = newElem;
205    realList->botPtr = newElem;
206    realList->length += 1;
207    if (itemHandle) *itemHandle = (lsHandle) newElem;
208    return(LS_OK);
209}
210
211/*
212 * Retrieving the first and last items of a list
213 */
214
215lsStatus lsFirstItem(
216  lsList list                   /* List to get item from */,
217  lsGeneric data                /* User data (returned)  */,
218  lsHandle *itemHandle          /* Handle to data (returned) */)
219/*
220 * Returns the first item in the list.  If the list is empty,
221 * it returns LS_NOMORE.  Otherwise,  it returns LS_OK.
222 * If 'itemHandle' is non-zero,  it will be filled with a
223 * handle which may be used to generate a generator.
224 */
225{
226    lsDesc *realList = (lsDesc *) list;
227
228    if (realList->topPtr != NIL(lsElem)) {
229        *(void **)data = realList->topPtr->userData;
230        if (itemHandle) *itemHandle = (lsHandle) (realList->topPtr);
231        return(LS_OK);
232    } else {
233        *(void **)data = (lsGeneric) 0;
234        if (itemHandle) *itemHandle = (lsHandle) 0;
235        return(LS_NOMORE);
236    }
237}
238
239lsStatus lsLastItem(
240  lsList list                   /* List to get item from */,
241  lsGeneric data                /* User data (returned)  */,
242  lsHandle *itemHandle          /* Handle to data (returned) */)
243/*
244 * Returns the last item of a list.  If the list is empty,
245 * the routine returns LS_NOMORE.  Otherwise,  'data' will
246 * be set to the last item and the routine will return LS_OK.
247 * If 'itemHandle' is non-zero,  it will be filled with a
248 * handle which can be used to generate a generator postioned
249 * at this item.
250 */
251{
252    lsDesc *realList = (lsDesc *) list;
253
254    if (realList->botPtr != NIL(lsElem)) {
255        *(void **)data = realList->botPtr->userData;
256        if (itemHandle) *itemHandle = (lsHandle) (realList->botPtr);
257        return(LS_OK);
258    } else {
259        *(void **)data = (lsGeneric) 0;
260        if (itemHandle) *itemHandle = (lsHandle) 0;
261        return(LS_NOMORE);
262    }
263}
264
265
266/* Length of a list */
267
268int lsLength(
269  lsList list                   /* List to get the length of */)
270/*
271 * Returns the length of the list.  The list must have been
272 * already created using lsCreate.
273 */
274{
275    lsDesc *realList = (lsDesc *) list;
276
277    return(realList->length);
278}
279
280
281/*
282 * Deleting first and last items of a list
283 */
284
285lsStatus lsDelBegin(
286  lsList list                   /* List to delete item from     */,
287  lsGeneric data                /* First item (returned)        */)
288/*
289 * This routine deletes the first item of a list.  The user
290 * data associated with the item is returned so the caller
291 * may dispose of it.  Returns LS_NOMORE if there is no
292 * item to delete.
293 */
294{
295    lsDesc *realList = (lsDesc *) list;
296    lsElem *temp;
297
298    if (realList->topPtr == NIL(lsElem)) {
299        /* Nothing to delete */
300        *(void **)data = (lsGeneric) 0;
301        return LS_NOMORE;
302    } else {
303        *(void **)data = realList->topPtr->userData;
304        temp = realList->topPtr;
305        realList->topPtr = realList->topPtr->nextPtr;
306        if (temp->nextPtr != NIL(lsElem)) {
307            /* There is something after the first item */
308            temp->nextPtr->prevPtr = NIL(lsElem);
309        } else {
310            /* Nothing after it - bottom becomes null as well */
311            realList->botPtr = NIL(lsElem);
312        }
313        FREE(temp);
314        realList->length -= 1;
315    }
316    return LS_OK;
317}
318
319
320lsStatus lsDelEnd(
321  lsList list                   /* List to delete item from */,
322  lsGeneric data                /* Last item (returned)     */)
323/*
324 * This routine deletes the last item of a list.  The user
325 * data associated with the item is returned so the caller
326 * may dispose of it.  Returns LS_NOMORE if there is nothing
327 * to delete.
328 */
329{
330    lsDesc *realList = (lsDesc *) list;
331    lsElem *temp;
332
333    if (realList->botPtr == NIL(lsElem)) {
334        /* Nothing to delete */
335        *(void **)data = (lsGeneric) 0;
336        return LS_NOMORE;
337    } else {
338        *(void **)data = realList->botPtr->userData;
339        temp = realList->botPtr;
340        realList->botPtr = realList->botPtr->prevPtr;
341        if (temp->prevPtr != NIL(lsElem)) {
342            /* There is something before the last item */
343            temp->prevPtr->nextPtr = NIL(lsElem);
344        } else {
345            /* Nothing before it - top becomes null as well */
346            realList->topPtr = NIL(lsElem);
347        }
348        FREE(temp);
349        realList->length -= 1;
350    }
351    return LS_OK;
352}
353
354
355/*
356 * List Generation Routines
357 *
358 * nowPtr is the element just before the next one to be generated
359 */
360
361lsGen lsStart(
362  lsList list                   /* List to generate items from */)
363/*
364 * This routine defines a generator which is used to step through
365 * each item of the list.  It returns a generator handle which should
366 * be used when calling lsNext, lsPrev, lsInBefore, lsInAfter, lsDelete,
367 * or lsFinish.
368 */
369{
370    lsDesc *realList = (lsDesc *) list;
371    lsGenInternal *newGen;
372
373    newGen = ALLOC(lsGenInternal, 1);
374    newGen->mainList = realList;
375    newGen->beforeSpot = NIL(lsElem);
376    newGen->afterSpot = realList->topPtr;
377    return ( (lsGen) newGen );
378}
379
380lsGen lsEnd(
381  lsList list                   /* List to generate items from */)
382/*
383 * This routine defines a generator which is used to step through
384 * each item of a list.  The generator is initialized to the end
385 * of the list.
386 */
387{
388    lsDesc *realList = (lsDesc *) list;
389    lsGenInternal *newGen;
390
391    newGen = ALLOC(lsGenInternal, 1);
392    newGen->mainList = realList;
393    newGen->beforeSpot = realList->botPtr;
394    newGen->afterSpot = NIL(lsElem);
395    return (lsGen) newGen;
396}
397
398lsGen lsGenHandle(
399  lsHandle itemHandle           /* Handle of an item         */,
400  lsGeneric data                /* Data associated with item */,
401  int option                    /* LS_BEFORE or LS_AFTER     */)
402/*
403 * This routine produces a generator given a handle.  Handles
404 * are produced whenever an item is added to a list.  The generator
405 * produced by this routine may be used when calling any of
406 * the standard generation routines.  NOTE:  the generator
407 * should be freed using lsFinish.  The 'option' parameter
408 * determines whether the generator spot is before or after
409 * the handle item.
410 */
411{
412    lsElem *realItem = (lsElem *) itemHandle;
413    lsGenInternal *newGen;
414
415    newGen = ALLOC(lsGenInternal, 1);
416    newGen->mainList = realItem->mainList;
417    *(void **)data = realItem->userData;
418    if (option & LS_BEFORE) {
419        newGen->beforeSpot = realItem->prevPtr;
420        newGen->afterSpot = realItem;
421    } else if (option & LS_AFTER) {
422        newGen->beforeSpot = realItem;
423        newGen->afterSpot = realItem->nextPtr;
424    } else {
425        FREE(newGen);
426        newGen = (lsGenInternal *) 0;
427    }
428    return ( (lsGen) newGen );
429}
430
431
432lsStatus lsNext(
433  lsGen generator               /* Generator handle        */,
434  lsGeneric data                /* User data (return)      */,
435  lsHandle *itemHandle          /* Handle to item (return) */)
436/*
437 * Generates the item after the item previously generated by lsNext
438 * or lsPrev.   It returns a pointer to the user data structure in 'data'.
439 * 'itemHandle' may be used to get a generation handle without
440 * generating through the list to find the item.  If there are no more
441 * elements to generate, the routine returns  LS_NOMORE (normally it
442 * returns LS_OK).  lsNext DOES NOT automatically clean up after all
443 * elements have been generated.  lsFinish must be called explicitly to do this.
444 */
445{
446    register lsGenInternal *realGen = (lsGenInternal *) generator;
447
448    if (realGen->afterSpot == NIL(lsElem)) {
449        /* No more stuff to generate */
450        *(void **) data = (lsGeneric) 0;
451        if (itemHandle) *itemHandle = (lsHandle) 0;
452        return LS_NOMORE;
453    } else {
454        *(void **) data = realGen->afterSpot->userData;
455        if (itemHandle) *itemHandle = (lsHandle) (realGen->afterSpot);
456        /* Move the pointers down one */
457        realGen->beforeSpot = realGen->afterSpot;
458        realGen->afterSpot = realGen->afterSpot->nextPtr;
459        return LS_OK;
460    }
461}
462
463
464lsStatus lsPrev(
465  lsGen generator               /* Generator handle        */,
466  lsGeneric data                /* User data (return)      */,
467  lsHandle *itemHandle          /* Handle to item (return) */)
468/*
469 * Generates the item before the item previously generated by lsNext
470 * or lsPrev.   It returns a pointer to the user data structure in 'data'.
471 * 'itemHandle' may be used to get a generation handle without
472 * generating through the list to find the item.  If there are no more
473 * elements to generate, the routine returns  LS_NOMORE (normally it
474 * returns LS_OK).  lsPrev DOES NOT automatically clean up after all
475 * elements have been generated.  lsFinish must be called explicitly to do this.
476 */
477{
478    register lsGenInternal *realGen = (lsGenInternal *) generator;
479
480    if (realGen->beforeSpot == NIL(lsElem)) {
481        /* No more stuff to generate */
482        *(void **) data = (lsGeneric) 0;
483        if (itemHandle) *itemHandle = (lsHandle) 0;
484        return LS_NOMORE;
485    } else {
486        *(void **) data = realGen->beforeSpot->userData;
487        if (itemHandle) *itemHandle = (lsHandle) (realGen->beforeSpot);
488        /* Move the pointers down one */
489        realGen->afterSpot = realGen->beforeSpot;
490        realGen->beforeSpot = realGen->beforeSpot->prevPtr;
491        return LS_OK;
492    }
493
494}
495
496lsStatus lsInBefore(
497  lsGen generator               /* Generator handle          */,
498  lsGeneric data                /* Arbitrary pointer to data */,
499  lsHandle *itemHandle          /* Handle to item (return) */)
500/*
501 * Inserts an element BEFORE the current spot.  The item generated
502 * by lsNext will be unchanged;  the inserted item will be generated
503 * by lsPrev.  This modifies the list.  'itemHandle' may be used at
504 * a later time to produce a generation handle without generating
505 * through the list.
506 */
507{
508    lsGenInternal *realGen = (lsGenInternal *) generator;
509    lsElem *newElem;
510
511    if (realGen->beforeSpot == NIL(lsElem)) {
512        /* Item added to the beginning of the list */
513        (void) lsNewBegin((lsList) realGen->mainList, data, itemHandle);
514        realGen->beforeSpot = realGen->mainList->topPtr;
515        return LS_OK;
516    } else if (realGen->afterSpot == NIL(lsElem)) {
517        /* Item added to the end of the list */
518        (void) lsNewEnd((lsList) realGen->mainList, data, itemHandle);
519        realGen->afterSpot = realGen->mainList->botPtr;
520        return LS_OK;
521    } else {
522        /* Item added in the middle of the list */
523        newElem = ALLOC(lsElem, 1);
524        newElem->mainList = realGen->mainList;
525        newElem->prevPtr = realGen->beforeSpot;
526        newElem->nextPtr = realGen->afterSpot;
527        newElem->userData = data;
528        realGen->beforeSpot->nextPtr = newElem;
529        realGen->afterSpot->prevPtr = newElem;
530        realGen->beforeSpot = newElem;
531        realGen->mainList->length += 1;
532        if (itemHandle) *itemHandle = (lsHandle) newElem;
533        return LS_OK;
534    }
535}
536
537lsStatus lsInAfter(
538  lsGen generator               /* Generator handle          */,
539  lsGeneric data                /* Arbitrary pointer to data */,
540  lsHandle *itemHandle          /* Handle to item (return)   */)
541/*
542 * Inserts an element AFTER the current spot.  The next item generated
543 * by lsNext will be the new element.  The next  item generated by
544 * lsPrev is unchanged.  This modifies the list.  'itemHandle' may
545 * be used at a later time to generate a generation handle without
546 * searching through the list to find the item.
547 */
548{
549    lsGenInternal *realGen = (lsGenInternal *) generator;
550    lsElem *newElem;
551
552    if (realGen->beforeSpot == NIL(lsElem)) {
553        /* Item added to the beginning of the list */
554        (void) lsNewBegin((lsList) realGen->mainList, data, itemHandle);
555        realGen->beforeSpot = realGen->mainList->topPtr;
556        return LS_OK;
557    } else if (realGen->afterSpot == NIL(lsElem)) {
558        /* Item added to the end of the list */
559        (void) lsNewEnd((lsList) realGen->mainList, data, itemHandle);
560        realGen->afterSpot = realGen->mainList->botPtr;
561        return LS_OK;
562    } else {
563        /* Item added in the middle of the list */
564        newElem = ALLOC(lsElem, 1);
565        newElem->mainList = realGen->mainList;
566        newElem->prevPtr = realGen->beforeSpot;
567        newElem->nextPtr = realGen->afterSpot;
568        newElem->userData = data;
569        realGen->beforeSpot->nextPtr = newElem;
570        realGen->afterSpot->prevPtr = newElem;
571        realGen->afterSpot = newElem;
572        realGen->mainList->length += 1;
573        if (itemHandle) *itemHandle = (lsHandle) newElem;
574        return LS_OK;
575    }
576}
577
578
579lsStatus lsDelBefore(
580  lsGen generator               /* Generator handle        */,
581  lsGeneric data                /* Deleted item (returned) */)
582/*
583 * Removes the item before the current spot.  The next call to lsPrev
584 * will return the item before the deleted item.  The next call to lsNext
585 * will be uneffected.  This modifies the list.  The routine returns
586 * LS_BADSTATE if the user tries to call the routine and there is
587 * no item before the current spot.  This routine returns the userData
588 * of the deleted item so it may be freed (if necessary).
589 */
590{
591    lsGenInternal *realGen = (lsGenInternal *) generator;
592    lsElem *doomedItem;
593
594    if (realGen->beforeSpot == NIL(lsElem)) {
595        /* No item to delete */
596        *(void **)data = (lsGeneric) 0;
597        return LS_BADSTATE;
598    } else if (realGen->beforeSpot == realGen->mainList->topPtr) {
599        /* Delete the first item of the list */
600        realGen->beforeSpot = realGen->beforeSpot->prevPtr;
601        return lsDelBegin((lsList) realGen->mainList, data);
602    } else if (realGen->beforeSpot == realGen->mainList->botPtr) {
603        /* Delete the last item of the list */
604        realGen->beforeSpot = realGen->beforeSpot->prevPtr;
605        return lsDelEnd((lsList) realGen->mainList, data);
606    } else {
607        /* Normal mid list deletion */
608        doomedItem = realGen->beforeSpot;
609        doomedItem->prevPtr->nextPtr = doomedItem->nextPtr;
610        doomedItem->nextPtr->prevPtr = doomedItem->prevPtr;
611        realGen->beforeSpot = doomedItem->prevPtr;
612        realGen->mainList->length -= 1;
613        *(void **)data = doomedItem->userData;
614        FREE(doomedItem);
615        return LS_OK;
616    }
617}
618
619
620lsStatus lsDelAfter(
621  lsGen generator               /* Generator handle        */,
622  lsGeneric data                /* Deleted item (returned) */)
623/*
624 * Removes the item after the current spot.  The next call to lsNext
625 * will return the item after the deleted item.  The next call to lsPrev
626 * will be uneffected.  This modifies the list.  The routine returns
627 * LS_BADSTATE if the user tries to call the routine and there is
628 * no item after the current spot.  This routine returns the userData
629 * of the deleted item so it may be freed (if necessary).
630 */
631{
632    lsGenInternal *realGen = (lsGenInternal *) generator;
633    lsElem *doomedItem;
634
635    if (realGen->afterSpot == NIL(lsElem)) {
636        /* No item to delete */
637        *(void **)data = (lsGeneric) 0;
638        return LS_BADSTATE;
639    } else if (realGen->afterSpot == realGen->mainList->topPtr) {
640        /* Delete the first item of the list */
641        realGen->afterSpot = realGen->afterSpot->nextPtr;
642        return lsDelBegin((lsList) realGen->mainList, data);
643    } else if (realGen->afterSpot == realGen->mainList->botPtr) {
644        /* Delete the last item of the list */
645        realGen->afterSpot = realGen->afterSpot->nextPtr;
646        return lsDelEnd((lsList) realGen->mainList, data);
647    } else {
648        /* Normal mid list deletion */
649        doomedItem = realGen->afterSpot;
650        doomedItem->prevPtr->nextPtr = doomedItem->nextPtr;
651        doomedItem->nextPtr->prevPtr = doomedItem->prevPtr;
652        realGen->afterSpot = doomedItem->nextPtr;
653        realGen->mainList->length -= 1;
654        *(void **)data = doomedItem->userData;
655        FREE(doomedItem);
656        return LS_OK;
657    }
658}
659
660
661lsStatus lsFinish(
662  lsGen generator               /* Generator handle */)
663/*
664 * Marks the completion of a generation of list items.  This routine should
665 * be called after calls to lsNext to free resources used by the
666 * generator.  This rule applies even if all items of a list are
667 * generated by lsNext.
668 */
669{
670    lsGenInternal *realGen = (lsGenInternal *) generator;
671
672    FREE(realGen);
673    return(LS_OK);
674}
675
676
677
678/*
679 * Functional list generation
680 *
681 * An alternate form of generating through items of a list is provided.
682 * The routines below generatae through all items of a list in a given
683 * direction and call a user provided function for each one.
684 */
685
686static lsStatus lsGenForm(lsStatus (*userFunc)(lsGeneric, lsGeneric),
687                          lsGeneric arg, lsGen gen,
688                          lsStatus (*gen_func)(lsGen, lsGeneric, lsHandle *),
689                          lsStatus (*del_func)(lsGen, lsGeneric));
690
691lsStatus lsForeach(
692  lsList list                   /* List to generate through */,
693  lsStatus (*userFunc)(lsGeneric, lsGeneric) /* User provided function   */,
694  lsGeneric arg                 /* User provided data       */)
695/*
696 * This routine generates all items in `list' from the first item
697 * to the last calling `userFunc' for each item.  The function
698 * should have the following form:
699 *   lsStatus userFunc(data, arg)
700 *   lsGeneric data;
701 *   lsGeneric arg;
702 * `data' will be the user data associated with the item generated.
703 * `arg' will be the same pointer provided to lsForeach.  The
704 * routine should return LS_OK to continue the generation,  LS_STOP
705 * to stop generating items,  and LS_DELETE to delete the item
706 * from the list.  If the generation was stopped prematurely,
707 * the routine will return LS_STOP.  If the user provided function
708 * does not return an appropriate value,  the routine will return
709 * LS_BADPARAM.
710 */
711{
712    return lsGenForm(userFunc, arg, lsStart(list), lsNext, lsDelBefore);
713}
714
715
716lsStatus lsBackeach(
717  lsList list                   /* List to generate through */,
718  lsStatus (*userFunc)(lsGeneric, lsGeneric) /* User provided function   */,
719  lsGeneric arg                 /* User provided data       */)
720/*
721 * This routine is just like lsForeach except it generates
722 * all items in `list' from the last item to the first.
723 */
724{
725    return lsGenForm(userFunc, arg, lsEnd(list), lsPrev, lsDelAfter);
726}
727
728
729static lsStatus lsGenForm(
730  lsStatus (*userFunc)(lsGeneric, lsGeneric) /* User provided function */,
731  lsGeneric arg                 /* Data to pass to function       */,
732  lsGen gen                     /* Generator to use               */,
733  lsStatus (*gen_func)(lsGen, lsGeneric, lsHandle *)
734                                /* Generator function to use      */,
735  lsStatus (*del_func)(lsGen, lsGeneric) /* Deletion function to use */)
736/*
737 * This is the function used to implement the two functional
738 * generation interfaces to lists.
739 */
740{
741    lsGeneric data;
742
743    while ((*gen_func)(gen, &data, LS_NH) == LS_OK) {
744        switch ((*userFunc)(data, arg)) {
745        case LS_OK:
746            /* Nothing */
747            break;
748        case LS_STOP:
749            (void) lsFinish(gen);
750            return LS_STOP;
751        case LS_DELETE:
752            (*del_func)(gen, &data);
753            break;
754        default:
755            return LS_BADPARAM;
756        }
757    }
758    (void) lsFinish(gen);
759    return LS_OK;
760}
761
762
763lsList lsQueryHandle(
764  lsHandle itemHandle           /* Handle of an item  */)
765/*
766 * This routine returns the associated list of the specified
767 * handle.  Returns 0 if there were problems.
768 */
769{
770    lsElem *realHandle = (lsElem *) itemHandle;
771
772    if (realHandle) {
773        return (lsList) realHandle->mainList;
774    } else {
775        return (lsList) 0;
776    }
777}
778
779lsGeneric lsFetchHandle(lsHandle itemHandle)
780/*
781 * This routine returns the user data of the item associated with
782 * `itemHandle'.
783 */
784{
785    return ((lsElem *) itemHandle)->userData;
786}
787
788lsStatus lsRemoveItem(
789  lsHandle itemHandle           /* Handle of an item */,
790  lsGeneric userData            /* Returned data     */)
791/*
792 * This routine removes the item associated with `handle' from
793 * its list and returns the user data associated with the item
794 * for reclaimation purposes.  Note this modifies the list
795 * that originally contained `item'.
796 */
797{
798    lsElem *realItem = (lsElem *) itemHandle;
799    lsGenInternal gen;
800
801    gen.mainList = realItem->mainList;
802    gen.beforeSpot = realItem->prevPtr;
803    gen.afterSpot = realItem;
804    return lsDelAfter((lsGen) &gen, userData);
805}
806
807
808/* List sorting support */
809#define TYPE            lsElem
810#define SORT            lsSortItems
811#define NEXT            nextPtr
812#define FIELD           userData
813#include "lsort.h"              /* Merge sort by R. Rudell */
814
815lsStatus lsSort(
816  lsList list                           /* List to sort        */,
817  int (*compare)(lsGeneric, lsGeneric)  /* Comparison function */)
818/*
819 * This routine sorts `list' using `compare' as the comparison
820 * function between items in the list.  `compare' has the following form:
821 *   int compare(item1, item2)
822 *   lsGeneric item1, item2;
823 * The routine should return -1 if item1 is less than item2, 0 if
824 * they are equal,  and 1 if item1 is greater than item2.
825 * The routine uses a generic merge sort written by Rick Rudell.
826 */
827{
828    lsDesc *realList = (lsDesc *) list;
829    lsElem *idx, *lastElem;
830
831    realList->topPtr = lsSortItems(realList->topPtr, compare,
832                                  realList->length);
833
834    /* Forward pointers are correct - fix backward pointers */
835    lastElem = (lsElem *) 0;
836    for (idx = realList->topPtr;  idx != (lsElem *) 0;  idx = idx->nextPtr) {
837        idx->prevPtr = lastElem;
838        lastElem = idx;
839    }
840    /* lastElem is last item in list */
841    realList->botPtr = lastElem;
842    return LS_OK;
843}
844
845
846lsStatus lsUniq(
847  lsList list                           /* List to remove duplicates from */,
848  int (*compare)(lsGeneric, lsGeneric)  /* Item comparison function       */,
849  void (*delFunc)(lsGeneric)            /* Function to release user data  */)
850/*
851 * This routine takes a sorted list and removes all duplicates
852 * from it.  `compare' has the following form:
853 *   int compare(item1, item2)
854 *   lsGeneric item1, item2;
855 * The routine should return -1 if item1 is less than item2, 0 if
856 * they are equal,  and 1 if item1 is greater than item2. `delFunc'
857 * will be called with a pointer to a user data item for each
858 * duplicate destroyed.  `delFunc' can be zero if no clean up
859 * is required.
860 */
861{
862    lsGeneric this_item, last_item;
863    lsGenInternal realGen;
864    lsDesc *realList = (lsDesc *) list;
865
866    if (realList->length > 1) {
867        last_item = realList->topPtr->userData;
868
869        /* Inline creation of generator */
870        realGen.mainList = realList;
871        realGen.beforeSpot = realList->topPtr;
872        realGen.afterSpot = realList->topPtr->nextPtr;
873
874        while (realGen.afterSpot) {
875            this_item = realGen.afterSpot->userData;
876            if ((*compare)(this_item, last_item) == 0) {
877                /* Duplicate -- eliminate */
878                (void) lsDelAfter((lsGen) &realGen, &this_item);
879                if (delFunc) (*delFunc)(this_item);
880            } else {
881                /* Move generator forward */
882                realGen.beforeSpot = realGen.afterSpot;
883                realGen.afterSpot = realGen.afterSpot->nextPtr;
884                last_item = this_item;
885            }
886        }
887    }
888    return LS_OK;
889}
Note: See TracBrowser for help on using the repository browser.