|
|
1.1 root 1: /* dat_file.c */
2:
3: /* Functions that deal with line-based (text) data files and lists */
4:
5: /* $Id: dat_file.c,v 1.2 2004/09/11 09:24:55 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 2004 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 "dat_file.h"
39: #include "genwrap.h" /* lastchar */
40: #include "filewrap.h" /* chsize */
41: #include <stdlib.h> /* malloc */
42: #include <string.h> /* strdup */
43:
44: /***********************************/
45: /* CSV (Comma Separated Value) API */
46: /***********************************/
47:
48: static char* csvEncode(char* field)
49: {
50: char* dst;
51: char* src;
52: char* buf;
53: char* comma;
54: char* quote;
55: char first;
56: char last;
57: char* nl;
58: BOOL enclose;
59:
60: if((buf=malloc(strlen(field)*2))==NULL)
61: return(NULL);
62:
63: nl=strchr(field,'\n');
64: comma=strchr(field,',');
65: quote=strchr(field,'"');
66: first=field[0];
67: last=*lastchar(field);
68:
69: enclose = (quote || comma || nl || first==' ' || last==' ');
70:
71: dst=buf;
72: if(enclose)
73: *(dst++)='"';
74: src=field;
75: while(*src) {
76: if(*src=='"')
77: *(dst++)='"'; /* escape quotes */
78: *(dst++)=*src++;
79: }
80: if(enclose)
81: *(dst++)='"';
82:
83: *dst=0;
84:
85: return(buf);
86: }
87:
88: char* csvLineCreator(str_list_t columns)
89: {
90: char* str=NULL;
91: char* p;
92: char* val;
93: size_t i,len;
94:
95: if(columns==NULL)
96: return(NULL);
97:
98: for(i=0;columns[i]!=NULL;i++) {
99: len=strlen(columns[i])*2;
100: if(str)
101: len+=strlen(str);
102: if((p=realloc(str,len))==NULL)
103: break;
104: str=p;
105: if(i) strcat(str,",");
106: else *str=0;
107: if((val=csvEncode(columns[i]))==NULL)
108: break;
109: strcat(str,val);
110: free(val);
111: }
112:
113: return(str);
114: }
115:
116: str_list_t csvLineParser(char* line)
117: {
118: char* p;
119: char* buf;
120: size_t count=0;
121: str_list_t list;
122:
123: if((list=strListInit())==NULL)
124: return(NULL);
125:
126: if((buf=strdup(line))==NULL) {
127: strListFree(&list);
128: return(NULL);
129: }
130:
131: truncsp(buf);
132:
133: for(p=strtok(buf,",");p;p=strtok(NULL,","))
134: strListAppend(&list,p,count++);
135:
136: free(buf);
137:
138: return(list);
139: }
140:
141: /*********************/
142: /* Tab-Delimited API */
143: /*********************/
144:
145: char* tabLineCreator(str_list_t columns)
146: {
147: char* str=NULL;
148: char* p;
149: size_t i,len;
150:
151: if(columns==NULL)
152: return(NULL);
153:
154: for(i=0;columns[i]!=NULL;i++) {
155: len=strlen(columns[i])*2;
156: if(str)
157: len+=strlen(str);
158: if((p=realloc(str,len))==NULL)
159: break;
160: str=p;
161: if(i) strcat(str,"\t");
162: else *str=0;
163: strcat(str,columns[i]);
164: }
165:
166: return(str);
167: }
168:
169: str_list_t tabLineParser(char* line)
170: {
171: char* p;
172: char* buf;
173: size_t count=0;
174: str_list_t list;
175:
176: if((list=strListInit())==NULL)
177: return(NULL);
178:
179: if((buf=strdup(line))==NULL) {
180: strListFree(&list);
181: return(NULL);
182: }
183:
184: for(p=strtok(buf,"\t");p;p=strtok(NULL,"\t"))
185: strListAppend(&list,p,count++);
186:
187: free(buf);
188:
189: return(list);
190: }
191:
192: /* Generic API */
193:
194: str_list_t dataCreateList(str_list_t records[], str_list_t columns, dataLineCreator_t lineCreator)
195: {
196: char* p;
197: str_list_t list;
198: size_t i;
199: size_t li=0;
200:
201: if((list=strListInit())==NULL)
202: return(NULL);
203:
204: if(columns!=NULL) {
205: p=lineCreator(columns);
206: strListAppend(&list,p,li++);
207: free(p);
208: }
209:
210: if(records!=NULL)
211: for(i=0;records[i]!=NULL;i++) {
212: p=lineCreator(records[i]);
213: strListAppend(&list,p,li++);
214: free(p);
215: }
216:
217: return(list);
218: }
219:
220: BOOL dataWriteFile(FILE* fp, str_list_t records[], str_list_t columns, dataLineCreator_t lineCreator)
221: {
222: size_t count,total;
223: str_list_t list;
224:
225: rewind(fp);
226:
227: if(chsize(fileno(fp),0)!=0) /* truncate */
228: return(FALSE);
229:
230: if((list=dataCreateList(records,columns,lineCreator))==NULL)
231: return(FALSE);
232:
233: total = strListCount(list);
234: count = strListWriteFile(fp,list,"\n");
235: strListFree(&list);
236:
237: return(count == total);
238: }
239:
240: str_list_t* dataParseList(str_list_t records, str_list_t* columns, dataLineParser_t lineParser)
241: {
242: size_t ri=0;
243: size_t li=0;
244: str_list_t* list;
245:
246: if(records==NULL)
247: return(NULL);
248:
249: if((list=(str_list_t*)malloc(sizeof(str_list_t*)*(strListCount(records)+1)))==NULL)
250: return(NULL);
251:
252: if(columns!=NULL) {
253: if((*columns=lineParser(records[ri++]))==NULL)
254: return(NULL);
255: }
256:
257: while(records[ri]!=NULL)
258: list[li++]=lineParser(records[ri++]);
259:
260: list[li]=NULL; /* terminate */
261:
262: return(list);
263: }
264:
265: str_list_t* dataReadFile(FILE* fp, str_list_t* columns, dataLineParser_t lineParser)
266: {
267: str_list_t* records;
268: str_list_t lines;
269: size_t i;
270:
271: rewind(fp);
272:
273: if((lines=strListReadFile(fp, NULL, 0))==NULL)
274: return(NULL);
275:
276: /* truncate line-feed chars off end of strings */
277: for(i=0; lines[i]!=NULL; i++)
278: truncnl(lines[i]);
279:
280: records=dataParseList(lines,columns,lineParser);
281:
282: strListFree(&lines);
283:
284: return(records);
285: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.