|
|
1.1 root 1: /* link_list.c */
2:
3: /* Double-Linked-list library */
4:
5: /* $Id: link_list.c,v 1.35 2006/05/29 07:32:43 rswindell Exp $ */
6:
7: /****************************************************************************
8: * @format.tab-size 4 (Plain Text/Source Code File Header) *
9: * @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
10: * *
11: * Copyright 2006 Rob Swindell - http://www.synchro.net/copyright.html *
12: * *
13: * This library is free software; you can redistribute it and/or *
14: * modify it under the terms of the GNU Lesser General Public License *
15: * as published by the Free Software Foundation; either version 2 *
16: * of the License, or (at your option) any later version. *
17: * See the GNU Lesser General Public License for more details: lgpl.txt or *
18: * http://www.fsf.org/copyleft/lesser.html *
19: * *
20: * Anonymous FTP access to the most recent released source is available at *
21: * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net *
22: * *
23: * Anonymous CVS access to the development source and modification history *
24: * is available at cvs.synchro.net:/cvsroot/sbbs, example: *
25: * cvs -d :pserver:[email protected]:/cvsroot/sbbs login *
26: * (just hit return, no password is necessary) *
27: * cvs -d :pserver:[email protected]:/cvsroot/sbbs checkout src *
28: * *
29: * For Synchronet coding style and modification guidelines, see *
30: * http://www.synchro.net/source.html *
31: * *
32: * You are encouraged to submit any modifications (preferably in Unix diff *
33: * format) via e-mail to [email protected] *
34: * *
35: * Note: If this box doesn't appear square, then you need to fix your tabs. *
36: ****************************************************************************/
37:
38: #include <stdlib.h> /* malloc */
39: #include <string.h> /* memset */
40: #include "link_list.h"
41: #include "genwrap.h"
42:
43: #if defined(LINK_LIST_THREADSAFE)
44: #define MUTEX_INIT(list) { if(list->flags&LINK_LIST_MUTEX) pthread_mutex_init((pthread_mutex_t*)&list->mutex,NULL); }
45: #define MUTEX_DESTROY(list) { if(list->flags&LINK_LIST_MUTEX) { while(pthread_mutex_destroy((pthread_mutex_t*)&list->mutex)==EBUSY) SLEEP(1);} }
46: #define MUTEX_LOCK(list) { if(list->flags&LINK_LIST_MUTEX) pthread_mutex_lock((pthread_mutex_t*)&list->mutex); }
47: #define MUTEX_UNLOCK(list) { if(list->flags&LINK_LIST_MUTEX) pthread_mutex_unlock((pthread_mutex_t*)&list->mutex); }
48: #else
49: #define MUTEX_INIT(list)
50: #define MUTEX_DESTROY(list)
51: #define MUTEX_LOCK(list)
52: #define MUTEX_UNLOCK(list)
53: #endif
54:
55: link_list_t* DLLCALL listInit(link_list_t* list, long flags)
56: {
57: if(flags&LINK_LIST_MALLOC || list==NULL) {
58: if((list=(link_list_t*)malloc(sizeof(link_list_t)))==NULL)
59: return(NULL);
60: flags |= LINK_LIST_MALLOC;
61: }
62:
63: memset(list,0,sizeof(link_list_t));
64:
65: list->flags = flags;
66:
67: MUTEX_INIT(list);
68:
69: #if defined(LINK_LIST_THREADSAFE)
70: if(list->flags&LINK_LIST_SEMAPHORE)
71: sem_init(&list->sem,0,0);
72: #endif
73:
74: if(flags&LINK_LIST_ATTACH)
75: listAttach(list);
76:
77: return(list);
78: }
79:
80: BOOL DLLCALL listFreeNodeData(list_node_t* node)
81: {
82: if(node!=NULL && node->data!=NULL && !(node->flags&LINK_LIST_NODE_LOCKED)) {
83: free(node->data);
84: node->data = NULL;
85: return(TRUE);
86: }
87: return(FALSE);
88: }
89:
90: long DLLCALL listFreeNodes(link_list_t* list)
91: {
92: list_node_t* node;
93: list_node_t* next;
94:
95: for(node=list->first; node!=NULL; node=next) {
96:
97: if(node->flags&LINK_LIST_NODE_LOCKED)
98: break;
99:
100: if((list->flags&LINK_LIST_ALWAYS_FREE || node->flags&LINK_LIST_MALLOC)
101: && !(list->flags&LINK_LIST_NEVER_FREE))
102: listFreeNodeData(node);
103:
104: next = node->next;
105:
106: free(node);
107:
108: if(list->count)
109: list->count--;
110: }
111:
112: list->first = node;
113: if(!list->count)
114: list->last = NULL;
115:
116: return(list->count);
117: }
118:
119: BOOL DLLCALL listFree(link_list_t* list)
120: {
121: if(list==NULL)
122: return(FALSE);
123:
124: if(listFreeNodes(list))
125: return(FALSE);
126:
127: MUTEX_DESTROY(list);
128:
129: #if defined(LINK_LIST_THREADSAFE)
130: if(list->flags&LINK_LIST_SEMAPHORE) {
131: while(sem_destroy(&list->sem)==-1 && errno==EBUSY)
132: SLEEP(1);
133: list->sem=NULL;
134: }
135: #endif
136:
137: if(list->flags&LINK_LIST_MALLOC)
138: free(list);
139:
140: return(TRUE);
141: }
142:
143: long DLLCALL listAttach(link_list_t* list)
144: {
145: if(list==NULL)
146: return(-1);
147:
148: MUTEX_LOCK(list);
149: list->refs++;
150: MUTEX_UNLOCK(list);
151:
152: return(list->refs);
153: }
154:
155: long DLLCALL listDettach(link_list_t* list)
156: {
157: int refs;
158:
159: if(list==NULL || list->refs<1)
160: return(-1);
161:
162: MUTEX_LOCK(list);
163: if((refs=--list->refs)==0)
164: listFree(list);
165: else
166: MUTEX_UNLOCK(list);
167:
168: return(refs);
169: }
170:
171: void* DLLCALL listSetPrivateData(link_list_t* list, void* p)
172: {
173: void* old;
174:
175: if(list==NULL)
176: return(NULL);
177:
178: old=list->private_data;
179: list->private_data=p;
180: return(old);
181: }
182:
183: void* DLLCALL listGetPrivateData(link_list_t* list)
184: {
185: if(list==NULL)
186: return(NULL);
187: return(list->private_data);
188: }
189:
190: #if defined(LINK_LIST_THREADSAFE)
191:
192: BOOL DLLCALL listSemPost(link_list_t* list)
193: {
194: if(list==NULL || !(list->flags&LINK_LIST_SEMAPHORE))
195: return(FALSE);
196:
197: return(sem_post(&list->sem)==0);
198: }
199:
200: BOOL DLLCALL listSemWait(link_list_t* list)
201: {
202: if(list==NULL || !(list->flags&LINK_LIST_SEMAPHORE))
203: return(FALSE);
204:
205: return(sem_wait(&list->sem)==0);
206: }
207:
208: BOOL DLLCALL listSemTryWait(link_list_t* list)
209: {
210: if(list==NULL || !(list->flags&LINK_LIST_SEMAPHORE))
211: return(FALSE);
212:
213: return(sem_trywait(&list->sem)==0);
214: }
215:
216: BOOL DLLCALL listSemTryWaitBlock(link_list_t* list, unsigned long timeout)
217: {
218: if(list==NULL || !(list->flags&LINK_LIST_SEMAPHORE))
219: return(FALSE);
220:
221: return(sem_trywait_block(&list->sem,timeout)==0);
222: }
223:
224: #endif
225:
226: #if defined(__BORLANDC__)
227: #pragma argsused
228: #endif
229: void DLLCALL listLock(const link_list_t* list)
230: {
231: MUTEX_LOCK(list);
232: }
233:
234: #if defined(__BORLANDC__)
235: #pragma argsused
236: #endif
237: void DLLCALL listUnlock(const link_list_t* list)
238: {
239: MUTEX_UNLOCK(list);
240: }
241:
242: long DLLCALL listCountNodes(const link_list_t* list)
243: {
244: long count=0;
245: list_node_t* node;
246:
247: if(list==NULL)
248: return(-1);
249:
250: if(list->count)
251: return(list->count);
252:
253: MUTEX_LOCK(list);
254:
255: for(node=list->first; node!=NULL; node=node->next)
256: count++;
257:
258: MUTEX_UNLOCK(list);
259:
260: return(count);
261: }
262:
263: list_node_t* DLLCALL listFindNode(const link_list_t* list, const void* data, size_t length)
264: {
265: list_node_t* node;
266:
267: if(list==NULL)
268: return(NULL);
269:
270: MUTEX_LOCK(list);
271:
272: for(node=list->first; node!=NULL; node=node->next) {
273: if(length==0) {
274: if(node->data==data)
275: break;
276: } else if(node->data!=NULL && memcmp(node->data,data,length)==0)
277: break;
278: }
279:
280: MUTEX_UNLOCK(list);
281:
282: return(node);
283: }
284:
285: str_list_t DLLCALL listStringList(const link_list_t* list)
286: {
287: list_node_t* node;
288: str_list_t str_list;
289: size_t count=0;
290:
291: if(list==NULL)
292: return(NULL);
293:
294: if((str_list=strListInit())==NULL)
295: return(NULL);
296:
297: MUTEX_LOCK(list);
298:
299: for(node=list->first; node!=NULL; node=node->next) {
300: if(node->data!=NULL)
301: strListAppend(&str_list, (char*)node->data, count++);
302: }
303:
304: MUTEX_UNLOCK(list);
305:
306: return(str_list);
307: }
308:
309: str_list_t DLLCALL listSubStringList(const list_node_t* node, long max)
310: {
311: long count;
312: str_list_t str_list;
313:
314: if(node==NULL)
315: return(NULL);
316:
317: if((str_list=strListInit())==NULL)
318: return(NULL);
319:
320: MUTEX_LOCK(node->list);
321:
322: for(count=0; count<max && node!=NULL; node=node->next) {
323: if(node->data!=NULL)
324: strListAppend(&str_list, (char*)node->data, count++);
325: }
326:
327: MUTEX_UNLOCK(node->list);
328:
329: return(str_list);
330: }
331:
332: void* DLLCALL listFreeStringList(str_list_t list)
333: {
334: strListFree(&list);
335: return(list);
336: }
337:
338: list_node_t* DLLCALL listFirstNode(const link_list_t* list)
339: {
340: if(list==NULL)
341: return(NULL);
342:
343: return(list->first);
344: }
345:
346: list_node_t* DLLCALL listLastNode(const link_list_t* list)
347: {
348: list_node_t* node;
349: list_node_t* last=NULL;
350:
351: if(list==NULL)
352: return(NULL);
353:
354: if(list->last!=NULL)
355: return(list->last);
356:
357: MUTEX_LOCK(list);
358:
359: for(node=list->first; node!=NULL; node=node->next)
360: last=node;
361:
362: MUTEX_UNLOCK(list);
363:
364: return(last);
365: }
366:
367: long DLLCALL listNodeIndex(const link_list_t* list, list_node_t* find_node)
368: {
369: long i=0;
370: list_node_t* node;
371:
372: if(list==NULL)
373: return(-1);
374:
375: MUTEX_LOCK(list);
376:
377: for(node=list->first; node!=NULL; node=node->next)
378: if(node==find_node)
379: break;
380:
381: MUTEX_UNLOCK(list);
382:
383: if(node==NULL)
384: return(-1);
385:
386: return(i);
387: }
388:
389: list_node_t* DLLCALL listNodeAt(const link_list_t* list, long index)
390: {
391: long i=0;
392: list_node_t* node;
393:
394: if(list==NULL || index<0)
395: return(NULL);
396:
397: MUTEX_LOCK(list);
398:
399: for(node=list->first; node!=NULL && i<index; node=node->next)
400: i++;
401:
402: MUTEX_UNLOCK(list);
403:
404: return(node);
405: }
406:
407: list_node_t* DLLCALL listNextNode(const list_node_t* node)
408: {
409: if(node==NULL)
410: return(NULL);
411:
412: return(node->next);
413: }
414:
415: list_node_t* DLLCALL listPrevNode(const list_node_t* node)
416: {
417: if(node==NULL)
418: return(NULL);
419:
420: return(node->prev);
421: }
422:
423: void* DLLCALL listNodeData(const list_node_t* node)
424: {
425: if(node==NULL)
426: return(NULL);
427:
428: return(node->data);
429: }
430:
431: BOOL DLLCALL listNodeIsLocked(const list_node_t* node)
432: {
433: return(node!=NULL && node->flags&LINK_LIST_NODE_LOCKED);
434: }
435:
436: BOOL DLLCALL listLockNode(list_node_t* node)
437: {
438: if(node==NULL || node->flags&LINK_LIST_NODE_LOCKED)
439: return(FALSE);
440:
441: node->flags|=LINK_LIST_NODE_LOCKED;
442:
443: return(TRUE);
444: }
445:
446: BOOL DLLCALL listUnlockNode(list_node_t* node)
447: {
448: if(!listNodeIsLocked(node))
449: return(FALSE);
450:
451: node->flags&=~LINK_LIST_NODE_LOCKED;
452:
453: return(TRUE);
454: }
455:
456: static list_node_t* DLLCALL list_add_node(link_list_t* list, list_node_t* node, list_node_t* after)
457: {
458: if(list==NULL)
459: return(NULL);
460:
461: MUTEX_LOCK(list);
462:
463: node->list = list;
464: if(after==LAST_NODE) /* e.g. listPushNode() */
465: after=list->last;
466: node->prev = after;
467:
468: if(after==list->last) /* append to list */
469: list->last = node;
470: if(after==FIRST_NODE) { /* insert at beginning of list */
471: node->next = list->first;
472: if(node->next!=NULL)
473: node->next->prev = node;
474: list->first = node;
475: } else {
476: if(after->next!=NULL) {
477: after->next->prev = node;
478: node->next = after->next;
479: }
480: after->next = node;
481: }
482:
483: list->count++;
484:
485: MUTEX_UNLOCK(list);
486:
487: #if defined(LINK_LIST_THREADSAFE)
488: if(list->flags&LINK_LIST_SEMAPHORE)
489: listSemPost(list);
490: #endif
491:
492: return(node);
493: }
494:
495: list_node_t* DLLCALL listAddNode(link_list_t* list, void* data, list_node_t* after)
496: {
497: list_node_t* node;
498:
499: if(list==NULL || data==NULL)
500: return(NULL);
501:
502: if((node=(list_node_t*)malloc(sizeof(list_node_t)))==NULL)
503: return(NULL);
504:
505: memset(node,0,sizeof(list_node_t));
506: node->data = data;
507:
508: return(list_add_node(list,node,after));
509: }
510:
511: long DLLCALL listAddNodes(link_list_t* list, void** data, list_node_t* after)
512: {
513: long i;
514: list_node_t* node=NULL;
515:
516: if(data==NULL)
517: return(-1);
518:
519: for(i=0; data[i]!=NULL ;i++)
520: if((node=listAddNode(list,data[i],node==NULL ? after:node))==NULL)
521: return(i);
522:
523: return(i);
524: }
525:
526: list_node_t* DLLCALL listAddNodeData(link_list_t* list, const void* data, size_t length, list_node_t* after)
527: {
528: list_node_t* node;
529: void* buf;
530:
531: if((buf=malloc(length))==NULL)
532: return(NULL);
533: memcpy(buf,data,length);
534:
535: if((node=listAddNode(list,buf,after))==NULL) {
536: free(buf);
537: return(NULL);
538: }
539: node->flags |= LINK_LIST_MALLOC;
540:
541: return(node);
542: }
543:
544: list_node_t* DLLCALL listAddNodeString(link_list_t* list, const char* str, list_node_t* after)
545: {
546: list_node_t* node;
547: char* buf;
548:
549: if(str==NULL)
550: return(NULL);
551:
552: if((buf=strdup(str))==NULL)
553: return(NULL);
554:
555: if((node=listAddNode(list,buf,after))==NULL) {
556: free(buf);
557: return(NULL);
558: }
559: node->flags |= LINK_LIST_MALLOC;
560:
561: return(node);
562: }
563:
564: long DLLCALL listAddStringList(link_list_t* list, str_list_t str_list, list_node_t* after)
565: {
566: long i;
567: list_node_t* node=NULL;
568:
569: if(str_list==NULL)
570: return(-1);
571:
572: for(i=0; str_list[i]!=NULL ;i++)
573: if((node=listAddNodeString(list,str_list[i],node==NULL ? after:node))==NULL)
574: return(i);
575:
576: return(i);
577: }
578:
579: long DLLCALL listAddNodeList(link_list_t* list, const link_list_t* src, list_node_t* after)
580: {
581: long count=0;
582: list_node_t* node=NULL;
583: list_node_t* src_node;
584:
585: if(src==NULL)
586: return(-1);
587:
588: for(src_node=src->first; src_node!=NULL; src_node=src_node->next, count++) {
589: if((node=listAddNode(list, src_node->data, node==NULL ? after:node))==NULL)
590: return(count);
591: node->flags = src_node->flags;
592: }
593:
594: return(count);
595: }
596:
597: long DLLCALL listMerge(link_list_t* list, const link_list_t* src, list_node_t* after)
598: {
599: long count=0;
600: list_node_t* node=NULL;
601: list_node_t* src_node;
602:
603: if(src==NULL)
604: return(-1);
605:
606: for(src_node=src->first; src_node!=NULL; src_node=src_node->next, count++)
607: if((node=list_add_node(list, src_node, node==NULL ? after:node))==NULL)
608: return(count);
609:
610: return(count);
611: }
612:
613: link_list_t* DLLCALL listExtract(link_list_t* dest_list, const list_node_t* node, long max)
614: {
615: long count;
616: link_list_t* list;
617:
618: if(node==NULL || node->list==NULL)
619: return(NULL);
620:
621: if((list=listInit(dest_list, node->list->flags))==NULL)
622: return(NULL);
623:
624: for(count=0; count<max && node!=NULL; node=node->next) {
625: listAddNode(list, node->data, list->last);
626: count++;
627: }
628:
629: return(list);
630: }
631:
632: static void* list_remove_node(link_list_t* list, list_node_t* node, BOOL free_data)
633: {
634: void* data;
635:
636: if(node==FIRST_NODE)
637: node=list->first;
638: else if(node==LAST_NODE)
639: node=list->last;
640: if(node==NULL)
641: return(NULL);
642:
643: if(node->flags&LINK_LIST_NODE_LOCKED)
644: return(NULL);
645:
646: if(node->prev!=NULL)
647: node->prev->next = node->next;
648: if(node->next!=NULL)
649: node->next->prev = node->prev;
650: if(list->first==node)
651: list->first = node->next;
652: if(list->last==node)
653: list->last = node->prev;
654:
655: if(free_data)
656: listFreeNodeData(node);
657:
658: data = node->data;
659:
660: free(node);
661:
662: if(list->count)
663: list->count--;
664:
665: return(data);
666: }
667:
668: void* DLLCALL listRemoveNode(link_list_t* list, list_node_t* node, BOOL free_data)
669: {
670: void* data;
671:
672: if(list==NULL)
673: return(NULL);
674:
675: MUTEX_LOCK(list);
676:
677: data = list_remove_node(list, node, free_data);
678:
679: MUTEX_UNLOCK(list);
680:
681: return(data);
682: }
683:
684: long DLLCALL listRemoveNodes(link_list_t* list, list_node_t* node, long max, BOOL free_data)
685: {
686: long count;
687:
688: if(list==NULL)
689: return(-1);
690:
691: MUTEX_LOCK(list);
692:
693: if(node==FIRST_NODE)
694: node=list->first;
695:
696: for(count=0; node!=NULL && count<max; node=node->next, count++)
697: if(listRemoveNode(list, node, free_data)==NULL)
698: break;
699:
700: MUTEX_UNLOCK(list);
701:
702: return(count);
703: }
704:
705: BOOL DLLCALL listSwapNodes(list_node_t* node1, list_node_t* node2)
706: {
707: list_node_t tmp;
708:
709: if(node1==NULL || node2==NULL || node1==node2)
710: return(FALSE);
711:
712: if(listNodeIsLocked(node1) || listNodeIsLocked(node2))
713: return(FALSE);
714:
715: if(node1->list==NULL || node2->list==NULL)
716: return(FALSE);
717:
718: #if defined(LINK_LIST_THREADSAFE)
719: MUTEX_LOCK(node1->list);
720: if(node1->list != node2->list)
721: MUTEX_LOCK(node2->list);
722: #endif
723:
724: tmp=*node1;
725: node1->data=node2->data;
726: node1->flags=node2->flags;
727: node2->data=tmp.data;
728: node2->flags=tmp.flags;
729:
730: #if defined(LINK_LIST_THREADSAFE)
731: MUTEX_UNLOCK(node1->list);
732: if(node1->list != node2->list)
733: MUTEX_UNLOCK(node2->list);
734: #endif
735:
736: return(TRUE);
737: }
738:
739: #if 0
740:
741: #include <stdio.h> /* printf, sprintf */
742:
743: int main(int arg, char** argv)
744: {
745: int i;
746: char* p;
747: char str[32];
748: link_list_t list;
749:
750: listInit(&list,0);
751: for(i=0; i<100; i++) {
752: sprintf(str,"%u",i);
753: listPushNodeString(&list,str);
754: }
755:
756: while((p=listShiftNode(&list))!=NULL)
757: printf("%d %s\n",listCountNodes(&list),p), free(p);
758:
759: /* Yes, this test code leaks heap memory. :-) */
760: gets(str);
761: return 0;
762: }
763:
764: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.