#!/usr/bin/perl
#
#    regsort - sorts a dump of a windows 9x registry (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 sort a windows 9x registry dump (keys are sorted in ascending
# order, as are entries within keys).  Useful when comparing the output of
# windows95's regedit (which doesn't generate sorted output).
#
# (pod at end)
#


use strict;
use Getopt::Std;
use IO::Handle;

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


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

my $Usage = "Usage: $prog [-v] [-V] [reg-dump]
	-v	verbose mode
	-V	Print version number and exit.
    Sorts the keys and entries of a registry dump.
";

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

my $verbose = defined $opt{'v'} ? $opt{'v'} : 0;

die "$prog: wrong number of arguments\n$Usage" unless @ARGV <= 1;

my $file;
my $in;
if (@ARGV) {
    $file = $ARGV[0];
    $in = new IO::File $file, "r";
    if (!defined $in) {
	die "$prog: can't open $file - $!\n";
    }
} else {
    $file = "stdin";
    $in = new IO::Handle;
    if (!$in->fdopen("STDIN", "r")) {
	die "$prog: can't fdopen STDIN - $!\n";
    }
}

my %keys;
my $nkeys = 0;

print STDERR "Reading keys" if ($verbose);
for ($nkeys = 0; ; $nkeys++) {
    if ($nkeys % 100 == 0) {
	print STDERR "." if ($verbose);
    }
    my $key = &regfilter::readKey($in);
    if (!defined $key) {
	die "$prog: error reading key from $file - $regfilter::errorString\n";
    }
    last if !%$key;
    $keys{$key->{'key'}} = $key;
}
print STDERR "\nSorting keys\n" if ($verbose);

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

my $name;
foreach $name (sort { &regfilter::cmpKey($a, $b) } keys %keys) {
    if (defined $keys{$name}->{'entries'}) {
	my @entries = sort { &regfilter::cmpEntryName($a->{'name'}, $b->{'name'}); }
			  @{$keys{$name}->{'entries'}};
	$keys{$name}->{'entries'} = \@entries;
    }
    &regfilter::printKey($out, $keys{$name});
}

exit(0);

__END__

=head1 NAME

regsort - sorts a dump of a windows 9x registry

=head1 SYNOPSYS

B<regsort> [B<-v>] [B<-V>] [I<file>]

=head1 DESCRIPTION

B<regsort> reads a windows 9x registry dump from the specified file (or
from standard input, if no file is given), sorts the dump and prints
the results to standard output.
Both the keys within the dump and the entries within the keys are
sorted in ascending order.

Typically used to sort a dump obtained from the windows 9x B<regedit> (which
is generally unordered) so it can be used as input to B<regdiff>.


=head1 OPTIONS

=over 4

=item B<-v>

Verbose output: indicates on standard error what it is doing (including
printing a dot for every 100 keys it reads).

=item B<-V>

Prints the version number - the program then exits
immediately.

=back


=head1 SEE ALSO

L<regedit>, L<regdiff>.

=head1 AUTHOR

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