source: trunk/src/helpers/linklist.c

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

First attempt at new container contol.

  • Property svn:eol-style set to CRLF
  • Property svn:keywords set to Author Date Id Revision
File size: 33.3 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
525 return NULL;
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 *@@ InsertFront:
678 *
679 *@@added V1.0.1 (2003-01-17) [umoeller]
680 */
681
682VOID InsertFront(PLINKLIST pList,
683 PLISTNODE pNewNode)
684{
685 if (pList->pFirst)
686 pList->pFirst->pPrevious = pNewNode;
687
688 pNewNode->pNext = pList->pFirst;
689 pNewNode->pPrevious = NULL;
690
691 pList->pFirst = pNewNode;
692
693 if (!pList->pLast)
694 // the list was empty:
695 pList->pLast = pNewNode; // V0.9.14 (2001-07-14) [umoeller]
696
697 (pList->ulCount)++;
698}
699
700/*
701 *@@ InsertAfterNode:
702 *
703 *@@added V1.0.1 (2003-01-17) [umoeller]
704 */
705
706VOID InsertAfterNode(PLINKLIST pList,
707 PLISTNODE pNewNode,
708 PLISTNODE pNodeInsertAfter)
709{
710 // 1) set pointers for new node
711 pNewNode->pPrevious = pNodeInsertAfter;
712 pNewNode->pNext = pNodeInsertAfter->pNext;
713
714 // 2) adjust next item
715 // so that it points to the new node
716 if (pNodeInsertAfter->pNext)
717 pNodeInsertAfter->pNext->pPrevious = pNewNode;
718
719 // 3) adjust previous item
720 // so that it points to the new node
721 pNodeInsertAfter->pNext = pNewNode;
722
723 // 4) adjust last item, if necessary
724 if (pList->pLast == pNodeInsertAfter)
725 pList->pLast = pNewNode;
726
727 (pList->ulCount)++;
728}
729
730/*
731 *@@ lstInsertItemBefore:
732 * this inserts a new node to the list. As opposed to
733 * lstAppendItem, the new node can be appended anywhere
734 * in the list, that is, it will be appended BEFORE
735 * the specified index lIndex.
736 *
737 * So if ulIndex == 0, the new item will be made the first
738 * item.
739 *
740 * If ulIndex is larger than the item count on the list,
741 * the new node will be appended at the tail of the list
742 * (as with lstAppendItem).
743 *
744 * This needs to traverse the list to find the indexed
745 * item, so for larger ulIndex's this function is not
746 * terribly fast.
747 *
748 * This returns the LISTNODE of the new list item,
749 * or NULL upon errors.
750 *
751 *@@changed V0.9.14 (2001-07-14) [umoeller]: this never worked on empty lists, fixed
752 */
753
754PLISTNODE lstInsertItemBefore(PLINKLIST pList,
755 void* pNewItemData, // in: data to store in list node
756 unsigned long ulIndex) // in: index before which to insert
757{
758 PLISTNODE pNewNode = NULL;
759
760 if ( (pList)
761 && (pList->ulMagic == LINKLISTMAGIC)
762 && (pNewNode = (PLISTNODE)malloc(sizeof(LISTNODE)))
763 )
764 {
765 memset(pNewNode, 0, sizeof(LISTNODE));
766 pNewNode->pItemData = pNewItemData;
767
768 if (ulIndex == 0)
769 {
770 // insert at beginning:
771 InsertFront(pList,
772 pNewNode);
773 }
774 else
775 {
776 // insert at a later position:
777 PLISTNODE pNodeInsertAfter;
778
779 if (pNodeInsertAfter = lstNodeFromIndex(pList,
780 ulIndex - 1))
781 {
782 InsertAfterNode(pList,
783 pNewNode,
784 pNodeInsertAfter);
785 }
786 else
787 {
788 // item index too large: append instead
789 free(pNewNode);
790 pNewNode = lstAppendItem(pList, pNewItemData);
791 }
792 }
793 }
794
795 return pNewNode;
796}
797
798/*
799 *@@ lstInsertItemAfterNode:
800 * this inserts a new node to the list. As opposed to
801 * lstAppendItem, the new node can be appended anywhere
802 * in the list, that is, it will be appended AFTER
803 * the given existing list node.
804 *
805 * If pNodeAfter is NULL, the new item will be made the
806 * first item.
807 *
808 * As opposed to lstInsertItemBefore, this does not
809 * need to traverse the list, so it is very quick.
810 *
811 * This returns the LISTNODE of the new list item,
812 * or NULL upon errors.
813 *
814 *@@added V1.0.1 (2003-01-17) [umoeller]
815 */
816
817PLISTNODE lstInsertItemAfterNode(PLINKLIST pList,
818 void* pNewItemData, // in: data to store in list node
819 PLISTNODE pNodeInsertAfter) // in: node to insert after or NULL to make new node the first
820{
821 PLISTNODE pNewNode = NULL;
822
823 if ( (pList)
824 && (pList->ulMagic == LINKLISTMAGIC)
825 && (pNewNode = (PLISTNODE)malloc(sizeof(LISTNODE)))
826 )
827 {
828 memset(pNewNode, 0, sizeof(LISTNODE));
829 pNewNode->pItemData = pNewItemData;
830
831 if (!pNodeInsertAfter)
832 // insert at beginning:
833 InsertFront(pList,
834 pNewNode);
835 else
836 InsertAfterNode(pList,
837 pNewNode,
838 pNodeInsertAfter);
839 }
840
841 return pNewNode;
842}
843
844/*
845 *@@ lstRemoveNode:
846 * this will remove a given pRemoveNode from
847 * the given linked list.
848 *
849 * To remove a node according to the item pointer,
850 * use lstRemoveItem.
851 * To get the node from a node index, use
852 * lstNodeFromIndex.
853 *
854 * Since the LISTNODE is known, this function
855 * operates very fast.
856 *
857 * If fItemsFreeable had been specified as TRUE
858 * when the list was created (lstInit or lstCreate),
859 * free() will be invoked on the data item pointer also.
860 * See the remarks there.
861 *
862 * Returns TRUE if successful, FALSE upon errors.
863 */
864
865BOOL lstRemoveNode(PLINKLIST pList,
866 PLISTNODE pRemoveNode)
867{
868 BOOL fFound = FALSE;
869
870 if ( (pList)
871 && (pList->ulMagic == LINKLISTMAGIC)
872 && (pRemoveNode)
873 )
874 {
875 if (pList->pFirst == pRemoveNode)
876 // item to be removed is first: adjust first
877 pList->pFirst = pRemoveNode->pNext; // can be NULL
878
879 if (pList->pLast == pRemoveNode)
880 // item to be removed is last: adjust last
881 pList->pLast = pRemoveNode->pPrevious; // can be NULL
882
883 if (pRemoveNode->pPrevious)
884 // adjust previous item
885 pRemoveNode->pPrevious->pNext = pRemoveNode->pNext;
886
887 if (pRemoveNode->pNext)
888 // adjust next item
889 pRemoveNode->pNext->pPrevious = pRemoveNode->pPrevious;
890
891 // decrease list count
892 pList->ulCount--;
893
894 // free node data
895 if (pList->fItemsFreeable)
896 if (pRemoveNode->pItemData)
897 free(pRemoveNode->pItemData);
898 // free node
899 free(pRemoveNode);
900
901 fFound = TRUE;
902 }
903
904 return fFound;
905}
906
907/*
908 *@@ lstRemoveItem:
909 * as opposed to lstRemoveNode, this removes a
910 * node according to an item data pointer.
911 *
912 * This needs to call lstNodeFromItem first and
913 * then invokes lstRemoveNode, so this is a lot
914 * slower.
915 *
916 * If fItemsFreeable had been specified as TRUE
917 * when the list was created (lstInit or lstCreate),
918 * free() will be invoked on the data item pointer also.
919 * See the remarks there.
920 *
921 * Returns TRUE if successful, FALSE upon errors.
922 */
923
924BOOL lstRemoveItem(PLINKLIST pList, void* pRemoveItem)
925{
926 PLISTNODE pNode;
927
928 if (pNode = lstNodeFromItem(pList, pRemoveItem))
929 return lstRemoveNode(pList, pNode);
930
931 return FALSE;
932}
933
934/*
935 *@@ lstSwapItems:
936 * this will swap the items pNode1 and pNode2.
937 * This is used in the sort routines.
938 *
939 * Note that it is not really the nodes that are swapped,
940 * but only the data item pointers. This is a lot quicker
941 * than what we did in versions < 0.9.0.
942 */
943
944BOOL lstSwapNodes(PLISTNODE pNode1,
945 PLISTNODE pNode2)
946{
947 if ( (pNode1) && (pNode2) )
948 {
949 void* pTemp = pNode1->pItemData;
950 pNode1->pItemData = pNode2->pItemData;
951 pNode2->pItemData = pTemp;
952
953 return TRUE;
954 }
955
956 return FALSE;
957}
958
959/* ******************************************************************
960 *
961 * List sorting
962 *
963 ********************************************************************/
964
965/*
966 * lstQuickSort2:
967 * helper routine for recursing during quicksort (lstQuickSort).
968 */
969
970void lstQuickSort2(PLINKLIST pList,
971 PFNSORTLIST pfnSort,
972 void* pStorage,
973 long lLeft,
974 long lRight)
975{
976 long ll = lLeft,
977 lr = lRight - 1,
978 lPivot = lRight;
979
980 if (lRight > lLeft)
981 {
982 PLISTNODE pNodeLeft = lstNodeFromIndex(pList, ll),
983 pNodeRight = lstNodeFromIndex(pList, lr),
984 pNodePivot = lstNodeFromIndex(pList, lPivot);
985
986 while (TRUE)
987 {
988 // compare left item data to pivot item data
989 while ( pfnSort(pNodeLeft->pItemData,
990 pNodePivot->pItemData,
991 pStorage)
992 < 0 )
993 {
994 ll++;
995 // advance to next
996 pNodeLeft = pNodeLeft->pNext;
997 }
998
999 // compare right item to pivot
1000 while ( ( pfnSort(pNodeRight->pItemData,
1001 pNodePivot->pItemData,
1002 pStorage)
1003 >= 0 )
1004 && (lr > ll)
1005 )
1006 {
1007 lr--;
1008 // step to previous
1009 pNodeRight = pNodeRight->pPrevious;
1010 }
1011
1012 if (lr <= ll)
1013 break;
1014
1015 // swap pNodeLeft and pNodeRight
1016 lstSwapNodes(pNodeLeft, pNodeRight);
1017 }
1018
1019 // swap pNodeLeft and pNodePivot
1020 lstSwapNodes(pNodeLeft, pNodePivot);
1021
1022 // recurse!
1023 lstQuickSort2(pList, pfnSort, pStorage,
1024 lLeft,
1025 ll - 1);
1026 lstQuickSort2(pList, pfnSort, pStorage,
1027 ll + 1,
1028 lRight);
1029 }
1030}
1031
1032/*
1033 *@@ lstQuickSort:
1034 * this will sort the given linked list using the
1035 * sort function pfnSort, which works similar to those of the
1036 * container sorts, i.e. it must be declared as a
1037 + signed short XWPENTRY fnSort(void* pItem1, void* pItem2, void* pStorage)
1038 *
1039 * These sort functions need to return the following:
1040 * -- 0: pItem1 == pItem2
1041 * -- -1: pItem1 < pItem2
1042 * -- +1: pItem1 > pItem2
1043 *
1044 * Note that the comparison function does not get the PLISTNODEs,
1045 * but the item data pointers instead.
1046 *
1047 * The pStorage parameter will simply be passed to the comparison
1048 * function. This might be useful for additional data you might need.
1049 *
1050 * This returns FALSE upon errors.
1051 *
1052 * This function implements the "quick sort" algorithm, which is one
1053 * of the fastest sort algorithms known to mankind. However, this is
1054 * an "instable" sort algorithm, meaning that list items considered
1055 * equal by pfnSort do _not_ retain their position, but might be
1056 * changed. If you need these to remain where they are, use
1057 * lstBubbleSort, which is a lot slower though.
1058 *
1059 * This calls lstSwapNodes to swap the list items.
1060 */
1061
1062BOOL lstQuickSort(PLINKLIST pList,
1063 PFNSORTLIST pfnSort,
1064 void* pStorage)
1065{
1066 BOOL brc = FALSE;
1067
1068 if ( (pList)
1069 && (pList->ulMagic == LINKLISTMAGIC)
1070 && (pfnSort)
1071 )
1072 {
1073 long lRight = lstCountItems(pList) - 1;
1074
1075 lstQuickSort2(pList, pfnSort, pStorage,
1076 0, // lLeft
1077 lRight);
1078 brc = TRUE;
1079 }
1080
1081 return brc;
1082}
1083
1084/*
1085 *@@ lstBubbleSort:
1086 * just like lstQuickSort, this will sort a given linked list.
1087 * See lstQuickSort for the parameters.
1088 *
1089 * However, this function uses the "bubble sort" algorithm, which
1090 * will cause a lot of calls to pfnSort and which is really
1091 * ineffective for lists with more than 100 items.
1092 * Use only if you absolutely need a stable sort.
1093 *
1094 * This calls lstSwapNodes to swap the list items.
1095 */
1096
1097BOOL lstBubbleSort(PLINKLIST pList,
1098 PFNSORTLIST pfnSort,
1099 void* pStorage)
1100{
1101 BOOL brc = FALSE;
1102
1103 if (pList)
1104 if ( (pList->ulMagic == LINKLISTMAGIC)
1105 && (pfnSort)
1106 )
1107 {
1108 long lRight = lstCountItems(pList),
1109 lSorted,
1110 x;
1111
1112 do {
1113 lRight--;
1114 lSorted = 0;
1115 for (x = 0; x < lRight; x++)
1116 {
1117 // ulComp++;
1118 PLISTNODE pNode1 = lstNodeFromIndex(pList, x),
1119 pNode2 = pNode1->pNext;
1120 if ((pNode1) && (pNode2))
1121 if ( (*pfnSort)(pNode1->pItemData,
1122 pNode2->pItemData,
1123 pStorage) > 0
1124 )
1125 {
1126 lstSwapNodes(pNode1, pNode2);
1127 lSorted++;
1128 }
1129 }
1130 } while ( lSorted && (lRight > 1) );
1131
1132 brc = TRUE;
1133 }
1134
1135 return brc;
1136}
1137
1138/* ******************************************************************
1139 *
1140 * List pseudo-stacks
1141 *
1142 ********************************************************************/
1143
1144/*
1145 *@@ lstPush:
1146 * pushes any data onto a "stack", which is a plain
1147 * LINKLIST being abused as a stack.
1148 * The "stack" is last-in, first-out (LIFO), meaning
1149 * that the last item pushed onto the list will be
1150 * the first returned by lstPop. See lstPop for example
1151 * usage.
1152 *
1153 *@@added V0.9.3 (2000-05-18) [umoeller]
1154 */
1155
1156PLISTNODE lstPush(PLINKLIST pList,
1157 void* pNewItemData) // in: data to store in list node
1158{
1159 return lstAppendItem(pList, pNewItemData);
1160}
1161
1162/*
1163 *@@ lstPop:
1164 * returns the last item which has been pushed onto
1165 * a pseudo-stack LIFO LINKLIST using lstPush.
1166 *
1167 * If (fRemove == TRUE), the item is also removed
1168 * from the stack. Otherwise it remains there so the
1169 * next lstPop would return the next item.
1170 *
1171 * Example:
1172 *
1173 + LINKLIST ll;
1174 + PLISTNODE pNode;
1175 + lstInit(&ll, FALSE);
1176 +
1177 + lstPush(&ll, (PVOID)1);
1178 + lstPush(&ll, (PVOID)2);
1179 +
1180 + pNode = lstPop(&ll); // returns the node containing "2"
1181 + lstRemoveNode(pNode);
1182 + pNode = lstPop(&ll); // returns the node containing "1"
1183 *
1184 *@@added V0.9.3 (2000-05-18) [umoeller]
1185 */
1186
1187PLISTNODE lstPop(PLINKLIST pList)
1188{
1189 return pList->pLast;
1190}
1191
1192
Note: See TracBrowser for help on using the repository browser.