First version
[people/dverkamp/gpxe.git] / src / util / mkconfig.pl
1 #!/usr/bin/perl -w
2
3 use File::Spec::Functions qw ( :ALL );
4 use strict;
5 use warnings;
6
7 my $cfgdir = "config";
8 my $config_h = "config.h";
9
10 # Read in a whole file
11 #
12 sub read_file {
13   my $file = shift;
14
15   open my $fh, "<$file" or die "Could not open file $file: $!\n";
16   local $/;
17   my $data = <$fh>;
18   close $fh;
19   return $data;
20 }
21
22 # Write out a whole file
23 #
24 sub write_file {
25   my $file = shift;
26   my $data = shift;
27
28   open my $fh, ">$file" or die "Could not write $file: $!\n";
29   print $fh $data;
30   close $fh;
31 }
32
33 # Delete a file
34 #
35 sub delete_file {
36   my $file = shift;
37
38   unlink $file or die "Could not delete $file: $!\n";
39 }
40
41 # Read a directory listing (excluding the . and .. entries)
42 #
43 sub read_dir {
44   my $dir = shift;
45
46   opendir my $dh, $dir or die "Could not open directory $dir: $!\n";
47   my @entries = grep { ! /^(\.)+$/ } readdir $dh;
48   closedir $dh;
49   return @entries;
50 }
51
52 # Get the current configuration by reading the configuration file
53 # fragments
54 #
55 sub current_config {
56   my $dir = shift;
57
58   my $cfg = {};
59   foreach my $file ( read_dir ( $dir ) ) {
60     $cfg->{$file} = read_file ( catfile ( $dir, $file ) );
61   }
62   return $cfg;
63 }
64
65 # Calculate guard name for a header file
66 #
67 sub guard {
68   my $name = shift;
69
70   $name =~ s/\W/_/g;
71   return "CONFIG_".( uc $name );
72 }
73
74 # Calculate preamble for a header file
75 #
76 sub preamble {
77   my $name = shift;
78   my $master = shift;
79
80   my $guard = guard ( $name );
81   my $preamble = <<"EOF";
82 /*
83  * This file is automatically generated from $master.  Do not edit this
84  * file; edit $master instead.
85  *
86  */
87
88 #ifndef $guard
89 #define $guard
90 EOF
91   return $preamble;
92 }
93
94 # Calculate postamble for a header file
95 #
96 sub postamble {
97   my $name = shift;
98
99   my $guard = guard ( $name );
100   return "\n#endif /* $guard */\n";
101
102
103 # Get the new configuration by splitting config.h file using the
104 # @BEGIN/@END tags
105 #
106 sub new_config {
107   my $file = shift;
108
109   my $cfg = {};
110   my $cursor = "";
111
112   open my $fh, "<$file" or die "Could not open $file: $!\n";
113   while ( <$fh> ) {
114     if ( ( my $newcursor, my $suffix ) = /\@BEGIN\s+(\w+\.h)(.*)$/ ) {
115       die "Missing \"\@END $cursor\" before \"\@BEGIN $1\""
116           ." at $file line $.\n" if $cursor;
117       $cursor = $newcursor;
118       $cfg->{$cursor} = preamble ( $cursor, $file )
119           unless exists $cfg->{$cursor};
120       $cfg->{$cursor} .= "\n/*".$suffix."\n";
121     } elsif ( ( my $prefix, my $oldcursor ) = /^(.*)\@END\s+(\w+\.h)/ ) {
122       die "Missing \"\@BEGIN $oldcursor\" before \"\@END $oldcursor\""
123           ." at $file line $.\n" unless $cursor eq $oldcursor;
124       $cfg->{$cursor} .= $prefix."*/\n";
125       $cursor = "";
126     } else {
127       $cfg->{$cursor} .= $_ if $cursor;
128     }
129   }
130   close $fh;
131   die "Missing \"\@END $cursor\" in $file\n" if $cursor;
132
133   foreach $cursor ( keys %$cfg ) {
134     $cfg->{$cursor} .= postamble ( $cursor );
135   }
136
137   return $cfg;
138 }  
139
140 #############################################################################
141 #
142 # Main program
143
144 # Read in current config file fragments
145 #
146 my $current = current_config ( $cfgdir );
147
148 # Read in config.h and split it into fragments
149 #
150 my $new = new_config ( $config_h );
151
152 # Delete any no-longer-wanted config file fragments
153 #
154 foreach my $file ( keys %$current ) {
155   unlink catfile ( $cfgdir, $file ) unless exists $new->{$file};
156 }
157
158 # Write out any modified fragments
159 #
160 foreach my $file ( keys %$new ) {
161   write_file ( catfile ( $cfgdir, $file ), $new->{$file} )
162       unless $current->{$file} && $new->{$file} eq $current->{$file};
163 }