/*************************************************************************** begin : Sat Nov 15 2003 copyright : (C) 2003 by Martin Preuss email : martin@libchipcard.de *************************************************************************** * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2.1 of the License, or (at your option) any later version. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * * MA 02111-1307 USA * * * ***************************************************************************/ #ifdef HAVE_CONFIG_H # include #endif #include "list1_p.h" #include #include static GWENHYWFAR_CB int GWEN_List1__defaultSortFn(GWEN_UNUSED const void *a, GWEN_UNUSED const void *b, GWEN_UNUSED int ascending) { return 0; } GWEN_LIST1 *GWEN_List1_new(void) { GWEN_LIST1 *l; GWEN_NEW_OBJECT(GWEN_LIST1, l); l->sortFunction=GWEN_List1__defaultSortFn; return l; } void GWEN_List1_free(GWEN_LIST1 *l) { if (l) { GWEN_FREE_OBJECT(l); } } int GWEN_List1_GetCount(const GWEN_LIST1 *l) { assert(l); return l->count; } int GWEN_List1_Add(GWEN_LIST1 *l, GWEN_LIST1_ELEMENT *el) { assert(l); assert(el); if (el->listPtr) { /* element is already part of another list */ DBG_ERROR(GWEN_LOGDOMAIN, "Element is already part of a list"); assert(0); return -1; } if (l->firstElement==0) l->firstElement=el; el->prevElement=l->lastElement; if (l->lastElement) l->lastElement->nextElement=el; l->lastElement=el; el->listPtr=l; l->count++; return 0; } int GWEN_List1_AddList(GWEN_LIST1 *dest, GWEN_LIST1 *l) { GWEN_LIST1_ELEMENT *el; assert(dest); assert(l); while ((el=l->firstElement)) { GWEN_List1_Del(el); GWEN_List1_Add(dest, el); } return 0; } int GWEN_List1_Insert(GWEN_LIST1 *l, GWEN_LIST1_ELEMENT *el) { assert(l); assert(el); if (el->listPtr) { /* element is already part of another list */ DBG_ERROR(GWEN_LOGDOMAIN, "Element is already part of a list"); return -1; } el->nextElement=l->firstElement; l->firstElement=el; if (l->lastElement==0) l->lastElement=el; if (el->nextElement) el->nextElement->prevElement=el; el->listPtr=l; l->count++; return 0; } int GWEN_List1_Del(GWEN_LIST1_ELEMENT *el) { GWEN_LIST1 *l; assert(el); l=el->listPtr; if (l==0) { /* not part of any list */ DBG_ERROR(GWEN_LOGDOMAIN, "Element is not part of any list"); return -1; } /* unlink from previous */ if (el->prevElement) el->prevElement->nextElement=el->nextElement; /* unlink from next */ if (el->nextElement) el->nextElement->prevElement=el->prevElement; /* unlink from list */ if (l->firstElement==el) l->firstElement=el->nextElement; if (l->lastElement==el) l->lastElement=el->prevElement; l->count--; el->nextElement=0; el->prevElement=0; el->listPtr=0; return 0; } void *GWEN_List1_GetFirst(const GWEN_LIST1 *l) { if (l->firstElement) return l->firstElement->data; return 0; } void *GWEN_List1_GetLast(const GWEN_LIST1 *l) { if (l->lastElement) return l->lastElement->data; return 0; } GWEN_LIST1_ELEMENT *GWEN_List1Element_new(void *d) { GWEN_LIST1_ELEMENT *el; GWEN_NEW_OBJECT(GWEN_LIST1_ELEMENT, el); el->data=d; return el; } void GWEN_List1Element_free(GWEN_LIST1_ELEMENT *el) { if (el) { if (el->listPtr) GWEN_List1_Del(el); GWEN_FREE_OBJECT(el); } } void *GWEN_List1Element_GetData(const GWEN_LIST1_ELEMENT *el) { return el->data; } void *GWEN_List1Element_GetPrevious(const GWEN_LIST1_ELEMENT *el) { if (el->prevElement) return el->prevElement->data; return 0; } void *GWEN_List1Element_GetNext(const GWEN_LIST1_ELEMENT *el) { if (el->nextElement) return el->nextElement->data; return 0; } #if 0 static int GWEN_List1__compar_asc(const void *a, const void *b) { const GWEN_LIST1_ELEMENT *const *pse1 = a, * const * pse2 = b; const GWEN_LIST1_ELEMENT *se1 = *pse1, *se2 = *pse2; return (se1->listPtr->sortFunction)(se1->data, se2->data, 1); } static int GWEN_List1__compar_desc(const void *a, const void *b) { const GWEN_LIST1_ELEMENT *const *pse1 = a, * const * pse2 = b; const GWEN_LIST1_ELEMENT *se1 = *pse1, *se2 = *pse2; return (se1->listPtr->sortFunction)(se1->data, se2->data, 0); } GWEN_LIST1_SORT_FN GWEN_List1_SetSortFn(GWEN_LIST1 *l, GWEN_LIST1_SORT_FN fn) { GWEN_LIST1_SORT_FN oldFn; assert(l); oldFn=l->sortFunction; l->sortFunction=fn; return oldFn; } void GWEN_List1_Sort(GWEN_LIST1 *l, int ascending) { GWEN_LIST1_ELEMENT **tmpEntries; GWEN_LIST1_ELEMENT *sentry; GWEN_LIST1_ELEMENT **psentry; uint32_t count; uint32_t i; if (l->count<1) return; count=l->count; /* sort entries into a linear pointer list */ tmpEntries=(GWEN_LIST1_ELEMENT **)malloc((count+1)* sizeof(GWEN_LIST1_ELEMENT *)); assert(tmpEntries); psentry=tmpEntries; sentry=l->firstElement; while (sentry) { GWEN_LIST1_ELEMENT *next; *(psentry++)=sentry; next=sentry->nextElement; sentry->prevElement=NULL; sentry->nextElement=NULL; sentry->listPtr=l; sentry=next; } /* while */ *psentry=NULL; /* clear list */ l->count=0; l->firstElement=NULL; l->lastElement=NULL; /* sort */ if (ascending) qsort(tmpEntries, count, sizeof(GWEN_LIST1_ELEMENT *), GWEN_List1__compar_asc); else qsort(tmpEntries, count, sizeof(GWEN_LIST1_ELEMENT *), GWEN_List1__compar_desc); /* sort entries back into GWEN_LIST1 according to temporary list */ psentry=tmpEntries; /* we use "<=count" because the list contains count+1 elements */ for (i=0; i<=count; i++) { if (*psentry) { (*psentry)->listPtr=NULL; GWEN_List1_Add(l, *psentry); } psentry++; } /* for */ free(tmpEntries); } #endif /* ------------------------------------------------------------------------------------------------- * Sort * ------------------------------------------------------------------------------------------------- */ static int GWEN_List1__compar(const void *a, const void *b) { const GWEN_LIST1_SORT_ELEM *const *pse1 = a, * const * pse2 = b; const GWEN_LIST1_SORT_ELEM *se1 = *pse1, *se2 = *pse2; const GWEN_LIST1_SORT_CTX *ctx=se1->context; const GWEN_LIST1_ELEMENT *e1=se1->element; const GWEN_LIST1_ELEMENT *e2=se2->element; return (ctx->list->sortFunction)(e1->data, e2->data, ctx->param); } GWEN_LIST1_SORT_FN GWEN_List1_SetSortFn(GWEN_LIST1 *l, GWEN_LIST1_SORT_FN fn) { GWEN_LIST1_SORT_FN oldFn; assert(l); oldFn=l->sortFunction; l->sortFunction=fn; return oldFn; } GWEN_LIST1_SORT_CTX *GWEN_List1_SortCtx_new(GWEN_LIST1 *list, int param) { GWEN_LIST1_SORT_CTX *ctx; GWEN_NEW_OBJECT(GWEN_LIST1_SORT_CTX, ctx); ctx->list=list; ctx->param=param; return ctx; } void GWEN_List1_SortCtx_free(GWEN_LIST1_SORT_CTX *ctx) { if (ctx) { GWEN_FREE_OBJECT(ctx); } } GWEN_LIST1_SORT_ELEM *GWEN_List1_SortElem_new(GWEN_LIST1_SORT_CTX *ctx, GWEN_LIST1_ELEMENT *elem) { GWEN_LIST1_SORT_ELEM *e; GWEN_NEW_OBJECT(GWEN_LIST1_SORT_ELEM, e); e->context=ctx; e->element=elem; return e; } void GWEN_List1_SortElem_free(GWEN_LIST1_SORT_ELEM *e) { if (e) { GWEN_FREE_OBJECT(e); } } void GWEN_List1_Sort(GWEN_LIST1 *l, int ascending) { GWEN_LIST1_SORT_ELEM **tmpEntries; GWEN_LIST1_SORT_ELEM **psentry; GWEN_LIST1_ELEMENT *sentry; uint32_t count; uint32_t i; GWEN_LIST1_SORT_CTX *sortContext; if (l->count<1) return; count=l->count; sortContext=GWEN_List1_SortCtx_new(l, ascending); /* sort entries into a linear pointer list */ tmpEntries=(GWEN_LIST1_SORT_ELEM **)malloc((count+1)* sizeof(GWEN_LIST1_SORT_ELEM *)); assert(tmpEntries); psentry=tmpEntries; sentry=l->firstElement; while (sentry) { GWEN_LIST1_ELEMENT *next; GWEN_LIST1_SORT_ELEM *se; se=GWEN_List1_SortElem_new(sortContext, sentry); *(psentry++)=se; next=sentry->nextElement; sentry->prevElement=NULL; sentry->nextElement=NULL; sentry->listPtr=l; sentry=next; } /* while */ *psentry=NULL; /* clear list */ l->count=0; l->firstElement=NULL; l->lastElement=NULL; /* sort */ qsort(tmpEntries, count, sizeof(GWEN_LIST1_SORT_ELEM *), GWEN_List1__compar); /* sort entries back into GWEN_LIST1 according to temporary list */ psentry=tmpEntries; /* we use "<=count" because the list contains count+1 elements */ for (i=0; i<=count; i++) { GWEN_LIST1_SORT_ELEM *se; se=*psentry; if (se) { sentry=se->element; sentry->listPtr=NULL; GWEN_List1_Add(l, sentry); GWEN_List1_SortElem_free(se); *psentry=NULL; } psentry++; } /* for */ free(tmpEntries); GWEN_List1_SortCtx_free(sortContext); }