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