diff --git a/src/util/mkconfig.pl b/src/util/mkconfig.pl new file mode 100755 index 00000000..2f2d6a4c --- /dev/null +++ b/src/util/mkconfig.pl @@ -0,0 +1,163 @@ +#!/usr/bin/perl -w + +use File::Spec::Functions qw ( :ALL ); +use strict; +use warnings; + +my $cfgdir = "config"; +my $config_h = "config.h"; + +# Read in a whole file +# +sub read_file { + my $file = shift; + + open my $fh, "<$file" or die "Could not open file $file: $!\n"; + local $/; + my $data = <$fh>; + close $fh; + return $data; +} + +# Write out a whole file +# +sub write_file { + my $file = shift; + my $data = shift; + + open my $fh, ">$file" or die "Could not write $file: $!\n"; + print $fh $data; + close $fh; +} + +# Delete a file +# +sub delete_file { + my $file = shift; + + unlink $file or die "Could not delete $file: $!\n"; +} + +# Read a directory listing (excluding the . and .. entries) +# +sub read_dir { + my $dir = shift; + + opendir my $dh, $dir or die "Could not open directory $dir: $!\n"; + my @entries = grep { ! /^(\.)+$/ } readdir $dh; + closedir $dh; + return @entries; +} + +# Get the current configuration by reading the configuration file +# fragments +# +sub current_config { + my $dir = shift; + + my $cfg = {}; + foreach my $file ( read_dir ( $dir ) ) { + $cfg->{$file} = read_file ( catfile ( $dir, $file ) ); + } + return $cfg; +} + +# Calculate guard name for a header file +# +sub guard { + my $name = shift; + + $name =~ s/\W/_/g; + return "CONFIG_".( uc $name ); +} + +# Calculate preamble for a header file +# +sub preamble { + my $name = shift; + my $master = shift; + + my $guard = guard ( $name ); + my $preamble = <<"EOF"; +/* + * This file is automatically generated from $master. Do not edit this + * file; edit $master instead. + * + */ + +#ifndef $guard +#define $guard +EOF + return $preamble; +} + +# Calculate postamble for a header file +# +sub postamble { + my $name = shift; + + my $guard = guard ( $name ); + return "\n#endif /* $guard */\n"; +} + +# Get the new configuration by splitting config.h file using the +# @BEGIN/@END tags +# +sub new_config { + my $file = shift; + + my $cfg = {}; + my $cursor = ""; + + open my $fh, "<$file" or die "Could not open $file: $!\n"; + while ( <$fh> ) { + if ( ( my $newcursor, my $suffix ) = /\@BEGIN\s+(\w+\.h)(.*)$/ ) { + die "Missing \"\@END $cursor\" before \"\@BEGIN $1\"" + ." at $file line $.\n" if $cursor; + $cursor = $newcursor; + $cfg->{$cursor} = preamble ( $cursor, $file ) + unless exists $cfg->{$cursor}; + $cfg->{$cursor} .= "\n/*".$suffix."\n"; + } elsif ( ( my $prefix, my $oldcursor ) = /^(.*)\@END\s+(\w+\.h)/ ) { + die "Missing \"\@BEGIN $oldcursor\" before \"\@END $oldcursor\"" + ." at $file line $.\n" unless $cursor eq $oldcursor; + $cfg->{$cursor} .= $prefix."*/\n"; + $cursor = ""; + } else { + $cfg->{$cursor} .= $_ if $cursor; + } + } + close $fh; + die "Missing \"\@END $cursor\" in $file\n" if $cursor; + + foreach $cursor ( keys %$cfg ) { + $cfg->{$cursor} .= postamble ( $cursor ); + } + + return $cfg; +} + +############################################################################# +# +# Main program + +# Read in current config file fragments +# +my $current = current_config ( $cfgdir ); + +# Read in config.h and split it into fragments +# +my $new = new_config ( $config_h ); + +# Delete any no-longer-wanted config file fragments +# +foreach my $file ( keys %$current ) { + unlink catfile ( $cfgdir, $file ) unless exists $new->{$file}; +} + +# Write out any modified fragments +# +foreach my $file ( keys %$new ) { + write_file ( catfile ( $cfgdir, $file ), $new->{$file} ) + unless $current->{$file} && $new->{$file} eq $current->{$file}; +}