head	1.3;
access;
symbols
	tcllib-1-13:1.3
	tcllib-1-12:1.3
	tklib-0-5:1.3
	tcllib-1-11-1:1.3
	tcllib-1-11:1.3
	tcllib-1-10:1.3
	tcllib-1-9:1.3
	tcllib-1-8:1.3
	tcllib-1-7:1.3
	tcllib-1-6-1:1.2.2.1
	tcllib-1-6-branch:1.2.0.2
	tcllib-1-6:1.2
	tcllib-1-4-0:1.2
	tcllib-1-3-0:1.2
	tcllib-1-2-0:1.1.0.4
	RELEASES:1.1.0.2;
locks; strict;
comment	@# @;


1.3
date	2004.03.09.08.20.17;	author andreas_kupries;	state Exp;
branches;
next	1.2;

1.2
date	2002.05.10.05.51.33;	author andreas_kupries;	state Exp;
branches
	1.2.2.1;
next	1.1;

1.1
date	2002.01.17.17.07.25;	author andreas_kupries;	state Exp;
branches;
next	;

1.2.2.1
date	2004.05.24.02.58.09;	author andreas_kupries;	state Exp;
branches;
next	;


desc
@@


1.3
log
@Unified the startup header of all applications, using
suggestions made by Stuart Cassof <stwo@@telus.net>.
@
text
@#! /bin/sh
# -*- tcl -*- \
exec tclsh "$0" ${1+"$@@"}

# Perform a diff on two CSV files.
# The result is a CSV file

package require csv
package require cmdline

# ----------------------------------------------------
# csvdiff ?-sep sepchar? ?-key LIST? file1 file2
#
# Argument processing and checks.

set sepChar ,
set usage   "Usage: $argv0 ?-n? ?-sep sepchar? ?-key LIST? file1 file2\n\tLIST=idx,...\n\tidx in \{n, -m, n-, n-m\}"
set keySpec "0-"

# lineout = boolean flag, indicates if linenumbers has to be written
# as part of the output (1) or not (0). Defaults to 0.

set lineout 0
while {[set ok [cmdline::getopt argv {sep.arg key.arg n} opt val]] > 0} {
    #puts stderr "= $opt $val"
    switch -exact -- $opt {
	sep   {set sepChar $val}
	key   {set keySpec $val}
	n     {set lineout 1}
    }
}
if {($ok < 0) || ([llength $argv] != 2)} {
    puts stderr $usage
    exit -1
}

foreach {fileA fileB} $argv break


if {[llength $keySpec] == 0} {
    #puts stderr >>$keySpec<<
    #puts stderr B
    puts stderr $usage
    exit -1    
}

set idx [list]
foreach i $keySpec {
    if {[regexp -- {[0-9]+-[0-9]+} $i]} {
	foreach {f t} [split $i -] break
	lappend idx [list $f $t]
    } elseif {[regexp -- {[0-9]+-} $i]} {
	foreach {f t} [split $i -] break
	lappend idx [list $f end]
    } elseif {[regexp -- {-[0-9]+} $i]} {
	foreach {f t} [split $i -] break
	lappend idx [list 0 $t]
    } elseif {[regexp -- {[0-9]+} $i]} {
	lappend idx [list $i $i]
    } else {
	#puts stderr >>$idx<<
	#puts stderr C
	puts stderr $usage
	exit -1
    }
}
set keySpec $idx


set inA [open $fileA r]
set inB [open $fileB r]

# ----------------------------------------------------
# Actual processing, uses the following information from the
# commandline:
#
# inA     - channel for input A
# inB     - channel for input B
# sepChar - separator character

# We read file2 completely and then go through the records of
# file1. For any record we don't find we write a "deleted" record. If
# we find the matching record we remove it from the internal
# storage. In a second sweep through the internal array we write
# "added" records for the remaining data as that was not in file1 but
# is in file2.

proc keyof {data} {
    global keySpec
    set key [list]
    foreach i $keySpec {
	foreach {f t} $i break
	eval lappend key [lrange $data $f $t]
    }
    return $key
}



set order [list]
array set map {}
set linenum 0
while {![eof $inB]} {
    if {[gets $inB line] < 0} {
	continue
    }
    incr linenum
    set  data [::csv::split $line $sepChar]
    set  key  [keyof $data]

    if {[info exist map($key)]} {
	puts stderr "warning: $key occurs multiple times in $fileB (lines $linenum and $map($key))"
    }
    set map($key) $linenum
    lappend order $data
}
close $inB

set linenum 0

if {$lineout} {
    array set lmap {}
}

while {![eof $inA]} {
    if {[gets $inA line] < 0} {
	continue
    }
    incr linenum
    set  data [::csv::split $line $sepChar]
    set  key  [keyof $data]

    if {$lineout} {set lmap($key) $linenum}

    if {[info exists map($key)]} {
	if {$map($key) < 0} {
	    puts stderr "warning: $key occurs multiple times\
		    in $fileA (lines $linenum and [expr {-$map($key)}]"
	} else {
	    set map($key) [expr {-$linenum}]
	}
	continue
    }

    if {$lineout} {
	puts stdout [::csv::join [linsert $data 0 - $linenum] $sepChar]
    } else {
	puts stdout [::csv::join [linsert $data 0 -] $sepChar]
    }
}
close $inA

foreach data $order {
    set key [keyof $data]
    if {$map($key) > 0} {
	if {$lineout} {
	    puts stdout [::csv::join [linsert $data 0 + $lmap($key)] $sepChar]
	} else {
	    puts stdout [::csv::join [linsert $data 0 +] $sepChar]
	}
    }
}

exit
@


1.2
log
@
	* examples/csv/csvdiff: Applied patch associated with tcllib SF
	  bug #551133. Bug reported by <lvirden@@users.sourceforge.net>,
	  patch by <dgp@@users.sourceforge.net>.

	  Accepted FR #551127 and added code implementing the feature.
@
text
@d1 4
a4 3
#!/bin/sh
# use -*- tcl -*- \
exec tclsh "$0" "$@@"
@


1.2.2.1
log
@Downgraded to version 1.3.6, removed -decode extension from
this branch.

Import of ftpd bugfix by Gerald Lester.

Last commit was a bad update, caused duplicates of changes
to appear. Failed testsuite. Removed all the duplicates now.

Fixed SF Tcllib Bug 954328. Mime now adapts at runtime to
whatever version of md5 has been loaded.

Updated test for rewritten adjust which fixed the infinite
looping demonstrated by tests 2.6 and 2.7. Also fixed a var
usage typo which caused a copy of the input to appear in the
output, before the expected formatted result.

Fixed bug in the processing of multi-word section titles for
text based formats.

Fixed bug 951568, regarding the usage of Trf's generic
transform.

Fixed problems with jpeg recognition (was unable to detect a
jpeg file, if it contained exif data).

Changelog for last patch, and updates in related package.

Completed application of code for various fixes.

Rewritten text adjustment and hyphenation, fixing SF TCllib
Bug 882402.

Fixed SF Tcllib Bug 936064, and evals more robust.

Fixed SF Tcllib Bug 893516

Fixed SF Tcllib Patch 763712

Fixed SF Tcllib Patch 758742

Fixed SF Tcllib Bug 620852

Eval usage made more robust and similar.

Fixed SF Tcllib Bug 943146.

Fixed SF Tcllib Bug 940651

SF Tcllib Bug 784519 fixed.

Pat: sak.tcl update for better use of critcl.

Joe: Fix in doctools xml support.

Import bugfix by Pat Thoyts, Handling of data starting with
hyphen/dash

Import of uuencode changes by Jeff Hobbs.

Changed defaults for package 'log'. No output for the all
levels below 'error'.

Unified the startup header of all applications, using
suggestions made by Stuart Cassof <stwo@@telus.net>.

Added testcase for Tcllib SF Bug 860753. The bug itself was
already fixed for Tcllib 1.6.

Fix for bug 899204. Test data file is opened read-only, and
tests made independent of each other.

Bugfix 899152, 899209. Require Tcl 8.2 for installer, delete
file before writing over it.

Import of time fix by Pat Thoyts, patch #905132.

Cleanup fix: Snit depends on Tcl 8.4, this is documented,
however neither package index, nor testsuite enforced the
restriction, allowing for errors. This has been changed now.

Fixed typos
@
text
@d1 3
a3 4
#! /bin/sh
# -*- tcl -*- \
exec tclsh "$0" ${1+"$@@"}

@


1.1
log
@
	* examples/csv/csvdiff: New example for csv module. FR #485717.
@
text
@d16 1
a16 1
set usage   "Usage: $argv0 ?-sep sepchar? ?-key LIST? file1 file2\n\tLIST=idx,...\n\tidx in \{n, -m, n-, n-m\}"
d19 5
a23 1
while {[set ok [cmdline::getopt argv {sep.arg key.arg} opt val]] > 0} {
d28 1
d36 1
a36 1
foreach {inA inB} $argv break
d69 2
a70 2
set inA [open $inA r]
set inB [open $inB r]
d83 3
a85 3
# storage. In a second sweep through internal array we write "added"
# records for the remaining data as that was not in file1 but is in
# file2.
d101 1
d106 3
d110 4
a113 3
    set data [::csv::split $line $sepChar]
    set key [keyof $data]
    set map($key) .
d118 6
d128 5
a132 1
    set data [::csv::split $line $sepChar]
a133 1
    set key [keyof $data]
d135 6
a140 1
	unset map($key)
d144 5
a148 1
    puts stdout [::csv::join [linsert $data 0 -] $sepChar]
d150 1
d154 6
a159 2
    if {[info exists map($key)]} {
	puts stdout [::csv::join [linsert $data 0 +] $sepChar]
@

