#!/usr/bin/perl # # File: DAMit2 # Author: Colin Mollenhour (mollenho@cs.utk.edu or colin@mollenhour.com) # http://colin.mollenhour.com # # Reads a DAM (Document for API Modification) document and any number of files, # and makes changes accordingly. # # This is version 2, which adds support for regular expressions in the DAM file! # It also supports VCS style conflict markers with the --conflict option so that # you can use your favorite merge tool to merge the DAM changes. # # The DAM document should be in this format: # # #Comments should be preceded by # # #Blank lines and comments are allowed anywhere. # #old and new are separated by ==> # #if a line does not have a replacement, it is ignored # # header1\.h ==> newheader.h # rotate_object\dd ==> RotateObject$1D # new MyClass ==> MyClass::factory # (MyClass1|MyClass1)-> ==> MyNamespace::$1-> # foo_\w+_bar ==> Foo$1Bar $USAGE = "Usage: DAMit2 [--conflict] [--dry-run] dam.txt file [file] ... --conflict write VCS style conflicts markers, must be removed after reviewing --dry-run output the log, but do not apply changes Examples: DAM all files in current directory: \$ DAMit2 --conflict dam.txt *.* DAM all .h, .c, and .cpp files in current directory (recursive): \$ DAMit2 dam.txt `find -name \\*.cpp` `find -name \\*.\\[hc\\]` "; # check arguments for options $TESTING = 0; $WRITECONFLICTS = 0; foreach $arg (@ARGV){ if( $arg eq "--dry-run"){ $TESTING = 1; } elsif( $arg eq "--conflict"){ $WRITECONFLICTS = 1; } elsif( $arg =~ /^-/ ){ die("Invlaid argument $arg\n\n$USAGE"); } else{ last; } } if($TESTING){ shift(@ARGV); } if($WRITECONFLICTS){ shift(@ARGV); } die($USAGE) unless @ARGV > 1; # build the DAM hash $damfile = shift(@ARGV); open(DAM, $damfile) || die( "Unable to open $damfile : $!\n" ); %hash = (); #hash of old and new function names while( ){ next if /^#/; #skip comments chop; ($old, $new) = split /\s+==>\s+/; # get old and new function names $hash{ $old } = $new if $old && $new; # add old and new to hash } close DAM; # process each file foreach $arg (@ARGV){ open FILE, "+<$arg" or die "Cannot open $arg: $!\n"; flock FILE, 2; # lock the file for rw @data = ; # buffer all the data print "For file: $arg\n"; $total = 0; # track total number of replacements $line = 1; # line number tracker # Variables for tracking conflicts @changes = (); $conflict = 0; @newdata = (); # scan each line foreach (@data){ $before = $_; $replace = 0; while( ($old, $new) = each %hash ){ eval '$count = ($_ =~ '."s/\\b$old\\b/$new/g)"; $replace += $count; } if($WRITECONFLICTS){ if($replace){ # changes made push( @newdata, "<<<<<<< mine\n" ) if !$conflict; # start new conflict $conflict = 1; push( @changes, $_ ); # store changes for later } elsif( $conflict ){ # no change, write and end conflict push( @newdata, "=======\n" ); push( @newdata, @changes ); push( @newdata, ">>>>>>> $damfile\n" ); @changes = (); $conflict = 0; } push( @newdata, $before ); } $total += $replace; print "$line: -$before$line: +$_" if $replace; $line++; } # print status and write file (if necessary) if( $total == 0 ){ print "No replacements made in $arg\n\n"; }else{ if( !$TESTING ){ #overwrite file with new contents seek FILE, 0, 0; truncate FILE, 0; if($WRITECONFLICTS){ print FILE @newdata; }else{ print FILE @data; } } print "Made $total total replacements in $arg\n\n"; } close FILE; } print "DAM'ed ".scalar(@ARGV)." files.\n";