chiark / gitweb /
Fix C%d[%d] messages
[inn-innduct.git] / storage / buildconfig.in
1 #! /usr/bin/perl
2
3 ##  $Id: buildconfig.in 6806 2004-05-18 01:18:57Z rra $
4 ##
5 ##  Generate linkage code and makefiles for storage and overview methods.
6 ##
7 ##  Goes through all subdirectories of the current directory and finds
8 ##  directories that are either storage methods or overview methods.  Builds
9 ##  methods.[ch] and ovmethods.[ch] as well as makefile stubs.
10
11 require 5.003;
12
13 use strict;
14 use vars qw(@OVERVIEW @STORAGE);
15
16 # Storage API functions.
17 @STORAGE = qw(init store retrieve next freearticle cancel ctl flushcacheddata
18               printfiles shutdown);
19
20 # Overview API functions.
21 @OVERVIEW = qw(open groupstats groupadd groupdel add cancel opensearch search
22                closesearch getartinfo expiregroup ctl close);
23
24 # Used to make heredocs more readable.
25 sub unquote { my ($string) = @_; $string =~ s/^:( {0,7}|\t)//gm; $string }
26
27 # Parse a method.config file for a storage method, putting information about
28 # that storage method into the given hash ref.
29 sub parse_config {
30     my ($dir, $file, $config) = @_;
31     local $_;
32     $$config{sources} ||= [];
33     $$config{extra} ||= [];
34     $$config{programs} ||= [];
35     $$config{makefiles} ||= [];
36     open (CONFIG, "$dir/$file") or die "Can't open $dir/$file: $!\n";
37     while (<CONFIG>) {
38         s/^\s+//;
39         s/\s+$//;
40         if (/^name\s*=\s*(\S+)$/) {
41             my $method = $1;
42             die "$dir/$file: $method has already been defined\n"
43                 if (defined $$config{method}{$method});
44             $$config{method}{$method} = $dir;
45         } elsif (/^number\s*=\s*(\d+)$/) {
46             my $number = $1;
47             if (defined $$config{number}{$number}) {
48                 die "$dir/$file: method number $number was already "
49                     . "allocated in $$config{number}{$number}\n";
50             }
51             $$config{number}{$dir} = $number;
52         } elsif (/^sources\s*=\s*(.*)/) {
53             my $sources = $1;
54             my @sources = split (' ', $sources);
55             push (@{ $$config{sources} }, map { "$dir/$_" } @sources);
56         } elsif (/^extra-sources\s*=\s*(.*)/) {
57             my $extra = $1;
58             my @extra = split (' ', $extra);
59             push (@{ $$config{extra} }, map { "$dir/$_" } @extra);
60         } elsif (/^programs\s*=\s*(.*)/) {
61             my $programs = $1;
62             my @programs = split (' ', $programs);
63             push (@{ $$config{programs} }, map { "$dir/$_" } @programs);
64         } else {
65             warn "$dir/$file: ignoring unknown line: $_\n";
66         }
67     }
68
69     # If there is a makefile fragment in the directory, note it.
70     if (-f "$dir/method.mk") {
71         push (@{ $$config{makefiles} }, "$dir/method.mk");
72     } elsif (-f "$dir/ovmethod.mk") {
73         push (@{ $$config{makefiles} }, "$dir/ovmethod.mk");
74     }
75 }
76
77 # Write out include directives for a list of files.
78 sub write_includes {
79     my ($fh, $config) = @_;
80     my $method;
81     for $method (sort keys %{ $$config{method} }) {
82         my $path = $$config{method}{$method};
83         print $fh qq(\#include "$path/$method.h"\n);
84     }
85 }
86
87 # Write out the method struct.
88 sub write_methods {
89     my ($fh, $config, $prefix, @funcs) = @_;
90     my ($notfirst, $method);
91     for $method (sort keys %{ $$config{method} }) {
92         print $fh "\n},\n" if $notfirst;
93         print $fh qq(\{\n    "$method");
94         print $fh ', ', $prefix, '_', uc ($method) if $prefix;
95         for (@funcs) {
96             print $fh ",\n    ${method}_$_";
97         }
98         $notfirst++;
99     }
100     print $fh "\n}\n};\n\n";
101 }
102
103 # Write out the constant defines for methods.
104 sub write_constants {
105     my ($fh, $config, $prefix) = @_;
106     my $method;
107     for $method (sort keys %{ $$config{method} }) {
108         printf $fh "#define ${prefix}_%-30s%d\n", uc ($method),
109             $$config{number}{$$config{method}{$method}};
110     }
111 }
112
113 # Write out methods.c and methods.h for the interface to the storage
114 # methods.
115 sub write_storage {
116     my $storage = shift;
117     open (DEF, '> methods.c.new') or die "Can't create methods.c.new: $!\n";
118     print DEF unquote (<<'EOE');
119 :       /* This file is automatically generated by buildconfig. */
120 :
121 :       #include "interface.h"
122 :       #include "methods.h"
123 EOE
124     my $method;
125     write_includes (\*DEF, $storage);
126     print DEF "\nSTORAGE_METHOD storage_methods[",
127         scalar (keys %{ $$storage{method} }), "] = {\n";
128     write_methods (\*DEF, $storage, 'TOKEN', @STORAGE);
129     close DEF;
130     rename ('methods.c.new', 'methods.c');
131
132     open (H, '> methods.h.new') or die "Can't open methods.h.new: $!\n";
133     print H unquote (<<'EOE');
134 :       /* This file is automatically generated by buildconfig */
135 :
136 :       #ifndef METHODS_H
137 :       #define METHODS_H 1
138 :
139 :       #include "interface.h"
140 :
141 EOE
142     print H '#define NUM_STORAGE_METHODS ',
143         scalar (keys %{ $$storage{method} }), "\n\n";
144     write_constants (\*H, $storage, 'TOKEN');
145     print H unquote (<<'EOE');
146 :
147 :       extern STORAGE_METHOD storage_methods[NUM_STORAGE_METHODS];
148 :
149 :       #endif /* METHODS_H */
150 EOE
151     close H;
152     rename ('methods.h.new', 'methods.h');
153 }
154
155 # Write out ovmethods.c and ovmethods.h for the interface to the overview
156 # methods.
157 sub write_overview {
158     my $overview = shift;
159     open (DEF, '> ovmethods.c.new')
160         or die "Can't create ovmethods.c.new: $!\n";
161     print DEF unquote (<<'EOE');
162 :       /* This file is automatically generated by buildconfig. */
163 :
164 :       #include "ovinterface.h"
165 EOE
166     write_includes (\*DEF, $overview);
167     print DEF "\nOV_METHOD ov_methods[",
168         scalar (keys %{ $$overview{method} }), "] = {\n";
169     write_methods (\*DEF, $overview, undef, @OVERVIEW);
170     close DEF;
171     rename ('ovmethods.c.new', 'ovmethods.c');
172
173     open (H, '> ovmethods.h.new') or die "Can't open ovmethods.h.new: $!\n";
174     print H unquote (<<'EOE');
175 :       /* This file is automatically generated by buildconfig */
176 :
177 :       #ifndef OVMETHODS_H
178 :       #define OVMETHODS_H 1
179 :
180 :       #include "ovinterface.h"
181 :
182 EOE
183     print H '#define NUM_OV_METHODS ',
184         scalar (keys %{ $$overview{method} }), "\n";
185     print H unquote (<<'EOE');
186 :
187 :       extern OV_METHOD ov_methods[NUM_OV_METHODS];
188 :
189 :       #endif /* OVMETHODS_H */
190 EOE
191     close H;
192     rename ('ovmethods.h.new', 'ovmethods.h');
193 }
194
195 # Return a string setting a makefile variable.  Tab over the = properly and
196 # wrap to fit our coding standards.
197 sub makefile_var {
198     my ($variable, @values) = @_;
199     my $output;
200     $output = sprintf ("%-15s =", $variable);
201     my $column = 17;
202     for (@values) {
203         if ($column > 17 && 77 - $column < length ($_)) {
204             $output .= " \\\n" . ' ' x 17;
205             $column = 17;
206         }
207         $output .= " $_";
208         $column += 1 + length ($_);
209     }
210     $output .= "\n";
211     return $output;
212 }
213
214 # Write out the makefile fragment for overview and storage methods.
215 sub write_makefile {
216     my ($dirs, $sources, $extra, $programs, $makefiles) = @_;
217     open (MAKE, '> Make.methods.new')
218         or die "Can't create Make.methods.new: $!\n";
219     print MAKE "# This file is automatically generated by buildconfig\n\n";
220     print MAKE makefile_var ('METHOD_SOURCES', @$sources);
221     print MAKE makefile_var ('EXTRA_SOURCES', @$extra);
222     print MAKE makefile_var ('PROGRAMS', @$programs);
223     for (@$makefiles) {
224         print MAKE "\n\n##  Included from $_\n\n";
225         open (FRAG, $_) or die "Can't open $_: $!\n";
226         print MAKE <FRAG>;
227         close FRAG;
228     }
229     rename ('Make.methods.new', 'Make.methods');
230 }
231
232 my ($dir, %storage, %overview);
233 if (!-d 'cnfs') {
234     if (-d 'storage/cnfs') {
235         chdir 'storage' or die "Can't chdir to storage: $!\n";
236     } else {
237         die "Can't find storage directory (looking for storage/cnfs)\n";
238     }
239 }
240 opendir (D, ".") or die "Can't open current directory: $!\n";
241 my @dirs = sort readdir D;
242 for $dir (@dirs) {
243     if (-e "$dir/method.config") {
244         parse_config ($dir, 'method.config', \%storage);
245     }
246     if (-e "$dir/ovmethod.config") {
247         parse_config ($dir, 'ovmethod.config', \%overview);
248     }
249 }
250 write_storage (\%storage);
251 write_overview (\%overview);
252 @dirs = (sort values %{ $storage{method} },
253          sort values %{ $overview{method} });
254 my @sources = (sort @{ $storage{sources} }, sort @{ $overview{sources} });
255 my @extra = (sort @{ $storage{extra} }, sort @{ $overview{extra} });
256 my @programs = sort (@{ $storage{programs} }, @{ $overview{programs} });
257 my @makefiles = sort (@{ $storage{makefiles} }, @{ $overview{makefiles} });
258 write_makefile (\@dirs, \@sources, \@extra, \@programs, \@makefiles);