#!/usr/bin/perl
#
#    regfilter - make changes to a registry patch (regutils package)
#    Copyright (C) 1998 Memorial University of Newfoundland
#    
#    This program is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation; either version 2 of the License, or
#    (at your option) any later version.
#    
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#    
#    You should have received a copy of the GNU General Public License
#    along with this program; if not, write to the Free Software
#    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#    


#
# Script to make modifications to a window 9x registry dump - the modified
# dump is sent to standard output.  Modifications are read from one or more
# `filter' files.
#
# (pod at end)
#

use strict;
use Getopt::Std;

push(@INC, '/usr/lib');
require 'regfilterLib.pl';

my $prog = $0;
$prog =~ s:.*/::;


my $Usage = "Usage: $prog [-f file] [-V] filter-file [filter-file ...]
	-f file	Read from file (defaults to stdin)
	-V	Print version number and exit.
    Reads patterns from filter-file(s), then filters keys matching those
    patterns from the specified (exported) registry file or regdiff
    output.
";

my %opt;
if (!&getopts('f:V', \%opt)) {
    print STDERR $Usage;
    exit 1;
}
if (defined $opt{'V'}) {
    print "$prog: version 0.10\n";
    exit 0;
}
my $inFile = defined $opt{'f'} ? $opt{'f'} : undef;

if (@ARGV == 0) {
    print STDERR "$prog: no filter-pattern files specified on command line\n";
    die $Usage;
}

my $filter = new RegFile::Filter;

my $if;
foreach $if (@ARGV) {
    if (!$filter->readConf($if)) {
	die "$prog: $RegFile::Filter::errorString\n";
    }
}

my $in;
if (defined $inFile) {
    $in = new IO::File($inFile, 'r');
    if (!defined $in) {
	die "$prog: can't open $inFile - $!\n";
    }
} else {
    $in = new IO::Handle;
    if (!$in->fdopen('STDIN', 'r')) {
	die "$prog: can't dup STDIN - $!\n";
    }
}

my $out = new IO::Handle;
if (!$out->fdopen('STDOUT', 'w')) {
    die "$prog: can't dup STDOUT - $!\n";
}

my $first = 1;
while (1) {
    my $info = &regfilter::readKey($in);
    if (!defined $info) {
	die "$prog: $regfilter::errorString\n";
    }
    last if !%$info;
    if (!$filter->filter($info)) {
	die "$prog: error filtering key $info->{'key'}: $RegFile::Filter::errorString\n";
    }
    next if !%$info;
    if ($first) {
	$first = 0;
	print $out "REGEDIT4\n\n";
    }
    &regfilter::printKey($out, $info);
}

exit(0);

__END__

=head1 NAME

regfilter - filter a windows 9x registry dump by making substitutions and deletions to keys and entries

=head1 SYNOPSYS

B<regfilter> [B<-f> I<regdump>] [B<-V>] I<filter-file> ...

=head1 DESCRIPTION

B<regfilter> is used to modify a windows 9x registry dump (or a registry
patch) by applying to it the substitutions and deletions specified
in one or more I<filter file>s.
Such filtering is useful when one needs to do
common transformations (such as changing where the windows system directory is, where
the `Program Files' directory is, I<etc.>)
to a number of registry dumps.
It is also useful for filtering out common ignorable changes (I<e.g.>,
C<Explorer\StreamMRU>, C<Explorer\Streams> and other such keys)
from a registry diff, so only important changes remain.

=head1 Filter File Format

The  filter files that control what B<regfilter> does
consist of a number of registry key patterns (enclosed in brackets).
Each key pattern contains lines indicating which entries in matching
keys are to be modified (entries can be matched based on their name or
their value).
Finally, actions can be specified for each matching entry: an entry's
name or value can be changed or it may be deleted entirely.
Key patterns and entry name or value patterns are specified as case insensitive
B<perl> regular expressions, while name and value changes are
specified B<perl> substitution commands.

Comments are indicated by lines beginning with a # character (a # in
the middle of a line does not introduce a comment).

The following example demonstrates the syntax of filter files:

    # Read contents of another filter file:
    include "anotherFile"

    # Check for matching entries in everything under the HKEY_USERS key
    # (actually, under any key - see below)
    [HKEY_USERS\\.*]
	# Change C:\PROGRA~1\ to F:\Program files\ in entries whose
	# values containing the former
	value .*C:\\\\PROGRA~1\\\\.*
	    subst value s/C:\\\\PROGRA~1\\\\/F:\\\\Program Files\\\\/gi
	# Do the same for entry names (paths sometimes appear there...)
	name .*C:\\\\PROGRA~1\\\\.*
	    subst name s/C:\\\\PROGRA~1\\\\/F:\\\\Program Files\\\\/gi

    # Delete any changes under Explorer\Streams
    # (- at end of line means delete any keys matching the pattern)
    [HKEY_USERS\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Streams\.*] -

    # Delete a particular entry by name
    [HKEY_LOCAL_MACHINE\\SOFTWARE\\Description\\Microsoft\\Rpc\\UuidPersistentData]
    name LastTimeAllocated
	delete 

    # Change both the name of value of some key
    [HKLM\\foo\\bar]
    name something
	subst name s/X/Y/gi
	subst value s/A/B/gi

Some things to note about these files: you need lots of backslashes
in the key names (since backslash is used as a path separator in registries,
and since it is special to perl); the leading part of the key name (I<e.g.>,
C<HKEY_USERS>, C<HKEY_LOCAL_MACHINE>) is ignored when comparing keys;
the key, name and value patterns are always anchored, so don't
forget to put an explicit C<.*> in front of or after patterns where you want
a substring match.

The C<include> command is used to read filter commands from another file.
The file is first looked for relative to the same directory as the file
that included it, then in the process's current directory.


=head1 OPTIONS

=over 4

=item B<-f> I<regdump>

Read the registry dump from the specified file (instead of from standard
input).

=item B<-V>

Prints the version number - the program then exits
immediately.

=back


=head1 SEE ALSO

L<regedit>, L<regdiff>, L<perl>.

=head1 AUTHOR

Michael Rendell, Memorial University of Newfoundland (michael@cs.mun.ca).
