scripts: get_abi.pl: don't skip what that ends with wildcards
[linux-block.git] / scripts / get_abi.pl
CommitLineData
c25ce589 1#!/usr/bin/env perl
ecb351f1 2# SPDX-License-Identifier: GPL-2.0
bbc249f2
MCC
3
4use strict;
234948bf 5use warnings;
55e5414f 6use utf8;
bbc249f2
MCC
7use Pod::Usage;
8use Getopt::Long;
9use File::Find;
10use Fcntl ':mode';
ab02c515 11use Cwd 'abs_path';
bbc249f2 12
234948bf 13my $help = 0;
ab02c515 14my $hint = 0;
234948bf
MCC
15my $man = 0;
16my $debug = 0;
17my $enable_lineno = 0;
f090db43 18my $show_warnings = 1;
33e3e991 19my $prefix="Documentation/ABI";
f090db43 20my $sysfs_prefix="/sys";
14c94257 21my $search_string;
bbc249f2 22
11ce90a4
MCC
23#
24# If true, assumes that the description is formatted with ReST
25#
2fcce37a 26my $description_is_rst = 1;
11ce90a4 27
bbc249f2
MCC
28GetOptions(
29 "debug|d+" => \$debug,
61439c4a 30 "enable-lineno" => \$enable_lineno,
11ce90a4 31 "rst-source!" => \$description_is_rst,
33e3e991 32 "dir=s" => \$prefix,
bbc249f2 33 'help|?' => \$help,
ab02c515 34 "show-hints" => \$hint,
14c94257 35 "search-string=s" => \$search_string,
bbc249f2
MCC
36 man => \$man
37) or pod2usage(2);
38
39pod2usage(1) if $help;
40pod2usage(-exitstatus => 0, -verbose => 2) if $man;
41
33e3e991 42pod2usage(2) if (scalar @ARGV < 1 || @ARGV > 2);
bbc249f2 43
33e3e991
MCC
44my ($cmd, $arg) = @ARGV;
45
f090db43 46pod2usage(2) if ($cmd ne "search" && $cmd ne "rest" && $cmd ne "validate" && $cmd ne "undefined");
33e3e991 47pod2usage(2) if ($cmd eq "search" && !$arg);
bbc249f2
MCC
48
49require Data::Dumper if ($debug);
50
51my %data;
234948bf 52my %symbols;
bbc249f2
MCC
53
54#
55# Displays an error message, printing file name and line
56#
57sub parse_error($$$$) {
58 my ($file, $ln, $msg, $data) = @_;
59
f090db43
MCC
60 return if (!$show_warnings);
61
75442fb0
MCC
62 $data =~ s/\s+$/\n/;
63
64 print STDERR "Warning: file $file#$ln:\n\t$msg";
65
66 if ($data ne "") {
67 print STDERR ". Line\n\t\t$data";
68 } else {
69 print STDERR "\n";
70 }
bbc249f2
MCC
71}
72
73#
74# Parse an ABI file, storing its contents at %data
75#
76sub parse_abi {
77 my $file = $File::Find::name;
78
79 my $mode = (stat($file))[2];
80 return if ($mode & S_IFDIR);
81 return if ($file =~ m,/README,);
82
83 my $name = $file;
84 $name =~ s,.*/,,;
85
a4ea67bc
MCC
86 my $fn = $file;
87 $fn =~ s,Documentation/ABI/,,;
88
89 my $nametag = "File $fn";
d0ebaf51
MCC
90 $data{$nametag}->{what} = "File $name";
91 $data{$nametag}->{type} = "File";
92 $data{$nametag}->{file} = $name;
33e3e991 93 $data{$nametag}->{filepath} = $file;
d0ebaf51 94 $data{$nametag}->{is_file} = 1;
61439c4a 95 $data{$nametag}->{line_no} = 1;
d0ebaf51 96
bbc249f2
MCC
97 my $type = $file;
98 $type =~ s,.*/(.*)/.*,$1,;
99
100 my $what;
101 my $new_what;
234948bf 102 my $tag = "";
bbc249f2 103 my $ln;
6619c661 104 my $xrefs;
4e6a6234 105 my $space;
d0ebaf51 106 my @labels;
234948bf 107 my $label = "";
bbc249f2
MCC
108
109 print STDERR "Opening $file\n" if ($debug > 1);
110 open IN, $file;
111 while(<IN>) {
112 $ln++;
4e6a6234 113 if (m/^(\S+)(:\s*)(.*)/i) {
bbc249f2 114 my $new_tag = lc($1);
4e6a6234
MCC
115 my $sep = $2;
116 my $content = $3;
bbc249f2 117
7ce7b89b 118 if (!($new_tag =~ m/(what|where|date|kernelversion|contact|description|users)/)) {
bbc249f2 119 if ($tag eq "description") {
4e6a6234
MCC
120 # New "tag" is actually part of
121 # description. Don't consider it a tag
122 $new_tag = "";
7d7ea8d2 123 } elsif ($tag ne "") {
bbc249f2
MCC
124 parse_error($file, $ln, "tag '$tag' is invalid", $_);
125 }
126 }
127
2c0700e7
MCC
128 # Invalid, but it is a common mistake
129 if ($new_tag eq "where") {
75442fb0 130 parse_error($file, $ln, "tag 'Where' is invalid. Should be 'What:' instead", "");
2c0700e7
MCC
131 $new_tag = "what";
132 }
133
bbc249f2 134 if ($new_tag =~ m/what/) {
4e6a6234 135 $space = "";
234948bf
MCC
136 $content =~ s/[,.;]$//;
137
c7ba3334
MCC
138 push @{$symbols{$content}->{file}}, " $file:" . ($ln - 1);
139
bbc249f2 140 if ($tag =~ m/what/) {
ab9c1480 141 $what .= "\xac" . $content;
bbc249f2 142 } else {
234948bf
MCC
143 if ($what) {
144 parse_error($file, $ln, "What '$what' doesn't have a description", "") if (!$data{$what}->{description});
145
ab9c1480 146 foreach my $w(split /\xac/, $what) {
c7ba3334 147 $symbols{$w}->{xref} = $what;
234948bf
MCC
148 };
149 }
4e6a6234 150
bbc249f2 151 $what = $content;
d0ebaf51 152 $label = $content;
bbc249f2
MCC
153 $new_what = 1;
154 }
d0ebaf51 155 push @labels, [($content, $label)];
bbc249f2 156 $tag = $new_tag;
6619c661 157
234948bf 158 push @{$data{$nametag}->{symbols}}, $content if ($data{$nametag}->{what});
bbc249f2
MCC
159 next;
160 }
161
7d7ea8d2 162 if ($tag ne "" && $new_tag) {
4e6a6234 163 $tag = $new_tag;
bbc249f2 164
4e6a6234 165 if ($new_what) {
234948bf 166 @{$data{$what}->{label_list}} = @labels if ($data{$nametag}->{what});
d0ebaf51
MCC
167 @labels = ();
168 $label = "";
4e6a6234 169 $new_what = 0;
bbc249f2 170
4e6a6234 171 $data{$what}->{type} = $type;
c7ba3334
MCC
172 if (!defined($data{$what}->{file})) {
173 $data{$what}->{file} = $name;
174 $data{$what}->{filepath} = $file;
175 } else {
176 if ($name ne $data{$what}->{file}) {
177 $data{$what}->{file} .= " " . $name;
178 $data{$what}->{filepath} .= " " . $file;
179 }
180 }
4e6a6234 181 print STDERR "\twhat: $what\n" if ($debug > 1);
c7ba3334
MCC
182 $data{$what}->{line_no} = $ln;
183 } else {
184 $data{$what}->{line_no} = $ln if (!defined($data{$what}->{line_no}));
4e6a6234 185 }
bbc249f2 186
4e6a6234
MCC
187 if (!$what) {
188 parse_error($file, $ln, "'What:' should come first:", $_);
189 next;
190 }
f82a8a74
MCC
191 if ($new_tag eq "description") {
192 $sep =~ s,:, ,;
11ce90a4 193 $content = ' ' x length($new_tag) . $sep . $content;
f82a8a74
MCC
194 while ($content =~ s/\t+/' ' x (length($&) * 8 - length($`) % 8)/e) {}
195 if ($content =~ m/^(\s*)(\S.*)$/) {
196 # Preserve initial spaces for the first line
11ce90a4 197 $space = $1;
f82a8a74
MCC
198 $content = "$2\n";
199 $data{$what}->{$tag} .= $content;
200 } else {
201 undef($space);
4e6a6234 202 }
e9bca891 203
4e6a6234
MCC
204 } else {
205 $data{$what}->{$tag} = $content;
206 }
bbc249f2
MCC
207 next;
208 }
bbc249f2
MCC
209 }
210
4e6a6234 211 # Store any contents before tags at the database
d0ebaf51
MCC
212 if (!$tag && $data{$nametag}->{what}) {
213 $data{$nametag}->{description} .= $_;
6619c661
MCC
214 next;
215 }
bbc249f2 216
4e6a6234 217 if ($tag eq "description") {
e9bca891
MCC
218 my $content = $_;
219 while ($content =~ s/\t+/' ' x (length($&) * 8 - length($`) % 8)/e) {}
f82a8a74
MCC
220 if (m/^\s*\n/) {
221 $data{$what}->{$tag} .= "\n";
222 next;
223 }
224
225 if (!defined($space)) {
e9bca891 226 # Preserve initial spaces for the first line
f82a8a74 227 if ($content =~ m/^(\s*)(\S.*)$/) {
e9bca891 228 $space = $1;
f82a8a74 229 $content = "$2\n";
4e6a6234
MCC
230 }
231 } else {
4e6a6234 232 $space = "" if (!($content =~ s/^($space)//));
4e6a6234 233 }
f82a8a74
MCC
234 $data{$what}->{$tag} .= $content;
235
4e6a6234
MCC
236 next;
237 }
bbc249f2
MCC
238 if (m/^\s*(.*)/) {
239 $data{$what}->{$tag} .= "\n$1";
240 $data{$what}->{$tag} =~ s/\n+$//;
241 next;
242 }
243
244 # Everything else is error
75442fb0 245 parse_error($file, $ln, "Unexpected content", $_);
bbc249f2 246 }
234948bf
MCC
247 $data{$nametag}->{description} =~ s/^\n+// if ($data{$nametag}->{description});
248 if ($what) {
249 parse_error($file, $ln, "What '$what' doesn't have a description", "") if (!$data{$what}->{description});
250
ab9c1480 251 foreach my $w(split /\xac/,$what) {
c7ba3334 252 $symbols{$w}->{xref} = $what;
234948bf
MCC
253 };
254 }
bbc249f2
MCC
255 close IN;
256}
257
234948bf
MCC
258sub create_labels {
259 my %labels;
bbc249f2 260
234948bf
MCC
261 foreach my $what (keys %data) {
262 next if ($data{$what}->{file} eq "File");
4e6a6234 263
234948bf 264 foreach my $p (@{$data{$what}->{label_list}}) {
d0ebaf51
MCC
265 my ($content, $label) = @{$p};
266 $label = "abi_" . $label . " ";
267 $label =~ tr/A-Z/a-z/;
268
269 # Convert special chars to "_"
270 $label =~s/([\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\xff])/_/g;
271 $label =~ s,_+,_,g;
272 $label =~ s,_$,,;
273
2e7ce055
MCC
274 # Avoid duplicated labels
275 while (defined($labels{$label})) {
276 my @chars = ("A".."Z", "a".."z");
277 $label .= $chars[rand @chars];
278 }
279 $labels{$label} = 1;
280
234948bf 281 $data{$what}->{label} = $label;
d0ebaf51
MCC
282
283 # only one label is enough
284 last;
6619c661 285 }
234948bf
MCC
286 }
287}
288
289#
290# Outputs the book on ReST format
291#
292
50ebf8f4
MCC
293# \b doesn't work well with paths. So, we need to define something else:
294# Boundaries are punct characters, spaces and end-of-line
295my $start = qr {(^|\s|\() }x;
296my $bondary = qr { ([,.:;\)\s]|\z) }x;
87ec9ea1 297my $xref_match = qr { $start(\/(sys|config|proc|dev|kvd)\/[^,.:;\)\s]+)$bondary }x;
b0f9580a 298my $symbols = qr { ([\x01-\x08\x0e-\x1f\x21-\x2f\x3a-\x40\x7b-\xff]) }x;
55e5414f 299
234948bf
MCC
300sub output_rest {
301 create_labels();
302
9d4fdda3
MCC
303 my $part = "";
304
234948bf
MCC
305 foreach my $what (sort {
306 ($data{$a}->{type} eq "File") cmp ($data{$b}->{type} eq "File") ||
307 $a cmp $b
308 } keys %data) {
309 my $type = $data{$what}->{type};
c7ba3334
MCC
310
311 my @file = split / /, $data{$what}->{file};
312 my @filepath = split / /, $data{$what}->{filepath};
234948bf
MCC
313
314 if ($enable_lineno) {
315 printf "#define LINENO %s%s#%s\n\n",
c7ba3334 316 $prefix, $file[0],
234948bf
MCC
317 $data{$what}->{line_no};
318 }
6619c661 319
234948bf 320 my $w = $what;
6619c661 321
c7ba3334 322 if ($type ne "File") {
9d4fdda3
MCC
323 my $cur_part = $what;
324 if ($what =~ '/') {
325 if ($what =~ m#^(\/?(?:[\w\-]+\/?){1,2})#) {
326 $cur_part = "Symbols under $1";
327 $cur_part =~ s,/$,,;
328 }
329 }
330
331 if ($cur_part ne "" && $part ne $cur_part) {
332 $part = $cur_part;
333 my $bar = $part;
334 $bar =~ s/./-/g;
335 print "$part\n$bar\n\n";
336 }
337
234948bf 338 printf ".. _%s:\n\n", $data{$what}->{label};
45f96517 339
ab9c1480 340 my @names = split /\xac/,$w;
45f96517
MCC
341 my $len = 0;
342
343 foreach my $name (@names) {
b0f9580a 344 $name =~ s/$symbols/\\$1/g;
c01d62d3 345 $name = "**$name**";
45f96517
MCC
346 $len = length($name) if (length($name) > $len);
347 }
348
45f96517
MCC
349 print "+-" . "-" x $len . "-+\n";
350 foreach my $name (@names) {
351 printf "| %s", $name . " " x ($len - length($name)) . " |\n";
352 print "+-" . "-" x $len . "-+\n";
353 }
45f96517 354
c7ba3334
MCC
355 print "\n";
356 }
357
358 for (my $i = 0; $i < scalar(@filepath); $i++) {
359 my $path = $filepath[$i];
360 my $f = $file[$i];
361
362 $path =~ s,.*/(.*/.*),$1,;;
363 $path =~ s,[/\-],_,g;;
364 my $fileref = "abi_file_".$path;
365
366 if ($type eq "File") {
c7ba3334 367 print ".. _$fileref:\n\n";
c7ba3334
MCC
368 } else {
369 print "Defined on file :ref:`$f <$fileref>`\n\n";
370 }
234948bf 371 }
bbc249f2 372
a4ea67bc
MCC
373 if ($type eq "File") {
374 my $bar = $w;
375 $bar =~ s/./-/g;
376 print "$w\n$bar\n\n";
377 }
378
234948bf
MCC
379 my $desc = "";
380 $desc = $data{$what}->{description} if (defined($data{$what}->{description}));
381 $desc =~ s/\s+$/\n/;
bbc249f2 382
4e6a6234 383 if (!($desc =~ /^\s*$/)) {
11ce90a4 384 if ($description_is_rst) {
daaaf58a
MCC
385 # Remove title markups from the description
386 # Having titles inside ABI files will only work if extra
387 # care would be taken in order to strictly follow the same
388 # level order for each markup.
389 $desc =~ s/\n[\-\*\=\^\~]+\n/\n\n/g;
390
55e5414f
MCC
391 # Enrich text by creating cross-references
392
c27c2e34 393 my $new_desc = "";
2ae7bb57
MCC
394 my $init_indent = -1;
395 my $literal_indent = -1;
396
c27c2e34
MCC
397 open(my $fh, "+<", \$desc);
398 while (my $d = <$fh>) {
2ae7bb57
MCC
399 my $indent = $d =~ m/^(\s+)/;
400 my $spaces = length($indent);
401 $init_indent = $indent if ($init_indent < 0);
402 if ($literal_indent >= 0) {
403 if ($spaces > $literal_indent) {
404 $new_desc .= $d;
405 next;
406 } else {
407 $literal_indent = -1;
408 }
409 } else {
410 if ($d =~ /()::$/ && !($d =~ /^\s*\.\./)) {
411 $literal_indent = $spaces;
412 }
413 }
414
c27c2e34
MCC
415 $d =~ s,Documentation/(?!devicetree)(\S+)\.rst,:doc:`/$1`,g;
416
417 my @matches = $d =~ m,Documentation/ABI/([\w\/\-]+),g;
418 foreach my $f (@matches) {
419 my $xref = $f;
420 my $path = $f;
421 $path =~ s,.*/(.*/.*),$1,;;
422 $path =~ s,[/\-],_,g;;
423 $xref .= " <abi_file_" . $path . ">";
424 $d =~ s,\bDocumentation/ABI/$f\b,:ref:`$xref`,g;
425 }
55e5414f 426
c27c2e34
MCC
427 # Seek for cross reference symbols like /sys/...
428 @matches = $d =~ m/$xref_match/g;
55e5414f 429
c27c2e34
MCC
430 foreach my $s (@matches) {
431 next if (!($s =~ m,/,));
432 if (defined($data{$s}) && defined($data{$s}->{label})) {
433 my $xref = $s;
55e5414f 434
c27c2e34
MCC
435 $xref =~ s/$symbols/\\$1/g;
436 $xref = ":ref:`$xref <" . $data{$s}->{label} . ">`";
55e5414f 437
c27c2e34
MCC
438 $d =~ s,$start$s$bondary,$1$xref$2,g;
439 }
55e5414f 440 }
c27c2e34 441 $new_desc .= $d;
55e5414f 442 }
c27c2e34
MCC
443 close $fh;
444
55e5414f 445
c27c2e34 446 print "$new_desc\n\n";
4e6a6234 447 } else {
11ce90a4 448 $desc =~ s/^\s+//;
bbc249f2 449
11ce90a4
MCC
450 # Remove title markups from the description, as they won't work
451 $desc =~ s/\n[\-\*\=\^\~]+\n/\n\n/g;
452
453 if ($desc =~ m/\:\n/ || $desc =~ m/\n[\t ]+/ || $desc =~ m/[\x00-\x08\x0b-\x1f\x7b-\xff]/) {
454 # put everything inside a code block
455 $desc =~ s/\n/\n /g;
456
457 print "::\n\n";
458 print " $desc\n\n";
459 } else {
460 # Escape any special chars from description
461 $desc =~s/([\x00-\x08\x0b-\x1f\x21-\x2a\x2d\x2f\x3c-\x40\x5c\x5e-\x60\x7b-\xff])/\\$1/g;
462 print "$desc\n\n";
463 }
4e6a6234 464 }
bbc249f2 465 } else {
d0ebaf51 466 print "DESCRIPTION MISSING for $what\n\n" if (!$data{$what}->{is_file});
bbc249f2 467 }
6619c661 468
234948bf 469 if ($data{$what}->{symbols}) {
d0ebaf51
MCC
470 printf "Has the following ABI:\n\n";
471
234948bf 472 foreach my $content(@{$data{$what}->{symbols}}) {
c7ba3334 473 my $label = $data{$symbols{$content}->{xref}}->{label};
d0ebaf51
MCC
474
475 # Escape special chars from content
476 $content =~s/([\x00-\x1f\x21-\x2f\x3a-\x40\x7b-\xff])/\\$1/g;
477
478 print "- :ref:`$content <$label>`\n\n";
479 }
480 }
a16ab14e
MCC
481
482 if (defined($data{$what}->{users})) {
483 my $users = $data{$what}->{users};
484
485 $users =~ s/\n/\n\t/g;
486 printf "Users:\n\t%s\n\n", $users if ($users ne "");
487 }
488
bbc249f2
MCC
489 }
490}
491
33e3e991
MCC
492#
493# Searches for ABI symbols
494#
495sub search_symbols {
496 foreach my $what (sort keys %data) {
497 next if (!($what =~ m/($arg)/));
498
499 my $type = $data{$what}->{type};
500 next if ($type eq "File");
501
502 my $file = $data{$what}->{filepath};
503
504 my $bar = $what;
505 $bar =~ s/./-/g;
506
507 print "\n$what\n$bar\n\n";
508
234948bf
MCC
509 my $kernelversion = $data{$what}->{kernelversion} if (defined($data{$what}->{kernelversion}));
510 my $contact = $data{$what}->{contact} if (defined($data{$what}->{contact}));
511 my $users = $data{$what}->{users} if (defined($data{$what}->{users}));
512 my $date = $data{$what}->{date} if (defined($data{$what}->{date}));
513 my $desc = $data{$what}->{description} if (defined($data{$what}->{description}));
514
515 $kernelversion =~ s/^\s+// if ($kernelversion);
516 $contact =~ s/^\s+// if ($contact);
517 if ($users) {
518 $users =~ s/^\s+//;
519 $users =~ s/\n//g;
520 }
521 $date =~ s/^\s+// if ($date);
522 $desc =~ s/^\s+// if ($desc);
33e3e991
MCC
523
524 printf "Kernel version:\t\t%s\n", $kernelversion if ($kernelversion);
525 printf "Date:\t\t\t%s\n", $date if ($date);
526 printf "Contact:\t\t%s\n", $contact if ($contact);
527 printf "Users:\t\t\t%s\n", $users if ($users);
c7ba3334 528 print "Defined on file(s):\t$file\n\n";
33e3e991
MCC
529 print "Description:\n\n$desc";
530 }
531}
532
f090db43 533# Exclude /sys/kernel/debug and /sys/kernel/tracing from the search path
ab02c515 534sub dont_parse_special_attributes {
f090db43
MCC
535 if (($File::Find::dir =~ m,^/sys/kernel,)) {
536 return grep {!/(debug|tracing)/ } @_;
537 }
538
539 if (($File::Find::dir =~ m,^/sys/fs,)) {
540 return grep {!/(pstore|bpf|fuse)/ } @_;
541 }
542
543 return @_
544}
545
546my %leaf;
ab02c515
MCC
547my %aliases;
548my @files;
f090db43 549
ab02c515 550my $escape_symbols = qr { ([\x01-\x08\x0e-\x1f\x21-\x29\x2b-\x2d\x3a-\x40\x7b-\xfe]) }x;
f090db43
MCC
551sub parse_existing_sysfs {
552 my $file = $File::Find::name;
ab02c515
MCC
553 my $mode = (lstat($file))[2];
554 my $abs_file = abs_path($file);
f090db43 555
ab02c515
MCC
556 if (S_ISLNK($mode)) {
557 $aliases{$file} = $abs_file;
558 return;
559 }
560
561 return if (S_ISDIR($mode));
f090db43 562
ab02c515
MCC
563 # Trivial: file is defined exactly the same way at ABI What:
564 return if (defined($data{$file}));
565 return if (defined($data{$abs_file}));
f090db43 566
ab02c515
MCC
567 push @files, $abs_file;
568}
f090db43 569
ab02c515
MCC
570sub check_undefined_symbols {
571 foreach my $file (sort @files) {
f090db43 572
ab02c515
MCC
573 # Ignore cgroup and firmware
574 next if ($file =~ m#^/sys/(fs/cgroup|firmware)/#);
f090db43 575
ab02c515
MCC
576 my $defined = 0;
577 my $exact = 0;
578 my $whats = "";
14c94257 579 my $found_string;
f090db43 580
ab02c515
MCC
581 my $leave = $file;
582 $leave =~ s,.*/,,;
583
584 my $path = $file;
585 $path =~ s,(.*/).*,$1,;
586
14c94257
MCC
587 if ($search_string) {
588 next if (!($file =~ m#$search_string#));
589 $found_string = 1;
590 }
591
50116aec
MCC
592 if ($leave =~ /^\d+$/ || !defined($leaf{$leave})) {
593 $leave = "others";
594 }
595
14c94257 596 print "--> $file\n" if ($found_string && $hint);
50116aec
MCC
597 my $what = $leaf{$leave};
598 $whats .= " $what" if (!($whats =~ m/$what/));
599
600 foreach my $w (split / /, $what) {
601 if ($file =~ m#^$w$#) {
602 $exact = 1;
603 last;
ab02c515 604 }
50116aec
MCC
605 }
606 # Check for aliases
607 #
608 # TODO: this algorithm is O(w * n²). It can be
609 # improved in the future in order to handle it
610 # faster, by changing parse_existing_sysfs to
611 # store the sysfs inside a tree, at the expense
612 # on making the code less readable and/or using some
613 # additional perl library.
614 foreach my $a (keys %aliases) {
615 my $new = $aliases{$a};
616 my $len = length($new);
617
618 if (substr($file, 0, $len) eq $new) {
619 my $newf = $a . substr($file, $len);
620
621 print " $newf\n" if ($found_string && $hint);
622 foreach my $w (split / /, $what) {
623 if ($newf =~ m#^$w$#) {
624 $exact = 1;
625 last;
ab02c515
MCC
626 }
627 }
f090db43
MCC
628 }
629 }
50116aec
MCC
630
631 $defined++;
632
ab02c515 633 next if ($exact);
f090db43 634
ab02c515
MCC
635 # Ignore some sysfs nodes
636 next if ($file =~ m#/(sections|notes)/#);
f090db43 637
ab02c515
MCC
638 # Would need to check at
639 # Documentation/admin-guide/kernel-parameters.txt, but this
640 # is not easily parseable.
641 next if ($file =~ m#/parameters/#);
f090db43 642
50116aec 643 if ($hint && $defined && $leave ne "others") {
14c94257 644 print "$leave at $path might be one of:$whats\n" if (!$search_string || $found_string);
ab02c515
MCC
645 next;
646 }
14c94257 647 print "$file not found.\n" if (!$search_string || $found_string);
ab02c515 648 }
f090db43
MCC
649}
650
651sub undefined_symbols {
ab02c515
MCC
652 find({
653 wanted =>\&parse_existing_sysfs,
654 preprocess =>\&dont_parse_special_attributes,
655 no_chdir => 1
656 }, $sysfs_prefix);
657
f090db43
MCC
658 foreach my $w (sort keys %data) {
659 foreach my $what (split /\xac /,$w) {
ab02c515
MCC
660 next if (!($what =~ m/^$sysfs_prefix/));
661
662 # Convert what into regular expressions
663
664 $what =~ s,/\.\.\./,/*/,g;
665 $what =~ s,\*,.*,g;
666
667 # Temporarily change [0-9]+ type of patterns
668 $what =~ s/\[0\-9\]\+/\xff/g;
669
670 # Temporarily change [\d+-\d+] type of patterns
671 $what =~ s/\[0\-\d+\]/\xff/g;
672 $what =~ s/\[(\d+)\]/\xf4$1\xf5/g;
673
674 # Temporarily change [0-9] type of patterns
675 $what =~ s/\[(\d)\-(\d)\]/\xf4$1-$2\xf5/g;
676
677 # Handle multiple option patterns
678 $what =~ s/[\{\<\[]([\w_]+)(?:[,|]+([\w_]+)){1,}[\}\>\]]/($1|$2)/g;
679
680 # Handle wildcards
681 $what =~ s/\<[^\>]+\>/.*/g;
682 $what =~ s/\{[^\}]+\}/.*/g;
683 $what =~ s/\[[^\]]+\]/.*/g;
684
685 $what =~ s/[XYZ]/.*/g;
686
687 # Recover [0-9] type of patterns
688 $what =~ s/\xf4/[/g;
689 $what =~ s/\xf5/]/g;
690
691 # Remove duplicated spaces
692 $what =~ s/\s+/ /g;
693
694 # Special case: this ABI has a parenthesis on it
695 $what =~ s/sqrt\(x^2\+y^2\+z^2\)/sqrt\(x^2\+y^2\+z^2\)/;
696
697 # Special case: drop comparition as in:
698 # What: foo = <something>
699 # (this happens on a few IIO definitions)
700 $what =~ s,\s*\=.*$,,;
701
f090db43
MCC
702 my $leave = $what;
703 $leave =~ s,.*/,,;
704
50116aec
MCC
705 # $leave is used to improve search performance at
706 # check_undefined_symbols, as the algorithm there can seek
707 # for a small number of "what". It also allows giving a
708 # hint about a leave with the same name somewhere else.
709 # However, there are a few occurences where the leave is
710 # either a wildcard or a number. Just group such cases
711 # altogether.
712 if ($leave =~ m/^\.\*/ || $leave eq "" || $leave =~ /^\d+$/) {
713 $leave = "others" ;
714 }
ab02c515
MCC
715
716 # Escape all other symbols
717 $what =~ s/$escape_symbols/\\$1/g;
718 $what =~ s/\\\\/\\/g;
719 $what =~ s/\\([\[\]\(\)\|])/$1/g;
720 $what =~ s/(\d+)\\(-\d+)/$1$2/g;
721
14c94257
MCC
722 $what =~ s/\xff/\\d+/g;
723
724
725 # Special case: IIO ABI which a parenthesis.
726 $what =~ s/sqrt(.*)/sqrt\(.*\)/;
727
ab02c515
MCC
728 $leave =~ s/[\(\)]//g;
729
14c94257 730 my $added = 0;
ab02c515
MCC
731 foreach my $l (split /\|/, $leave) {
732 if (defined($leaf{$l})) {
733 next if ($leaf{$l} =~ m/$what/);
734 $leaf{$l} .= " " . $what;
14c94257 735 $added = 1;
ab02c515
MCC
736 } else {
737 $leaf{$l} = $what;
14c94257 738 $added = 1;
ab02c515 739 }
f090db43 740 }
14c94257
MCC
741 if ($search_string && $added) {
742 print "What: $what\n" if ($what =~ m#$search_string#);
743 }
744
f090db43
MCC
745 }
746 }
ab02c515 747 check_undefined_symbols;
f090db43
MCC
748}
749
61439c4a
MCC
750# Ensure that the prefix will always end with a slash
751# While this is not needed for find, it makes the patch nicer
752# with --enable-lineno
753$prefix =~ s,/?$,/,;
33e3e991 754
f090db43
MCC
755if ($cmd eq "undefined" || $cmd eq "search") {
756 $show_warnings = 0;
757}
bbc249f2
MCC
758#
759# Parses all ABI files located at $prefix dir
760#
761find({wanted =>\&parse_abi, no_chdir => 1}, $prefix);
762
763print STDERR Data::Dumper->Dump([\%data], [qw(*data)]) if ($debug);
764
765#
33e3e991 766# Handles the command
bbc249f2 767#
f090db43
MCC
768if ($cmd eq "undefined") {
769 undefined_symbols;
770} elsif ($cmd eq "search") {
33e3e991 771 search_symbols;
c7ba3334
MCC
772} else {
773 if ($cmd eq "rest") {
774 output_rest;
775 }
776
777 # Warn about duplicated ABI entries
778 foreach my $what(sort keys %symbols) {
779 my @files = @{$symbols{$what}->{file}};
780
781 next if (scalar(@files) == 1);
bbc249f2 782
c7ba3334
MCC
783 printf STDERR "Warning: $what is defined %d times: @files\n",
784 scalar(@files);
785 }
786}
bbc249f2
MCC
787
788__END__
789
790=head1 NAME
791
792abi_book.pl - parse the Linux ABI files and produce a ReST book.
793
794=head1 SYNOPSIS
795
61439c4a 796B<abi_book.pl> [--debug] [--enable-lineno] [--man] [--help]
ab02c515 797 [--(no-)rst-source] [--dir=<dir>] [--show-hints]
14c94257 798 [--search-string <regex>]
ab02c515 799 <COMAND> [<ARGUMENT>]
33e3e991
MCC
800
801Where <COMMAND> can be:
802
803=over 8
804
805B<search> [SEARCH_REGEX] - search for [SEARCH_REGEX] inside ABI
806
7ce7b89b
MCC
807B<rest> - output the ABI in ReST markup language
808
809B<validate> - validate the ABI contents
33e3e991 810
f090db43
MCC
811B<undefined> - existing symbols at the system that aren't
812 defined at Documentation/ABI
813
33e3e991 814=back
bbc249f2
MCC
815
816=head1 OPTIONS
817
818=over 8
819
33e3e991
MCC
820=item B<--dir>
821
822Changes the location of the ABI search. By default, it uses
823the Documentation/ABI directory.
824
11ce90a4
MCC
825=item B<--rst-source> and B<--no-rst-source>
826
827The input file may be using ReST syntax or not. Those two options allow
828selecting between a rst-compliant source ABI (--rst-source), or a
829plain text that may be violating ReST spec, so it requres some escaping
830logic (--no-rst-source).
831
61439c4a
MCC
832=item B<--enable-lineno>
833
834Enable output of #define LINENO lines.
835
bbc249f2
MCC
836=item B<--debug>
837
838Put the script in verbose mode, useful for debugging. Can be called multiple
839times, to increase verbosity.
840
ab02c515
MCC
841=item B<--show-hints>
842
843Show hints about possible definitions for the missing ABI symbols.
844Used only when B<undefined>.
845
14c94257
MCC
846=item B<--search-string> [regex string]
847
848Show only occurences that match a search string.
849Used only when B<undefined>.
850
bbc249f2
MCC
851=item B<--help>
852
853Prints a brief help message and exits.
854
855=item B<--man>
856
857Prints the manual page and exits.
858
859=back
860
861=head1 DESCRIPTION
862
33e3e991
MCC
863Parse the Linux ABI files from ABI DIR (usually located at Documentation/ABI),
864allowing to search for ABI symbols or to produce a ReST book containing
865the Linux ABI documentation.
866
867=head1 EXAMPLES
868
869Search for all stable symbols with the word "usb":
870
871=over 8
872
873$ scripts/get_abi.pl search usb --dir Documentation/ABI/stable
874
875=back
876
877Search for all symbols that match the regex expression "usb.*cap":
878
879=over 8
880
881$ scripts/get_abi.pl search usb.*cap
882
883=back
884
885Output all obsoleted symbols in ReST format
886
887=over 8
888
889$ scripts/get_abi.pl rest --dir Documentation/ABI/obsolete
890
891=back
bbc249f2
MCC
892
893=head1 BUGS
894
7ce7b89b 895Report bugs to Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
bbc249f2
MCC
896
897=head1 COPYRIGHT
898
7ce7b89b 899Copyright (c) 2016-2019 by Mauro Carvalho Chehab <mchehab+samsung@kernel.org>.
bbc249f2
MCC
900
901License GPLv2: GNU GPL version 2 <http://gnu.org/licenses/gpl.html>.
902
903This is free software: you are free to change and redistribute it.
904There is NO WARRANTY, to the extent permitted by law.
905
906=cut