source: vis_dev/glu-2.1/src/list/list.c @ 13

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

src glu

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