|
|
1.1 root 1: /* str_list.c */
2:
3: /* Functions to deal with NULL-terminated string lists */
4:
1.1.1.2 ! root 5: /* $Id: str_list.c,v 1.37 2009/08/14 10:02:22 rswindell Exp $ */
1.1 root 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: * *
1.1.1.2 ! root 11: * Copyright 2009 Rob Swindell - http://www.synchro.net/copyright.html *
1.1 root 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:
1.1.1.2 ! root 46: str_list_t strListInit(void)
1.1 root 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:
1.1.1.2 ! root 66: int strListIndexOf(const str_list_t list, const char* str)
! 67: {
! 68: size_t i;
! 69:
! 70: if(list==NULL)
! 71: return -1;
! 72:
! 73: for(i=0; list[i]!=NULL; i++) {
! 74: if(list[i]==str)
! 75: return i;
! 76: }
! 77:
! 78: return -1;
! 79: }
! 80:
1.1 root 81: static char* str_list_append(str_list_t* list, char* str, size_t index)
82: {
83: str_list_t lp;
84:
85: if((lp=(str_list_t)realloc(*list,sizeof(char*)*(index+2)))==NULL)
86: return(NULL);
87:
88: *list=lp;
89: lp[index++]=str;
90: lp[index]=NULL; /* terminate list */
91:
92: return(str);
93: }
94:
95: static char* str_list_insert(str_list_t* list, char* str, size_t index)
96: {
97: size_t i;
98: size_t count;
99: str_list_t lp;
100:
101: count = strListCount(*list);
102: if(index > count) /* invalid index, do nothing */
103: return(NULL);
104:
105: count++;
106: if((lp=(str_list_t)realloc(*list,sizeof(char*)*(count+1)))==NULL)
107: return(NULL);
108:
109: *list=lp;
110: for(i=count; i>index; i--)
111: lp[i]=lp[i-1];
112: lp[index]=str;
113:
114: return(str);
115: }
116:
117: char* strListRemove(str_list_t* list, size_t index)
118: {
119: char* str;
120: size_t i;
121: size_t count;
122: str_list_t lp;
123:
124: count = strListCount(*list);
125:
126: if(index==STR_LIST_LAST_INDEX && count)
127: index = count-1;
128:
129: if(index >= count) /* invalid index, do nothing */
130: return(NULL);
131:
132: count--;
133: if((lp=(str_list_t)realloc(*list,sizeof(char*)*(count+1)))==NULL)
134: return(NULL);
135:
136: *list=lp;
137: str=lp[index];
138: for(i=index; i<count; i++)
139: lp[i]=lp[i+1];
140: lp[count]=NULL;
141:
142: return(str);
143: }
144:
145: BOOL strListDelete(str_list_t* list, size_t index)
146: {
147: char* str;
148:
149: if((str=strListRemove(list, index))==NULL)
150: return(FALSE);
151:
152: free(str);
153:
154: return(TRUE);
155: }
156:
157: char* strListReplace(const str_list_t list, size_t index, const char* str)
158: {
159: char* buf;
160: size_t count;
161:
162: if(str==NULL)
163: return(NULL);
164:
165: count = strListCount(list);
166:
167: if(index==STR_LIST_LAST_INDEX && count)
168: index = count-1;
169:
170: if(index >= count) /* invalid index, do nothing */
171: return(NULL);
172:
173: if((buf=(char*)realloc(list[index],strlen(str)+1))==NULL)
174: return(NULL);
175:
176: list[index]=buf;
177: strcpy(buf,str);
178:
179: return(buf);
180: }
181:
182: BOOL strListSwap(const str_list_t list, size_t index1, size_t index2)
183: {
184: char* tmp;
185: size_t count;
186:
187: count = strListCount(list);
188:
189: if(index1==STR_LIST_LAST_INDEX && count)
190: index1 = count-1;
191:
192: if(index2==STR_LIST_LAST_INDEX && count)
193: index2 = count-1;
194:
195: if(index1 >= count || index2 >= count || index1 == index2)
196: return(FALSE); /* invalid index, do nothing */
197:
198: tmp=list[index1];
199: list[index1]=list[index2];
200: list[index2]=tmp;
201:
202: return(TRUE);
203: }
204:
205: char* strListAppend(str_list_t* list, const char* str, size_t index)
206: {
207: char* buf;
208:
209: if(str==NULL)
210: return(NULL);
211:
212: if((buf=strdup(str))==NULL)
213: return(NULL);
214:
215: if(index==STR_LIST_LAST_INDEX)
216: index=strListCount(*list);
217:
218: return(str_list_append(list,buf,index));
219: }
220:
221: size_t strListAppendList(str_list_t* list, const str_list_t add_list)
222: {
223: size_t i;
224: size_t count;
225:
226: count=strListCount(*list);
227: for(i=0; add_list[i]!=NULL; i++)
228: strListAppend(list,add_list[i],count++);
229:
230: return(count);
231: }
232:
233: char* strListInsert(str_list_t* list, const char* str, size_t index)
234: {
235: char* buf;
236:
237: if(str==NULL)
238: return(NULL);
239:
240: if((buf=strdup(str))==NULL)
241: return(NULL);
242:
243: return(str_list_insert(list,buf,index));
244: }
245:
246: size_t strListInsertList(str_list_t* list, const str_list_t add_list, size_t index)
247: {
248: size_t i;
249:
250: for(i=0; add_list[i]!=NULL; i++)
251: if(strListInsert(list,add_list[i],index++)==NULL)
252: break;
253:
254: return(i);
255: }
256:
257: str_list_t strListSplit(str_list_t* lp, char* str, const char* delimit)
258: {
259: size_t count;
260: char* token;
261: char* tmp;
262: str_list_t list;
263:
264: if(str==NULL || delimit==NULL)
265: return(NULL);
266:
267: if(lp==NULL) {
268: if((list = strListInit())==NULL)
269: return(NULL);
270: lp=&list;
271: count=0;
272: } else
273: count=strListCount(*lp);
274:
275: for(token = strtok_r(str, delimit, &tmp); token!=NULL; token=strtok_r(NULL, delimit, &tmp))
276: if(strListAppend(lp, token, count++)==NULL)
277: break;
278:
279: return(*lp);
280: }
281:
282: str_list_t strListSplitCopy(str_list_t* list, const char* str, const char* delimit)
283: {
284: char* buf;
285: str_list_t new_list;
286:
287: if(str==NULL || delimit==NULL)
288: return(NULL);
289:
290: if((buf=strdup(str))==NULL)
291: return(NULL);
292:
293: new_list=strListSplit(list,buf,delimit);
294:
295: free(buf);
296:
297: if(list!=NULL)
298: *list = new_list;
299:
300: return(new_list);
301: }
302:
1.1.1.2 ! root 303: size_t strListMerge(str_list_t* list, str_list_t add_list)
1.1 root 304: {
305: size_t i;
306: size_t count;
307:
308: count=strListCount(*list);
309: for(i=0; add_list[i]!=NULL; i++)
310: str_list_append(list,add_list[i],count++);
311:
312: return(i);
313: }
314:
1.1.1.2 ! root 315: char* strListCombine(str_list_t list, char* buf, size_t maxlen, const char* delimit)
! 316: {
! 317: size_t i;
! 318: char* end;
! 319: char* ptr;
! 320:
! 321: if(list==NULL || maxlen<1)
! 322: return(NULL);
! 323:
! 324: if(buf==NULL)
! 325: if((buf=(char*)malloc(maxlen))==NULL)
! 326: return(NULL);
! 327:
! 328: *buf=0;
! 329: end=buf+maxlen;
! 330: for(i=0, ptr=buf; list[i]!=NULL && buf<end; i++)
! 331: ptr += safe_snprintf(ptr, end-ptr, "%s%s", i ? delimit:"", list[i]);
! 332:
! 333: return(buf);
! 334: }
! 335:
1.1 root 336: #if defined(_WIN32)
337: #define QSORT_CALLBACK_TYPE _cdecl
338: #else
339: #define QSORT_CALLBACK_TYPE
340: #endif
341:
342: static int QSORT_CALLBACK_TYPE strListCompareAlpha(const void *arg1, const void *arg2)
343: {
344: return stricmp(*(char**)arg1, *(char**)arg2);
345: }
346:
347: static int QSORT_CALLBACK_TYPE strListCompareAlphaReverse(const void *arg1, const void *arg2)
348: {
349: return stricmp(*(char**)arg2, *(char**)arg1);
350: }
351:
352: static int QSORT_CALLBACK_TYPE strListCompareAlphaCase(const void *arg1, const void *arg2)
353: {
354: return strcmp(*(char**)arg1, *(char**)arg2);
355: }
356:
357: static int QSORT_CALLBACK_TYPE strListCompareAlphaCaseReverse(const void *arg1, const void *arg2)
358: {
359: return strcmp(*(char**)arg2, *(char**)arg1);
360: }
361:
362: void strListSortAlpha(str_list_t list)
363: {
364: qsort(list,strListCount(list),sizeof(char*),strListCompareAlpha);
365: }
366:
367: void strListSortAlphaReverse(str_list_t list)
368: {
369: qsort(list,strListCount(list),sizeof(char*),strListCompareAlphaReverse);
370: }
371:
372: void strListSortAlphaCase(str_list_t list)
373: {
374: qsort(list,strListCount(list),sizeof(char*),strListCompareAlphaCase);
375: }
376:
377: void strListSortAlphaCaseReverse(str_list_t list)
378: {
379: qsort(list,strListCount(list),sizeof(char*),strListCompareAlphaCaseReverse);
380: }
381:
382: void strListFreeStrings(str_list_t list)
383: {
384: size_t i;
385:
386: FREE_LIST_ITEMS(list,i);
387: }
388:
389: void strListFree(str_list_t* list)
390: {
391: if(*list!=NULL) {
392: strListFreeStrings(*list);
393: FREE_AND_NULL(*list);
394: }
395: }
396:
397: static str_list_t str_list_read_file(FILE* fp, str_list_t* lp, size_t max_line_len)
398: {
399: char* buf=NULL;
400: size_t count;
401: str_list_t list;
402:
403: if(max_line_len<1)
404: max_line_len=2048;
405:
406: if(lp==NULL) {
407: if((list = strListInit())==NULL)
408: return(NULL);
409: lp=&list;
410: }
411:
412: if(fp!=NULL) {
413: count=strListCount(*lp);
414: while(!feof(fp)) {
415: if(buf==NULL && (buf=(char*)alloca(max_line_len+1))==NULL)
416: return(NULL);
417:
418: if(fgets(buf,max_line_len+1,fp)==NULL)
419: break;
420: strListAppend(lp, buf, count++);
421: }
422: }
423:
424: return(*lp);
425: }
426:
427: size_t strListInsertFile(FILE* fp, str_list_t* lp, size_t index, size_t max_line_len)
428: {
429: str_list_t list;
430: size_t count;
431:
432: if((list=str_list_read_file(fp, NULL, max_line_len)) == NULL)
433: return(0);
434:
435: count = strListInsertList(lp, list, index);
436:
437: strListFree(&list);
438:
439: return(count);
440: }
441:
442: str_list_t strListReadFile(FILE* fp, str_list_t* lp, size_t max_line_len)
443: {
444: return str_list_read_file(fp,lp,max_line_len);
445: }
446:
447: size_t strListWriteFile(FILE* fp, const str_list_t list, const char* separator)
448: {
449: size_t i;
450:
451: if(list==NULL)
452: return(0);
453:
454: for(i=0; list[i]!=NULL; i++) {
455: if(fputs(list[i],fp)==EOF)
456: break;
457: if(separator!=NULL && fputs(separator,fp)==EOF)
458: break;
459: }
460:
461: return(i);
462: }
463:
464: size_t strListBlockLength(char* block)
465: {
466: char* p=block;
467: size_t str_len;
468: size_t block_len=0;
469:
470: if(block==NULL)
471: return(0);
472:
473: /* calculate total block length */
474: while((str_len=strlen(p))!=0) {
475: block_len+=(str_len + 1);
476: p+=(str_len + 1);
477: }
478: /* block must be double-NULL terminated */
479: if(!block_len)
480: block_len=1;
481: block_len++;
482:
483: return(block_len);
484: }
485:
486: char* strListCopyBlock(char* block)
487: {
488: char* p;
489: size_t block_len;
490:
491: if((block_len=strListBlockLength(block))==0)
492: return(NULL);
493:
494: if((p=(char*)malloc(block_len))==NULL)
495: return(NULL);
496: memcpy(p, block, block_len);
497: return(p);
498: }
499:
500: char* strListAppendBlock(char* block, str_list_t list)
501: {
502: char* p;
503: size_t str_len;
504: size_t block_len;
505: size_t i;
506:
507: if((block_len=strListBlockLength(block))!=0)
508: block_len--; /* Over-write existing NULL terminator */
509:
510: for(i=0; list[i]!=NULL; i++) {
511: str_len=strlen(list[i]);
512: if(str_len==0)
513: continue; /* can't include empty strings in block */
514: if((p=(char*)realloc(block, block_len + str_len + 1))==NULL) {
515: FREE_AND_NULL(block);
516: return(block);
517: }
518: block=p;
519: strcpy(block + block_len, list[i]);
520: block_len += (str_len + 1);
521: }
522:
523: /* block must be double-NULL terminated */
524: if(!block_len)
525: block_len=1;
526: block_len++;
527: if((p=(char*)realloc(block, block_len))==NULL) {
528: FREE_AND_NULL(block);
529: return(block);
530: }
531: block=p;
532: memset(block + (block_len-2), 0, 2);
533:
534: return(block);
535: }
536:
537: char* strListCreateBlock(str_list_t list)
538: {
539: return(strListAppendBlock(NULL,list));
540: }
541:
542: void strListFreeBlock(char* block)
543: {
544: if(block!=NULL)
545: free(block); /* this must be done here for Windows-DLL reasons */
546: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.