#!/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!
#
# Use this script to make changes to your source files, or in library
# files which reference other library files.
#
# 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

if( @ARGV < 2 || (@ARGV < 3 && $ARGV[@ARGV-1] eq "test")){
print "Usage: DAMit2 dam.txt file [file] ... [test]\n";
print "The \"test\" option will output the log, but not apply changes.\n";
print "Examples:\n";
print "DAM all files in current directory:\n";
print " DAMit2 dam.txt *.*`\n";
print "DAM all .h files in current directory (recursive), but do not apply changes:\n";
print " DAMit2 dam.txt `find -name \\*.h` test\n";
print "DAM all .h, .c, and .cpp files in current directory (recursive):\n";
print " DAMit2 dam.txt `find -name \\*.cpp` `find -name \\*.\\[hc\\]`\n";
exit;
}

#build the DAM hash
$damfile = shift(@ARGV);
if($ARGV[@ARGV-1] eq "test"){
$TESTING = 1;
pop(@ARGV);
}else{
$TESTING = 0;
}
open(DAM, $damfile) || die( "Unable to open $damfile : $!\n" );
%hash = (); #hash of old and new function names
while( <DAM> ){
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){ #for each file
&CMreplaceALL();
}
print "DAM'ed ".scalar(@ARGV)." files.\n";

#Does the replacement in $arg
sub CMreplaceALL{
open FILE, "+<$arg" or die "Cannot open $arg: $!\n";
flock FILE, 2; #lock the file for rw
@data = <FILE>; #buffer all the data

print "For file: $arg\n";
$total = 0;
$line = 1;
foreach (@data){
$before = $_;
$replace = 0;
while( ($old, $new) = each %hash ){
eval '$count = ($_ =~ '."s/\\b$old\\b/$new/g)";
$replace += $count;
}
$total += $replace;
print "$line: -$before$line: +$_" if $replace != 0;
$line++;
}
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;
print FILE @data;
}
print "Made $total total replacements in $arg\n\n";
}
close FILE;
}