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