00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
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 }
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
00169 GWEN_StringList_AppendString(sl, tmpStr, 1, checkDup);
00170 s=t+1;
00171 }
00172 else {
00173
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 }
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 }
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 }
00258 }
00259 }
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 }
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 }
00297 }
00298 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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
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 }
00568 *psentry=0;
00569
00570
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
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 }
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 }
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
00647 while(*s && *s<33)
00648 s++;
00649
00650 if (*s) {
00651 const unsigned char *pStart;
00652 int len;
00653
00654
00655 pStart=s;
00656
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