File guards of Package kernel-source (Revision cf170d4631bbd5bb1e6db8418deb34e0)
Currently displaying revision cf170d4631bbd5bb1e6db8418deb34e0, show latest
1
#!/usr/bin/perl -w
2
3
#
4
# Guards:
5
#
6
# +xxx include if xxx is defined
7
# -xxx exclude if xxx is defined
8
# +!xxx include if xxx is not defined
9
# -!xxx exclude if xxx is not defined
10
#
11
12
use FileHandle;
13
use Getopt::Long;
14
use strict;
15
16
# Prototypes
17
sub files_in($$);
18
sub parse($$);
19
sub help();
20
21
#sub strip_ext($) {
22
# local ($_) = @_;
23
# s/\.(diff?|patch)$//;
24
#}
25
26
#sub try_ext($) {
27
# my ($path) = @_;
28
# for my $p in (($path, "$path.diff", "$path.dif", "$path.patch")) {
29
# return $p
30
# if (-f $p);
31
# }
32
# return undef;
33
#}
34
35
sub slashme($) {
36
my ($dir) = @_;
37
$dir =~ s#([^/])$#$&/#; # append a slash if necessary
38
if ($dir eq './') {
39
return '';
40
} else {
41
return $dir;
42
}
43
}
44
45
# Generate a list of files in a directory
46
#
47
sub files_in($$) {
48
my ($dir, $path) = @_;
49
my $dh = new FileHandle;
50
my (@files, $file);
51
52
53
opendir $dh, length("$dir$path") ? "$dir$path" : '.'
54
or die "$dir$path: $!\n";
55
while ($file = readdir($dh)) {
56
next if $file =~ /^(\.|\.\.|\.#.*|CVS|.*~)$/;
57
if (-d "$dir$path$file") {
58
@files = (@files, files_in($dir, "$path$file/"));
59
} else {
60
#print "[$path$file]\n";
61
push @files, "$path$file";
62
}
63
}
64
closedir $dh;
65
return @files;
66
}
67
68
# Parse a configuration file
69
# Callback called with ($patch, @guards) arguments
70
#
71
sub parse($$) {
72
my ($fh, $callback) = @_;
73
74
my $line = "";
75
76
while (<$fh>) {
77
chomp;
78
s/(^|\s+)#.*//;
79
if (s/\\$/ /) {
80
$line .= $_;
81
next;
82
}
83
$line .= $_;
84
my @guards = ();
85
foreach my $token (split /[\s\t\n]+/, $line) {
86
next if $token eq "";
87
if ($token =~ /^[-+]/) {
88
push @guards, $token;
89
} else {
90
#print "[" . join(",", @guards) . "] $token\n";
91
&$callback($token, @guards);
92
}
93
}
94
$line = "";
95
}
96
}
97
98
# Command line options
99
#
100
my ($dir, $config, $default, $check, $list, $invert_match, $with_guards) =
101
( '', '-', 1, 0, 0, 0, 0);
102
my @path;
103
104
# Help text
105
#
106
sub help() {
107
print "$0 - select from a list of files guarded by conditions\n";
108
print "SYNOPSIS: $0 [--prefix=dir] [--path=dir1:dir2:...]\n" .
109
" [--default=0|1] [--check|--list] [--invert-match]\n" .
110
" [--with-guards] [--config=file] symbol ...\n\n" .
111
" (Default values: --path='" . join(':', @path) . "', " .
112
"--default=$default)\n";
113
exit 0;
114
}
115
116
# Parse command line options
117
#
118
Getopt::Long::Configure ("bundling");
119
eval {
120
unless (GetOptions (
121
'd|prefix=s' => \$dir,
122
'c|config=s' => \$config,
123
'C|check' => \$check,
124
'l|list' => \$list,
125
'w|with-guards' => \$with_guards,
126
'p|path=s' => \@path,
127
'D|default=i' => \$default,
128
'v|invert-match' => \$invert_match,
129
'h|help' => sub { help(); exit 0; })) {
130
help();
131
exit 1;
132
}
133
};
134
if ($@) {
135
print "$@";
136
help();
137
exit 1;
138
}
139
140
@path = ('.')
141
unless (@path);
142
@path = split(/:/, join(':', @path));
143
144
my $fh = ($config eq '-') ? \*STDIN : new FileHandle($config)
145
or die "$config: $!\n";
146
147
$dir = slashme($dir);
148
149
if ($check) {
150
# Check for duplicate files, or for files that are not referenced by
151
# the specification.
152
153
my $problems = 0;
154
my @files;
155
156
foreach (@path) {
157
@files = (@files, files_in($dir, slashme($_)));
158
}
159
my %files = map { $_ => 0 } @files;
160
161
parse($fh, sub {
162
my ($patch, @guards) = @_;
163
if (exists $files{$patch}) {
164
$files{$patch}++;
165
} else {
166
print "Not found: $dir$patch\n";
167
$problems++;
168
}});
169
170
$fh->close();
171
172
my ($file, $ref);
173
while (($file, $ref) = each %files) {
174
next if $ref == 1;
175
176
if ($ref == 0) {
177
print "Unused: $file\n" if $ref == 0;
178
$problems++;
179
}
180
if ($ref > 1) {
181
print "Warning: multiple uses: $file\n" if $ref > 1;
182
# This is not an error if the entries are mutually exclusive...
183
}
184
}
185
exit $problems ? 1 : 0;
186
187
} elsif ($list) {
188
parse($fh, sub {
189
my ($patch, @guards) = @_;
190
print join(' ', @guards), ' '
191
if (@guards && $with_guards);
192
print "$dir$patch\n";
193
});
194
} else {
195
# Generate a list of patches to apply.
196
197
my %symbols = map { $_ => 1 } @ARGV;
198
199
parse($fh, sub {
200
my ($patch, @guards) = @_;
201
202
my $selected;
203
if (@guards) {
204
# If the first guard is -xxx, the patch is included by default;
205
# if it is +xxx, the patch is excluded by default.
206
$selected = ($guards[0] =~ /^-/);
207
208
foreach (@guards) {
209
/^([-+])(!?)(.*)?/
210
or die "Bad guard '$_'\n";
211
212
# Check if the guard matches
213
if (($2 eq '!' && !exists $symbols{$3}) ||
214
($2 eq '' && ( $3 eq '' || exists $symbols{$3}))) {
215
# Include or exclude
216
$selected = ($1 eq '+');
217
}
218
}
219
} else {
220
# If there are no guards, use the specified default result.
221
$selected = $default;
222
}
223
224
print "$dir$patch\n"
225
if $selected ^ $invert_match;
226
});
227
228
$fh->close();
229
230
exit 0;
231
}
232
233
__END__
234
235
=head1 NAME
236
237
guards - select from a list of files guarded by conditions
238
239
=head1 SYNOPSIS
240
241
F<guards> [--prefix=F<dir>] [--path=F<dir1:dir2:...>] [--default=<0|1>]
242
[--check|--list] [--invert-match] [--with-guards] [--config=<file>]
243
I<symbol> ...
244
245
246
=head1 DESCRIPTION
247
248
The script reads a configuration file that may contain so-called guards, file
249
names, and comments, and writes those file names that satisfy all guards to
250
standard output. The script takes a list of symbols as its arguments. Each line
251
in the configuration file is processed separately. Lines may start with a
252
number of guards. The following guards are defined:
253
254
=over
255
256
+I<xxx> Include the file(s) on this line if the symbol I<xxx> is defined.
257
258
-I<xxx> Exclude the file(s) on this line if the symbol I<xxx> is defined.
259
260
+!I<xxx> Include the file(s) on this line if the symbol I<xxx> is not defined.
261
262
-!I<xxx> Exclude the file(s) on this line if the symbol I<xxx> is not defined.
263
264
- Exclude this file. Used to avoid spurious I<--check> messages.
265
266
=back
267
268
The guards are processed left to right. The last guard that matches determines
269
if the file is included. If no guard is specified, the I<--default>
270
setting determines if the file is included.
271
272
If no configuration file is specified, the script reads from standard input.
273
274
The I<--check> option is used to compare the specification file against the
275
file system. If files are referenced in the specification that do not exist, or
276
if files are not enlisted in the specification file warnings are printed. The
277
I<--path> option can be used to specify which directory or directories to scan.
278
Multiple directories are eparated by a colon (C<:>) character. The
279
I<--prefix> option specifies the location of the files.
280
281
Use I<--list> to list all files independend of any rules. Use I<--invert-match>
282
to list only the excluded patches. Use I<--with-guards> to also include all
283
inclusion and exclusion rules.
284
285
=head1 AUTHOR
286
287
Andreas Gruenbacher <agruen@suse.de>, SUSE Labs
288