|
|
1.1 ! root 1: /* str_list.c */ ! 2: ! 3: /* Functions to deal with NULL-terminated string lists */ ! 4: ! 5: /* $Id: str_list.c,v 1.35 2006/08/14 22:55:48 rswindell Exp $ */ ! 6: ! 7: /**************************************************************************** ! 8: * @format.tab-size 4 (Plain Text/Source Code File Header) * ! 9: * @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) * ! 10: * * ! 11: * Copyright 2006 Rob Swindell - http://www.synchro.net/copyright.html * ! 12: * * ! 13: * This library is free software; you can redistribute it and/or * ! 14: * modify it under the terms of the GNU Lesser General Public License * ! 15: * as published by the Free Software Foundation; either version 2 * ! 16: * of the License, or (at your option) any later version. * ! 17: * See the GNU Lesser General Public License for more details: lgpl.txt or * ! 18: * http://www.fsf.org/copyleft/lesser.html * ! 19: * * ! 20: * Anonymous FTP access to the most recent released source is available at * ! 21: * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net * ! 22: * * ! 23: * Anonymous CVS access to the development source and modification history * ! 24: * is available at cvs.synchro.net:/cvsroot/sbbs, example: * ! 25: * cvs -d :pserver:[email protected]:/cvsroot/sbbs login * ! 26: * (just hit return, no password is necessary) * ! 27: * cvs -d :pserver:[email protected]:/cvsroot/sbbs checkout src * ! 28: * * ! 29: * For Synchronet coding style and modification guidelines, see * ! 30: * http://www.synchro.net/source.html * ! 31: * * ! 32: * You are encouraged to submit any modifications (preferably in Unix diff * ! 33: * format) via e-mail to [email protected] * ! 34: * * ! 35: * Note: If this box doesn't appear square, then you need to fix your tabs. * ! 36: ****************************************************************************/ ! 37: ! 38: #include <stdlib.h> /* malloc and qsort */ ! 39: #include <string.h> /* strtok */ ! 40: #if defined(_WIN32) ! 41: #include <malloc.h> /* alloca() on Win32 */ ! 42: #endif ! 43: #include "genwrap.h" /* stricmp */ ! 44: #include "str_list.h" ! 45: ! 46: str_list_t strListInit() ! 47: { ! 48: str_list_t list; ! 49: ! 50: if((list=(str_list_t)malloc(sizeof(char*)))==NULL) ! 51: return(NULL); ! 52: ! 53: list[0]=NULL; /* terminated by default */ ! 54: return(list); ! 55: } ! 56: ! 57: size_t strListCount(const str_list_t list) ! 58: { ! 59: size_t i; ! 60: ! 61: COUNT_LIST_ITEMS(list,i); ! 62: ! 63: return(i); ! 64: } ! 65: ! 66: static char* str_list_append(str_list_t* list, char* str, size_t index) ! 67: { ! 68: str_list_t lp; ! 69: ! 70: if((lp=(str_list_t)realloc(*list,sizeof(char*)*(index+2)))==NULL) ! 71: return(NULL); ! 72: ! 73: *list=lp; ! 74: lp[index++]=str; ! 75: lp[index]=NULL; /* terminate list */ ! 76: ! 77: return(str); ! 78: } ! 79: ! 80: static char* str_list_insert(str_list_t* list, char* str, size_t index) ! 81: { ! 82: size_t i; ! 83: size_t count; ! 84: str_list_t lp; ! 85: ! 86: count = strListCount(*list); ! 87: if(index > count) /* invalid index, do nothing */ ! 88: return(NULL); ! 89: ! 90: count++; ! 91: if((lp=(str_list_t)realloc(*list,sizeof(char*)*(count+1)))==NULL) ! 92: return(NULL); ! 93: ! 94: *list=lp; ! 95: for(i=count; i>index; i--) ! 96: lp[i]=lp[i-1]; ! 97: lp[index]=str; ! 98: ! 99: return(str); ! 100: } ! 101: ! 102: char* strListRemove(str_list_t* list, size_t index) ! 103: { ! 104: char* str; ! 105: size_t i; ! 106: size_t count; ! 107: str_list_t lp; ! 108: ! 109: count = strListCount(*list); ! 110: ! 111: if(index==STR_LIST_LAST_INDEX && count) ! 112: index = count-1; ! 113: ! 114: if(index >= count) /* invalid index, do nothing */ ! 115: return(NULL); ! 116: ! 117: count--; ! 118: if((lp=(str_list_t)realloc(*list,sizeof(char*)*(count+1)))==NULL) ! 119: return(NULL); ! 120: ! 121: *list=lp; ! 122: str=lp[index]; ! 123: for(i=index; i<count; i++) ! 124: lp[i]=lp[i+1]; ! 125: lp[count]=NULL; ! 126: ! 127: return(str); ! 128: } ! 129: ! 130: BOOL strListDelete(str_list_t* list, size_t index) ! 131: { ! 132: char* str; ! 133: ! 134: if((str=strListRemove(list, index))==NULL) ! 135: return(FALSE); ! 136: ! 137: free(str); ! 138: ! 139: return(TRUE); ! 140: } ! 141: ! 142: char* strListReplace(const str_list_t list, size_t index, const char* str) ! 143: { ! 144: char* buf; ! 145: size_t count; ! 146: ! 147: if(str==NULL) ! 148: return(NULL); ! 149: ! 150: count = strListCount(list); ! 151: ! 152: if(index==STR_LIST_LAST_INDEX && count) ! 153: index = count-1; ! 154: ! 155: if(index >= count) /* invalid index, do nothing */ ! 156: return(NULL); ! 157: ! 158: if((buf=(char*)realloc(list[index],strlen(str)+1))==NULL) ! 159: return(NULL); ! 160: ! 161: list[index]=buf; ! 162: strcpy(buf,str); ! 163: ! 164: return(buf); ! 165: } ! 166: ! 167: BOOL strListSwap(const str_list_t list, size_t index1, size_t index2) ! 168: { ! 169: char* tmp; ! 170: size_t count; ! 171: ! 172: count = strListCount(list); ! 173: ! 174: if(index1==STR_LIST_LAST_INDEX && count) ! 175: index1 = count-1; ! 176: ! 177: if(index2==STR_LIST_LAST_INDEX && count) ! 178: index2 = count-1; ! 179: ! 180: if(index1 >= count || index2 >= count || index1 == index2) ! 181: return(FALSE); /* invalid index, do nothing */ ! 182: ! 183: tmp=list[index1]; ! 184: list[index1]=list[index2]; ! 185: list[index2]=tmp; ! 186: ! 187: return(TRUE); ! 188: } ! 189: ! 190: char* strListAppend(str_list_t* list, const char* str, size_t index) ! 191: { ! 192: char* buf; ! 193: ! 194: if(str==NULL) ! 195: return(NULL); ! 196: ! 197: if((buf=strdup(str))==NULL) ! 198: return(NULL); ! 199: ! 200: if(index==STR_LIST_LAST_INDEX) ! 201: index=strListCount(*list); ! 202: ! 203: return(str_list_append(list,buf,index)); ! 204: } ! 205: ! 206: size_t strListAppendList(str_list_t* list, const str_list_t add_list) ! 207: { ! 208: size_t i; ! 209: size_t count; ! 210: ! 211: count=strListCount(*list); ! 212: for(i=0; add_list[i]!=NULL; i++) ! 213: strListAppend(list,add_list[i],count++); ! 214: ! 215: return(count); ! 216: } ! 217: ! 218: char* strListInsert(str_list_t* list, const char* str, size_t index) ! 219: { ! 220: char* buf; ! 221: ! 222: if(str==NULL) ! 223: return(NULL); ! 224: ! 225: if((buf=strdup(str))==NULL) ! 226: return(NULL); ! 227: ! 228: return(str_list_insert(list,buf,index)); ! 229: } ! 230: ! 231: size_t strListInsertList(str_list_t* list, const str_list_t add_list, size_t index) ! 232: { ! 233: size_t i; ! 234: ! 235: ! 236: for(i=0; add_list[i]!=NULL; i++) ! 237: if(strListInsert(list,add_list[i],index++)==NULL) ! 238: break; ! 239: ! 240: return(i); ! 241: } ! 242: ! 243: str_list_t strListSplit(str_list_t* lp, char* str, const char* delimit) ! 244: { ! 245: size_t count; ! 246: char* token; ! 247: char* tmp; ! 248: str_list_t list; ! 249: ! 250: if(str==NULL || delimit==NULL) ! 251: return(NULL); ! 252: ! 253: if(lp==NULL) { ! 254: if((list = strListInit())==NULL) ! 255: return(NULL); ! 256: lp=&list; ! 257: count=0; ! 258: } else ! 259: count=strListCount(*lp); ! 260: ! 261: for(token = strtok_r(str, delimit, &tmp); token!=NULL; token=strtok_r(NULL, delimit, &tmp)) ! 262: if(strListAppend(lp, token, count++)==NULL) ! 263: break; ! 264: ! 265: return(*lp); ! 266: } ! 267: ! 268: str_list_t strListSplitCopy(str_list_t* list, const char* str, const char* delimit) ! 269: { ! 270: char* buf; ! 271: str_list_t new_list; ! 272: ! 273: if(str==NULL || delimit==NULL) ! 274: return(NULL); ! 275: ! 276: if((buf=strdup(str))==NULL) ! 277: return(NULL); ! 278: ! 279: new_list=strListSplit(list,buf,delimit); ! 280: ! 281: free(buf); ! 282: ! 283: if(list!=NULL) ! 284: *list = new_list; ! 285: ! 286: return(new_list); ! 287: } ! 288: ! 289: size_t strListMerge(str_list_t* list, str_list_t add_list) ! 290: { ! 291: size_t i; ! 292: size_t count; ! 293: ! 294: count=strListCount(*list); ! 295: for(i=0; add_list[i]!=NULL; i++) ! 296: str_list_append(list,add_list[i],count++); ! 297: ! 298: return(i); ! 299: } ! 300: ! 301: #if defined(_WIN32) ! 302: #define QSORT_CALLBACK_TYPE _cdecl ! 303: #else ! 304: #define QSORT_CALLBACK_TYPE ! 305: #endif ! 306: ! 307: static int QSORT_CALLBACK_TYPE strListCompareAlpha(const void *arg1, const void *arg2) ! 308: { ! 309: return stricmp(*(char**)arg1, *(char**)arg2); ! 310: } ! 311: ! 312: static int QSORT_CALLBACK_TYPE strListCompareAlphaReverse(const void *arg1, const void *arg2) ! 313: { ! 314: return stricmp(*(char**)arg2, *(char**)arg1); ! 315: } ! 316: ! 317: static int QSORT_CALLBACK_TYPE strListCompareAlphaCase(const void *arg1, const void *arg2) ! 318: { ! 319: return strcmp(*(char**)arg1, *(char**)arg2); ! 320: } ! 321: ! 322: static int QSORT_CALLBACK_TYPE strListCompareAlphaCaseReverse(const void *arg1, const void *arg2) ! 323: { ! 324: return strcmp(*(char**)arg2, *(char**)arg1); ! 325: } ! 326: ! 327: void strListSortAlpha(str_list_t list) ! 328: { ! 329: qsort(list,strListCount(list),sizeof(char*),strListCompareAlpha); ! 330: } ! 331: ! 332: void strListSortAlphaReverse(str_list_t list) ! 333: { ! 334: qsort(list,strListCount(list),sizeof(char*),strListCompareAlphaReverse); ! 335: } ! 336: ! 337: void strListSortAlphaCase(str_list_t list) ! 338: { ! 339: qsort(list,strListCount(list),sizeof(char*),strListCompareAlphaCase); ! 340: } ! 341: ! 342: void strListSortAlphaCaseReverse(str_list_t list) ! 343: { ! 344: qsort(list,strListCount(list),sizeof(char*),strListCompareAlphaCaseReverse); ! 345: } ! 346: ! 347: void strListFreeStrings(str_list_t list) ! 348: { ! 349: size_t i; ! 350: ! 351: FREE_LIST_ITEMS(list,i); ! 352: } ! 353: ! 354: void strListFree(str_list_t* list) ! 355: { ! 356: if(*list!=NULL) { ! 357: strListFreeStrings(*list); ! 358: FREE_AND_NULL(*list); ! 359: } ! 360: } ! 361: ! 362: static str_list_t str_list_read_file(FILE* fp, str_list_t* lp, size_t max_line_len) ! 363: { ! 364: char* buf=NULL; ! 365: size_t count; ! 366: str_list_t list; ! 367: ! 368: if(max_line_len<1) ! 369: max_line_len=2048; ! 370: ! 371: if(lp==NULL) { ! 372: if((list = strListInit())==NULL) ! 373: return(NULL); ! 374: lp=&list; ! 375: } ! 376: ! 377: if(fp!=NULL) { ! 378: count=strListCount(*lp); ! 379: while(!feof(fp)) { ! 380: if(buf==NULL && (buf=(char*)alloca(max_line_len+1))==NULL) ! 381: return(NULL); ! 382: ! 383: if(fgets(buf,max_line_len+1,fp)==NULL) ! 384: break; ! 385: strListAppend(lp, buf, count++); ! 386: } ! 387: } ! 388: ! 389: return(*lp); ! 390: } ! 391: ! 392: size_t strListInsertFile(FILE* fp, str_list_t* lp, size_t index, size_t max_line_len) ! 393: { ! 394: str_list_t list; ! 395: size_t count; ! 396: ! 397: if((list=str_list_read_file(fp, NULL, max_line_len)) == NULL) ! 398: return(0); ! 399: ! 400: count = strListInsertList(lp, list, index); ! 401: ! 402: strListFree(&list); ! 403: ! 404: return(count); ! 405: } ! 406: ! 407: str_list_t strListReadFile(FILE* fp, str_list_t* lp, size_t max_line_len) ! 408: { ! 409: return str_list_read_file(fp,lp,max_line_len); ! 410: } ! 411: ! 412: size_t strListWriteFile(FILE* fp, const str_list_t list, const char* separator) ! 413: { ! 414: size_t i; ! 415: ! 416: if(list==NULL) ! 417: return(0); ! 418: ! 419: for(i=0; list[i]!=NULL; i++) { ! 420: if(fputs(list[i],fp)==EOF) ! 421: break; ! 422: if(separator!=NULL && fputs(separator,fp)==EOF) ! 423: break; ! 424: } ! 425: ! 426: return(i); ! 427: } ! 428: ! 429: size_t strListBlockLength(char* block) ! 430: { ! 431: char* p=block; ! 432: size_t str_len; ! 433: size_t block_len=0; ! 434: ! 435: if(block==NULL) ! 436: return(0); ! 437: ! 438: /* calculate total block length */ ! 439: while((str_len=strlen(p))!=0) { ! 440: block_len+=(str_len + 1); ! 441: p+=(str_len + 1); ! 442: } ! 443: /* block must be double-NULL terminated */ ! 444: if(!block_len) ! 445: block_len=1; ! 446: block_len++; ! 447: ! 448: return(block_len); ! 449: } ! 450: ! 451: char* strListCopyBlock(char* block) ! 452: { ! 453: char* p; ! 454: size_t block_len; ! 455: ! 456: if((block_len=strListBlockLength(block))==0) ! 457: return(NULL); ! 458: ! 459: if((p=(char*)malloc(block_len))==NULL) ! 460: return(NULL); ! 461: memcpy(p, block, block_len); ! 462: return(p); ! 463: } ! 464: ! 465: char* strListAppendBlock(char* block, str_list_t list) ! 466: { ! 467: char* p; ! 468: size_t str_len; ! 469: size_t block_len; ! 470: size_t i; ! 471: ! 472: if((block_len=strListBlockLength(block))!=0) ! 473: block_len--; /* Over-write existing NULL terminator */ ! 474: ! 475: for(i=0; list[i]!=NULL; i++) { ! 476: str_len=strlen(list[i]); ! 477: if(str_len==0) ! 478: continue; /* can't include empty strings in block */ ! 479: if((p=(char*)realloc(block, block_len + str_len + 1))==NULL) { ! 480: FREE_AND_NULL(block); ! 481: return(block); ! 482: } ! 483: block=p; ! 484: strcpy(block + block_len, list[i]); ! 485: block_len += (str_len + 1); ! 486: } ! 487: ! 488: /* block must be double-NULL terminated */ ! 489: if(!block_len) ! 490: block_len=1; ! 491: block_len++; ! 492: if((p=(char*)realloc(block, block_len))==NULL) { ! 493: FREE_AND_NULL(block); ! 494: return(block); ! 495: } ! 496: block=p; ! 497: memset(block + (block_len-2), 0, 2); ! 498: ! 499: return(block); ! 500: } ! 501: ! 502: char* strListCreateBlock(str_list_t list) ! 503: { ! 504: return(strListAppendBlock(NULL,list)); ! 505: } ! 506: ! 507: void strListFreeBlock(char* block) ! 508: { ! 509: if(block!=NULL) ! 510: free(block); /* this must be done here for Windows-DLL reasons */ ! 511: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.