Article Listing 1 Listing 2 mar2006.tar

Listing 1 dwreplace.pl

#!/usr/bin/perl
# This program is licensed under the terms of the GNU 
# General Public License (GPL). 
# This program is a copyrighted by Neptune Web, Inc.
# Please send improvements and changes to 
# charles.dalsass@neptuneweb.com

use Getopt::Long;

my $replacementfile;
my $searchonly;
my ($showexample);
my $verbose;
my $casesensitive;
Getopt::Long::GetOptions("rfile=s" => \$replacementfile, "s+" => \
             \$searchonly, "e+" => \$showexample, "v+" => \$verbose, 
             "ni+" => \$casesensitive);

if (!$replacementfile && !$showexample) {
    print <<'END_OF_MARKER';

usage: dwreplace (--s) --rfile=rfile file1 <file2 ... file(n)>\n\n

Flags:
--rfile=<file> => where file is the rfile to use (this is a mandatory argument)
--s            => search only, do not replace
--e            => show an example rfile
--v            => verbose mode, shows detailed matching info and \
                  highlighted text for changes
--ni           => case sensitive mode (not insensitive)

END_OF_MARKER

exit(1);

} elsif ($showexample) {
    
#################################### SAMPLE RFILE #########################
print <<'END_OF_MARKER';

# Example rfile:

$OLD[0] = <<'END_OF_TEXT';
Sample Love Letter:
END_OF_TEXT

$NEW[0] = <<'END_OF_TEXT';
<font color="blue">Sample Love Letter:</font>
END_OF_TEXT

# Reversing the file to match a <table (unkown) ..(unkown) known text

$OPTIONS[1] = [ isregexp , reversefile,  casesensitive ];

$OLD[1] = 'ot ereh kcilC.*?elbat<';

$NEW[1] = '<p><center>{$sendbutton}</center></p>';

## if you want to interpolate from a regexp, those things found using
## brace notation.  use in conjunction with
## "escape_perl_regular_expression" program if your regular expression
## contains alot of whitespace and HTML

# Another words -- you can't put a HERE document for the right side (new 
# text) if you are doing interpolation! There should be a way to make this 
# work, however.

$OPTIONS[2] = [ isregexp , interpolator ];

$OLD[2] = '<SPAN\s*CLASS=\"body\">(.*?)<a\s*href=\"#\"\s*onclick=\"backToTop\ \
  (0\)\">Back\s*To\s*Top<\/a>';

$NEW[2] = '<editable>$1</editable><a href="#" onclick="backToTop(0)"> \
  Back To Top</a>';

# Example 4 most advanced. Pull out all absolute URLS and replace with an 
# interstitial page. 

sub urlEncode {
    my ($toencode) = @_;
    return undef unless defined($toencode);
    $toencode=~s/([^a-zA-Z0-9_.-])/uc sprintf("%%%02x",ord($1))/eg;
    return $toencode;
}

$OLD[3] = '(href|src)="?(http:\/\/.*?)[">\s]';
$NEW[3] = '"speedbump.html?page=$1=\"" . urlEncode($2) . "\""';

$OPTIONS[3] = [ isregexp , interpolator , eflag  ]; # use the eflag to 
                                                    # evaluate the right 
                                                    # hand side.

#################################### SAMPLE RFILE #########################
END_OF_MARKER

    exit();
} else {
    if (!open(F,"$replacementfile")) {
        print STDERR "Your rfile $replacementfile could not be opened.\n";
        exit(-599);
    }
    my $f; # read in the file.
    while (<F>) {
        $f .= $_;
    }
    close (F);
    eval($f);
    if ($@) {
    if ($@ =~ /did not return a true value/i) {
        print STDERR "Your rfile ($replacementfile) must return a true \
          value... \nYou may need to put a '1;' at the bottom of the rfile. \
          run with --e for an example rfile\n"; print STDERR "Error: $@\n";
    } else {
        print STDERR "Your rfile ($replacementfile) did not compile \
          properly\n"; print STDERR "Error: $@\n"; 
    }
    exit()
    };
}

if ($#ARGV == -1) {
    print "no files specified\n";
    exit();
}

if ($#NEW == -1 || $#OLD == -1) {
    print "nothing to do (OLD OR NEW EMPTY)\n";
    exit();
}

if (!($#NEW == $#OLD)) {
    print "NEW, OLD, AND OPTIONS arrays are of differing size\n";
    exit();
}

if ($#OPTIONS > $#NEW) {
    print "options array larger than newtext array.\n";
    exit();
}
if ($#OPTIONS > $#OLD) {
    print "options array larger than newtext array.\n";
    exit();
}


my $j;
foreach ($j = 0; $j <  $#NEW; $j++) {
    if (!defined($OLD[$j]) || !defined($NEW[$j])) {
    print "NEW[$j], OLD[$j], AND OPTIONS[$j] are empty.\n";
    exit();
    }
}

my $filename;
# loop through each file provided on the command prompt
foreach $filename (@ARGV) {
    open G, "<$filename" or die "Cannot open file $filename for reading";
    undef $/; 
    my $file = <G>; $/ = "\n";

    my $index;
    my $matchcount = 0;
    my %failedMatches;

    my %mperstr;         # match per str
    my $mperstrcnt = 0;  #  "     "   "  count
    my $hlitfile = $file;    # file with parts to be changed highlighted

    for ($index = 0; $index <= $#NEW; $index++) {
    my $regexp;
    my $endingModifiers;
    if ($OPTIONS[$index] && grep(/^isregexp$/,@{$OPTIONS[$index]})) {
        $regexp = $OLD[$index];
    } else {
        $regexp = removeWhiteSpaceAndEscapeRegexp($OLD[$index]);
    }
    # the main 'workhorse' regular expression
    my $finalRegexp;
    my $reversedRightHandSide; # only used if reversing, so as not to 
                               # override the actual global variables.
    
    if ($OPTIONS[$index] && grep(/^isregexp$/,@{$OPTIONS[$index]}) && \
      grep(/^interpolator$/,@{$OPTIONS[$index]})) {
        my $rightSideExp = $NEW[$index];
        # it seems that they never want / in the right hand side if they 
        # are doing interpolation on right.
        $rightSideExp  =~ s/([\/])/\\$1/g;
        if (!$searchonly) {
        $finalRegexp = '$file =~ ' .  "s/\$regexp/" . $rightSideExp. "/";
        } else {
        $finalRegexp = '$file =~ ' .  "/\$regexp/";
        }
    } else {
        
        if ($OPTIONS[$index] && grep(/^reversefile$/,@{$OPTIONS[$index]}) ) {
        # reverse the right hand side for convenience ....
        $reversedRightHandSide = scalar reverse $NEW[$index];
        if (!$searchonly) {
            $finalRegexp = '$file =~ ' .  "s/\$regexp/\$reversedRightHandSide/";
        } else {
            $finalRegexp = '$file =~ ' .  "/\$regexp/";
        }
        } else {
        if (!$searchonly) {
            $finalRegexp = '$file =~ ' .  "s/\$regexp/\$NEW[\$index]/";
        } else {
            $finalRegexp = '$file =~ ' .  "/\$regexp/";
        }
        }
    }
    if (!$searchonly && $OPTIONS[$index] && \
      grep(/^nonglobalreplace$/,@{$OPTIONS[$index]}) ) {
        $endingModifiers = "is";
        if ($casesensitive ||grep(/^casesensitive$/,@{$OPTIONS[$index]})) {
        $endingModifiers = "s";
        }
    } elsif (!$searchonly) {
        $endingModifiers = "isg";
        if ($casesensitive || grep(/^casesensitive$/,@{$OPTIONS[$index]})) {
        $endingModifiers = "sg";
        }
    } else {  # search only
        $endingModifiers = "isg";
        if ($casesensitive || grep(/^casesensitive$/,@{$OPTIONS[$index]})) {
        $endingModifiers = "sg";
        }
    }
    # sometimes you'll need to reverse the contents of the file.
    if ($OPTIONS[$index] && grep(/^reversefile$/,@{$OPTIONS[$index]})) {
        $file = scalar reverse $file;
    }

    #print "\n\n------\n\n$regexp\n\n$finalRegexp\n\n$file\n\n-----\n\n";

    # count how many times a particular match occurs
    my $rr = "\$file =~ " . "/$regexp/" . $endingModifiers;
    while (eval($rr)){
        die "Error ---: $@\n Code:\n$rr\n" if ($@);
        $mperstrcnt++; 
    }
    $mperstr{$index} = $mperstrcnt;
    $mperstrcnt = 0;

    # if you want to see what you are replacing highlighted within the 
    # file, only in verbose mode
    if ($verbose) {
        $hlitfile = highlightFile($regexp, $endingModifiers, $hlitfile);
        }
    $finalRegexp .= $endingModifiers;

    # use the e flag when we want to evaluate the right side of the reg 
    # exp. during replace
    if (!$searchonly && grep(/^eflag$/,@{$OPTIONS[$index]})) {
        $finalRegexp .= "e";
    }

    if (eval($finalRegexp)) {
        die "Error ---: $@\n Code:\n$finalRegexp\n"  if ($@);  
        $matchcount++;
    } else {
        # count your failed matches...
        $failedMatches{$index} = 1;
    };
# sometimes you'll need to reverse the contents of the file, but don't 
# forget to put it back!!
    if ($OPTIONS[$index] && grep(/^reversefile$/,@{$OPTIONS[$index]})) {
        $file = scalar reverse $file;
    }
    }
    if (!$searchonly) {
    open G, ">$filename" or die "Cannot open file $filename for writing";
    print G "$file";
    close G;
    }
    print "$filename ($matchcount matches found)\n";

    if($verbose) {    # sometimes you may want more information on 
                      # matching, triggers verbose mode
    my $ii = 1;
    my $value;    # print out how many matches for each match type 

        print $hlitfile . "\n";

        print "Times each match is found data below: \n";
        foreach $value (keys %mperstr) {
        # ii --> match index,   hash value --> how many of that type of 
        # match was made
        print "\t$ii -- $mperstr{$value} times\n"; 
        $ii++;
    }
    }
}

sub removeWhiteSpaceAndEscapeRegexp() {
    my ($ins) = @_;
# remove all regexp meaningful characters.
    $ins =~ s/([\@\$\|\*\?\]\[\^\/\+\.\"\(\)])/\\$1/isg;
    # add whitespace independence, but only after weird 
    # (regular expression) chars have been removed.
    $ins =~ s/\s+/\\s*/isg;
    return $ins;
}

sub highlightFile() {
    my ($r, $endMods, $f) = @_;

    my $hfile = $f;

    require POSIX;       
    use Term::Cap;  # use the terminal feature to create highlighted text 
                    # on the screen
        
    my $term = $ENV{TERM} || 'vt100';
    my $terminal;
        
    my $termios = POSIX::Termios->new();
    $termios->getattr;
    my $ospeed = $termios->getospeed;
        
    $terminal =  Term::Cap->Tgetent( { TERM=>undef, OSPEED=>$ospeed } );
        
    print "Error from eval: $@" if ($@);
        
    my ($SO, $SE) = ($terminal->Tputs('so'), $terminal->Tputs('se'));

    my $exp = '$hfile =~ ' . "s/($r)/\${SO}\$1\${SE}/" . $endMods;

    eval($exp);

    die "Error ---: $@\n Code:\n$exp\n" if ($@);
   
    return $hfile;
}