Created on 2003-06-06 Howdy y'all, its [Rohan Pall] here, and here is some code I use to glue diff, patch, and md5sum with [Snit]. package require Tk 8.4 package require snit 0.81 puts "loading gunkata..." if {[namespace exists gunkata]} {namespace delete gunkata} namespace eval gunkata { namespace export * proc readb {fn} { set f [open $fn] fconfigure $f -translation binary set content [read $f] close $f return $content } proc writeb {fn c} { set f [open $fn w] fconfigure $f -translation binary puts -nonewline $f $c close $f } } namespace import gunkata::* puts "loading cleric..." if {[namespace exists cleric]} {cleric destroy} snit::type cleric { variable tmpdir constructor {args} { #puts " $self breathes (type $type)" set tmpdir [file join \ [file dirname [info script]] \ cleric_tmp_[pid]_[clock seconds]_[clock clicks] ] file mkdir $tmpdir #puts "@> created tmpdir $tmpdir" $self configurelist $args } destructor { #puts " $self dies (type $type)" file delete -force $tmpdir #puts "@> deleted tmpdir $tmpdir" } method new_sub_tmpdir {} { set sub_tmpdir [file join $tmpdir "tmp_[clock seconds]_[clock clicks]"] file mkdir $sub_tmpdir ; return $sub_tmpdir } method md5_file {fn} {return [lindex [exec md5sum $fn] 0]} method md5_data {data} { set sub_tmpdir [$self new_sub_tmpdir] set data_file [file join $sub_tmpdir data] writeb $data_file $data set md5 [$self md5_file $data_file] file delete -force $sub_tmpdir return $md5 } method patch_data {old_data diff_data} { set sub_tmpdir [$self new_sub_tmpdir] writeb [file join $sub_tmpdir old] $old_data writeb [file join $sub_tmpdir diff] $diff_data set working_dir [pwd] cd $sub_tmpdir ; catch {exec patch -o new old diff} ; cd $working_dir set new_data [readb [file join $sub_tmpdir new]] file delete -force $sub_tmpdir return $new_data } # You get unified diff_data back, but it is not known if it will help # make correct new_data again using patch. # This proc is useless if you care about actually using the diff to # recreate the original data. method diff_data_without_check {old_data new_data} { set sub_tmpdir [$self new_sub_tmpdir] writeb [file join $sub_tmpdir old] $old_data writeb [file join $sub_tmpdir new] $new_data set working_dir [pwd] cd $sub_tmpdir ; catch {exec diff -u old new > diff} ; cd $working_dir set diff_data [readb [file join $sub_tmpdir diff]] file delete -force $sub_tmpdir return $diff_data } # You get unified diff_data that is known to generate the correct data. method diff_data {old_data new_data} { set new_md5 [$self md5_data $new_data] set new_size [string length $new_data] #puts "$new_md5 -- $new_size" set diff_data [$self diff_data_without_check $old_data $new_data] set gen_data [$self patch_data $old_data $diff_data] set gen_md5 [$self md5_data $gen_data] set gen_size [string length $gen_data] #puts "$gen_md5 -- $gen_size" if {($new_md5 eq $gen_md5) && ($new_size eq $gen_size)} { return $diff_data } else { return -code error "could not recreate correct data" } } }