From azcb0@ccc.amdahl.com Tue Apr 11 13:29:57 1995 Newsgroups: comp.lang.tcl Path: dove.nist.gov!uunet!news.mathworks.com!udel!gatech!howland.reston.ans.net!news.sprintlink.net!news.clark.net!rahul.net!a2i!olivea!nntp-hub2.barrnet.net!nntp-sc.barrnet.net!news.fujitsu.com!amdahl.com!juts.ccc.amdahl.com!azcb0 From: azcb0@ccc.amdahl.com (Alistair G. Crooks) Subject: idiff - interactive diff program Message-ID: <1995Apr11.130256.4702@ccc.amdahl.com> Reply-To: azcb0@JUTS.ccc.amdahl.com (Alistair G. Crooks) Organization: Amdahl Corporation, Sunnyvale CA Date: Tue, 11 Apr 1995 13:02:56 GMT Lines: 195 I've translated the idiff program from Kernighan & Pike's "The Unix Programming Environment" from C into tcl. This version of idiff uses expect. For those of you still a bit unsure, idiff is an interactive diff program, taking two files, running diff on them, and then prompting the user to decide which version of each difference to include in the output. Individual diffs may be edited, using the user's preferred editor, and external commands may be run. The command line to run idiff thus looks like: idiff file1 file2 and the resulting output is placed in the file idiff.out. Within idiff, 3 commands may be used: > take the right hand diff, i.e. the version from file2 < take the left hand diff, i.e. the version from file1 e edit the left and right hand diffs, and include the result ! execute an external command I've uploaded it to ftp.aud.alcatel.com:/tcl/incoming, and it should also be available from ftp://charon.amdahl.com/pub/agc/idiff Cheers, Alistair -- Alistair G. Crooks (agc@uts.amdahl.com) +44 125 234 6377 Amdahl European HQ, Dogmersfield Park, Hartley Wintney, Hants RG27 8TE, UK. [These are only my opinions, and certainly not those of Amdahl Corporation] #! /usr/local/bin/expect # # idiff, version 5.15 # # An interactive diff program, written in tcl from the version # written in C from Kernighan & Pike's "The Unix Programming Environment" # uses expect to spawn the vi process. # # Translated to tcl by # Alistair G. Crooks (agc@uts.amdahl.com) # 11th April 1995 # parse the diff command held in `s' proc parse { s from1name to1name cmdname from2name to2name } { upvar $from1name from1 upvar $to1name to1 upvar $cmdname cmd upvar $from2name from2 upvar $to2name to2 # don't change the order of these regexps, otherwise you'll # recognise the wrong expression at the wrong time if { [regexp -- "(\[0-9\]+),(\[0-9\]+)(\[a-z\])(\[0-9\]+),(\[0-9\]+)" \ $s a from1 to1 cmd to1 to2] } { return 1 } if { [regexp -- "(\[0-9\]+)(\[a-z\])(\[0-9\]+),(\[0-9\]+)" \ $s a from1 cmd from2 to2] } { set to1 $from1 return 1 } if { [regexp -- "(\[0-9\]+),(\[0-9\]+)(\[a-z\])(\[0-9\]+)" \ $s a from1 to1 cmd from2] } { set to2 $from2 return 1 } if { [regexp -- "(\[0-9\]+)(\[a-z\])(\[0-9\]+)" \ $s a from1 cmd from2] } { set to1 $from1 set to2 $from2 return 1 } return 0 } # skip `n' lines from `fin' proc nskip { fin n } { for {} { $n > 0 } { incr n -1 } { gets $fin buf } } # copy `n' lines from `fin' to `fout' proc ncopy { fin n fout } { if { $n == "all" } { while { [gets $fin buf] >= 0 } { puts $fout "$buf" } } else { for {} { $n > 0 } { incr n -1 } { if { [gets $fin buf] < 0 } { return } puts $fout "$buf" } } } # produce the interactive diff of files `f1' and `f2' from `fin' to `fout' proc idiff { f1 f2 fin fout } { set nf1 0 set nf2 0 while { [gets $fin buf] >= 0 } { # parse the diff command if { ![parse $buf from1 to1 cmd from2 to2] } { break } # calculate the number of lines to print out set n [expr $to1-$from1+$to2-$from2+1] switch $cmd { c { incr n 2 } a { incr from1 1 } d { incr from2 1 } } # print out the diff puts stdout "$buf" for {} { $n > 0 } { incr n -1 } { gets $fin buf puts stdout $buf } while 1 { puts -nonewline stdout "? " gets stdin in switch -regexp -- $in { ^\> { nskip $f1 [expr $to1-$nf1] ncopy $f2 [expr $to2-$nf2] $fout break } ^\< { nskip $f2 [expr $to2-$nf2] ncopy $f1 [expr $to1-$nf1] $fout break } ^e { ncopy $f1 [expr $from1-1-$nf1] $fout nskip $f2 [expr $from2-1-$nf2] set tmp [open "idiff.tmp" "w"] ncopy $f1 [expr $to1+1-$from1] $tmp puts $tmp "---" ncopy $f2 [expr $to2+1-$from2] $tmp close $tmp global editor set pid [spawn $editor idiff.tmp] interact set tmp [open "idiff.tmp"] ncopy $tmp all $fout close $tmp exec rm idiff.tmp break } ^! { set pid [eval spawn \ [string range $in 1 end]] interact } default { puts stderr "Use `<', `>', `e' or `!'" } } } set nf1 $to1 set nf2 $to2 } ncopy $f1 all $fout } # check the command line arguments if { [llength $argv] != 2 } { puts stderr "Usage: $argv0 file1 file2" exit 1 } # find the user's editor set editor "vi" if { [info exists env(EDITOR)] } { set editor $env(EDITOR) } if { [info exists env(VISUAL)] } { set editor $env(VISUAL) } # open files set fp1 [open [lindex $argv 0]] set fp2 [open [lindex $argv 1]] # open the diff pipeline set fin [open "| diff [lindex $argv 0] [lindex $argv 1]"] set fout [open idiff.out w] idiff $fp1 $fp2 $fin $fout puts stdout "Output in file idiff.out" exit 0