Annotation of sbbs/xpdev/dat_file.c, revision 1.1.1.1

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: }

unix.superglobalmegacorp.com

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