Annotation of sbbs/src/xpdev/dat_file.c, revision 1.1.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.