source: branches/branch-1-0/src/helpers/linklist.c

Last change on this file was 229, checked in by umoeller, 23 years ago

Sources as of 1.0.0.

  • Property svn:eol-style set to CRLF
  • Property svn:keywords set to Author Date Id Revision
File size: 31.6 KB
Line 
1
2/*
3 *@@sourcefile linklist.c:
4 * contains helper functions for maintaining doubly-linked lists.
5 * See explanations below.
6 *
7 * This file is new with V0.81 and contains all the functions
8 * that were in helpers.c previously.
9 *
10 * Usage: All C programs; not OS/2-specific.
11 *
12 * Function prefixes (new with V0.81):
13 * -- lst* linked list helper functions
14 *
15 * <B>Usage:</B>
16 *
17 * Linked lists are implemented through the LINKLIST structure.
18 * This can either be created on the stack or as a global variable
19 * (and must then be initialized using lstInit) or from the heap
20 * with lstCreate.
21 *
22 * Each list item is stored in a LISTNODE structure, which in
23 * turn has a pItemData field, which you can use to get your
24 * data. So a typical list would be coded like this (this is
25 * a heap list):
26 *
27 +
28 + typedef struct _YOURDATA
29 + {
30 + ULONG ulWhatever;
31 + } YOURDATA, *PYOURDATA
32 +
33 + // fill the list
34 + PLINKLIST pll = lstCreate(TRUE or FALSE);
35 + while ...
36 + {
37 + PYOURDATA pYourData = (PYOURDATA)malloc(sizeof(YOURDATA));
38 + lstAppendItem(pll, pYourData); // store the data in a new node
39 + }
40 +
41 + ...
42 +
43 + // now iterate over the list
44 + PLISTNODE pNode = lstQueryFirstNode(pll);
45 + while (pNode)
46 + {
47 + PYOURDATA pYourData = (PYOURDATA)pNode->pItemData;
48 + ...
49 + pNode = pNode->pNext;
50 + }
51 +
52 + lstFree(pll); // this is free the list items too, if TRUE had
53 + // been specified with lstCreate
54 *
55 * If __XWPMEMDEBUG__ is defined, the lstCreate and lstAppendItem funcs will
56 * automatically be replaced with lstCreateDebug and lstAppendItemDebug,
57 * and mapper macros are defined in linklist.h.
58 *
59 * Note: If you frequently need to search your data structures,
60 * you might prefer the new balanced binary trees in tree.c which
61 * have been added with V0.9.5.
62 *
63 * Note: Version numbering in this file relates to XWorkplace version
64 * numbering.
65 *
66 *@@header "helpers\linklist.h"
67 */
68
69/*
70 * Copyright (C) 1997-2001 Ulrich M”ller.
71 * This file is part of the "XWorkplace helpers" source package.
72 * This is free software; you can redistribute it and/or modify
73 * it under the terms of the GNU General Public License as published
74 * by the Free Software Foundation, in version 2 as it comes in the
75 * "COPYING" file of the XWorkplace main distribution.
76 * This program is distributed in the hope that it will be useful,
77 * but WITHOUT ANY WARRANTY; without even the implied warranty of
78 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
79 * GNU General Public License for more details.
80 */
81
82#include <stdlib.h>
83#include <string.h>
84
85#include "setup.h" // code generation and debugging options
86
87#define DONT_REPLACE_LIST_MALLOC
88#include "helpers\linklist.h"
89
90#pragma hdrstop
91
92/*
93 *@@category: Helpers\C helpers\Linked lists
94 * See linklist.c.
95 */
96
97/* ******************************************************************
98 *
99 * List base functions
100 *
101 ********************************************************************/
102
103/*
104 *@@ lstMalloc:
105 * wrapper around malloc() to make sure memory is
106 * allocated from the C runtime the helpers were
107 * compiled with. This is useful for auto-free
108 * lists.
109 *
110 *@@added V0.9.7 (2000-12-07) [umoeller]
111 */
112
113void* lstMalloc(size_t size)
114{
115 return (malloc(size));
116}
117
118/*
119 *@@ lstStrDup:
120 * wrapper around strdup() to make sure memory is
121 * allocated from the C runtime the helpers were
122 * compiled with. This is useful for auto-free
123 * lists.
124 *
125 *@@added V0.9.7 (2000-12-07) [umoeller]
126 */
127
128void* lstStrDup(const char *pcsz)
129{
130 return (strdup(pcsz));
131}
132
133/*
134 *@@ lstInit:
135 * this initializes a given LINKLIST structure.
136 *
137 * This is useful only if you have a static
138 * LINKLIST structure in your sources (either as
139 * a global variable or as a stack variable) and
140 * don't use lstCreate/lstFree to have lists created
141 * from the heap.
142 *
143 * In that case, use this function as follows:
144 +
145 + LINKLIST llWhatever;
146 + lstInit(&llWhatever);
147 + ...
148 + lstClear(&llWhatever);
149 *
150 * The list which is initialized here must be
151 * cleaned up using lstClear.
152 *
153 * If (fItemsFreeable == TRUE), free() will be
154 * invoked on list items automatically in lstClear,
155 * lstRemoveNode, and lstRemoveItem.
156 *
157 * -- Set this to TRUE if you have created the
158 * list items yourself using malloc().
159 *
160 * This of course will be a "flat" free(). If
161 * you store structures in the list using other
162 * heap pointers, auto-free would cause memory leaks.
163 *
164 * Also, auto-free only works if the malloc() that
165 * has been used on the list item is in the same C
166 * runtime as with the linklist functions. If the
167 * caller uses a different runtime (e.g. from a DLL),
168 * it can use lstMalloc() for allocating the list
169 * item and still use auto-free.
170 *
171 * -- Set this to FALSE if you're storing other
172 * objects, such as numbers or other static items.
173 *
174 * Note: You better call lstInit only once per list,
175 * because we don't check here if the list
176 * contains any data. This will lead to memory
177 * leaks if called upon existing lists, because
178 * we'll lose track of the allocated items.
179 */
180
181void lstInit(PLINKLIST pList,
182 BOOL fItemsFreeable) // in: invoke free() on the data
183 // item pointers upon destruction?
184{
185 if (pList)
186 {
187 memset(pList, 0, sizeof(LINKLIST));
188 pList->ulMagic = LINKLISTMAGIC; // set integrity check word
189 pList->fItemsFreeable = fItemsFreeable;
190 }
191}
192
193/*
194 *@@ lstClear:
195 * this will delete all list items. As opposed to
196 * lstFree, the "root" of the list will not be
197 * freed so that items can be added later again.
198 *
199 * This can be used on static lists initialized with
200 * lstInit also.
201 *
202 * If fItemsFreeable had been specified as TRUE
203 * when the list was initialized (lstInit), free()
204 * will be invoked on all data item pointers also.
205 * See the remarks for lstInit.
206 *
207 * Returns FALSE only upon errors, e.g. because
208 * integrity checks failed.
209 */
210
211BOOL lstClear(PLINKLIST pList)
212{
213 BOOL brc = FALSE;
214
215 if (pList)
216 if (pList->ulMagic == LINKLISTMAGIC)
217 {
218 PLISTNODE pNode = pList->pFirst,
219 pNode2;
220
221 while (pNode)
222 {
223 if (pList->fItemsFreeable)
224 if (pNode->pItemData)
225 free(pNode->pItemData);
226 pNode2 = pNode->pNext;
227 free(pNode);
228 pNode = pNode2;
229 } // while (pNode);
230
231 lstInit(pList, pList->fItemsFreeable);
232 brc = TRUE;
233 }
234
235 return brc;
236}
237
238#ifdef __DEBUG_MALLOC_ENABLED__
239
240/*
241 *@@ lstCreateDebug:
242 * debug version of lstCreate, using _debug_malloc.
243 *
244 * Calls to lstCreate are automatically mapped to
245 * this function if __XWPMEMDEBUG__ is defined.
246 * This makes sure that the source file and line stored
247 * with the debug memory functions will be that of the
248 * caller, not the ones in this file.
249 *
250 *@@added V0.9.1 (99-12-18) [umoeller]
251 */
252
253PLINKLIST lstCreateDebug(BOOL fItemsFreeable,
254 const char *file,
255 unsigned long line,
256 const char *function)
257{
258 PLINKLIST pNewList = (PLINKLIST)memdMalloc(sizeof(LINKLIST),
259 file,
260 line,
261 function);
262
263 lstInit(pNewList, fItemsFreeable);
264
265 return pNewList;
266}
267
268#endif
269
270// #else // __DEBUG_MALLOC_ENABLED__
271
272/*
273 *@@ lstCreate:
274 * this creates a new linked list and initializes it
275 * (using lstInit).
276 * The LINKLIST structure which defines the "root" of
277 * the list is returned. This must be passed to all
278 * other list functions.
279 *
280 * The list which is created here must be destroyed
281 * using lstFree.
282 *
283 * See lstInit for the description of fItemsFreeable.
284 *
285 * Returns NULL upon errors.
286 *
287 * <B>Usage:</B>
288 + PLINKLIST pllWhatever = lstCreate();
289 + ...
290 + lstFree(pllWhatever);
291 */
292
293PLINKLIST lstCreate(BOOL fItemsFreeable) // in: invoke free() on the data
294 // item pointers upon destruction?
295{
296 PLINKLIST pNewList;
297 if (pNewList = (PLINKLIST)malloc(sizeof(LINKLIST)))
298 lstInit(pNewList, fItemsFreeable);
299
300 return pNewList;
301}
302
303// #endif // __DEBUG_MALLOC_ENABLED__
304
305/*
306 *@@ lstFree:
307 * this will delete all list items (by calling
308 * lstClear) and the list "root" itself.
309 * Returns TRUE if anything was deleted at all
310 * (even if the list was empty)
311 * or FALSE upon errors, e.g. because integrity
312 * checks failed.
313 *
314 * If fItemsFreeable had been specified as TRUE
315 * when the list was created (lstCreate), free()
316 * will be invoked on all data item pointers also.
317 * See the remarks for lstInit.
318 *
319 * This must only be used with heap lists created
320 * with lstCreate.
321 *
322 * This uses a pointer to a PLINKLIST so that
323 * the pointer is automatically reset to NULL
324 * by this function AND to avoid confusion
325 * with lstClear.
326 *
327 *@@changed V0.9.12 (2001-05-24) [umoeller]: changed prototype to use pointer to pointer
328 */
329
330BOOL lstFree(PLINKLIST *ppList)
331{
332 BOOL brc = FALSE;
333 PLINKLIST p;
334
335 if ( (ppList)
336 && (p = *ppList)
337 )
338 if (lstClear(p)) // this checks for list integrity
339 {
340 // unset magic word; the pList pointer
341 // will point to invalid memory after
342 // freeing the list, and subsequent
343 // integrity checks must fail
344 p->ulMagic = 0;
345 free(p);
346
347 *ppList = NULL;
348
349 brc = TRUE;
350 }
351
352 return brc;
353}
354
355/*
356 *@@ lstCountItems:
357 * this will return the number of items
358 * in the given linked list.
359 * This returns 0 if the list is empty
360 * or -1 if the list is invalid or corrupt.
361 */
362
363long lstCountItems(const LINKLIST *pList)
364{
365 if ( (pList)
366 && (pList->ulMagic == LINKLISTMAGIC)
367 )
368 return pList->ulCount;
369
370 return -1;
371}
372
373/*
374 *@@ lstQueryFirstNode:
375 * this returns the first node of the list,
376 * or NULL if the list is empty. This is
377 * preferred over getting the first directly
378 * from the LINKLIST structure, because this
379 * one checks for data integrity.
380 *
381 * The item data can be queried from the node
382 * as follows:
383 *
384 + PLINKLIST pll = lstCreate();
385 + ... // add items here
386 + PLISTNODE pNode = lstQueryFirstNode(pll);
387 + PYOURDATA pData = pNode->pItemData;
388 *
389 * You can iterate over the whole list like this:
390 *
391 + PLISTNODE pNode = lstQueryFirstNode(pll);
392 + while (pNode)
393 + {
394 + PYOURDATA pYourData = (PYOURDATA)pNode->pItemData;
395 + ...
396 + pNode = pNode->pNext;
397 + }
398 */
399
400PLISTNODE lstQueryFirstNode(const LINKLIST *pList)
401{
402 if ( (pList)
403 && (pList->ulMagic == LINKLISTMAGIC)
404 )
405 return pList->pFirst;
406
407 return 0;
408}
409
410/*
411 *@@ lstQueryLastNode:
412 * similar to lstQueryFirstNode, but this returns
413 * the last node.
414 *
415 *@@added V0.9.9 (2001-02-14) [umoeller]
416 */
417
418PLISTNODE lstQueryLastNode(const LINKLIST *pList)
419{
420 if ( (pList)
421 && (pList->ulMagic == LINKLISTMAGIC)
422 )
423 return pList->pLast;
424
425 return 0;
426}
427
428/*
429 *@@ lstNodeFromIndex:
430 * returns the data of list item with a given ulIndex
431 * (counting from 0), or NULL if ulIndex is too large.
432 *
433 * This traverses the whole list, so it's not terribly
434 * fast. See lstQueryFirstNode for how to traverse
435 * the list yourself.
436 *
437 * Note: As opposed to lstItemFromIndex, this one
438 * returns the LISTNODE structure.
439 */
440
441PLISTNODE lstNodeFromIndex(PLINKLIST pList,
442 unsigned long ulIndex)
443{
444 PLISTNODE pNode = NULL;
445
446 if ( (pList)
447 && (pList->ulMagic == LINKLISTMAGIC)
448 && (pList->pFirst)
449 )
450 {
451 unsigned long ulCount = 0;
452 pNode = pList->pFirst;
453 for (ulCount = 0;
454 ((pNode) && (ulCount < ulIndex));
455 ulCount++)
456 {
457 if (pNode->pNext)
458 pNode = pNode->pNext;
459 else
460 pNode = NULL; // exit
461 }
462 }
463
464 return pNode;
465}
466
467/*
468 *@@ lstNodeFromItem:
469 * this finds the list node which has the given
470 * data pointer or NULL if not found.
471 *
472 * This traverses the whole list, so it's not terribly
473 * fast. See lstQueryFirstNode for how to traverse
474 * the list yourself.
475 */
476
477PLISTNODE lstNodeFromItem(PLINKLIST pList,
478 void* pItemData)
479{
480 PLISTNODE pNode = 0,
481 pNodeFound = 0;
482
483 if ( (pList)
484 && (pList->ulMagic == LINKLISTMAGIC)
485 && (pItemData)
486 )
487 {
488 pNode = pList->pFirst;
489 while (pNode)
490 {
491 if (pNode->pItemData == pItemData)
492 {
493 pNodeFound = pNode;
494 break;
495 }
496
497 pNode = pNode->pNext;
498 }
499 }
500
501 return pNodeFound;
502}
503
504/*
505 *@@ lstItemFromIndex:
506 * returns the data of the list item with a given ulIndex
507 * (counting from 0), or NULL if ulIndex is too large.
508 *
509 * This traverses the whole list, so it's not terribly
510 * fast. See lstQueryFirstNode for how to traverse
511 * the list yourself.
512 *
513 * Note: As opposed to lstNodeFromIndex, this one
514 * returns the item data directly, not the LISTNODE
515 * structure.
516 */
517
518void* lstItemFromIndex(PLINKLIST pList,
519 unsigned long ulIndex)
520{
521 PLISTNODE pNode;
522 if (pNode = lstNodeFromIndex(pList, ulIndex))
523 return (pNode->pItemData);
524 else
525 return (0);
526}
527
528/*
529 *@@ lstIndexFromItem:
530 * returns the index of the list node with
531 * the specified item pointer. The first
532 * node returns 0, the second 1, and so on.
533 *
534 * Returns -1 if not found.
535 *
536 * In the worst case, this function traverses
537 * the whole list.
538 *
539 *@@added V0.9.7 (2000-12-13) [umoeller]
540 */
541
542unsigned long lstIndexFromItem(PLINKLIST pList, void *pItemData)
543{
544 ULONG ulrc = -1,
545 ulIndex = 0;
546 PLISTNODE pNode = lstQueryFirstNode(pList);
547 while (pNode)
548 {
549 if (pNode->pItemData == pItemData)
550 {
551 ulrc = ulIndex;
552 break;
553 }
554
555 pNode = pNode->pNext;
556 ulIndex++;
557 }
558
559 return ulrc;
560}
561
562#ifdef __DEBUG_MALLOC_ENABLED__
563
564/*
565 *@@ lstAppendItemDebug:
566 * debug version of lstAppendItem, using _debug_malloc.
567 *
568 * Calls to lstAppendItem are automatically mapped to
569 * this function if __XWPMEMDEBUG__ is defined.
570 * This makes sure that the source file and line stored
571 * with the debug memory functions will be that of the
572 * caller, not the ones in this file.
573 *
574 *@@added V0.9.1 (99-12-18) [umoeller]
575 */
576
577PLISTNODE lstAppendItemDebug(PLINKLIST pList,
578 void* pNewItemData, // in: data to store in list node
579 const char *file,
580 unsigned long line,
581 const char *function)
582{
583 PLISTNODE pNewNode = NULL;
584
585 if ( (pList)
586 && (pList->ulMagic == LINKLISTMAGIC)
587 && (pNewNode = (PLISTNODE)memdMalloc(sizeof(LISTNODE), file, line, function))
588 )
589 {
590 memset(pNewNode, 0, sizeof(LISTNODE));
591 pNewNode->pItemData = pNewItemData;
592
593 if (pList->pLast)
594 {
595 // list is not empty: append to tail
596
597 // 1) make last item point to new node
598 pList->pLast->pNext = pNewNode;
599 // 2) make new node point to last item
600 pNewNode->pPrevious = pList->pLast;
601 // 3) store new node as new last item
602 pList->pLast = pNewNode;
603
604 pList->ulCount++;
605 }
606 else
607 {
608 // list is empty: insert as first
609 pList->pFirst
610 = pList->pLast
611 = pNewNode;
612
613 pList->ulCount = 1;
614 }
615 }
616
617 return pNewNode;
618}
619
620#endif
621
622// #else // __DEBUG_MALLOC_ENABLED__
623
624/*
625 *@@ lstAppendItem:
626 * this adds a new node to the tail of the list.
627 * As opposed to lstInsertItemBefore, this is very
628 * fast, since the list always keeps track of its last item.
629 *
630 * This returns the LISTNODE of the new list item,
631 * or NULL upon errors.
632 */
633
634PLISTNODE lstAppendItem(PLINKLIST pList,
635 void* pNewItemData) // in: data to store in list node
636{
637 PLISTNODE pNewNode = NULL;
638
639 if ( (pList)
640 && (pList->ulMagic == LINKLISTMAGIC)
641 && (pNewNode = (PLISTNODE)malloc(sizeof(LISTNODE)))
642 )
643 {
644 memset(pNewNode, 0, sizeof(LISTNODE));
645 pNewNode->pItemData = pNewItemData;
646
647 if (pList->pLast)
648 {
649 // list is not empty: append to tail
650
651 // 1) make last item point to new node
652 pList->pLast->pNext = pNewNode;
653 // 2) make new node point to last item
654 pNewNode->pPrevious = pList->pLast;
655 // 3) store new node as new last item
656 pList->pLast = pNewNode;
657
658 pList->ulCount++;
659 }
660 else
661 {
662 // list is empty: insert as first
663 pList->pFirst
664 = pList->pLast
665 = pNewNode;
666
667 pList->ulCount = 1;
668 }
669 }
670
671 return pNewNode;
672}
673
674// #endif // __DEBUG_MALLOC_ENABLED__
675
676/*
677 *@@ lstInsertItemBefore:
678 * this inserts a new node to the list. As opposed to
679 * lstAppendItem, the new node can be appended anywhere
680 * in the list, that is, it will be appended BEFORE
681 * the specified index lIndex.
682 *
683 * So if ulIndex == 0, the new item will be made the first
684 * item.
685 *
686 * If ulIndex is larger than the item count on the list,
687 * the new node will be appended at the tail of the list
688 * (as with lstAppendItem).
689 *
690 * This needs to traverse the list to find the indexed
691 * item, so for larger ulIndex's this function is not
692 * terribly fast.
693 *
694 * This returns the LISTNODE of the new list item,
695 * or NULL upon errors.
696 *
697 *@@changed V0.9.14 (2001-07-14) [umoeller]: this never worked on empty lists, fixed
698 */
699
700PLISTNODE lstInsertItemBefore(PLINKLIST pList,
701 void* pNewItemData, // data to store in list node
702 unsigned long ulIndex)
703{
704 PLISTNODE pNewNode = NULL;
705
706 if ( (pList)
707 && (pList->ulMagic == LINKLISTMAGIC)
708 && (pNewNode = (PLISTNODE)malloc(sizeof(LISTNODE)))
709 )
710 {
711 memset(pNewNode, 0, sizeof(LISTNODE));
712 pNewNode->pItemData = pNewItemData;
713
714 if (ulIndex == 0)
715 {
716 // insert at beginning:
717 if (pList->pFirst)
718 pList->pFirst->pPrevious = pNewNode;
719
720 pNewNode->pNext = pList->pFirst;
721 pNewNode->pPrevious = NULL;
722
723 pList->pFirst = pNewNode;
724
725 if (!pList->pLast)
726 // the list was empty:
727 pList->pLast = pNewNode; // V0.9.14 (2001-07-14) [umoeller]
728
729 (pList->ulCount)++;
730 }
731 else
732 {
733 // insert at a later position:
734 PLISTNODE pNodeInsertAfter = lstNodeFromIndex(
735 pList,
736 (ulIndex-1));
737
738 if (pNodeInsertAfter)
739 {
740 // 1) set pointers for new node
741 pNewNode->pPrevious = pNodeInsertAfter;
742 pNewNode->pNext = pNodeInsertAfter->pNext;
743
744 // 2) adjust next item
745 // so that it points to the new node
746 if (pNodeInsertAfter->pNext)
747 pNodeInsertAfter->pNext->pPrevious = pNewNode;
748
749 // 3) adjust previous item
750 // so that it points to the new node
751 pNodeInsertAfter->pNext = pNewNode;
752
753 // 4) adjust last item, if necessary
754 if (pList->pLast == pNodeInsertAfter)
755 pList->pLast = pNewNode;
756
757 (pList->ulCount)++;
758 }
759 else
760 {
761 // item index too large: append instead
762 free(pNewNode);
763 pNewNode = lstAppendItem(pList, pNewItemData);
764 }
765 }
766 }
767
768 return pNewNode;
769}
770
771/*
772 *@@ lstRemoveNode:
773 * this will remove a given pRemoveNode from
774 * the given linked list.
775 *
776 * To remove a node according to the item pointer,
777 * use lstRemoveItem.
778 * To get the node from a node index, use
779 * lstNodeFromIndex.
780 *
781 * Since the LISTNODE is known, this function
782 * operates very fast.
783 *
784 * If fItemsFreeable had been specified as TRUE
785 * when the list was created (lstInit or lstCreate),
786 * free() will be invoked on the data item pointer also.
787 * See the remarks there.
788 *
789 * Returns TRUE if successful, FALSE upon errors.
790 */
791
792BOOL lstRemoveNode(PLINKLIST pList,
793 PLISTNODE pRemoveNode)
794{
795 BOOL fFound = FALSE;
796
797 if ( (pList)
798 && (pList->ulMagic == LINKLISTMAGIC)
799 && (pRemoveNode)
800 )
801 {
802 if (pList->pFirst == pRemoveNode)
803 // item to be removed is first: adjust first
804 pList->pFirst = pRemoveNode->pNext; // can be NULL
805
806 if (pList->pLast == pRemoveNode)
807 // item to be removed is last: adjust last
808 pList->pLast = pRemoveNode->pPrevious; // can be NULL
809
810 if (pRemoveNode->pPrevious)
811 // adjust previous item
812 pRemoveNode->pPrevious->pNext = pRemoveNode->pNext;
813
814 if (pRemoveNode->pNext)
815 // adjust next item
816 pRemoveNode->pNext->pPrevious = pRemoveNode->pPrevious;
817
818 // decrease list count
819 pList->ulCount--;
820
821 // free node data
822 if (pList->fItemsFreeable)
823 if (pRemoveNode->pItemData)
824 free(pRemoveNode->pItemData);
825 // free node
826 free(pRemoveNode);
827
828 fFound = TRUE;
829 }
830
831 return fFound;
832}
833
834/*
835 *@@ lstRemoveItem:
836 * as opposed to lstRemoveNode, this removes a
837 * node according to an item data pointer.
838 *
839 * This needs to call lstNodeFromItem first and
840 * then invokes lstRemoveNode, so this is a lot
841 * slower.
842 *
843 * If fItemsFreeable had been specified as TRUE
844 * when the list was created (lstInit or lstCreate),
845 * free() will be invoked on the data item pointer also.
846 * See the remarks there.
847 *
848 * Returns TRUE if successful, FALSE upon errors.
849 */
850
851BOOL lstRemoveItem(PLINKLIST pList, void* pRemoveItem)
852{
853 PLISTNODE pNode;
854
855 if (pNode = lstNodeFromItem(pList, pRemoveItem))
856 return lstRemoveNode(pList, pNode);
857
858 return FALSE;
859}
860
861/*
862 *@@ lstSwapItems:
863 * this will swap the items pNode1 and pNode2.
864 * This is used in the sort routines.
865 *
866 * Note that it is not really the nodes that are swapped,
867 * but only the data item pointers. This is a lot quicker
868 * than what we did in versions < 0.9.0.
869 */
870
871BOOL lstSwapNodes(PLISTNODE pNode1,
872 PLISTNODE pNode2)
873{
874 if ( (pNode1) && (pNode2) )
875 {
876 void* pTemp = pNode1->pItemData;
877 pNode1->pItemData = pNode2->pItemData;
878 pNode2->pItemData = pTemp;
879
880 return TRUE;
881 }
882
883 return FALSE;
884}
885
886/* ******************************************************************
887 *
888 * List sorting
889 *
890 ********************************************************************/
891
892/*
893 * lstQuickSort2:
894 * helper routine for recursing during quicksort (lstQuickSort).
895 */
896
897void lstQuickSort2(PLINKLIST pList,
898 PFNSORTLIST pfnSort,
899 void* pStorage,
900 long lLeft,
901 long lRight)
902{
903 long ll = lLeft,
904 lr = lRight - 1,
905 lPivot = lRight;
906
907 if (lRight > lLeft)
908 {
909 PLISTNODE pNodeLeft = lstNodeFromIndex(pList, ll),
910 pNodeRight = lstNodeFromIndex(pList, lr),
911 pNodePivot = lstNodeFromIndex(pList, lPivot);
912
913 while (TRUE)
914 {
915 // compare left item data to pivot item data
916 while ( pfnSort(pNodeLeft->pItemData,
917 pNodePivot->pItemData,
918 pStorage)
919 < 0 )
920 {
921 ll++;
922 // advance to next
923 pNodeLeft = pNodeLeft->pNext;
924 }
925
926 // compare right item to pivot
927 while ( ( pfnSort(pNodeRight->pItemData,
928 pNodePivot->pItemData,
929 pStorage)
930 >= 0 )
931 && (lr > ll)
932 )
933 {
934 lr--;
935 // step to previous
936 pNodeRight = pNodeRight->pPrevious;
937 }
938
939 if (lr <= ll)
940 break;
941
942 // swap pNodeLeft and pNodeRight
943 lstSwapNodes(pNodeLeft, pNodeRight);
944 }
945
946 // swap pNodeLeft and pNodePivot
947 lstSwapNodes(pNodeLeft, pNodePivot);
948
949 // recurse!
950 lstQuickSort2(pList, pfnSort, pStorage,
951 lLeft,
952 ll - 1);
953 lstQuickSort2(pList, pfnSort, pStorage,
954 ll + 1,
955 lRight);
956 }
957}
958
959/*
960 *@@ lstQuickSort:
961 * this will sort the given linked list using the
962 * sort function pfnSort, which works similar to those of the
963 * container sorts, i.e. it must be declared as a
964 + signed short XWPENTRY fnSort(void* pItem1, void* pItem2, void* pStorage)
965 *
966 * These sort functions need to return the following:
967 * -- 0: pItem1 == pItem2
968 * -- -1: pItem1 < pItem2
969 * -- +1: pItem1 > pItem2
970 *
971 * Note that the comparison function does not get the PLISTNODEs,
972 * but the item data pointers instead.
973 *
974 * The pStorage parameter will simply be passed to the comparison
975 * function. This might be useful for additional data you might need.
976 *
977 * This returns FALSE upon errors.
978 *
979 * This function implements the "quick sort" algorithm, which is one
980 * of the fastest sort algorithms known to mankind. However, this is
981 * an "instable" sort algorithm, meaning that list items considered
982 * equal by pfnSort do _not_ retain their position, but might be
983 * changed. If you need these to remain where they are, use
984 * lstBubbleSort, which is a lot slower though.
985 *
986 * This calls lstSwapNodes to swap the list items.
987 */
988
989BOOL lstQuickSort(PLINKLIST pList,
990 PFNSORTLIST pfnSort,
991 void* pStorage)
992{
993 BOOL brc = FALSE;
994
995 if ( (pList)
996 && (pList->ulMagic == LINKLISTMAGIC)
997 && (pfnSort)
998 )
999 {
1000 long lRight = lstCountItems(pList) - 1;
1001
1002 lstQuickSort2(pList, pfnSort, pStorage,
1003 0, // lLeft
1004 lRight);
1005 brc = TRUE;
1006 }
1007
1008 return brc;
1009}
1010
1011/*
1012 *@@ lstBubbleSort:
1013 * just like lstQuickSort, this will sort a given linked list.
1014 * See lstQuickSort for the parameters.
1015 *
1016 * However, this function uses the "bubble sort" algorithm, which
1017 * will cause a lot of calls to pfnSort and which is really
1018 * ineffective for lists with more than 100 items.
1019 * Use only if you absolutely need a stable sort.
1020 *
1021 * This calls lstSwapNodes to swap the list items.
1022 */
1023
1024BOOL lstBubbleSort(PLINKLIST pList,
1025 PFNSORTLIST pfnSort,
1026 void* pStorage)
1027{
1028 BOOL brc = FALSE;
1029
1030 if (pList)
1031 if ( (pList->ulMagic == LINKLISTMAGIC)
1032 && (pfnSort)
1033 )
1034 {
1035 long lRight = lstCountItems(pList),
1036 lSorted,
1037 x;
1038
1039 do {
1040 lRight--;
1041 lSorted = 0;
1042 for (x = 0; x < lRight; x++)
1043 {
1044 // ulComp++;
1045 PLISTNODE pNode1 = lstNodeFromIndex(pList, x),
1046 pNode2 = pNode1->pNext;
1047 if ((pNode1) && (pNode2))
1048 if ( (*pfnSort)(pNode1->pItemData,
1049 pNode2->pItemData,
1050 pStorage) > 0
1051 )
1052 {
1053 lstSwapNodes(pNode1, pNode2);
1054 lSorted++;
1055 }
1056 }
1057 } while ( lSorted && (lRight > 1) );
1058
1059 brc = TRUE;
1060 }
1061
1062 return brc;
1063}
1064
1065/* ******************************************************************
1066 *
1067 * List pseudo-stacks
1068 *
1069 ********************************************************************/
1070
1071/*
1072 *@@ lstPush:
1073 * pushes any data onto a "stack", which is a plain
1074 * LINKLIST being abused as a stack.
1075 * The "stack" is last-in, first-out (LIFO), meaning
1076 * that the last item pushed onto the list will be
1077 * the first returned by lstPop. See lstPop for example
1078 * usage.
1079 *
1080 *@@added V0.9.3 (2000-05-18) [umoeller]
1081 */
1082
1083PLISTNODE lstPush(PLINKLIST pList,
1084 void* pNewItemData) // in: data to store in list node
1085{
1086 return lstAppendItem(pList, pNewItemData);
1087}
1088
1089/*
1090 *@@ lstPop:
1091 * returns the last item which has been pushed onto
1092 * a pseudo-stack LIFO LINKLIST using lstPush.
1093 *
1094 * If (fRemove == TRUE), the item is also removed
1095 * from the stack. Otherwise it remains there so the
1096 * next lstPop would return the next item.
1097 *
1098 * Example:
1099 *
1100 + LINKLIST ll;
1101 + PLISTNODE pNode;
1102 + lstInit(&ll, FALSE);
1103 +
1104 + lstPush(&ll, (PVOID)1);
1105 + lstPush(&ll, (PVOID)2);
1106 +
1107 + pNode = lstPop(&ll); // returns the node containing "2"
1108 + lstRemoveNode(pNode);
1109 + pNode = lstPop(&ll); // returns the node containing "1"
1110 *
1111 *@@added V0.9.3 (2000-05-18) [umoeller]
1112 */
1113
1114PLISTNODE lstPop(PLINKLIST pList)
1115{
1116 return pList->pLast;
1117}
1118
1119
Note: See TracBrowser for help on using the repository browser.