Index: ChangeLog
===================================================================
RCS file: /cvsroot/tcllib/tcllib/ChangeLog,v
retrieving revision 1.51
diff -u -r1.51 ChangeLog
--- ChangeLog	2001/03/31 13:44:17	1.51
+++ ChangeLog	2001/04/12 14:34:16
@@ -1,4 +1,8 @@
-2001-03-26  Tcl Project  <a.kupries@westend.com>
+2001-04-12  Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+	* Makefile.in (MODULES): Added module 'csv'.
+
+2001-03-26  Andreas Kupries <andreas_kupries@users.sourceforge.net>
 
 	* Makefile.in (install-libraries):  [Bug #404917]
 	  Added 'smtp' explictly to the list of modules for the full
Index: Makefile.in
===================================================================
RCS file: /cvsroot/tcllib/tcllib/Makefile.in,v
retrieving revision 1.42
diff -u -r1.42 Makefile.in
--- Makefile.in	2001/03/31 13:44:17	1.42
+++ Makefile.in	2001/04/12 14:34:17
@@ -20,6 +20,9 @@
 # Option processing package (like opt)
 CMDLINE=cmdline
 
+# CSV processing
+CSV=csv
+
 # File utilities (grep, find, etc.)
 FILEUTIL=fileutil
 
@@ -78,6 +81,7 @@
 MODULES= \
 	$(BASE64)	\
 	$(CMDLINE)	\
+	$(CSV)		\
 	$(COUNTER)	\
 	$(STRUCT)	\
 	$(FILEUTIL)	\
Index: modules/csv/ChangeLog
===================================================================
RCS file: ChangeLog
diff -N ChangeLog
--- /dev/null	Mon Dec 11 17:26:27 2000
+++ ChangeLog	Thu Apr 12 07:34:17 2001
@@ -0,0 +1,3 @@
+2001-04-12  Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+	* New module for the processing of CSV lines and files.
Index: modules/csv/csv.n
===================================================================
RCS file: csv.n
diff -N csv.n
--- /dev/null	Mon Dec 11 17:26:27 2000
+++ csv.n	Thu Apr 12 07:34:17 2001
@@ -0,0 +1,67 @@
+'\"
+'\" Copyright (c) 2001 by ActiveState Tool Corp.
+'\" All rights reserved.
+'\" 
+'\" RCS: @(#) $Id: log.n,v 1.1 2001/03/26 16:50:21 andreas_kupries Exp $
+'\" 
+.so man.macros
+.TH csv n 1.0 Csv "CSV processing"
+.BS
+'\" Note:  do not modify the .SH NAME line immediately below!
+.SH NAME
+::csv \- Procedures to handle CSV data
+.SH SYNOPSIS
+\fBpackage require csv ?0.1?\fR
+.sp
+\fB::csv::split\fR \fIline {sepChar ,}\fR
+.sp
+\fB::csv::join\fR \fIvalues {sepChar ,}\fR
+.sp
+.BE
+.SH DESCRIPTION
+.PP
+The \fB::csv\fR package provides commands to manipulate information in
+CSV format (CSV = Comma Separated Values).
+.SH FORMAT
+.PP
+Each record of a csv file (comma-separated values, as exported e.g. by
+Excel) is a set of ascii values separated by ",". For other languages
+it may be ";" however, although this is not important for this case
+(The functions provided here allow any separator character).
+.PP
+If a value contains itself the separator ",", then it (the value) is
+put between "".
+.PP
+If a value contains ", it is replaced by "".
+.PP
+The following commands are available:
+.TP
+\fB::csv::split\fR \fIline {sepChar ,}\fR
+converts a line in CSV format into a list of the values contained in
+the line. The separator character can be defined by the caller, but
+this is optional. The default is ",".
+.TP
+\fB::csv::join\fR \fIvalues {sepChar ,}\fR
+Takes a list of values and returns a string in CSV format containing
+these values. The separator character can be defined by the caller,
+but this is optional. The default is ",".
+.SH EXAMPLE
+.PP
+The record
+.TP
+*
+123,"123,521.2","Mary says ""Hello, I am Mary"""
+.PP
+is parsed as follows:
+.TP
+a)
+123
+.TP
+b)
+123,521.2
+.TP
+c)
+Mary says "Hello, I am Mary"
+.SH SEE ALSO
+.SH KEYWORDS
+csv
Index: modules/csv/csv.tcl
===================================================================
RCS file: csv.tcl
diff -N csv.tcl
--- /dev/null	Mon Dec 11 17:26:27 2000
+++ csv.tcl	Thu Apr 12 07:34:17 2001
@@ -0,0 +1,74 @@
+# csv.tcl --
+#
+#	Tcl implementations of CSV reader and writer
+#
+# Copyright (c) 2001 ActiveState Tool Corp.
+#
+# See the file "license.terms" for information on usage and redistribution
+# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+# 
+# RCS: @(#) $Id: csv.tcl,v 1.5 2001/03/26 16:50:21 andreas_kupries Exp $
+
+package provide csv 0.1
+
+namespace eval ::csv {
+    namespace export *
+}
+
+# ::csv::split --
+#
+#	Split a string according to the rules for CSV processing.
+#	This assumes that the string contains a single line of CSVs
+#
+# Arguments:
+#	line		The string to split
+#	sepChar		The separator character, defaults to comma
+#
+# Results:
+#	results		A list of the values in 'line'.
+
+proc ::csv::split {line {sepChar ,}} {
+    regsub -all {(\A\"|\"\Z)} $line \0 line
+    set line [string map [list $sepChar\"\"\" $sepChar\0\" \
+	    \"\"\"$sepChar \"\0$sepChar \
+	    \"\" \" \" \0 ] $line]
+    set end 0
+    while {[regexp -indices -start $end {(\0)[^\0]*(\0)} $line -> start end]} {
+	set start [lindex $start 0]
+	set end   [lindex $end 0]
+	set range [string range $line $start $end]
+	set first [string first $sepChar $range]
+	if {$first >= 0} {
+	    set line [string replace $line $start $end \
+		    [string map [list $sepChar \1] $range]]
+	}
+	incr end
+    }
+    set line [string map [list $sepChar \0 \1 $sepChar \0 {} ] $line]
+    return [::split $line \0]
+}
+
+# ::csv::join --
+#
+#	Takes a list of values and generates a string in CSV format.
+#
+# Arguments:
+#	values		A list of the values to join
+#	sepChar		The separator character, defaults to comma
+#
+# Results:
+#	results		A string containing the values in CSV format.
+
+proc ::csv::join {values {sepChar ,}} {
+    set out ""
+    set sep {}
+    foreach val $values {
+	if {[string match "*\[\"$sepChar\]*" $val]} {
+	    append out $sep\"[string map [list \" \"\"] $val]\"
+	} else {
+	    append out $sep$val
+	}
+	set sep $sepChar
+    }
+    return $out
+}
Index: modules/csv/csv.test
===================================================================
RCS file: csv.test
diff -N csv.test
--- /dev/null	Mon Dec 11 17:26:27 2000
+++ csv.test	Thu Apr 12 07:34:17 2001
@@ -0,0 +1,96 @@
+# -*- tcl -*-
+# Tests for the find function.
+#
+# Sourcing this file into Tcl runs the tests and generates output for errors.
+# No output means no errors were found.
+#
+# Copyright (c) 1998-2000 by Ajuba Solutions.
+# Copyright (c) 2001 by ActiveState Tool Corp.
+# All rights reserved.
+#
+# RCS: @(#) $Id: fileutil.test,v 1.4 2001/03/26 16:50:21 andreas_kupries Exp $
+
+if {[lsearch [namespace children] ::tcltest] == -1} {
+    package require tcltest
+    namespace import ::tcltest::*
+}
+
+if { [lsearch $auto_path [file dirname [info script]]] == -1 } {
+    set auto_path [linsert $auto_path 0 [file dirname [info script]]]
+}
+
+package require csv
+puts "csv [package present csv]"
+
+set str1 {"123","""a""",,hello}
+set str2 {1," o, ""a"" ,b ", 3}
+set str3 {"1"," o, "","" ,b ", 3}
+set str4 {1," foo,bar,baz", 3}
+set str5 {1,"""""a""""",b}
+set str6 {123,"123,521.2","Mary says ""Hello, I am Mary"""}
+
+set str1a {123,"""a""",,hello}
+set str3a {1," o, "","" ,b ", 3}
+
+
+test csv-1.1 {split} {
+    csv::split $str1
+} {123 {"a"} {} hello}
+
+test csv-1.2 {split} {
+    csv::split $str2
+} {1 { o, "a" ,b } { 3}}
+
+test csv-1.3 {split} {
+    csv::split $str3
+} {1 { o, "," ,b } { 3}}
+
+test csv-1.4 {split} {
+    csv::split $str4
+} {1 { foo,bar,baz} { 3}}
+
+test csv-1.5 {split} {
+    csv::split $str5
+} {1 {""a""} b}
+
+test csv-1.6 {split} {
+    csv::split $str6
+} {123 123,521.2 {Mary says "Hello, I am Mary"}}
+
+
+test csv-2.1 {join} {
+    csv::join {123 {"a"} {} hello}
+} $str1a
+
+test csv-2.2 {join} {
+    csv::join {1 { o, "a" ,b } { 3}}
+} $str2
+
+test csv-2.3 {join} {
+    csv::join {1 { o, "," ,b } { 3}}
+} $str3a
+
+test csv-2.4 {join} {
+    csv::join {1 { foo,bar,baz} { 3}}
+} $str4
+
+test csv-2.5 {join} {
+    csv::join {1 {""a""} b}
+} $str5
+
+test csv-2.6 {join} {
+    csv::join {123 123,521.2 {Mary says "Hello, I am Mary"}}
+} $str6
+
+# Malformed inputs
+
+test csv-3.1 {split} {
+    csv::split {abcd,abc",abc}
+} {abcd abc abc}
+
+test csv-3.2 {split} {
+    csv::split {abcd,abc"",abc}
+} {abcd abc\" abc}
+
+::tcltest::cleanupTests
+return
Index: modules/csv/pkgIndex.tcl
===================================================================
RCS file: pkgIndex.tcl
diff -N pkgIndex.tcl
--- /dev/null	Mon Dec 11 17:26:27 2000
+++ pkgIndex.tcl	Thu Apr 12 07:34:21 2001
@@ -0,0 +1,11 @@
+# Tcl package index file, version 1.1
+# This file is generated by the "pkg_mkIndex" command
+# and sourced either when an application starts up or
+# by a "package unknown" script.  It invokes the
+# "package ifneeded" command to set up package-related
+# information so that packages will be loaded automatically
+# in response to "package require" commands.  When this
+# script is sourced, the variable $dir must contain the
+# full path name of this file's directory.
+
+package ifneeded csv 0.1 [list source [file join $dir csv.tcl]]
