/*************************************************************************** begin : Thu Apr 03 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 #define DISABLE_DEBUGLOG #include #include #include "stringlist_p.h" #include "debug.h" #include #include #include #ifdef HAVE_STRINGS_H # include #endif GWEN_STRINGLIST *GWEN_StringList_new(void) { GWEN_STRINGLIST *sl; GWEN_NEW_OBJECT(GWEN_STRINGLIST, sl); assert(sl); sl->ignoreRefCount=1; return sl; } void GWEN_StringList_free(GWEN_STRINGLIST *sl) { GWEN_STRINGLISTENTRY *curr, *next; if (sl) { curr=sl->first; while (curr) { next=curr->next; GWEN_StringListEntry_free(curr); curr=next; } /* while */ GWEN_FREE_OBJECT(sl); } } void GWEN_StringList_SetSenseCase(GWEN_STRINGLIST *sl, int i) { assert(sl); sl->senseCase=i; } void GWEN_StringList_SetIgnoreRefCount(GWEN_STRINGLIST *sl, int i) { assert(sl); sl->ignoreRefCount=i; } GWEN_STRINGLISTENTRY *GWEN_StringListEntry_new(const char *s, int take) { GWEN_STRINGLISTENTRY *sl; GWEN_NEW_OBJECT(GWEN_STRINGLISTENTRY, sl); assert(sl); sl->refCount=1; if (s) { if (take) sl->data=s; else sl->data=strdup(s); } return sl; } void GWEN_StringListEntry_ReplaceString(GWEN_STRINGLISTENTRY *e, const char *s, int take) { assert(e); if (e->data) free((void *)(e->data)); if (take) e->data=s; else e->data=strdup(s); } void GWEN_StringListEntry_free(GWEN_STRINGLISTENTRY *sl) { if (sl) { if (sl->data) free((void *)(sl->data)); GWEN_FREE_OBJECT(sl); } } void GWEN_StringList_AppendEntry(GWEN_STRINGLIST *sl, GWEN_STRINGLISTENTRY *se) { GWEN_STRINGLISTENTRY *curr; assert(sl); assert(se); curr=sl->first; if (!curr) { sl->first=se; } else { while (curr->next) { curr=curr->next; } curr->next=se; } sl->count++; } GWEN_STRINGLIST *GWEN_StringList_fromTabString(const char *s, int checkDup) { GWEN_STRINGLIST *sl; sl=GWEN_StringList_new(); if (s && *s) { while (*s) { const char *t; char *tmpStr; t=strchr(s, '\t'); if (t) { int len; len=(t-s); tmpStr=(char *) malloc(len+1); assert(tmpStr); memmove(tmpStr, s, len); tmpStr[len]=0; /* add partial string, take it over */ GWEN_StringList_AppendString(sl, tmpStr, 1, checkDup); s=t+1; } else { /* just add the remaining string (don't take over, copy!) */ GWEN_StringList_AppendString(sl, s, 0, checkDup); break; } } } return sl; } void GWEN_StringList_RemoveEntry(GWEN_STRINGLIST *sl, GWEN_STRINGLISTENTRY *se) { GWEN_STRINGLISTENTRY *curr; assert(sl); assert(se); curr=sl->first; if (curr) { if (curr==se) { sl->first=curr->next; if (sl->count) sl->count--; } else { while (curr->next!=se) { curr=curr->next; } if (curr) { curr->next=se->next; if (sl->count) sl->count--; } } } } void GWEN_StringList_Clear(GWEN_STRINGLIST *sl) { GWEN_STRINGLISTENTRY *se, *next; assert(sl); se=sl->first; sl->first=0; sl->count=0; while (se) { next=se->next; GWEN_StringListEntry_free(se); se=next; } /* while */ } int GWEN_StringList_AppendString(GWEN_STRINGLIST *sl, const char *s, int take, int checkDouble) { GWEN_STRINGLISTENTRY *se; if (checkDouble) { se=sl->first; if (sl->senseCase) { while (se) { if (strcmp(se->data, s)==0) { if (take) free((char *)s); se->refCount++; return 0; } se=se->next; } /* while */ } else { while (se) { if (strcasecmp(se->data, s)==0) { if (take) free((char *)s); se->refCount++; return 0; } se=se->next; } /* while */ } } /* if checkdouble */ se=GWEN_StringListEntry_new(s, take); GWEN_StringList_AppendEntry(sl, se); return 1; } int GWEN_StringList_InsertString(GWEN_STRINGLIST *sl, const char *s, int take, int checkDouble) { GWEN_STRINGLISTENTRY *se; if (checkDouble) { se=sl->first; if (sl->senseCase) { while (se) { if (strcmp(se->data, s)==0) { if (take) free((char *)s); se->refCount++; return 0; } se=se->next; } /* while */ } else { while (se) { if (strcasecmp(se->data, s)==0) { if (take) free((char *)s); se->refCount++; return 0; } se=se->next; } /* while */ } } /* if checkdouble */ se=GWEN_StringListEntry_new(s, take); se->next=sl->first; sl->first=se; sl->count++; return 1; } int GWEN_StringList_RemoveString(GWEN_STRINGLIST *sl, const char *s) { GWEN_STRINGLISTENTRY *se; se=sl->first; if (sl->senseCase) { while (se) { if (strcmp(se->data, s)==0) { assert(se->refCount); se->refCount--; if (sl->ignoreRefCount) GWEN_StringList_RemoveEntry(sl, se); else { if (se->refCount==0) GWEN_StringList_RemoveEntry(sl, se); } return 1; } se=se->next; } /* while */ return 0; } else { while (se) { if (strcasecmp(se->data, s)==0) { assert(se->refCount); se->refCount--; if (sl->ignoreRefCount) GWEN_StringList_RemoveEntry(sl, se); else { if (se->refCount==0) GWEN_StringList_RemoveEntry(sl, se); } return 1; } se=se->next; } /* while */ return 0; } } void GWEN_StringList_RemoveFirstString(GWEN_STRINGLIST *sl) { GWEN_STRINGLISTENTRY *se; assert(sl); se=sl->first; if (se) { assert(se->refCount); se->refCount--; if (sl->ignoreRefCount) GWEN_StringList_RemoveEntry(sl, se); else { if (se->refCount==0) GWEN_StringList_RemoveEntry(sl, se); } } } GWEN_STRINGLISTENTRY *GWEN_StringList_FirstEntry(const GWEN_STRINGLIST *sl) { assert(sl); return sl->first; } GWEN_STRINGLISTENTRY *GWEN_StringListEntry_Next(const GWEN_STRINGLISTENTRY *se) { assert(se); return se->next; } const char *GWEN_StringListEntry_Data(const GWEN_STRINGLISTENTRY *se) { assert(se); return se->data; } void GWEN_StringListEntry_SetData(GWEN_STRINGLISTENTRY *se, const char *s) { assert(se); if (se->data) free((void *)(se->data)); if (s) se->data=strdup(s); else se->data=NULL; } unsigned int GWEN_StringList_Count(const GWEN_STRINGLIST *sl) { assert(sl); return sl->count; } int GWEN_StringList_HasString(const GWEN_STRINGLIST *sl, const char *s) { GWEN_STRINGLISTENTRY *se; assert(sl); se=sl->first; if (sl->senseCase) { while (se) { if (strcmp(se->data, s)==0) { return 1; } se=se->next; } /* while */ return 0; } else { while (se) { if (strcasecmp(se->data, s)==0) { return 1; } se=se->next; } /* while */ return 0; } } int GWEN_StringList_GetStringPos(const GWEN_STRINGLIST *sl, const char *s) { GWEN_STRINGLISTENTRY *se; int i; assert(sl); se=sl->first; if (sl->senseCase) { i=0; while (se) { if (strcmp(se->data, s)==0) { return i; } i++; se=se->next; } /* while */ return -1; } else { i=0; while (se) { if (strcasecmp(se->data, s)==0) { return i; } i++; se=se->next; } /* while */ return -1; } } GWEN_STRINGLISTENTRY *GWEN_StringList_FindStringEntry(const GWEN_STRINGLIST *sl, const char *s) { GWEN_STRINGLISTENTRY *se; int i; assert(sl); se=sl->first; if (sl->senseCase) { i=0; while (se) { if (strcmp(se->data, s)==0) { return se; } i++; se=se->next; } /* while */ return NULL; } else { i=0; while (se) { if (strcasecmp(se->data, s)==0) { return se; } i++; se=se->next; } /* while */ return NULL; } } GWEN_STRINGLIST *GWEN_StringList_dup(const GWEN_STRINGLIST *sl) { GWEN_STRINGLISTENTRY *se; GWEN_STRINGLIST *newsl; assert(sl); newsl=GWEN_StringList_new(); se=sl->first; while (se) { GWEN_STRINGLISTENTRY *newse; newse=GWEN_StringListEntry_new(se->data, 0); GWEN_StringList_AppendEntry(newsl, newse); se=se->next; } /* while */ return newsl; } void *GWEN_StringList_ForEach(const GWEN_STRINGLIST *l, void *(*func)(const char *s, void *u), void *user_data) { GWEN_STRINGLISTENTRY *it; const char *el; void *result = 0; assert(l); it = GWEN_StringList_FirstEntry(l); if (!it) return 0; while (it) { el = GWEN_StringListEntry_Data(it); result = func(el, user_data); if (result) { return result; } it = GWEN_StringListEntry_Next(it); } return 0; } const char *GWEN_StringList_FirstString(const GWEN_STRINGLIST *l) { assert(l); if (l->first==0) return 0; return l->first->data; } static int GWEN_StringList__compar_asc_nocase(const void *a, const void *b) { const GWEN_STRINGLISTENTRY *const *pse1 = a, * const * pse2 = b; const GWEN_STRINGLISTENTRY *se1 = *pse1, *se2 = *pse2; if (se1 && se2 && se1->data && se2->data) return strcmp(se1->data, se2->data); else return 0; } static int GWEN_StringList__compar_desc_nocase(const void *a, const void *b) { const GWEN_STRINGLISTENTRY *const *pse1 = a, * const * pse2 = b; const GWEN_STRINGLISTENTRY *se1 = *pse1, *se2 = *pse2; if (se1 && se2 && se1->data && se2->data) return strcmp(se2->data, se1->data); else return 0; } static int GWEN_StringList__compar_asc_case(const void *a, const void *b) { const GWEN_STRINGLISTENTRY *const *pse1 = a, * const * pse2 = b; const GWEN_STRINGLISTENTRY *se1 = *pse1, *se2 = *pse2; if (se1 && se2 && se1->data && se2->data) return strcasecmp(se1->data, se2->data); else return 0; } static int GWEN_StringList__compar_desc_case(const void *a, const void *b) { const GWEN_STRINGLISTENTRY *const *pse1 = a, * const * pse2 = b; const GWEN_STRINGLISTENTRY *se1 = *pse1, *se2 = *pse2; if (se1 && se2 && se1->data && se2->data) return strcasecmp(se2->data, se1->data); else return 0; } static int GWEN_StringList__compar_asc_int(const void *a, const void *b) { const GWEN_STRINGLISTENTRY *const *pse1 = a, * const * pse2 = b; const GWEN_STRINGLISTENTRY *se1 = *pse1, *se2 = *pse2; if (se1 && se2 && se1->data && se2->data) { int i1, i2; i1=atoi(se1->data); i2=atoi(se2->data); return (i1>i2) - (i1data && se2->data) { int i1, i2; i1=atoi(se1->data); i2=atoi(se2->data); return (i2>i1) - (i2count<2) return; /* sort entries into a linear pointer list */ tmpEntries=(GWEN_STRINGLISTENTRY **)malloc((l->count+1)* sizeof(GWEN_STRINGLISTENTRY *)); assert(tmpEntries); sentry=l->first; psentry=tmpEntries; while (sentry) { *(psentry++)=sentry; sentry=sentry->next; } /* while */ *psentry=0; /* sort */ switch (sortMode) { case GWEN_StringList_SortModeNoCase: if (ascending) qsort(tmpEntries, l->count, sizeof(GWEN_STRINGLISTENTRY *), GWEN_StringList__compar_asc_nocase); else qsort(tmpEntries, l->count, sizeof(GWEN_STRINGLISTENTRY *), GWEN_StringList__compar_desc_nocase); break; case GWEN_StringList_SortModeCase: if (ascending) qsort(tmpEntries, l->count, sizeof(GWEN_STRINGLISTENTRY *), GWEN_StringList__compar_asc_case); else qsort(tmpEntries, l->count, sizeof(GWEN_STRINGLISTENTRY *), GWEN_StringList__compar_desc_case); break; case GWEN_StringList_SortModeInt: if (ascending) qsort(tmpEntries, l->count, sizeof(GWEN_STRINGLISTENTRY *), GWEN_StringList__compar_asc_int); else qsort(tmpEntries, l->count, sizeof(GWEN_STRINGLISTENTRY *), GWEN_StringList__compar_desc_int); break; default: DBG_ERROR(GWEN_LOGDOMAIN, "Unknown sortmode %d", sortMode); } /* sort entries back into GWEN_STRINGLIST */ psentry=tmpEntries; sentry=0; while (*psentry) { if (sentry) sentry->next=*psentry; else l->first=*psentry; sentry=*psentry; psentry++; } /* while */ sentry->next=NULL; free(tmpEntries); } const char *GWEN_StringList_StringAt(const GWEN_STRINGLIST *sl, int idx) { GWEN_STRINGLISTENTRY *se; assert(sl); se=sl->first; while (se) { if (idx--==0) return se->data; se=se->next; } /* while */ return 0; } GWEN_STRINGLIST *GWEN_StringList_fromString(const char *str, const char *delimiters, int checkDouble) { if (str && *str) { GWEN_STRINGLIST *sl; const unsigned char *s; sl=GWEN_StringList_new(); s=(const unsigned char *)str; while (*s) { /* skip blanks */ while (*s && *s<33) s++; if (*s) { const unsigned char *pStart; int len; /* read word */ pStart=s; //s++; while (*s && strchr(delimiters, *s)==NULL) s++; len=s-pStart; if (len) { char *toAdd; toAdd=(char *) malloc(len+1); assert(toAdd); memmove(toAdd, pStart, len); toAdd[len]=0; GWEN_StringList_AppendString(sl, toAdd, 1, checkDouble); } } if (*s==0) break; s++; } if (GWEN_StringList_Count(sl)==0) { GWEN_StringList_free(sl); return NULL; } return sl; } else return NULL; }