chiark / gitweb /
Fix memory management of argument to open_input_file
[inn-innduct.git] / history / 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 history methods or overview methods.  Builds
9 ##  hismethods.[ch] as well as makefile stubs.
10
11 require 5.003;
12
13 use strict;
14 use vars qw(@HISTORY);
15
16 # History API functions.
17 @HISTORY = qw(open close sync lookup check write replace expire walk remember
18               ctl);
19
20 # Used to make heredocs more readable.
21 sub unquote { my ($string) = @_; $string =~ s/^:( {0,7}|\t)//gm; $string }
22
23 # Parse a hismethod.config file for a history method, putting information
24 # about that history method into the given hash ref.
25 sub parse_config {
26     my ($dir, $file, $config) = @_;
27     local $_;
28     $$config{sources} ||= [];
29     $$config{extra} ||= [];
30     $$config{programs} ||= [];
31     $$config{makefiles} ||= [];
32     open (CONFIG, "$dir/$file") or die "Can't open $dir/$file: $!\n";
33     while (<CONFIG>) {
34         s/^\s+//;
35         s/\s+$//;
36         if (/^name\s*=\s*(\S+)$/) {
37             my $method = $1;
38             die "$dir/$file: $method has already been defined\n"
39                 if (defined $$config{method}{$method});
40             $$config{method}{$method} = $dir;
41         } elsif (/^number\s*=\s*(\d+)$/) {
42             my $number = $1;
43             if (defined $$config{number}{$number}) {
44                 die "$dir/$file: method number $number was already "
45                     . "allocated in $$config{number}{$number}\n";
46             }
47             $$config{number}{$dir} = $number;
48         } elsif (/^sources\s*=\s*(.*)/) {
49             my $sources = $1;
50             my @sources = split (' ', $sources);
51             push (@{ $$config{sources} }, map { "$dir/$_" } @sources);
52         } elsif (/^extra-sources\s*=\s*(.*)/) {
53             my $extra = $1;
54             my @extra = split (' ', $extra);
55             push (@{ $$config{extra} }, map { "$dir/$_" } @extra);
56         } elsif (/^programs\s*=\s*(.*)/) {
57             my $programs = $1;
58             my @programs = split (' ', $programs);
59             push (@{ $$config{programs} }, map { "$dir/$_" } @programs);
60         } else {
61             warn "$dir/$file: ignoring unknown line: $_\n";
62         }
63     }
64
65     # If there is a makefile fragment in the directory, note it.
66     if (-f "$dir/hismethod.mk") {
67         push (@{ $$config{makefiles} }, "$dir/hismethod.mk");
68     }
69 }
70
71 # Write out include directives for a list of files.
72 sub write_includes {
73     my ($fh, $config) = @_;
74     my $method;
75     for $method (sort keys %{ $$config{method} }) {
76         my $path = $$config{method}{$method};
77         print $fh qq(\#include "$path/$method.h"\n);
78     }
79 }
80
81 # Write out the method struct.
82 sub write_methods {
83     my ($fh, $config, $prefix, @funcs) = @_;
84     my ($notfirst, $method);
85     for $method (sort keys %{ $$config{method} }) {
86         print $fh "\n},\n" if $notfirst;
87         print $fh qq(\{\n    "$method");
88         print $fh ', ', $prefix, '_', uc ($method) if $prefix;
89         for (@funcs) {
90             print $fh ",\n    ${method}_$_";
91         }
92         $notfirst++;
93     }
94     print $fh "\n}\n};\n\n";
95 }
96
97 # Write out hismethods.c and hismethods.h for the interface to the history
98 # methods.
99 sub write_history {
100     my $history = shift;
101     open (DEF, '> hismethods.c.new')
102         or die "Can't create hismethods.c.new: $!\n";
103     print DEF unquote (<<'EOE');
104 :       /* This file is automatically generated by buildconfig. */
105 :
106 :       #include "hisinterface.h"
107 :       #include "hismethods.h"
108 EOE
109     my $method;
110     write_includes (\*DEF, $history);
111     print DEF "\nHIS_METHOD his_methods[",
112         scalar (keys %{ $$history{method} }), "] = {\n";
113     write_methods (\*DEF, $history, undef, @HISTORY);
114     close DEF;
115     rename ('hismethods.c.new', 'hismethods.c');
116
117     open (H, '> hismethods.h.new') or die "Can't open hismethods.h.new: $!\n";
118     print H unquote (<<'EOE');
119 :       /* This file is automatically generated by buildconfig */
120 :
121 :       #ifndef HISMETHODS_H
122 :       #define HISMETHODS_H 1
123 :
124 :       #include "hisinterface.h"
125 :
126 EOE
127     print H '#define NUM_HIS_METHODS ',
128         scalar (keys %{ $$history{method} }), "\n";
129     print H unquote (<<'EOE');
130 :
131 :       extern HIS_METHOD his_methods[NUM_HIS_METHODS];
132 :
133 :       #endif /* HISMETHODS_H */
134 EOE
135     close H;
136     rename ('hismethods.h.new', 'hismethods.h');
137 }
138
139 # Return a string setting a makefile variable.  Tab over the = properly and
140 # wrap to fit our coding standards.
141 sub makefile_var {
142     my ($variable, @values) = @_;
143     my $output;
144     $output = sprintf ("%-15s =", $variable);
145     my $column = 17;
146     for (@values) {
147         if ($column > 17 && 77 - $column < length ($_)) {
148             $output .= " \\\n" . ' ' x 17;
149             $column = 17;
150         }
151         $output .= " $_";
152         $column += 1 + length ($_);
153     }
154     $output .= "\n";
155     return $output;
156 }
157
158 # Write out the makefile fragment for history methods.
159 sub write_makefile {
160     my ($dirs, $sources, $extra, $programs, $makefiles) = @_;
161     open (MAKE, '> Make.methods.new')
162         or die "Can't create Make.methods.new: $!\n";
163     print MAKE "# This file is automatically generated by buildconfig\n\n";
164     print MAKE makefile_var ('METHOD_SOURCES', @$sources);
165     print MAKE makefile_var ('EXTRA_SOURCES', @$extra);
166     print MAKE makefile_var ('PROGRAMS', @$programs);
167     for (@$makefiles) {
168         print MAKE "\n\n##  Included from $_\n\n";
169         open (FRAG, $_) or die "Can't open $_: $!\n";
170         print MAKE <FRAG>;
171         close FRAG;
172     }
173     rename ('Make.methods.new', 'Make.methods');
174 }
175
176 my ($dir, %history);
177 if (!-d 'hisv6') {
178     if (-d 'history/cnfs') {
179         chdir 'history' or die "Can't chdir to history: $!\n";
180     } else {
181         die "Can't find history directory (looking for history/hisv6)\n";
182     }
183 }
184 opendir (D, ".") or die "Can't open current directory: $!\n";
185 my @dirs = sort readdir D;
186 for $dir (@dirs) {
187     if (-e "$dir/hismethod.config") {
188         parse_config ($dir, 'hismethod.config', \%history);
189     }
190 }
191 write_history (\%history);
192 @dirs = sort values %{ $history{method} };
193 my @sources = sort @{ $history{sources} };
194 my @extra = sort @{ $history{extra} };
195 my @programs = sort @{ $history{programs} };
196 my @makefiles = sort @{ $history{makefiles} };
197 write_makefile (\@dirs, \@sources, \@extra, \@programs, \@makefiles);