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
00027
00028
00029 #ifdef HAVE_CONFIG_H
00030 # include <config.h>
00031 #endif
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(){
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 void GWEN_StringList_RemoveEntry(GWEN_STRINGLIST *sl,
00151 GWEN_STRINGLISTENTRY *se){
00152 GWEN_STRINGLISTENTRY *curr;
00153
00154 assert(sl);
00155 assert(se);
00156
00157 curr=sl->first;
00158 if (curr) {
00159 if (curr==se) {
00160 sl->first=curr->next;
00161 if (sl->count)
00162 sl->count--;
00163 }
00164 else {
00165 while(curr->next!=se) {
00166 curr=curr->next;
00167 }
00168 if (curr) {
00169 curr->next=se->next;
00170 if (sl->count)
00171 sl->count--;
00172 }
00173 }
00174 }
00175 }
00176
00177
00178
00179 void GWEN_StringList_Clear(GWEN_STRINGLIST *sl){
00180 GWEN_STRINGLISTENTRY *se, *next;
00181
00182 assert(sl);
00183 se=sl->first;
00184 sl->first=0;
00185 while (se) {
00186 next=se->next;
00187 GWEN_StringListEntry_free(se);
00188 se=next;
00189 }
00190 }
00191
00192
00193
00194 int GWEN_StringList_AppendString(GWEN_STRINGLIST *sl,
00195 const char *s,
00196 int take,
00197 int checkDouble){
00198 GWEN_STRINGLISTENTRY *se;
00199
00200 if (checkDouble) {
00201 se=sl->first;
00202 if (sl->senseCase) {
00203 while(se) {
00204 if (strcmp(se->data, s)==0) {
00205 if (take)
00206 free((char*)s);
00207 se->refCount++;
00208 return 0;
00209 }
00210 se=se->next;
00211 }
00212 }
00213 else {
00214 while(se) {
00215 if (strcasecmp(se->data, s)==0) {
00216 if (take)
00217 free((char*)s);
00218 se->refCount++;
00219 return 0;
00220 }
00221 se=se->next;
00222 }
00223 }
00224 }
00225
00226 se=GWEN_StringListEntry_new(s, take);
00227 GWEN_StringList_AppendEntry(sl, se);
00228 return 1;
00229 }
00230
00231
00232
00233 int GWEN_StringList_InsertString(GWEN_STRINGLIST *sl,
00234 const char *s,
00235 int take,
00236 int checkDouble){
00237 GWEN_STRINGLISTENTRY *se;
00238
00239 if (checkDouble) {
00240 se=sl->first;
00241 if (sl->senseCase) {
00242 while(se) {
00243 if (strcmp(se->data, s)==0) {
00244 if (take)
00245 free((char*)s);
00246 se->refCount++;
00247 return 0;
00248 }
00249 se=se->next;
00250 }
00251 }
00252 else {
00253 while(se) {
00254 if (strcasecmp(se->data, s)==0) {
00255 if (take)
00256 free((char*)s);
00257 se->refCount++;
00258 return 0;
00259 }
00260 se=se->next;
00261 }
00262 }
00263 }
00264 se=GWEN_StringListEntry_new(s, take);
00265 se->next=sl->first;
00266 sl->first=se;
00267 return 1;
00268 }
00269
00270
00271
00272 GWENHYWFAR_API int GWEN_StringList_RemoveString(GWEN_STRINGLIST *sl,
00273 const char *s){
00274 GWEN_STRINGLISTENTRY *se;
00275
00276 se=sl->first;
00277 if (sl->senseCase) {
00278 while(se) {
00279 if (strcmp(se->data, s)==0) {
00280 assert(se->refCount);
00281 se->refCount--;
00282 if (sl->ignoreRefCount)
00283 GWEN_StringList_RemoveEntry(sl, se);
00284 else {
00285 if (se->refCount==0)
00286 GWEN_StringList_RemoveEntry(sl, se);
00287 }
00288 return 1;
00289 }
00290 se=se->next;
00291 }
00292 return 0;
00293 }
00294 else {
00295 while(se) {
00296 if (strcasecmp(se->data, s)==0) {
00297 assert(se->refCount);
00298 se->refCount--;
00299 if (sl->ignoreRefCount)
00300 GWEN_StringList_RemoveEntry(sl, se);
00301 else {
00302 assert(se->refCount);
00303 if (se->refCount==0)
00304 GWEN_StringList_RemoveEntry(sl, se);
00305 }
00306 return 1;
00307 }
00308 se=se->next;
00309 }
00310 return 0;
00311 }
00312 }
00313
00314
00315
00316 GWEN_STRINGLISTENTRY *GWEN_StringList_FirstEntry(const GWEN_STRINGLIST *sl){
00317 assert(sl);
00318 return sl->first;
00319 }
00320
00321
00322
00323 GWEN_STRINGLISTENTRY *GWEN_StringListEntry_Next(const GWEN_STRINGLISTENTRY *se){
00324 assert(se);
00325 return se->next;
00326 }
00327
00328
00329
00330 const char *GWEN_StringListEntry_Data(const GWEN_STRINGLISTENTRY *se){
00331 assert(se);
00332 return se->data;
00333 }
00334
00335
00336 unsigned int GWEN_StringList_Count(const GWEN_STRINGLIST *sl){
00337 assert(sl);
00338 return sl->count;
00339 }
00340
00341
00342
00343 int GWEN_StringList_HasString(const GWEN_STRINGLIST *sl,
00344 const char *s){
00345 GWEN_STRINGLISTENTRY *se;
00346
00347 assert(sl);
00348 se=sl->first;
00349 if (sl->senseCase) {
00350 while(se) {
00351 if (strcmp(se->data, s)==0) {
00352 return 1;
00353 }
00354 se=se->next;
00355 }
00356 return 0;
00357 }
00358 else {
00359 while(se) {
00360 if (strcasecmp(se->data, s)==0) {
00361 return 1;
00362 }
00363 se=se->next;
00364 }
00365 return 0;
00366 }
00367 }
00368
00369
00370
00371 GWEN_STRINGLIST *GWEN_StringList_dup(const GWEN_STRINGLIST *sl){
00372 GWEN_STRINGLISTENTRY *se;
00373 GWEN_STRINGLIST *newsl;
00374
00375 assert(sl);
00376 newsl=GWEN_StringList_new();
00377
00378 se=sl->first;
00379 while(se) {
00380 GWEN_STRINGLISTENTRY *newse;
00381
00382 newse=GWEN_StringListEntry_new(se->data, 0);
00383 GWEN_StringList_AppendEntry(newsl, newse);
00384 se=se->next;
00385 }
00386
00387 return newsl;
00388 }
00389
00390
00391 void *GWEN_StringList_ForEach(const GWEN_STRINGLIST *l,
00392 void *(*func)(const char *s, void *u),
00393 void *user_data) {
00394 GWEN_STRINGLISTENTRY *it;
00395 const char *el;
00396 void *result = 0;
00397 assert(l);
00398
00399 it = GWEN_StringList_FirstEntry(l);
00400 if (!it)
00401 return 0;
00402 while(it) {
00403 el = GWEN_StringListEntry_Data(it);
00404 result = func(el, user_data);
00405 if (result) {
00406 return result;
00407 }
00408 it = GWEN_StringListEntry_Next(it);
00409 }
00410 return 0;
00411 }
00412
00413
00414
00415 const char *GWEN_StringList_FirstString(const GWEN_STRINGLIST *l){
00416 assert(l);
00417 if (l->first==0)
00418 return 0;
00419 return l->first->data;
00420 }
00421
00422
00423
00424 static int GWEN_StringList__compar_asc_nocase(const void *a, const void *b) {
00425 const GWEN_STRINGLISTENTRY * const * pse1 = a, * const * pse2 = b;
00426 const GWEN_STRINGLISTENTRY *se1 = *pse1, *se2 = *pse2;
00427 if (se1 && se2 && se1->data && se2->data)
00428 return strcmp(se1->data, se2->data);
00429 else
00430 return 0;
00431 }
00432 static int GWEN_StringList__compar_desc_nocase(const void *a, const void *b) {
00433 const GWEN_STRINGLISTENTRY * const * pse1 = a, * const * pse2 = b;
00434 const GWEN_STRINGLISTENTRY *se1 = *pse1, *se2 = *pse2;
00435 if (se1 && se2 && se1->data && se2->data)
00436 return strcmp(se2->data, se1->data);
00437 else
00438 return 0;
00439 }
00440 static int GWEN_StringList__compar_asc_case(const void *a, const void *b) {
00441 const GWEN_STRINGLISTENTRY * const * pse1 = a, * const * pse2 = b;
00442 const GWEN_STRINGLISTENTRY *se1 = *pse1, *se2 = *pse2;
00443 if (se1 && se2 && se1->data && se2->data)
00444 return strcasecmp(se1->data, se2->data);
00445 else
00446 return 0;
00447 }
00448 static int GWEN_StringList__compar_desc_case(const void *a, const void *b) {
00449 const GWEN_STRINGLISTENTRY * const * pse1 = a, * const * pse2 = b;
00450 const GWEN_STRINGLISTENTRY *se1 = *pse1, *se2 = *pse2;
00451 if (se1 && se2 && se1->data && se2->data)
00452 return strcasecmp(se2->data, se1->data);
00453 else
00454 return 0;
00455 }
00456
00457 static int GWEN_StringList__compar_asc_int(const void *a, const void *b) {
00458 const GWEN_STRINGLISTENTRY * const * pse1 = a, * const * pse2 = b;
00459 const GWEN_STRINGLISTENTRY *se1 = *pse1, *se2 = *pse2;
00460 if (se1 && se2 && se1->data && se2->data)
00461 return (atoi(se1->data)<atoi(se2->data));
00462 else
00463 return 0;
00464 }
00465
00466 static int GWEN_StringList__compar_desc_int(const void *a, const void *b) {
00467 const GWEN_STRINGLISTENTRY * const * pse1 = a, * const * pse2 = b;
00468 const GWEN_STRINGLISTENTRY *se1 = *pse1, *se2 = *pse2;
00469 if (se1 && se2 && se1->data && se2->data)
00470 return (atoi(se1->data)>atoi(se2->data));
00471 else
00472 return 0;
00473 }
00474
00475
00476
00477 void GWEN_StringList_Sort(GWEN_STRINGLIST *l,
00478 int ascending,
00479 GWEN_STRINGLIST_SORT_MODE sortMode) {
00480 GWEN_STRINGLISTENTRY **tmpEntries;
00481 GWEN_STRINGLISTENTRY *sentry;
00482 GWEN_STRINGLISTENTRY **psentry;
00483
00484 if (l->count<1)
00485 return;
00486
00487
00488 tmpEntries=(GWEN_STRINGLISTENTRY **)malloc((l->count+1)*
00489 sizeof(GWEN_STRINGLISTENTRY*));
00490 assert(tmpEntries);
00491 sentry=l->first;
00492 psentry=tmpEntries;
00493 while(sentry) {
00494 GWEN_STRINGLISTENTRY *nsentry;
00495
00496 *(psentry++)=sentry;
00497 nsentry=sentry->next;
00498 sentry->next=0;
00499 sentry=nsentry;
00500 }
00501 *psentry=0;
00502
00503
00504 switch(sortMode) {
00505 case GWEN_StringList_SortModeNoCase:
00506 if (ascending)
00507 qsort(tmpEntries, l->count, sizeof(GWEN_STRINGLISTENTRY*),
00508 GWEN_StringList__compar_desc_nocase);
00509 else
00510 qsort(tmpEntries, l->count, sizeof(GWEN_STRINGLISTENTRY*),
00511 GWEN_StringList__compar_asc_nocase);
00512 break;
00513
00514 case GWEN_StringList_SortModeCase:
00515 if (ascending)
00516 qsort(tmpEntries, l->count, sizeof(GWEN_STRINGLISTENTRY*),
00517 GWEN_StringList__compar_desc_case);
00518 else
00519 qsort(tmpEntries, l->count, sizeof(GWEN_STRINGLISTENTRY*),
00520 GWEN_StringList__compar_asc_case);
00521 break;
00522
00523 case GWEN_StringList_SortModeInt:
00524 if (ascending)
00525 qsort(tmpEntries, l->count, sizeof(GWEN_STRINGLISTENTRY*),
00526 GWEN_StringList__compar_desc_int);
00527 else
00528 qsort(tmpEntries, l->count, sizeof(GWEN_STRINGLISTENTRY*),
00529 GWEN_StringList__compar_asc_int);
00530 break;
00531
00532 default:
00533 DBG_ERROR(GWEN_LOGDOMAIN, "Unknown sortmode %d", sortMode);
00534 }
00535
00536
00537 psentry=tmpEntries;
00538 sentry=0;
00539 while(*psentry) {
00540 (*psentry)->next=0;
00541 if (sentry)
00542 sentry->next=*psentry;
00543 else
00544 l->first=*psentry;
00545 sentry=*psentry;
00546 psentry++;
00547 }
00548
00549 free(tmpEntries);
00550
00551 }
00552
00553
00554
00555 const char *GWEN_StringList_StringAt(const GWEN_STRINGLIST *sl, int idx) {
00556 GWEN_STRINGLISTENTRY *se;
00557
00558 assert(sl);
00559 se=sl->first;
00560 while(se) {
00561 if (idx--==0)
00562 return se->data;
00563 se=se->next;
00564 }
00565 return 0;
00566 }
00567
00568
00569
00570