Annotation of sbbs/src/xpdev/dat_file.c, revision 1.1

1.1     ! root        1: /* dat_file.c */
        !             2: 
        !             3: /* Functions to deal with comma (CSV) and tab-delimited files and lists */
        !             4: 
        !             5: /* $Id: dat_file.c,v 1.5 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 "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(const 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(const char* line)
        !           117: {
        !           118:        char*           p;
        !           119:        char*           buf;
        !           120:        char*           tmp;
        !           121:        size_t          count=0;
        !           122:        str_list_t      list;
        !           123: 
        !           124:        if((list=strListInit())==NULL)
        !           125:                return(NULL);
        !           126: 
        !           127:        if((buf=strdup(line))==NULL) {
        !           128:                strListFree(&list);
        !           129:                return(NULL);
        !           130:        }
        !           131: 
        !           132:        truncsp(buf);
        !           133: 
        !           134:        for(p=strtok_r(buf,",",&tmp);p;p=strtok_r(NULL,",",&tmp))
        !           135:                strListAppend(&list,p,count++);
        !           136: 
        !           137:        free(buf);
        !           138: 
        !           139:        return(list);
        !           140: }
        !           141: 
        !           142: /*********************/
        !           143: /* Tab-Delimited API */
        !           144: /*********************/
        !           145: 
        !           146: char* tabLineCreator(const str_list_t columns)
        !           147: {
        !           148:        char*   str=NULL;
        !           149:        char*   p;
        !           150:        size_t  i,len;
        !           151: 
        !           152:        if(columns==NULL)
        !           153:                return(NULL);
        !           154: 
        !           155:        for(i=0;columns[i]!=NULL;i++) {
        !           156:                len=strlen(columns[i])*2;
        !           157:                if(str)
        !           158:                        len+=strlen(str);
        !           159:                if((p=realloc(str,len))==NULL)
        !           160:                        break;
        !           161:                str=p;
        !           162:                if(i) strcat(str,"\t");
        !           163:                else  *str=0;
        !           164:                strcat(str,columns[i]);
        !           165:        }
        !           166: 
        !           167:        return(str);
        !           168: }
        !           169: 
        !           170: str_list_t tabLineParser(const char* line)
        !           171: {
        !           172:        char*           p;
        !           173:        char*           buf;
        !           174:        char*           tmp;
        !           175:        size_t          count=0;
        !           176:        str_list_t      list;
        !           177: 
        !           178:        if((list=strListInit())==NULL)
        !           179:                return(NULL);
        !           180: 
        !           181:        if((buf=strdup(line))==NULL) {
        !           182:                strListFree(&list);
        !           183:                return(NULL);
        !           184:        }
        !           185: 
        !           186:        for(p=strtok_r(buf,"\t",&tmp);p;p=strtok_r(NULL,"\t",&tmp))
        !           187:                strListAppend(&list,p,count++);
        !           188: 
        !           189:        free(buf);
        !           190: 
        !           191:        return(list);
        !           192: }
        !           193: 
        !           194: /* Generic API */
        !           195: 
        !           196: str_list_t dataCreateList(const str_list_t records[], const str_list_t columns, dataLineCreator_t lineCreator)
        !           197: {
        !           198:        char*           p;
        !           199:        str_list_t      list;
        !           200:        size_t          i;
        !           201:        size_t          li=0;
        !           202: 
        !           203:        if((list=strListInit())==NULL)
        !           204:                return(NULL);
        !           205: 
        !           206:        if(columns!=NULL) {
        !           207:                p=lineCreator(columns);
        !           208:                strListAppend(&list,p,li++);
        !           209:                free(p);
        !           210:        }
        !           211:                
        !           212:        if(records!=NULL)
        !           213:                for(i=0;records[i]!=NULL;i++) {
        !           214:                        p=lineCreator(records[i]);
        !           215:                        strListAppend(&list,p,li++);
        !           216:                        free(p);
        !           217:                }
        !           218: 
        !           219:        return(list);
        !           220: }
        !           221: 
        !           222: BOOL dataWriteFile(FILE* fp, const str_list_t records[], const str_list_t columns, const char* separator
        !           223:                                   ,dataLineCreator_t lineCreator)
        !           224: {
        !           225:        size_t          count,total;
        !           226:        str_list_t      list;
        !           227: 
        !           228:        rewind(fp);
        !           229: 
        !           230:        if(chsize(fileno(fp),0)!=0)     /* truncate */
        !           231:                return(FALSE);
        !           232: 
        !           233:        if((list=dataCreateList(records,columns,lineCreator))==NULL)
        !           234:                return(FALSE);
        !           235: 
        !           236:        total = strListCount(list);
        !           237:        count = strListWriteFile(fp,list,separator);
        !           238:        strListFree(&list);
        !           239: 
        !           240:        return(count == total);
        !           241: }
        !           242: 
        !           243: str_list_t* dataParseList(const str_list_t records, str_list_t* columns, dataLineParser_t lineParser)
        !           244: {
        !           245:        size_t          ri=0;
        !           246:        size_t          li=0;
        !           247:        str_list_t* list;
        !           248: 
        !           249:        if(records==NULL)
        !           250:                return(NULL);
        !           251: 
        !           252:        if((list=(str_list_t*)malloc(sizeof(str_list_t*)*(strListCount(records)+1)))==NULL)
        !           253:                return(NULL);
        !           254: 
        !           255:        if(columns!=NULL) {
        !           256:                if((*columns=lineParser(records[ri++]))==NULL)
        !           257:                        return(NULL);
        !           258:        }
        !           259: 
        !           260:        while(records[ri]!=NULL)
        !           261:                list[li++]=lineParser(records[ri++]);
        !           262: 
        !           263:        list[li]=NULL; /* terminate */
        !           264: 
        !           265:        return(list);
        !           266: }
        !           267: 
        !           268: str_list_t*    dataReadFile(FILE* fp, str_list_t* columns, dataLineParser_t lineParser)
        !           269: {
        !           270:        str_list_t*     records;
        !           271:        str_list_t      lines;
        !           272:        size_t          i;
        !           273: 
        !           274:        rewind(fp);
        !           275: 
        !           276:        if((lines=strListReadFile(fp, NULL, 0))==NULL)
        !           277:                return(NULL);
        !           278: 
        !           279:        /* truncate line-feed chars off end of strings */
        !           280:        for(i=0; lines[i]!=NULL; i++)
        !           281:                truncnl(lines[i]);
        !           282: 
        !           283:        records=dataParseList(lines,columns,lineParser);
        !           284: 
        !           285:        strListFree(&lines);
        !           286: 
        !           287:        return(records);
        !           288: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.