]> git.ipfire.org Git - people/ms/linux.git/blame - scripts/get_feat.pl
scripts: kernel-doc: fix parsing function-like typedefs
[people/ms/linux.git] / scripts / get_feat.pl
CommitLineData
52a4be3f
MCC
1#!/usr/bin/perl
2# SPDX-License-Identifier: GPL-2.0
3
4use strict;
5use Pod::Usage;
6use Getopt::Long;
7use File::Find;
8use Fcntl ':mode';
ca908577 9use Cwd 'abs_path';
52a4be3f
MCC
10
11my $help;
12my $man;
13my $debug;
14my $arch;
15my $feat;
ca908577
MCC
16
17my $basename = abs_path($0);
18$basename =~ s,/[^/]+$,/,;
19
20my $prefix=$basename . "../Documentation/features";
52a4be3f
MCC
21
22GetOptions(
23 "debug|d+" => \$debug,
24 "dir=s" => \$prefix,
25 'help|?' => \$help,
26 'arch=s' => \$arch,
27 'feat=s' => \$feat,
ca908577 28 'feature=s' => \$feat,
52a4be3f
MCC
29 man => \$man
30) or pod2usage(2);
31
32pod2usage(1) if $help;
33pod2usage(-exitstatus => 0, -verbose => 2) if $man;
34
ca908577 35pod2usage(1) if (scalar @ARGV < 1 || @ARGV > 2);
52a4be3f
MCC
36
37my ($cmd, $arg) = @ARGV;
38
ca908577
MCC
39pod2usage(2) if ($cmd ne "current" && $cmd ne "rest" && $cmd ne "validate"
40 && $cmd ne "ls" && $cmd ne "list");
52a4be3f
MCC
41
42require Data::Dumper if ($debug);
43
44my %data;
45my %archs;
46
47#
48# Displays an error message, printing file name and line
49#
50sub parse_error($$$$) {
51 my ($file, $ln, $msg, $data) = @_;
52
53 $data =~ s/\s+$/\n/;
54
55 print STDERR "Warning: file $file#$ln:\n\t$msg";
56
57 if ($data ne "") {
58 print STDERR ". Line\n\t\t$data";
59 } else {
60 print STDERR "\n";
61 }
62}
63
64#
65# Parse a features file, storing its contents at %data
66#
67
68my $h_name = "Feature";
69my $h_kconfig = "Kconfig";
70my $h_description = "Description";
71my $h_subsys = "Subsystem";
72my $h_status = "Status";
73my $h_arch = "Architecture";
74
75my $max_size_name = length($h_name);
76my $max_size_kconfig = length($h_kconfig);
77my $max_size_description = length($h_description);
78my $max_size_subsys = length($h_subsys);
79my $max_size_status = length($h_status);
80my $max_size_arch = length($h_arch);
81
82sub parse_feat {
83 my $file = $File::Find::name;
84
85 my $mode = (stat($file))[2];
86 return if ($mode & S_IFDIR);
87 return if ($file =~ m,($prefix)/arch-support.txt,);
88 return if (!($file =~ m,arch-support.txt$,));
89
90 my $subsys = "";
91 $subsys = $2 if ( m,.*($prefix)/([^/]+).*,);
92
93 if (length($subsys) > $max_size_subsys) {
94 $max_size_subsys = length($subsys);
95 }
96
97 my $name;
98 my $kconfig;
99 my $description;
100 my $comments = "";
101 my $last_status;
102 my $ln;
103 my %arch_table;
104
105 print STDERR "Opening $file\n" if ($debug > 1);
106 open IN, $file;
107
108 while(<IN>) {
109 $ln++;
110
111 if (m/^\#\s+Feature\s+name:\s*(.*\S)/) {
112 $name = $1;
113 if (length($name) > $max_size_name) {
114 $max_size_name = length($name);
115 }
116 next;
117 }
118 if (m/^\#\s+Kconfig:\s*(.*\S)/) {
119 $kconfig = $1;
120 if (length($kconfig) > $max_size_kconfig) {
121 $max_size_kconfig = length($kconfig);
122 }
123 next;
124 }
125 if (m/^\#\s+description:\s*(.*\S)/) {
126 $description = $1;
127 if (length($description) > $max_size_description) {
128 $max_size_description = length($description);
129 }
130 next;
131 }
132 next if (m/^\\s*$/);
133 next if (m/^\s*\-+\s*$/);
134 next if (m/^\s*\|\s*arch\s*\|\s*status\s*\|\s*$/);
135
136 if (m/^\#\s*(.*)/) {
137 $comments .= "$1\n";
138 next;
139 }
140 if (m/^\s*\|\s*(\S+):\s*\|\s*(\S+)\s*\|\s*$/) {
141 my $a = $1;
142 my $status = $2;
143
144 if (length($status) > $max_size_status) {
145 $max_size_status = length($status);
146 }
147 if (length($a) > $max_size_arch) {
148 $max_size_arch = length($a);
149 }
150
151 $status = "---" if ($status =~ m/^\.\.$/);
152
153 $archs{$a} = 1;
154 $arch_table{$a} = $status;
155 next;
156 }
157
158 #Everything else is an error
159 parse_error($file, $ln, "line is invalid", $_);
160 }
161 close IN;
162
163 if (!$name) {
164 parse_error($file, $ln, "Feature name not found", "");
165 return;
166 }
167
168 parse_error($file, $ln, "Subsystem not found", "") if (!$subsys);
169 parse_error($file, $ln, "Kconfig not found", "") if (!$kconfig);
170 parse_error($file, $ln, "Description not found", "") if (!$description);
171
172 if (!%arch_table) {
173 parse_error($file, $ln, "Architecture table not found", "");
174 return;
175 }
176
177 $data{$name}->{where} = $file;
178 $data{$name}->{subsys} = $subsys;
179 $data{$name}->{kconfig} = $kconfig;
180 $data{$name}->{description} = $description;
181 $data{$name}->{comments} = $comments;
182 $data{$name}->{table} = \%arch_table;
183}
184
185#
186# Output feature(s) for a given architecture
187#
188sub output_arch_table {
189 my $title = "Feature status on $arch architecture";
190
191 print "=" x length($title) . "\n";
192 print "$title\n";
193 print "=" x length($title) . "\n\n";
194
195 print "=" x $max_size_subsys;
196 print " ";
197 print "=" x $max_size_name;
198 print " ";
199 print "=" x $max_size_kconfig;
200 print " ";
201 print "=" x $max_size_status;
202 print " ";
203 print "=" x $max_size_description;
204 print "\n";
205 printf "%-${max_size_subsys}s ", $h_subsys;
206 printf "%-${max_size_name}s ", $h_name;
207 printf "%-${max_size_kconfig}s ", $h_kconfig;
208 printf "%-${max_size_status}s ", $h_status;
209 printf "%-${max_size_description}s\n", $h_description;
210 print "=" x $max_size_subsys;
211 print " ";
212 print "=" x $max_size_name;
213 print " ";
214 print "=" x $max_size_kconfig;
215 print " ";
216 print "=" x $max_size_status;
217 print " ";
218 print "=" x $max_size_description;
219 print "\n";
220
221 foreach my $name (sort {
222 ($data{$a}->{subsys} cmp $data{$b}->{subsys}) ||
ca908577 223 ("\L$a" cmp "\L$b")
52a4be3f
MCC
224 } keys %data) {
225 next if ($feat && $name ne $feat);
226
227 my %arch_table = %{$data{$name}->{table}};
228 printf "%-${max_size_subsys}s ", $data{$name}->{subsys};
229 printf "%-${max_size_name}s ", $name;
230 printf "%-${max_size_kconfig}s ", $data{$name}->{kconfig};
231 printf "%-${max_size_status}s ", $arch_table{$arch};
ca908577 232 printf "%-s\n", $data{$name}->{description};
52a4be3f
MCC
233 }
234
235 print "=" x $max_size_subsys;
236 print " ";
237 print "=" x $max_size_name;
238 print " ";
239 print "=" x $max_size_kconfig;
240 print " ";
241 print "=" x $max_size_status;
242 print " ";
243 print "=" x $max_size_description;
244 print "\n";
245}
246
ca908577
MCC
247#
248# list feature(s) for a given architecture
249#
250sub list_arch_features {
251 print "#\n# Kernel feature support matrix of the '$arch' architecture:\n#\n";
252
253 foreach my $name (sort {
254 ($data{$a}->{subsys} cmp $data{$b}->{subsys}) ||
255 ("\L$a" cmp "\L$b")
256 } keys %data) {
257 next if ($feat && $name ne $feat);
258
259 my %arch_table = %{$data{$name}->{table}};
260
261 my $status = $arch_table{$arch};
262 $status = " " x ((4 - length($status)) / 2) . $status;
263
264 printf " %${max_size_subsys}s/ ", $data{$name}->{subsys};
265 printf "%-${max_size_name}s: ", $name;
266 printf "%-5s| ", $status;
267 printf "%${max_size_kconfig}s # ", $data{$name}->{kconfig};
268 printf " %s\n", $data{$name}->{description};
269 }
270}
271
52a4be3f
MCC
272#
273# Output a feature on all architectures
274#
275sub output_feature {
276 my $title = "Feature $feat";
277
278 print "=" x length($title) . "\n";
279 print "$title\n";
280 print "=" x length($title) . "\n\n";
281
282 print ":Subsystem: $data{$feat}->{subsys} \n" if ($data{$feat}->{subsys});
283 print ":Kconfig: $data{$feat}->{kconfig} \n" if ($data{$feat}->{kconfig});
284
285 my $desc = $data{$feat}->{description};
286 $desc =~ s/^([a-z])/\U$1/;
287 $desc =~ s/\.?\s*//;
288 print "\n$desc.\n\n";
289
290 my $com = $data{$feat}->{comments};
291 $com =~ s/^\s+//;
292 $com =~ s/\s+$//;
293 if ($com) {
294 print "Comments\n";
295 print "--------\n\n";
296 print "$com\n\n";
297 }
298
299 print "=" x $max_size_arch;
300 print " ";
301 print "=" x $max_size_status;
302 print "\n";
303
304 printf "%-${max_size_arch}s ", $h_arch;
305 printf "%-${max_size_status}s", $h_status . "\n";
306
307 print "=" x $max_size_arch;
308 print " ";
309 print "=" x $max_size_status;
310 print "\n";
311
312 my %arch_table = %{$data{$feat}->{table}};
313 foreach my $arch (sort keys %arch_table) {
314 printf "%-${max_size_arch}s ", $arch;
315 printf "%-${max_size_status}s\n", $arch_table{$arch};
316 }
317
318 print "=" x $max_size_arch;
319 print " ";
320 print "=" x $max_size_status;
321 print "\n";
322}
323
324#
325# Output all features for all architectures
326#
327
ba813f7c
MCC
328sub matrix_lines($$) {
329 my $partial = shift;
330 my $header = shift;
331 my $split;
332 my $fill;
333 my $ln_marker;
334
335 if ($header) {
336 $ln_marker = "=";
337 } else {
338 $ln_marker = "-";
339 }
52a4be3f 340
ba813f7c
MCC
341 if ($partial) {
342 $split = "|";
343 $fill = " ";
344 } else {
345 $split = "+";
346 $fill = $ln_marker;
52a4be3f 347 }
ba813f7c
MCC
348
349 print $split;
350 print $fill x $max_size_name;
351 print $split;
352 print $fill x $max_size_kconfig;
353 print $split;
354 print $fill x $max_size_description;
355 print "+";
356 print $ln_marker x $max_size_arch;
357 print "+";
358 print $ln_marker x $max_size_status;
359 print "+\n";
52a4be3f
MCC
360}
361
362sub output_matrix {
ba813f7c 363 my $title = "Feature status on all architectures";
52a4be3f
MCC
364
365 print "=" x length($title) . "\n";
366 print "$title\n";
367 print "=" x length($title) . "\n\n";
368
ba813f7c
MCC
369 my $cur_subsys = "";
370 foreach my $name (sort {
371 ($data{$a}->{subsys} cmp $data{$b}->{subsys}) or
ca908577 372 ("\L$a" cmp "\L$b")
ba813f7c 373 } keys %data) {
52a4be3f 374
ba813f7c
MCC
375 if ($cur_subsys ne $data{$name}->{subsys}) {
376 if ($cur_subsys ne "") {
377 printf "\n";
378 }
52a4be3f 379
ba813f7c 380 $cur_subsys = $data{$name}->{subsys};
52a4be3f 381
ba813f7c
MCC
382 my $title = "Subsystem: $cur_subsys";
383 print "$title\n";
384 print "=" x length($title) . "\n\n";
52a4be3f 385
ba813f7c
MCC
386 matrix_lines(0, 0);
387 printf "|%-${max_size_name}s", $h_name;
388 printf "|%-${max_size_kconfig}s", $h_kconfig;
389 printf "|%-${max_size_description}s", $h_description;
52a4be3f 390
ba813f7c
MCC
391 printf "|%-${max_size_arch}s", $h_arch;
392 printf "|%-${max_size_status}s|\n", $h_status;
52a4be3f 393
ba813f7c
MCC
394 matrix_lines(0, 1);
395 }
52a4be3f 396
ba813f7c
MCC
397 my %arch_table = %{$data{$name}->{table}};
398 my $first = 1;
399 foreach my $arch (sort keys %arch_table) {
400 if ($first) {
401 printf "|%-${max_size_name}s", $name;
402 printf "|%-${max_size_kconfig}s", $data{$name}->{kconfig};
403 printf "|%-${max_size_description}s", $data{$name}->{description};
404 $first = 0;
405 } else {
406 matrix_lines(1, 0);
407
408 printf "|%-${max_size_name}s", "";
409 printf "|%-${max_size_kconfig}s", "";
410 printf "|%-${max_size_description}s", "";
411 }
412 printf "|%-${max_size_arch}s", $arch;
413 printf "|%-${max_size_status}s|\n", $arch_table{$arch};
52a4be3f 414 }
ba813f7c 415 matrix_lines(0, 0);
52a4be3f 416 }
52a4be3f
MCC
417}
418
419
420#
421# Parses all feature files located at $prefix dir
422#
423find({wanted =>\&parse_feat, no_chdir => 1}, $prefix);
424
425print STDERR Data::Dumper->Dump([\%data], [qw(*data)]) if ($debug);
426
427#
428# Handles the command
429#
430if ($cmd eq "current") {
431 $arch = qx(uname -m | sed 's/x86_64/x86/' | sed 's/i386/x86/');
432 $arch =~s/\s+$//;
433}
434
ca908577
MCC
435if ($cmd eq "ls" or $cmd eq "list") {
436 if (!$arch) {
437 $arch = qx(uname -m | sed 's/x86_64/x86/' | sed 's/i386/x86/');
438 $arch =~s/\s+$//;
439 }
440
441 list_arch_features;
442
443 exit;
444}
445
52a4be3f
MCC
446if ($cmd ne "validate") {
447 if ($arch) {
448 output_arch_table;
449 } elsif ($feat) {
450 output_feature;
451 } else {
452 output_matrix;
453 }
454}
455
456__END__
457
458=head1 NAME
459
460get_feat.pl - parse the Linux Feature files and produce a ReST book.
461
462=head1 SYNOPSIS
463
ca908577
MCC
464B<get_feat.pl> [--debug] [--man] [--help] [--dir=<dir>] [--arch=<arch>]
465 [--feature=<feature>|--feat=<feature>] <COMAND> [<ARGUMENT>]
52a4be3f
MCC
466
467Where <COMMAND> can be:
468
469=over 8
470
ca908577
MCC
471B<current> - output table in ReST compatible ASCII format
472 with features for this machine's architecture
473
474B<rest> - output table(s) in ReST compatible ASCII format
475 with features in ReST markup language. The output
476 is affected by --arch or --feat/--feature flags.
52a4be3f 477
ca908577
MCC
478B<validate> - validate the contents of the files under
479 Documentation/features.
52a4be3f 480
ca908577
MCC
481B<ls> or B<list> - list features for this machine's architecture,
482 using an easier to parse format.
483 The output is affected by --arch flag.
52a4be3f
MCC
484
485=back
486
487=head1 OPTIONS
488
489=over 8
490
491=item B<--arch>
492
493Output features for an specific architecture, optionally filtering for
494a single specific feature.
495
ca908577 496=item B<--feat> or B<--feature>
52a4be3f 497
ca908577 498Output features for a single specific feature.
52a4be3f
MCC
499
500=item B<--dir>
501
502Changes the location of the Feature files. By default, it uses
503the Documentation/features directory.
504
505=item B<--debug>
506
507Put the script in verbose mode, useful for debugging. Can be called multiple
508times, to increase verbosity.
509
510=item B<--help>
511
512Prints a brief help message and exits.
513
514=item B<--man>
515
516Prints the manual page and exits.
517
518=back
519
520=head1 DESCRIPTION
521
522Parse the Linux feature files from Documentation/features (by default),
523optionally producing results at ReST format.
524
525It supports output data per architecture, per feature or a
526feature x arch matrix.
527
528When used with B<rest> command, it will use either one of the tree formats:
529
530If neither B<--arch> or B<--feature> arguments are used, it will output a
531matrix with features per architecture.
532
533If B<--arch> argument is used, it will output the features availability for
534a given architecture.
535
536If B<--feat> argument is used, it will output the content of the feature
537file using ReStructured Text markup.
538
539=head1 BUGS
540
541Report bugs to Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
542
543=head1 COPYRIGHT
544
545Copyright (c) 2019 by Mauro Carvalho Chehab <mchehab+samsung@kernel.org>.
546
547License GPLv2: GNU GPL version 2 <http://gnu.org/licenses/gpl.html>.
548
549This is free software: you are free to change and redistribute it.
550There is NO WARRANTY, to the extent permitted by law.
551
552=cut