gwenhywfar  4.3.3
stringlist.c
Go to the documentation of this file.
00001 /***************************************************************************
00002  begin       : Thu Apr 03 2003
00003  copyright   : (C) 2003 by Martin Preuss
00004  email       : martin@libchipcard.de
00005 
00006  ***************************************************************************
00007  *                                                                         *
00008  *   This library is free software; you can redistribute it and/or         *
00009  *   modify it under the terms of the GNU Lesser General Public            *
00010  *   License as published by the Free Software Foundation; either          *
00011  *   version 2.1 of the License, or (at your option) any later version.    *
00012  *                                                                         *
00013  *   This library is distributed in the hope that it will be useful,       *
00014  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00015  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
00016  *   Lesser General Public License for more details.                       *
00017  *                                                                         *
00018  *   You should have received a copy of the GNU Lesser General Public      *
00019  *   License along with this library; if not, write to the Free Software   *
00020  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston,                 *
00021  *   MA  02111-1307  USA                                                   *
00022  *                                                                         *
00023  ***************************************************************************/
00024 
00025 
00026 #ifdef HAVE_CONFIG_H
00027 # include <config.h>
00028 #endif
00029 
00030 #define DISABLE_DEBUGLOG
00031 
00032 
00033 #include <gwenhywfar/gwenhywfarapi.h>
00034 #include <gwenhywfar/misc.h>
00035 #include "stringlist_p.h"
00036 #include "debug.h"
00037 #include <stdlib.h>
00038 #include <assert.h>
00039 #include <string.h>
00040 #ifdef HAVE_STRINGS_H
00041 # include <strings.h>
00042 #endif
00043 
00044 
00045 
00046 GWEN_STRINGLIST *GWEN_StringList_new(void){
00047   GWEN_STRINGLIST *sl;
00048 
00049   GWEN_NEW_OBJECT(GWEN_STRINGLIST, sl);
00050   assert(sl);
00051   sl->ignoreRefCount=1;
00052   return sl;
00053 }
00054 
00055 
00056 
00057 void GWEN_StringList_free(GWEN_STRINGLIST *sl){
00058   GWEN_STRINGLISTENTRY *curr, *next;
00059 
00060   if (sl) {
00061     curr=sl->first;
00062     while(curr) {
00063       next=curr->next;
00064       GWEN_StringListEntry_free(curr);
00065       curr=next;
00066     } /* while */
00067     GWEN_FREE_OBJECT(sl);
00068   }
00069 }
00070 
00071 
00072 
00073 void GWEN_StringList_SetSenseCase(GWEN_STRINGLIST *sl, int i) {
00074   assert(sl);
00075   sl->senseCase=i;
00076 }
00077 
00078 
00079 
00080 void GWEN_StringList_SetIgnoreRefCount(GWEN_STRINGLIST *sl, int i) {
00081   assert(sl);
00082   sl->ignoreRefCount=i;
00083 }
00084 
00085 
00086 
00087 GWEN_STRINGLISTENTRY *GWEN_StringListEntry_new(const char *s, int take){
00088   GWEN_STRINGLISTENTRY *sl;
00089 
00090   GWEN_NEW_OBJECT(GWEN_STRINGLISTENTRY, sl);
00091   assert(sl);
00092   sl->refCount=1;
00093   if (s) {
00094     if (take)
00095       sl->data=s;
00096     else
00097       sl->data=strdup(s);
00098   }
00099   return sl;
00100 }
00101 
00102 
00103 
00104 void GWEN_StringListEntry_ReplaceString(GWEN_STRINGLISTENTRY *e,
00105                                         const char *s,
00106                                         int take){
00107   assert(e);
00108   if (e->data)
00109     free((void*)(e->data));
00110   if (take)
00111     e->data=s;
00112   else
00113     e->data=strdup(s);
00114 }
00115 
00116 
00117 
00118 void GWEN_StringListEntry_free(GWEN_STRINGLISTENTRY *sl){
00119   if (sl) {
00120     if (sl->data)
00121       free((void*)(sl->data));
00122     GWEN_FREE_OBJECT(sl);
00123   }
00124 }
00125 
00126 
00127 
00128 void GWEN_StringList_AppendEntry(GWEN_STRINGLIST *sl,
00129                                  GWEN_STRINGLISTENTRY *se){
00130   GWEN_STRINGLISTENTRY *curr;
00131 
00132   assert(sl);
00133   assert(se);
00134 
00135   curr=sl->first;
00136   if (!curr) {
00137     sl->first=se;
00138   }
00139   else {
00140     while(curr->next) {
00141       curr=curr->next;
00142     }
00143     curr->next=se;
00144   }
00145   sl->count++;
00146 }
00147 
00148 
00149 
00150 GWEN_STRINGLIST *GWEN_StringList_fromTabString(const char *s, int checkDup) {
00151   GWEN_STRINGLIST *sl;
00152 
00153   sl=GWEN_StringList_new();
00154   if (s && *s) {
00155     while(*s) {
00156       const char *t;
00157       char *tmpStr;
00158   
00159       t=strchr(s, '\t');
00160       if (t) {
00161         int len;
00162   
00163         len=(t-s);
00164         tmpStr=(char*) malloc(len+1);
00165         assert(tmpStr);
00166         memmove(tmpStr, s, len);
00167         tmpStr[len]=0;
00168         /* add partial string, take it over */
00169         GWEN_StringList_AppendString(sl, tmpStr, 1, checkDup);
00170         s=t+1;
00171       }
00172       else {
00173         /* just add the remaining string (don't take over, copy!) */
00174         GWEN_StringList_AppendString(sl, s, 0, checkDup);
00175         break;
00176       }
00177     }
00178   }
00179 
00180   return sl;
00181 }
00182 
00183 
00184 
00185 void GWEN_StringList_RemoveEntry(GWEN_STRINGLIST *sl,
00186                                  GWEN_STRINGLISTENTRY *se){
00187   GWEN_STRINGLISTENTRY *curr;
00188 
00189   assert(sl);
00190   assert(se);
00191 
00192   curr=sl->first;
00193   if (curr) {
00194     if (curr==se) {
00195       sl->first=curr->next;
00196       if (sl->count)
00197         sl->count--;
00198     }
00199     else {
00200       while(curr->next!=se) {
00201         curr=curr->next;
00202       }
00203       if (curr) {
00204         curr->next=se->next;
00205         if (sl->count)
00206           sl->count--;
00207       }
00208     }
00209   }
00210 }
00211 
00212 
00213 
00214 void GWEN_StringList_Clear(GWEN_STRINGLIST *sl){
00215   GWEN_STRINGLISTENTRY *se, *next;
00216 
00217   assert(sl);
00218   se=sl->first;
00219   sl->first=0;
00220   while (se) {
00221     next=se->next;
00222     GWEN_StringListEntry_free(se);
00223     se=next;
00224   } /* while */
00225 }
00226 
00227 
00228 
00229 int GWEN_StringList_AppendString(GWEN_STRINGLIST *sl,
00230                                  const char *s,
00231                                  int take,
00232                                  int checkDouble){
00233   GWEN_STRINGLISTENTRY *se;
00234 
00235   if (checkDouble) {
00236     se=sl->first;
00237     if (sl->senseCase) {
00238       while(se) {
00239         if (strcmp(se->data, s)==0) {
00240           if (take)
00241             free((char*)s);
00242           se->refCount++;
00243           return 0;
00244         }
00245         se=se->next;
00246       } /* while */
00247     }
00248     else {
00249       while(se) {
00250         if (strcasecmp(se->data, s)==0) {
00251           if (take)
00252             free((char*)s);
00253           se->refCount++;
00254           return 0;
00255         }
00256         se=se->next;
00257       } /* while */
00258     }
00259   } /* if checkdouble */
00260 
00261   se=GWEN_StringListEntry_new(s, take);
00262   GWEN_StringList_AppendEntry(sl, se);
00263   return 1;
00264 }
00265 
00266 
00267 
00268 int GWEN_StringList_InsertString(GWEN_STRINGLIST *sl,
00269                                  const char *s,
00270                                  int take,
00271                                  int checkDouble){
00272   GWEN_STRINGLISTENTRY *se;
00273 
00274   if (checkDouble) {
00275     se=sl->first;
00276     if (sl->senseCase) {
00277       while(se) {
00278         if (strcmp(se->data, s)==0) {
00279           if (take)
00280             free((char*)s);
00281           se->refCount++;
00282           return 0;
00283         }
00284         se=se->next;
00285       } /* while */
00286     }
00287     else {
00288       while(se) {
00289         if (strcasecmp(se->data, s)==0) {
00290           if (take)
00291             free((char*)s);
00292           se->refCount++;
00293           return 0;
00294         }
00295         se=se->next;
00296       } /* while */
00297     }
00298   } /* if checkdouble */
00299   se=GWEN_StringListEntry_new(s, take);
00300   se->next=sl->first;
00301   sl->first=se;
00302   return 1;
00303 }
00304 
00305 
00306 
00307 GWENHYWFAR_API int GWEN_StringList_RemoveString(GWEN_STRINGLIST *sl,
00308                                                 const char *s){
00309   GWEN_STRINGLISTENTRY *se;
00310 
00311   se=sl->first;
00312   if (sl->senseCase) {
00313     while(se) {
00314       if (strcmp(se->data, s)==0) {
00315         assert(se->refCount);
00316         se->refCount--;
00317         if (sl->ignoreRefCount)
00318           GWEN_StringList_RemoveEntry(sl, se);
00319         else {
00320           if (se->refCount==0)
00321             GWEN_StringList_RemoveEntry(sl, se);
00322         }
00323         return 1;
00324       }
00325       se=se->next;
00326     } /* while */
00327     return 0;
00328   }
00329   else {
00330     while(se) {
00331       if (strcasecmp(se->data, s)==0) {
00332         assert(se->refCount);
00333         se->refCount--;
00334         if (sl->ignoreRefCount)
00335           GWEN_StringList_RemoveEntry(sl, se);
00336         else {
00337           assert(se->refCount);
00338           if (se->refCount==0)
00339             GWEN_StringList_RemoveEntry(sl, se);
00340         }
00341         return 1;
00342       }
00343       se=se->next;
00344     } /* while */
00345     return 0;
00346   }
00347 }
00348 
00349 
00350 
00351 GWEN_STRINGLISTENTRY *GWEN_StringList_FirstEntry(const GWEN_STRINGLIST *sl){
00352   assert(sl);
00353   return sl->first;
00354 }
00355 
00356 
00357 
00358 GWEN_STRINGLISTENTRY *GWEN_StringListEntry_Next(const GWEN_STRINGLISTENTRY *se){
00359   assert(se);
00360   return se->next;
00361 }
00362 
00363 
00364 
00365 const char *GWEN_StringListEntry_Data(const GWEN_STRINGLISTENTRY *se){
00366   assert(se);
00367   return se->data;
00368 }
00369 
00370 
00371 unsigned int GWEN_StringList_Count(const GWEN_STRINGLIST *sl){
00372   assert(sl);
00373   return sl->count;
00374 }
00375 
00376 
00377 
00378 int GWEN_StringList_HasString(const GWEN_STRINGLIST *sl,
00379                               const char *s){
00380   GWEN_STRINGLISTENTRY *se;
00381 
00382   assert(sl);
00383   se=sl->first;
00384   if (sl->senseCase) {
00385     while(se) {
00386       if (strcmp(se->data, s)==0) {
00387         return 1;
00388       }
00389       se=se->next;
00390     } /* while */
00391     return 0;
00392   }
00393   else {
00394     while(se) {
00395       if (strcasecmp(se->data, s)==0) {
00396         return 1;
00397       }
00398       se=se->next;
00399     } /* while */
00400     return 0;
00401   }
00402 }
00403 
00404 
00405 
00406 int GWEN_StringList_GetStringPos(const GWEN_STRINGLIST *sl, const char *s){
00407   GWEN_STRINGLISTENTRY *se;
00408   int i;
00409 
00410   assert(sl);
00411   se=sl->first;
00412   if (sl->senseCase) {
00413     i=0;
00414     while(se) {
00415       if (strcmp(se->data, s)==0) {
00416         return i;
00417       }
00418       i++;
00419       se=se->next;
00420     } /* while */
00421     return -1;
00422   }
00423   else {
00424     i=0;
00425     while(se) {
00426       if (strcasecmp(se->data, s)==0) {
00427         return i;
00428       }
00429       i++;
00430       se=se->next;
00431     } /* while */
00432     return -1;
00433   }
00434 }
00435 
00436 
00437 
00438 GWEN_STRINGLIST *GWEN_StringList_dup(const GWEN_STRINGLIST *sl){
00439   GWEN_STRINGLISTENTRY *se;
00440   GWEN_STRINGLIST *newsl;
00441 
00442   assert(sl);
00443   newsl=GWEN_StringList_new();
00444 
00445   se=sl->first;
00446   while(se) {
00447     GWEN_STRINGLISTENTRY *newse;
00448 
00449     newse=GWEN_StringListEntry_new(se->data, 0);
00450     GWEN_StringList_AppendEntry(newsl, newse);
00451     se=se->next;
00452   } /* while */
00453 
00454   return newsl;
00455 }
00456 
00457 
00458 void *GWEN_StringList_ForEach(const GWEN_STRINGLIST *l, 
00459                               void *(*func)(const char *s, void *u), 
00460                               void *user_data) {
00461   GWEN_STRINGLISTENTRY *it;
00462   const char *el;
00463   void *result = 0;
00464   assert(l);
00465 
00466   it = GWEN_StringList_FirstEntry(l);
00467   if (!it)
00468     return 0;
00469   while(it) {
00470     el = GWEN_StringListEntry_Data(it);
00471     result = func(el, user_data);
00472     if (result) {
00473       return result;
00474     }
00475     it = GWEN_StringListEntry_Next(it);
00476   }
00477   return 0;
00478 }
00479 
00480 
00481 
00482 const char *GWEN_StringList_FirstString(const GWEN_STRINGLIST *l){
00483   assert(l);
00484   if (l->first==0)
00485     return 0;
00486   return l->first->data;
00487 }
00488 
00489 
00490 
00491 static int GWEN_StringList__compar_asc_nocase(const void *a, const void *b) {
00492   const GWEN_STRINGLISTENTRY * const * pse1 = a, * const * pse2 = b;
00493   const GWEN_STRINGLISTENTRY *se1 = *pse1, *se2 = *pse2;
00494   if (se1 && se2 && se1->data && se2->data)
00495     return strcmp(se1->data, se2->data);
00496   else
00497     return 0;
00498 }
00499 static int GWEN_StringList__compar_desc_nocase(const void *a, const void *b) {
00500   const GWEN_STRINGLISTENTRY * const * pse1 = a, * const * pse2 = b;
00501   const GWEN_STRINGLISTENTRY *se1 = *pse1, *se2 = *pse2;
00502   if (se1 && se2 && se1->data && se2->data)
00503     return strcmp(se2->data, se1->data);
00504   else
00505     return 0;
00506 }
00507 static int GWEN_StringList__compar_asc_case(const void *a, const void *b) {
00508   const GWEN_STRINGLISTENTRY * const * pse1 = a, * const * pse2 = b;
00509   const GWEN_STRINGLISTENTRY *se1 = *pse1, *se2 = *pse2;
00510   if (se1 && se2 && se1->data && se2->data)
00511     return strcasecmp(se1->data, se2->data);
00512   else
00513     return 0;
00514 }
00515 static int GWEN_StringList__compar_desc_case(const void *a, const void *b) {
00516   const GWEN_STRINGLISTENTRY * const * pse1 = a, * const * pse2 = b;
00517   const GWEN_STRINGLISTENTRY *se1 = *pse1, *se2 = *pse2;
00518   if (se1 && se2 && se1->data && se2->data)
00519     return strcasecmp(se2->data, se1->data);
00520   else
00521     return 0;
00522 }
00523 
00524 static int GWEN_StringList__compar_asc_int(const void *a, const void *b) {
00525   const GWEN_STRINGLISTENTRY * const * pse1 = a, * const * pse2 = b;
00526   const GWEN_STRINGLISTENTRY *se1 = *pse1, *se2 = *pse2;
00527   if (se1 && se2 && se1->data && se2->data)
00528     return (atoi(se1->data)<atoi(se2->data));
00529   else
00530     return 0;
00531 }
00532 
00533 static int GWEN_StringList__compar_desc_int(const void *a, const void *b) {
00534   const GWEN_STRINGLISTENTRY * const * pse1 = a, * const * pse2 = b;
00535   const GWEN_STRINGLISTENTRY *se1 = *pse1, *se2 = *pse2;
00536   if (se1 && se2 && se1->data && se2->data)
00537     return (atoi(se1->data)>atoi(se2->data));
00538   else
00539     return 0;
00540 }
00541 
00542 
00543 
00544 void GWEN_StringList_Sort(GWEN_STRINGLIST *l,
00545                           int ascending,
00546                           GWEN_STRINGLIST_SORT_MODE sortMode) {
00547   GWEN_STRINGLISTENTRY **tmpEntries;
00548   GWEN_STRINGLISTENTRY *sentry;
00549   GWEN_STRINGLISTENTRY **psentry;
00550 
00551   if (l->count<1)
00552     return;
00553 
00554   /* sort entries into a linear pointer list */
00555   tmpEntries=(GWEN_STRINGLISTENTRY **)malloc((l->count+1)*
00556                                             sizeof(GWEN_STRINGLISTENTRY*));
00557   assert(tmpEntries);
00558   sentry=l->first;
00559   psentry=tmpEntries;
00560   while(sentry) {
00561     GWEN_STRINGLISTENTRY *nsentry;
00562 
00563     *(psentry++)=sentry;
00564     nsentry=sentry->next;
00565     sentry->next=0;
00566     sentry=nsentry;
00567   } /* while */
00568   *psentry=0;
00569 
00570   /* sort */
00571   switch(sortMode) {
00572   case GWEN_StringList_SortModeNoCase:
00573     if (ascending)
00574       qsort(tmpEntries, l->count, sizeof(GWEN_STRINGLISTENTRY*),
00575             GWEN_StringList__compar_desc_nocase);
00576     else
00577       qsort(tmpEntries, l->count, sizeof(GWEN_STRINGLISTENTRY*),
00578             GWEN_StringList__compar_asc_nocase);
00579     break;
00580 
00581   case GWEN_StringList_SortModeCase:
00582     if (ascending)
00583       qsort(tmpEntries, l->count, sizeof(GWEN_STRINGLISTENTRY*),
00584             GWEN_StringList__compar_desc_case);
00585     else
00586       qsort(tmpEntries, l->count, sizeof(GWEN_STRINGLISTENTRY*),
00587             GWEN_StringList__compar_asc_case);
00588     break;
00589 
00590   case GWEN_StringList_SortModeInt:
00591     if (ascending)
00592       qsort(tmpEntries, l->count, sizeof(GWEN_STRINGLISTENTRY*),
00593             GWEN_StringList__compar_desc_int);
00594     else
00595       qsort(tmpEntries, l->count, sizeof(GWEN_STRINGLISTENTRY*),
00596             GWEN_StringList__compar_asc_int);
00597     break;
00598 
00599   default:
00600     DBG_ERROR(GWEN_LOGDOMAIN, "Unknown sortmode %d", sortMode);
00601   }
00602 
00603   /* sort entries back into GWEN_STRINGLIST */
00604   psentry=tmpEntries;
00605   sentry=0;
00606   while(*psentry) {
00607     (*psentry)->next=0;
00608     if (sentry)
00609       sentry->next=*psentry;
00610     else
00611       l->first=*psentry;
00612     sentry=*psentry;
00613     psentry++;
00614   } /* while */
00615 
00616   free(tmpEntries);
00617 
00618 }
00619 
00620 
00621 
00622 const char *GWEN_StringList_StringAt(const GWEN_STRINGLIST *sl, int idx) {
00623   GWEN_STRINGLISTENTRY *se;
00624 
00625   assert(sl);
00626   se=sl->first;
00627   while(se) {
00628     if (idx--==0)
00629       return se->data;
00630     se=se->next;
00631   } /* while */
00632   return 0;
00633 }
00634 
00635 
00636 
00637 GWEN_STRINGLIST *GWEN_StringList_fromString(const char *str, const char *delimiters, int checkDouble) {
00638   if (str && *str) {
00639     GWEN_STRINGLIST *sl;
00640     const unsigned char *s;
00641   
00642     sl=GWEN_StringList_new();
00643     s=(const unsigned char*)str;
00644   
00645     while(*s) {
00646       /* skip blanks */
00647       while(*s && *s<33)
00648         s++;
00649 
00650       if (*s) {
00651         const unsigned char *pStart;
00652         int len;
00653 
00654         /* read word */
00655         pStart=s;
00656         //s++;
00657         while(*s && strchr(delimiters, *s)==NULL)
00658           s++;
00659         len=s-pStart;
00660     
00661         if (len) {
00662           char *toAdd;
00663 
00664           toAdd=(char*) malloc(len+1);
00665           assert(toAdd);
00666 
00667           memmove(toAdd, pStart, len);
00668           toAdd[len]=0;
00669     
00670           GWEN_StringList_AppendString(sl, toAdd, 1, checkDouble);
00671         }
00672       }
00673 
00674       if (*s==0)
00675         break;
00676       s++;
00677     }
00678   
00679     if (GWEN_StringList_Count(sl)==0) {
00680       GWEN_StringList_free(sl);
00681       return NULL;
00682     }
00683     return sl;
00684   }
00685   else
00686     return NULL;
00687 }
00688 
00689 
00690