You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

mkconfig.pl 4.0KB

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