rcs.tcl

Go to the documentation of this file.
00001 /*  rcs.tcl --*/
00002 /* */
00003 /*  Utilities for RCS related operations.*/
00004 /* */
00005 /*  Copyright (c) 2005 by Colin McCormack <coldstore@users.sourceforge.net>*/
00006 /*  Copyright (c) 2005 by Andreas Kupries <andreas_kupries@users.sourceforge.net>*/
00007 /* */
00008 /*  See the file "license.terms" for information on usage and redistribution*/
00009 /*  of this file, and for a DISCLAIMER OF ALL WARRANTIES.*/
00010 /*  */
00011 /*  RCS: @(#) $Id: rcs.tcl,v 1.4 2005/09/28 04:51:23 andreas_kupries Exp $*/
00012 
00013 /*  ### ### ### ######### ######### #########*/
00014 /*  Requisites.*/
00015 
00016 package require Tcl 8.4
00017 
00018 /*  ### ### ### ######### ######### #########*/
00019 /*  API Implementation*/
00020 
00021 namespace rcs {}
00022 
00023 /*  ::rcs::text2dict --*/
00024 /* */
00025 /*  Convert a text into a dictionary. The dictionary is keyed by line*/
00026 /*  numbers, and the value is the text of the corresponding line. The*/
00027 /*  first line has index/number 1.*/
00028 /* */
00029 /*  Arguments*/
00030 /*  - text  The text to convert.*/
00031 /* */
00032 /*  Results*/
00033 /*   A dictionary containing the text in split form.*/
00034 /* */
00035 /*  Side effects*/
00036 /*   None*/
00037 
00038 ret  ::rcs::text2dict (type text) {
00039     array set lines {}
00040     set lnum 0
00041     foreach line [split $text \n] {
00042     set lines([incr lnum]) $line
00043     }
00044     return [array get lines]
00045 }
00046 
00047 /*  ::rcs::file2dict --*/
00048 /* */
00049 /*  Convert a text stored in a file into a dictionary. The dictionary is*/
00050 /*  keyed by line numbers, and the value is the text of the*/
00051 /*  corresponding line. The first line has index/number 1.*/
00052 /* */
00053 /*  Arguments*/
00054 /*  - file  The path of the file containing the text to convert.*/
00055 /* */
00056 /*  Results*/
00057 /*   A dictionary containing the text in split form.*/
00058 /* */
00059 /*  Side effects*/
00060 /*   None*/
00061 
00062 ret  ::rcs::file2dict (type filename) {
00063     set chan [open $filename r]
00064     set text [read $chan]
00065     close $chan
00066 
00067     return [text2dict $text]
00068 }
00069 
00070 /*  ::rcs::dict2text --*/
00071 /* */
00072 /*  Converts a dictionary as created by the 2dict commands back into a*/
00073 /*  text. The dictionary is keyed by line numbers, and the value is the*/
00074 /*  text of the corresponding line. The first line has index/number 1.*/
00075 /*  The dictionary may have gaps in the line numbers.*/
00076 /* */
00077 /*  Arguments*/
00078 /*  - dict  The dictionary to convert.*/
00079 /* */
00080 /*  Results*/
00081 /*   The text stored in the dictionary.*/
00082 /* */
00083 /*  Side effects*/
00084 /*   None*/
00085 
00086 ret  ::rcs::dict2text (type dict) {
00087     array set lines $dict
00088     set result {}
00089     foreach lnum [lsort -integer [array names lines]] {
00090     lappend result $lines($lnum)
00091     }
00092     return [join $result \n]
00093 }
00094 
00095 /*  ::rcs::dict2file --*/
00096 /* */
00097 /*  Converts a dictionary as created by the 2dict commands back into a*/
00098 /*  text and stores it into the specified file. The dictionary is keyed*/
00099 /*  by line numbers, and the value is the text of the corresponding*/
00100 /*  line. The first line has index/number 1.  The dictionary may have*/
00101 /*  gaps in the line numbers.*/
00102 /* */
00103 /*  Arguments*/
00104 /*  - filename  The path to the file to store the reconstructed text into.*/
00105 /*  - dict  The dictionary to convert.*/
00106 /* */
00107 /*  Results*/
00108 /*   None.*/
00109 /* */
00110 /*  Side effects*/
00111 /*   None*/
00112 
00113 ret  ::rcs::dict2file (type filename , type dict) {
00114     set chan [open $filename w]
00115     puts -nonewline $chan [dict2text $dict]
00116     close $chan
00117 }
00118 
00119 /*  ::rcs::decodeRcsPatch --*/
00120 /* */
00121 /*  Converts a text containing a RCS patch (diff -n format) into a list*/
00122 /*  of patch commands. Each element of the list is a list containing the*/
00123 /*  patch command and its arguments, in this order.*/
00124 /* */
00125 /*  The valid patch commands are 'a' and 'd'. 'a' has two arguments, the*/
00126 /*  index of the line where to add the text, and the text itself. The*/
00127 /*  'd' command has two arguments as well, the index of the first line*/
00128 /*  to delete, and the number of lines to delete.*/
00129 /* */
00130 /*  Arguments*/
00131 /*  - patch The text in diff -n format, the patch to parse.*/
00132 /* */
00133 /*  Results*/
00134 /*    A list containing the patch as sequence of commands.*/
00135 /* */
00136 /*  Side effects*/
00137 /*   None*/
00138 
00139 ret  ::rcs::decodeRcsPatch (type patch) {
00140     set patch [split $patch \n]
00141     set plen  [llength $patch]
00142     set at    0
00143     set res   {}
00144 
00145     while {$at < $plen} {
00146     # I use an index into the list to avoid shifting the list
00147     # elements down with each line processed. That is a lot of
00148     # memcpy's.
00149 
00150     set cmd [string trim [lindex $patch $at]]
00151     incr at
00152 
00153     switch -glob -- $cmd {
00154         "" {}
00155         a* {
00156         foreach {start len} [split [string range $cmd 1 end]] break
00157 
00158         set to [expr {$at + $len - 1}]
00159         lappend res [list \
00160                  a \
00161                  $start \
00162                  [join [lrange $patch $at $to] \n]]
00163         incr to
00164         set at $to
00165         }
00166         d* {
00167         foreach {start len} [split [string range $cmd 1 end]] break
00168         lappend res [list d $start $len]
00169         }
00170         default {
00171         return -code error "Unknown patch command: '$cmd'"
00172         }
00173     }
00174     }
00175 
00176     return $res
00177 }
00178 
00179 /*  ::rcs::encodeRcsPatch --*/
00180 /* */
00181 /*  Converts a list of patch commands into a text containing the same*/
00182 /*  command as a RCS patch (i.e. in diff -n format). See decodePatch for*/
00183 /*  a description of the input format.*/
00184 /* */
00185 /*  Arguments*/
00186 /*  - patch The patch as list of patch commands.*/
00187 /* */
00188 /*  Results*/
00189 /*    A text containing the patch in diff -n format.*/
00190 /* */
00191 /*  Side effects*/
00192 /*   None*/
00193 
00194 ret  ::rcs::encodeRcsPatch (type patch) {
00195     set res {}
00196 
00197     foreach cmd $patch {
00198     foreach {op a b} $cmd break
00199 
00200     switch -exact -- $op {
00201         a {
00202         # a = index of line where to add
00203         # b = text to add
00204 
00205         set  lines [llength [split $b \n]]
00206 
00207         lappend res "a$a $lines"
00208         lappend res $b
00209         }
00210         d {
00211         # a = index of first line to delete.
00212         # b = #lines to delete.
00213 
00214         lappend res "d$a $b"
00215         }
00216         default {
00217         return -code error "Unknown patch command: '$op'"
00218         }
00219     }
00220     }
00221 
00222     return [join $res \n]\n
00223 }
00224 
00225 /*  ::rcs::applyRcsPatch --*/
00226 /* */
00227 /*  Apply a patch in the format returned by decodeRcsPatch to a text in*/
00228 /*  the format returned by the xx2dict commands. The result is*/
00229 /*  dictionary containing the modified text. Use the dict2xx commands to*/
00230 /*  convert this back into a regular text.*/
00231 /* */
00232 /*  Arguments*/
00233 /*  - text  The text (as dict) to patch*/
00234 /*  - patch The patch (as cmd list) to apply.*/
00235 /* */
00236 /*  Results*/
00237 /*   The modified text (as dict)*/
00238 /* */
00239 /*  Side effects*/
00240 /*   None*/
00241 
00242 ret  ::rcs::applyRcsPatch (type text , type patch) {
00243     array set lines $text
00244 
00245     foreach cmd $patch {
00246     foreach {op a b} $cmd break
00247 
00248     switch -exact -- $op {
00249         a {
00250         # a = index of line where to add
00251         # b = text to add
00252 
00253         if {[info exists lines($a)]} {
00254             append lines($a) \n $b
00255         } else {
00256             set lines($a) $b
00257         }
00258         }
00259         d {
00260         # a = index of first line to delete.
00261         # b = #lines to delete.
00262 
00263         while {$b > 0} {
00264             unset lines($a)
00265             incr a
00266             incr b -1
00267         }
00268         }
00269         default {
00270         return -code error "Unknown patch command: '$op'"
00271         }
00272     }
00273     }
00274 
00275     return [array get lines]
00276 }
00277 
00278 /*  ### ### ### ######### ######### #########*/
00279 /*  Ready for use.*/
00280 
00281 package provide rcs 0.1
00282 

Generated on 21 Sep 2010 for Gui by  doxygen 1.6.1