|
|
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.