Updated 2004-10-05 14:04:59 by CMCc

A quickie to apply patches generated by diff -n (so-called rcs format) - CMcC 20041006
   # patch a file given diffs in rcs (diff -n) format
   package require fileutil

   namespace eval rcs {}

   # convert \n delimited file to an array indexed by line name
   proc rcs::file2array {filename arr} {
       upvar 1 $arr lines
       set lnum 0
       fileutil::foreachLine line $filename {
   	set lines([incr lnum]) $line
       }
   }

   # convert \n delimited text to an array indexed by line name
   proc rcs::text2array {text arr} {
       upvar 1 $arr lines
       set lnum 0
       foreach line [split $text \n] {
   	set lines([incr lnum]) $line
       }
   }

   # Apply some rcs diff -n format patches to the text in array
   proc rcs::patch {patch arr} {
       upvar 1 $arr lines
       set patch [split $patch \n]
       while {$patch != {}} {
   	set pc [string trim [lindex $patch 0]]
   	puts stderr "doing $pc"
   	set patch [lrange $patch 1 end]
   	switch -glob -- $pc {
   	    "" {}
   	    a* {
   		foreach {start len} [split [string range $pc 1 end]] break
   		set adding [join [lrange $patch 0 [expr {$len - 1}]] \n]
   		if {[info exists lines($start)]} {
   		    append lines($start) \n
   		}
   		append lines($start) "$adding"
   		puts stderr "ADD: '$adding'"
   		set patch [lrange $patch $len end]
   		puts stderr "$pc: $lines($start)"
   	    }
   	    d* {
   		foreach {start len} [split [string range $pc 1 end]] break
   		while {$len > 0} {
   		    puts stderr "DEL $start: $lines($start)"
   		    unset lines($start)
   		    incr start
   		    incr len -1
   		}
   	    }
   	    default {
   		error "Unknown patch: '$pc'"
   	    }
   	}
       }

       set result ""
       foreach lnum [lsort -integer [array names lines]] {
   	append result \n $lines($lnum)
       }

       return [string range $result 1 end]
   }