From df42f5c0bc1a8757c1b66a92d3fb8faf9a000a87 Mon Sep 17 00:00:00 2001
From: rswindell <>
Date: Wed, 4 Aug 2004 09:41:39 +0000
Subject: [PATCH] Replaced csv_file.* and tab_file.* with combined dat_file.*
 with generic line-based (text) data file API.

---
 src/xpdev/{csv_file.c => dat_file.c} | 205 +++++++++++++++------------
 src/xpdev/{csv_file.h => dat_file.h} |  39 ++++-
 src/xpdev/tab_file.c                 | 161 ---------------------
 src/xpdev/tab_file.h                 |  56 --------
 4 files changed, 145 insertions(+), 316 deletions(-)
 rename src/xpdev/{csv_file.c => dat_file.c} (63%)
 rename src/xpdev/{csv_file.h => dat_file.h} (59%)
 delete mode 100644 src/xpdev/tab_file.c
 delete mode 100644 src/xpdev/tab_file.h

diff --git a/src/xpdev/csv_file.c b/src/xpdev/dat_file.c
similarity index 63%
rename from src/xpdev/csv_file.c
rename to src/xpdev/dat_file.c
index 26119e394b..0271fb088c 100644
--- a/src/xpdev/csv_file.c
+++ b/src/xpdev/dat_file.c
@@ -1,6 +1,6 @@
-/* csv_file.c */
+/* dat_file.c */
 
-/* Functions to deal with comma-separated value (CSV) files and lists */
+/* Functions that deal with line-based (text) data files and lists */
 
 /* $Id$ */
 
@@ -35,12 +35,19 @@
  * Note: If this box doesn't appear square, then you need to fix your tabs.	*
  ****************************************************************************/
 
-#include "csv_file.h"
+#include "dat_file.h"
 #include "genwrap.h"	/* lastchar */
+#include "filewrap.h"	/* chsize */
 #include <stdlib.h>		/* malloc */
 #include <string.h>		/* strdup */
 
-char* csvEncode(char* field)
+#include "truncsp.c"	/* truncsp() and truncnl() */
+
+/***********************************/
+/* CSV (Comma Separated Value) API */
+/***********************************/
+
+static char* csvEncode(char* field)
 {
 	char* dst;
 	char* src;
@@ -80,7 +87,7 @@ char* csvEncode(char* field)
 	return(buf);
 }
 
-char* csvLine(str_list_t columns)
+char* csvLineCreator(str_list_t columns)
 {
 	char*	str=NULL;
 	char*	p;
@@ -108,35 +115,60 @@ char* csvLine(str_list_t columns)
 	return(str);
 }
 
-str_list_t csvCreate(str_list_t records[], str_list_t columns)
+str_list_t csvLineParser(char* line)
 {
 	char*		p;
+	char*		buf;
+	size_t		count=0;
 	str_list_t	list;
-	size_t		i;
-	size_t		li=0;
 
 	if((list=strListInit())==NULL)
 		return(NULL);
 
-	if(columns!=NULL) {
-		p=csvLine(columns);
-		strListAppend(&list,p,li++);
-		free(p);
+	if((buf=strdup(line))==NULL) {
+		strListFree(&list);
+		return(NULL);
 	}
-		
-	if(records!=NULL)
-		for(i=0;records[i]!=NULL;i++) {
-			p=csvLine(records[i]);
-			strListAppend(&list,p,li++);
-			free(p);
-		}
+
+	truncsp(buf);
+
+	for(p=strtok(buf,",");p;p=strtok(NULL,","))
+		strListAppend(&list,p,count++);
+
+	free(buf);
 
 	return(list);
 }
 
-#include "truncsp.c"
+/*********************/
+/* Tab-Delimited API */
+/*********************/
 
-str_list_t csvParseLine(char* line)
+char* tabLineCreator(str_list_t columns)
+{
+	char*	str=NULL;
+	char*	p;
+	size_t	i,len;
+
+	if(columns==NULL)
+		return(NULL);
+
+	for(i=0;columns[i]!=NULL;i++) {
+		len=strlen(columns[i])*2;
+		if(str)
+			len+=strlen(str);
+		if((p=realloc(str,len))==NULL)
+			break;
+		str=p;
+		if(i) strcat(str,"\t");
+		else  *str=0;
+		strcat(str,columns[i]);
+	}
+
+	return(str);
+}
+
+str_list_t tabLineParser(char* line)
 {
 	char*		p;
 	char*		buf;
@@ -151,7 +183,7 @@ str_list_t csvParseLine(char* line)
 		return(NULL);
 	}
 
-	for(p=strtok(buf,",");p;p=strtok(NULL,","))
+	for(p=strtok(buf,"\t");p;p=strtok(NULL,"\t"))
 		strListAppend(&list,p,count++);
 
 	free(buf);
@@ -159,9 +191,58 @@ str_list_t csvParseLine(char* line)
 	return(list);
 }
 
-str_list_t* csvParseList(str_list_t records, str_list_t* columns)
+/* Generic API */
+
+str_list_t dataCreateList(str_list_t records[], str_list_t columns, dataLineCreator_t lineCreator)
+{
+	char*		p;
+	str_list_t	list;
+	size_t		i;
+	size_t		li=0;
+
+	if((list=strListInit())==NULL)
+		return(NULL);
+
+	if(columns!=NULL) {
+		p=lineCreator(columns);
+		strListAppend(&list,p,li++);
+		free(p);
+	}
+		
+	if(records!=NULL)
+		for(i=0;records[i]!=NULL;i++) {
+			p=lineCreator(records[i]);
+			strListAppend(&list,p,li++);
+			free(p);
+		}
+
+	return(list);
+}
+
+BOOL dataWriteFile(FILE* fp, str_list_t records[], str_list_t columns, dataLineCreator_t lineCreator)
+{
+	size_t		count,total;
+	str_list_t	list;
+
+	rewind(fp);
+
+	if(chsize(fileno(fp),0)!=0)	/* truncate */
+		return(FALSE);
+
+	if((list=dataCreateList(records,columns,lineCreator))==NULL)
+		return(FALSE);
+
+	total = strListCount(list);
+	count = strListWriteFile(fp,list,"\n");
+	strListFree(&list);
+
+	return(count == total);
+}
+
+str_list_t* dataParseList(str_list_t records, str_list_t* columns, dataLineParser_t lineParser)
 {
-	size_t		i=0;
+	size_t		ri=0;
+	size_t		li=0;
 	str_list_t* list;
 
 	if(records==NULL)
@@ -171,21 +252,19 @@ str_list_t* csvParseList(str_list_t records, str_list_t* columns)
 		return(NULL);
 
 	if(columns!=NULL) {
-		if((*columns=csvParseLine(records[i++]))==NULL)
+		if((*columns=lineParser(records[ri++]))==NULL)
 			return(NULL);
 	}
 
-	while(records[i]!=NULL) {
-		list[i]=csvParseLine(records[i]);
-		i++;
-	}
+	while(records[ri]!=NULL)
+		list[li++]=lineParser(records[ri++]);
 
-	list[i]=NULL; /* terminate */
+	list[li]=NULL; /* terminate */
 
 	return(list);
 }
 
-str_list_t*	csvReadFile(FILE* fp, str_list_t* columns)
+str_list_t*	dataReadFile(FILE* fp, str_list_t* columns, dataLineParser_t lineParser)
 {
 	str_list_t*	records;
 	str_list_t	lines;
@@ -196,71 +275,13 @@ str_list_t*	csvReadFile(FILE* fp, str_list_t* columns)
 	if((lines=strListReadFile(fp, NULL, 0))==NULL)
 		return(NULL);
 
-	/* truncate white-space off end of strings */
+	/* truncate line-feed chars off end of strings */
 	for(i=0; lines[i]!=NULL; i++)
-		truncsp(lines[i]);
+		truncnl(lines[i]);
 
-	records=csvParseList(lines,columns);
+	records=dataParseList(lines,columns,lineParser);
 
 	strListFree(&lines);
 
 	return(records);
 }
-
-#if 0
-
-int main()
-{
-	char* columns[] =	{"name", "rank", "serial number", NULL};
-	str_list_t	data[3];
-	str_list_t	list;
-	size_t		i;
-
-	data[0]=strListInit();
-	strListPush(&data[0],"rob \"the stud\"");
-	strListPush(&data[0],"general");
-	strListPush(&data[0],"549-71-1344");
-
-	data[1]=strListInit();
-	strListPush(&data[1],"mark");
-	strListPush(&data[1]," colonel");
-	strListPush(&data[1],"x,xx");
-
-	data[2]=NULL;
-
-	list=csvCreate(data, columns);
-
-	for(i=0;list[i];i++)
-		printf("%s\n",list[i]);
-}
-
-#elif 0	/* decode and display .csv file */
-
-void main(int argc, char** argv)
-{
-	str_list_t*	records;
-	str_list_t	columns;
-	FILE*		fp;
-	size_t		i,j;
-
-	if(argc<2) {
-		printf("usage: csv_file <file.csv>\n");
-		exit(0);
-	}
-
-	if((fp=fopen(argv[1],"r"))==NULL) {
-		printf("Error opening %s\n",argv[1]);
-		exit(0);
-	}
-
-	if((records=csvReadFile(fp, &columns))==NULL) {
-		printf("Error reading %s\n",argv[1]);
-		exit(0);
-	}
-
-	for(i=0;records[i];i++)
-		for(j=0;records[i][j];j++)
-			printf("%s[%d]=%s\n",columns[j],i,records[i][j]);
-}
-
-#endif
\ No newline at end of file
diff --git a/src/xpdev/csv_file.h b/src/xpdev/dat_file.h
similarity index 59%
rename from src/xpdev/csv_file.h
rename to src/xpdev/dat_file.h
index 8bd697a8f9..6766eb7fc3 100644
--- a/src/xpdev/csv_file.h
+++ b/src/xpdev/dat_file.h
@@ -1,4 +1,4 @@
-/* csv_file.h */
+/* dat_file.h */
 
 /* Functions to deal with comma-separated value (CSV) files and lists */
 
@@ -35,8 +35,8 @@
  * Note: If this box doesn't appear square, then you need to fix your tabs.	*
  ****************************************************************************/
 
-#ifndef _CSV_FILE_H
-#define _CSV_FILE_H
+#ifndef _DAT_FILE_H
+#define _DAT_FILE_H
 
 #include "str_list.h"
 
@@ -44,10 +44,35 @@
 extern "C" {
 #endif
 
-str_list_t	csvCreateList(str_list_t records[], str_list_t columns /* optional */);
-str_list_t	csvParseLine(char* line);
-str_list_t*	csvParseList(str_list_t list, str_list_t* columns /* optional */);
-str_list_t*	csvReadFile(FILE* fp, str_list_t* columns /* optional */);
+/***************/
+/* Generic API */
+/***************/
+
+typedef str_list_t	(*dataLineParser_t)(char*);
+typedef char*		(*dataLineCreator_t)(str_list_t);
+
+/* columns arguments are optional (may be NULL) */
+str_list_t*	dataParseList(str_list_t list, str_list_t* columns, dataLineParser_t);
+str_list_t*	dataReadFile(FILE* fp, str_list_t* columns, dataLineParser_t);
+
+str_list_t	dataCreateList(str_list_t records[], str_list_t columns, dataLineCreator_t);
+BOOL		dataWriteFile(FILE* fp, str_list_t records[], str_list_t columns, dataLineCreator_t);
+
+/* CSV (comma separated value) API */
+char*		csvLineCreator(str_list_t);
+str_list_t	csvLineParser(char* line);
+#define		csvParseList(list,col)		dataParseList(list,col,csvLineParser)
+#define		csvCreateList(rec,col)		dataCreateList(rec,col,csvLineCreator)
+#define		csvReadFile(fp,col)			dataReadFile(fp,col,csvLineParser)
+#define		csvWriteFile(fp,rec,col)	dataWriteFile(fp,rec,col,csvLineCreator)
+
+/* Tab-delimited API */
+char*		tabLineCreator(str_list_t);
+str_list_t	tabLineParser(char* line);
+#define		tabParseList(list,col)		dataParseList(list,col,tabLineParser)
+#define		tabCreateList(rec,col)		dataCreateList(rec,col,tabLineCreator)
+#define		tabReadFile(fp,col)			dataReadFile(fp,col,tabLineParser)
+#define		tabWriteFile(fp,rec,col)	dataWriteFile(fp,rec,col,tabLineCreator)
 
 #if defined(__cplusplus)
 }
diff --git a/src/xpdev/tab_file.c b/src/xpdev/tab_file.c
deleted file mode 100644
index 0880df1e07..0000000000
--- a/src/xpdev/tab_file.c
+++ /dev/null
@@ -1,161 +0,0 @@
-/* tab_file.c */
-
-/* Functions to deal with tab-delimited files and lists */
-
-/* $Id$ */
-
-/****************************************************************************
- * @format.tab-size 4		(Plain Text/Source Code File Header)			*
- * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
- *																			*
- * Copyright 2004 Rob Swindell - http://www.synchro.net/copyright.html		*
- *																			*
- * This library is free software; you can redistribute it and/or			*
- * modify it under the terms of the GNU Lesser General Public License		*
- * as published by the Free Software Foundation; either version 2			*
- * of the License, or (at your option) any later version.					*
- * See the GNU Lesser General Public License for more details: lgpl.txt or	*
- * http://www.fsf.org/copyleft/lesser.html									*
- *																			*
- * Anonymous FTP access to the most recent released source is available at	*
- * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net	*
- *																			*
- * Anonymous CVS access to the development source and modification history	*
- * is available at cvs.synchro.net:/cvsroot/sbbs, example:					*
- * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login			*
- *     (just hit return, no password is necessary)							*
- * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src		*
- *																			*
- * For Synchronet coding style and modification guidelines, see				*
- * http://www.synchro.net/source.html										*
- *																			*
- * You are encouraged to submit any modifications (preferably in Unix diff	*
- * format) via e-mail to mods@synchro.net									*
- *																			*
- * Note: If this box doesn't appear square, then you need to fix your tabs.	*
- ****************************************************************************/
-
-#include "tab_file.h"
-#include <stdlib.h>		/* malloc */
-
-char* tabLine(str_list_t columns)
-{
-	char*	str=NULL;
-	char*	p;
-	size_t	i,len;
-
-	if(columns==NULL)
-		return(NULL);
-
-	for(i=0;columns[i]!=NULL;i++) {
-		len=strlen(columns[i])*2;
-		if(str)
-			len+=strlen(str);
-		if((p=realloc(str,len))==NULL)
-			break;
-		str=p;
-		if(i) strcat(str,"\t");
-		else  *str=0;
-		strcat(str,columns[i]);
-	}
-
-	return(str);
-}
-
-str_list_t tabCreateList(str_list_t records[], str_list_t columns)
-{
-	char*		p;
-	str_list_t	list;
-	size_t		i;
-	size_t		li=0;
-
-	if((list=strListInit())==NULL)
-		return(NULL);
-
-	if(columns!=NULL) {
-		p=tabLine(columns);
-		strListAppend(&list,p,li++);
-		free(p);
-	}
-		
-	if(records!=NULL)
-		for(i=0;records[i]!=NULL;i++) {
-			p=tabLine(records[i]);
-			strListAppend(&list,p,li++);
-			free(p);
-		}
-
-	return(list);
-}
-
-str_list_t tabParseLine(char* line)
-{
-	char*		p;
-	char*		buf;
-	size_t		count=0;
-	str_list_t	list;
-
-	if((list=strListInit())==NULL)
-		return(NULL);
-
-	if((buf=strdup(line))==NULL) {
-		strListFree(&list);
-		return(NULL);
-	}
-
-	for(p=strtok(buf,"\t");p;p=strtok(NULL,"\t"))
-		strListAppend(&list,p,count++);
-
-	free(buf);
-
-	return(list);
-}
-
-str_list_t* tabParseList(str_list_t records, str_list_t* columns)
-{
-	size_t		i=0;
-	str_list_t* list;
-
-	if(records==NULL)
-		return(NULL);
-
-	if((list=(str_list_t*)malloc(sizeof(str_list_t*)*(strListCount(records)+1)))==NULL)
-		return(NULL);
-
-	if(columns!=NULL) {
-		if((*columns=tabParseLine(records[i++]))==NULL)
-			return(NULL);
-	}
-
-	while(records[i]!=NULL) {
-		list[i]=tabParseLine(records[i]);
-		i++;
-	}
-
-	list[i]=NULL; /* terminate */
-
-	return(list);
-}
-
-#include "truncsp.c"
-
-str_list_t*	tabReadFile(FILE* fp, str_list_t* columns)
-{
-	str_list_t*	records;
-	str_list_t	lines;
-	size_t		i;
-
-	if((lines=strListReadFile(fp, NULL, 0))==NULL)
-		return(NULL);
-
-	/* truncate new-line chars off end of strings */
-	for(i=0; lines[i]!=NULL; i++)
-		truncnl(lines[i]);
-
-	records=tabParseList(lines,columns);
-
-	strListFree(&lines);
-
-	return(records);
-}
-
diff --git a/src/xpdev/tab_file.h b/src/xpdev/tab_file.h
deleted file mode 100644
index 091afa6f95..0000000000
--- a/src/xpdev/tab_file.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/* tab_file.h */
-
-/* Functions to deal with tab-delimited files and lists */
-
-/* $Id$ */
-
-/****************************************************************************
- * @format.tab-size 4		(Plain Text/Source Code File Header)			*
- * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
- *																			*
- * Copyright 2004 Rob Swindell - http://www.synchro.net/copyright.html		*
- *																			*
- * This library is free software; you can redistribute it and/or			*
- * modify it under the terms of the GNU Lesser General Public License		*
- * as published by the Free Software Foundation; either version 2			*
- * of the License, or (at your option) any later version.					*
- * See the GNU Lesser General Public License for more details: lgpl.txt or	*
- * http://www.fsf.org/copyleft/lesser.html									*
- *																			*
- * Anonymous FTP access to the most recent released source is available at	*
- * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net	*
- *																			*
- * Anonymous CVS access to the development source and modification history	*
- * is available at cvs.synchro.net:/cvsroot/sbbs, example:					*
- * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login			*
- *     (just hit return, no password is necessary)							*
- * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src		*
- *																			*
- * For Synchronet coding style and modification guidelines, see				*
- * http://www.synchro.net/source.html										*
- *																			*
- * You are encouraged to submit any modifications (preferably in Unix diff	*
- * format) via e-mail to mods@synchro.net									*
- *																			*
- * Note: If this box doesn't appear square, then you need to fix your tabs.	*
- ****************************************************************************/
-
-#ifndef _TAB_FILE_H
-#define _TAB_FILE_H
-
-#include "str_list.h"
-
-#if defined(__cplusplus)
-extern "C" {
-#endif
-
-str_list_t	tabCreateList(str_list_t records[], str_list_t columns /* optional */);
-str_list_t	tabParseLine(char* line);
-str_list_t*	tabParseList(str_list_t list, str_list_t* columns /* optional */);
-str_list_t*	tabReadFile(FILE* fp, str_list_t* columns /* optional */);
-
-#if defined(__cplusplus)
-}
-#endif
-
-#endif	/* Don't add anything after this line */
-- 
GitLab