0001
0002
0003
0004 BEGIN { $Pod::Usage::Formatter = 'Pod::Text::Termcap'; }
0005
0006 use strict;
0007 use warnings;
0008 use utf8;
0009 use Pod::Usage ;
0010 use Getopt::Long;
0011 use File::Find;
0012 use IO::Handle;
0013 use Fcntl ':mode';
0014 use Cwd 'abs_path';
0015 use Data::Dumper;
0016
0017 my $help = 0;
0018 my $hint = 0;
0019 my $man = 0;
0020 my $debug = 0;
0021 my $enable_lineno = 0;
0022 my $show_warnings = 1;
0023 my $prefix="Documentation/ABI";
0024 my $sysfs_prefix="/sys";
0025 my $search_string;
0026
0027
0028 my $dbg_what_parsing = 1;
0029 my $dbg_what_open = 2;
0030 my $dbg_dump_abi_structs = 4;
0031 my $dbg_undefined = 8;
0032
0033 $Data::Dumper::Indent = 1;
0034 $Data::Dumper::Terse = 1;
0035
0036
0037
0038
0039 my $description_is_rst = 1;
0040
0041 GetOptions(
0042 "debug=i" => \$debug,
0043 "enable-lineno" => \$enable_lineno,
0044 "rst-source!" => \$description_is_rst,
0045 "dir=s" => \$prefix,
0046 'help|?' => \$help,
0047 "show-hints" => \$hint,
0048 "search-string=s" => \$search_string,
0049 man => \$man
0050 ) or pod2usage(2);
0051
0052 pod2usage(1) if $help;
0053 pod2usage(-exitstatus => 0, -noperldoc, -verbose => 2) if $man;
0054
0055 pod2usage(2) if (scalar @ARGV < 1 || @ARGV > 2);
0056
0057 my ($cmd, $arg) = @ARGV;
0058
0059 pod2usage(2) if ($cmd ne "search" && $cmd ne "rest" && $cmd ne "validate" && $cmd ne "undefined");
0060 pod2usage(2) if ($cmd eq "search" && !$arg);
0061
0062 require Data::Dumper if ($debug & $dbg_dump_abi_structs);
0063
0064 my %data;
0065 my %symbols;
0066
0067
0068
0069
0070 sub parse_error($$$$) {
0071 my ($file, $ln, $msg, $data) = @_;
0072
0073 return if (!$show_warnings);
0074
0075 $data =~ s/\s+$/\n/;
0076
0077 print STDERR "Warning: file $file#$ln:\n\t$msg";
0078
0079 if ($data ne "") {
0080 print STDERR ". Line\n\t\t$data";
0081 } else {
0082 print STDERR "\n";
0083 }
0084 }
0085
0086
0087
0088
0089 sub parse_abi {
0090 my $file = $File::Find::name;
0091
0092 my $mode = (stat($file))[2];
0093 return if ($mode & S_IFDIR);
0094 return if ($file =~ );
0095 return if ($file =~ );
0096
0097 my $name = $file;
0098 $name =~ s,.*/,,;
0099
0100 my $fn = $file;
0101 $fn =~ s,Documentation/ABI/,,;
0102
0103 my $nametag = "File $fn";
0104 $data{$nametag}->{what} = "File $name";
0105 $data{$nametag}->{type} = "File";
0106 $data{$nametag}->{file} = $name;
0107 $data{$nametag}->{filepath} = $file;
0108 $data{$nametag}->{is_file} = 1;
0109 $data{$nametag}->{line_no} = 1;
0110
0111 my $type = $file;
0112 $type =~ s,.*/(.*)/.*,$1,;
0113
0114 my $what;
0115 my $new_what;
0116 my $tag = "";
0117 my $ln;
0118 my $xrefs;
0119 my $space;
0120 my @labels;
0121 my $label = "";
0122
0123 print STDERR "Opening $file\n" if ($debug & $dbg_what_open);
0124 open IN, $file;
0125 while(<IN>) {
0126 $ln++;
0127 if () {
0128 my $new_tag = lc($1);
0129 my $sep = $2;
0130 my $content = $3;
0131
0132 if (!($new_tag =~ )) {
0133 if ($tag eq "description") {
0134
0135
0136 $new_tag = "";
0137 } elsif ($tag ne "") {
0138 parse_error($file, $ln, "tag '$tag' is invalid", $_);
0139 }
0140 }
0141
0142
0143 if ($new_tag eq "where") {
0144 parse_error($file, $ln, "tag 'Where' is invalid. Should be 'What:' instead", "");
0145 $new_tag = "what";
0146 }
0147
0148 if ($new_tag =~ ) {
0149 $space = "";
0150 $content =~ s/[,.;]$//;
0151
0152 push @{$symbols{$content}->{file}}, " $file:" . ($ln - 1);
0153
0154 if ($tag =~ ) {
0155 $what .= "\xac" . $content;
0156 } else {
0157 if ($what) {
0158 parse_error($file, $ln, "What '$what' doesn't have a description", "") if (!$data{$what}->{description});
0159
0160 foreach my $w(split /\xac/, $what) {
0161 $symbols{$w}->{xref} = $what;
0162 };
0163 }
0164
0165 $what = $content;
0166 $label = $content;
0167 $new_what = 1;
0168 }
0169 push @labels, [($content, $label)];
0170 $tag = $new_tag;
0171
0172 push @{$data{$nametag}->{symbols}}, $content if ($data{$nametag}->{what});
0173 next;
0174 }
0175
0176 if ($tag ne "" && $new_tag) {
0177 $tag = $new_tag;
0178
0179 if ($new_what) {
0180 @{$data{$what}->{label_list}} = @labels if ($data{$nametag}->{what});
0181 @labels = ();
0182 $label = "";
0183 $new_what = 0;
0184
0185 $data{$what}->{type} = $type;
0186 if (!defined($data{$what}->{file})) {
0187 $data{$what}->{file} = $name;
0188 $data{$what}->{filepath} = $file;
0189 } else {
0190 $data{$what}->{description} .= "\n\n" if (defined($data{$what}->{description}));
0191 if ($name ne $data{$what}->{file}) {
0192 $data{$what}->{file} .= " " . $name;
0193 $data{$what}->{filepath} .= " " . $file;
0194 }
0195 }
0196 print STDERR "\twhat: $what\n" if ($debug & $dbg_what_parsing);
0197 $data{$what}->{line_no} = $ln;
0198 } else {
0199 $data{$what}->{line_no} = $ln if (!defined($data{$what}->{line_no}));
0200 }
0201
0202 if (!$what) {
0203 parse_error($file, $ln, "'What:' should come first:", $_);
0204 next;
0205 }
0206 if ($new_tag eq "description") {
0207 $sep =~ s,:, ,;
0208 $content = ' ' x length($new_tag) . $sep . $content;
0209 while ($content =~ s/\t+/' ' x (length($&) * 8 - length($`) % 8)/e) {}
0210 if ($content =~ ) {
0211
0212 $space = $1;
0213 $content = "$2\n";
0214 $data{$what}->{$tag} .= $content;
0215 } else {
0216 undef($space);
0217 }
0218
0219 } else {
0220 $data{$what}->{$tag} = $content;
0221 }
0222 next;
0223 }
0224 }
0225
0226
0227 if (!$tag && $data{$nametag}->{what}) {
0228 $data{$nametag}->{description} .= $_;
0229 next;
0230 }
0231
0232 if ($tag eq "description") {
0233 my $content = $_;
0234 while ($content =~ s/\t+/' ' x (length($&) * 8 - length($`) % 8)/e) {}
0235 if () {
0236 $data{$what}->{$tag} .= "\n";
0237 next;
0238 }
0239
0240 if (!defined($space)) {
0241
0242 if ($content =~ ) {
0243 $space = $1;
0244 $content = "$2\n";
0245 }
0246 } else {
0247 $space = "" if (!($content =~ s/^($space)//));
0248 }
0249 $data{$what}->{$tag} .= $content;
0250
0251 next;
0252 }
0253 if () {
0254 $data{$what}->{$tag} .= "\n$1";
0255 $data{$what}->{$tag} =~ s/\n+$//;
0256 next;
0257 }
0258
0259
0260 parse_error($file, $ln, "Unexpected content", $_);
0261 }
0262 $data{$nametag}->{description} =~ s/^\n+// if ($data{$nametag}->{description});
0263 if ($what) {
0264 parse_error($file, $ln, "What '$what' doesn't have a description", "") if (!$data{$what}->{description});
0265
0266 foreach my $w(split /\xac/,$what) {
0267 $symbols{$w}->{xref} = $what;
0268 };
0269 }
0270 close IN;
0271 }
0272
0273 sub create_labels {
0274 my %labels;
0275
0276 foreach my $what (keys %data) {
0277 next if ($data{$what}->{file} eq "File");
0278
0279 foreach my $p (@{$data{$what}->{label_list}}) {
0280 my ($content, $label) = @{$p};
0281 $label = "abi_" . $label . " ";
0282 $label =~ tr/A-Z/a-z/;
0283
0284
0285 $label =~s/([\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\xff])/_/g;
0286 $label =~ s,_+,_,g;
0287 $label =~ s,_$,,;
0288
0289
0290 while (defined($labels{$label})) {
0291 my @chars = ("A".."Z", "a".."z");
0292 $label .= $chars[rand @chars];
0293 }
0294 $labels{$label} = 1;
0295
0296 $data{$what}->{label} = $label;
0297
0298
0299 last;
0300 }
0301 }
0302 }
0303
0304
0305
0306
0307
0308
0309
0310 my $start = ;
0311 my $bondary = ;
0312 my $xref_match = ;
0313 my $symbols = ;
0314
0315 sub output_rest {
0316 create_labels();
0317
0318 my $part = "";
0319
0320 foreach my $what (sort {
0321 ($data{$a}->{type} eq "File") cmp ($data{$b}->{type} eq "File") ||
0322 $a cmp $b
0323 } keys %data) {
0324 my $type = $data{$what}->{type};
0325
0326 my @file = split / /, $data{$what}->{file};
0327 my @filepath = split / /, $data{$what}->{filepath};
0328
0329 if ($enable_lineno) {
0330 printf ".. LINENO %s%s#%s\n\n",
0331 $prefix, $file[0],
0332 $data{$what}->{line_no};
0333 }
0334
0335 my $w = $what;
0336
0337 if ($type ne "File") {
0338 my $cur_part = $what;
0339 if ($what =~ '/') {
0340 if ($what =~ ) {
0341 $cur_part = "Symbols under $1";
0342 $cur_part =~ s,/$,,;
0343 }
0344 }
0345
0346 if ($cur_part ne "" && $part ne $cur_part) {
0347 $part = $cur_part;
0348 my $bar = $part;
0349 $bar =~ s/./-/g;
0350 print "$part\n$bar\n\n";
0351 }
0352
0353 printf ".. _%s:\n\n", $data{$what}->{label};
0354
0355 my @names = split /\xac/,$w;
0356 my $len = 0;
0357
0358 foreach my $name (@names) {
0359 $name =~ s/$symbols/\\$1/g;
0360 $name = "**$name**";
0361 $len = length($name) if (length($name) > $len);
0362 }
0363
0364 print "+-" . "-" x $len . "-+\n";
0365 foreach my $name (@names) {
0366 printf "| %s", $name . " " x ($len - length($name)) . " |\n";
0367 print "+-" . "-" x $len . "-+\n";
0368 }
0369
0370 print "\n";
0371 }
0372
0373 for (my $i = 0; $i < scalar(@filepath); $i++) {
0374 my $path = $filepath[$i];
0375 my $f = $file[$i];
0376
0377 $path =~ s,.*/(.*/.*),$1,;;
0378 $path =~ s,[/\-],_,g;;
0379 my $fileref = "abi_file_".$path;
0380
0381 if ($type eq "File") {
0382 print ".. _$fileref:\n\n";
0383 } else {
0384 print "Defined on file :ref:`$f <$fileref>`\n\n";
0385 }
0386 }
0387
0388 if ($type eq "File") {
0389 my $bar = $w;
0390 $bar =~ s/./-/g;
0391 print "$w\n$bar\n\n";
0392 }
0393
0394 my $desc = "";
0395 $desc = $data{$what}->{description} if (defined($data{$what}->{description}));
0396 $desc =~ s/\s+$/\n/;
0397
0398 if (!($desc =~ /^\s*$/)) {
0399 if ($description_is_rst) {
0400
0401
0402
0403
0404 $desc =~ s/\n[\-\*\=\^\~]+\n/\n\n/g;
0405
0406
0407
0408 my $new_desc = "";
0409 my $init_indent = -1;
0410 my $literal_indent = -1;
0411
0412 open(my $fh, "+<", \$desc);
0413 while (my $d = <$fh>) {
0414 my $indent = $d =~ ;
0415 my $spaces = length($indent);
0416 $init_indent = $indent if ($init_indent < 0);
0417 if ($literal_indent >= 0) {
0418 if ($spaces > $literal_indent) {
0419 $new_desc .= $d;
0420 next;
0421 } else {
0422 $literal_indent = -1;
0423 }
0424 } else {
0425 if ($d =~ /()::$/ && !($d =~ /^\s*\.\./)) {
0426 $literal_indent = $spaces;
0427 }
0428 }
0429
0430 $d =~ s,Documentation/(?!devicetree)(\S+)\.rst,:doc:`/$1`,g;
0431
0432 my @matches = $d =~ ;
0433 foreach my $f (@matches) {
0434 my $xref = $f;
0435 my $path = $f;
0436 $path =~ s,.*/(.*/.*),$1,;;
0437 $path =~ s,[/\-],_,g;;
0438 $xref .= " <abi_file_" . $path . ">";
0439 $d =~ s,\bDocumentation/ABI/$f\b,:ref:`$xref`,g;
0440 }
0441
0442
0443 @matches = $d =~ ;
0444
0445 foreach my $s (@matches) {
0446 next if (!($s =~ ));
0447 if (defined($data{$s}) && defined($data{$s}->{label})) {
0448 my $xref = $s;
0449
0450 $xref =~ s/$symbols/\\$1/g;
0451 $xref = ":ref:`$xref <" . $data{$s}->{label} . ">`";
0452
0453 $d =~ s,$start$s$bondary,$1$xref$2,g;
0454 }
0455 }
0456 $new_desc .= $d;
0457 }
0458 close $fh;
0459
0460
0461 print "$new_desc\n\n";
0462 } else {
0463 $desc =~ s/^\s+//;
0464
0465
0466 $desc =~ s/\n[\-\*\=\^\~]+\n/\n\n/g;
0467
0468 if ($desc =~ || $desc =~ || $desc =~ ) {
0469
0470 $desc =~ s/\n/\n /g;
0471
0472 print "::\n\n";
0473 print " $desc\n\n";
0474 } else {
0475
0476 $desc =~s/([\x00-\x08\x0b-\x1f\x21-\x2a\x2d\x2f\x3c-\x40\x5c\x5e-\x60\x7b-\xff])/\\$1/g;
0477 print "$desc\n\n";
0478 }
0479 }
0480 } else {
0481 print "DESCRIPTION MISSING for $what\n\n" if (!$data{$what}->{is_file});
0482 }
0483
0484 if ($data{$what}->{symbols}) {
0485 printf "Has the following ABI:\n\n";
0486
0487 foreach my $content(@{$data{$what}->{symbols}}) {
0488 my $label = $data{$symbols{$content}->{xref}}->{label};
0489
0490
0491 $content =~s/([\x00-\x1f\x21-\x2f\x3a-\x40\x7b-\xff])/\\$1/g;
0492
0493 print "- :ref:`$content <$label>`\n\n";
0494 }
0495 }
0496
0497 if (defined($data{$what}->{users})) {
0498 my $users = $data{$what}->{users};
0499
0500 $users =~ s/\n/\n\t/g;
0501 printf "Users:\n\t%s\n\n", $users if ($users ne "");
0502 }
0503
0504 }
0505 }
0506
0507
0508
0509
0510 sub search_symbols {
0511 foreach my $what (sort keys %data) {
0512 next if (!($what =~ ));
0513
0514 my $type = $data{$what}->{type};
0515 next if ($type eq "File");
0516
0517 my $file = $data{$what}->{filepath};
0518
0519 $what =~ s/\xac/, /g;
0520 my $bar = $what;
0521 $bar =~ s/./-/g;
0522
0523 print "\n$what\n$bar\n\n";
0524
0525 my $kernelversion = $data{$what}->{kernelversion} if (defined($data{$what}->{kernelversion}));
0526 my $contact = $data{$what}->{contact} if (defined($data{$what}->{contact}));
0527 my $users = $data{$what}->{users} if (defined($data{$what}->{users}));
0528 my $date = $data{$what}->{date} if (defined($data{$what}->{date}));
0529 my $desc = $data{$what}->{description} if (defined($data{$what}->{description}));
0530
0531 $kernelversion =~ s/^\s+// if ($kernelversion);
0532 $contact =~ s/^\s+// if ($contact);
0533 if ($users) {
0534 $users =~ s/^\s+//;
0535 $users =~ s/\n//g;
0536 }
0537 $date =~ s/^\s+// if ($date);
0538 $desc =~ s/^\s+// if ($desc);
0539
0540 printf "Kernel version:\t\t%s\n", $kernelversion if ($kernelversion);
0541 printf "Date:\t\t\t%s\n", $date if ($date);
0542 printf "Contact:\t\t%s\n", $contact if ($contact);
0543 printf "Users:\t\t\t%s\n", $users if ($users);
0544 print "Defined on file(s):\t$file\n\n";
0545 print "Description:\n\n$desc";
0546 }
0547 }
0548
0549
0550 sub dont_parse_special_attributes {
0551 if (($File::Find::dir =~ )) {
0552 return grep {!/(debug|tracing)/ } @_;
0553 }
0554
0555 if (($File::Find::dir =~ )) {
0556 return grep {!/(pstore|bpf|fuse)/ } @_;
0557 }
0558
0559 return @_
0560 }
0561
0562 my %leaf;
0563 my %aliases;
0564 my @files;
0565 my %root;
0566
0567 sub graph_add_file {
0568 my $file = shift;
0569 my $type = shift;
0570
0571 my $dir = $file;
0572 $dir =~ s,^(.*/).*,$1,;
0573 $file =~ s,.*/,,;
0574
0575 my $name;
0576 my $file_ref = \%root;
0577 foreach my $edge(split "/", $dir) {
0578 $name .= "$edge/";
0579 if (!defined ${$file_ref}{$edge}) {
0580 ${$file_ref}{$edge} = { };
0581 }
0582 $file_ref = \%{$$file_ref{$edge}};
0583 ${$file_ref}{"__name"} = [ $name ];
0584 }
0585 $name .= "$file";
0586 ${$file_ref}{$file} = {
0587 "__name" => [ $name ]
0588 };
0589
0590 return \%{$$file_ref{$file}};
0591 }
0592
0593 sub graph_add_link {
0594 my $file = shift;
0595 my $link = shift;
0596
0597
0598 my $file_ref = \%root;
0599 foreach my $edge(split "/", $file) {
0600 $file_ref = \%{$$file_ref{$edge}} || die "Missing node!";
0601 }
0602
0603
0604
0605 my @queue;
0606 my %seen;
0607 my $st;
0608
0609 push @queue, $file_ref;
0610 $seen{$start}++;
0611
0612 while (@queue) {
0613 my $v = shift @queue;
0614 my @child = keys(%{$v});
0615
0616 foreach my $c(@child) {
0617 next if $seen{$$v{$c}};
0618 next if ($c eq "__name");
0619
0620 if (!defined($$v{$c}{"__name"})) {
0621 printf STDERR "Error: Couldn't find a non-empty name on a children of $file/.*: ";
0622 print STDERR Dumper(%{$v});
0623 exit;
0624 }
0625
0626
0627 my $name = @{$$v{$c}{"__name"}}[0];
0628 if ($name =~ s#^$file/#$link/#) {
0629 push @{$$v{$c}{"__name"}}, $name;
0630 }
0631
0632 push @queue, $$v{$c};
0633 $seen{$c}++;
0634 }
0635 }
0636 }
0637
0638 my $escape_symbols = ;
0639 sub parse_existing_sysfs {
0640 my $file = $File::Find::name;
0641
0642 my $mode = (lstat($file))[2];
0643 my $abs_file = abs_path($file);
0644
0645 my @tmp;
0646 push @tmp, $file;
0647 push @tmp, $abs_file if ($abs_file ne $file);
0648
0649 foreach my $f(@tmp) {
0650
0651 return if ($f =~ );
0652
0653
0654
0655 return if ($f =~ );
0656
0657
0658 return if ($f =~ );
0659
0660
0661
0662
0663 return if ($f =~ );
0664 }
0665
0666 if (S_ISLNK($mode)) {
0667 $aliases{$file} = $abs_file;
0668 return;
0669 }
0670
0671 return if (S_ISDIR($mode));
0672
0673
0674 return if (defined($data{$file}));
0675 return if (defined($data{$abs_file}));
0676
0677 push @files, graph_add_file($abs_file, "file");
0678 }
0679
0680 sub get_leave($)
0681 {
0682 my $what = shift;
0683 my $leave;
0684
0685 my $l = $what;
0686 my $stop = 1;
0687
0688 $leave = $l;
0689 $leave =~ s,/$,,;
0690 $leave =~ s,.*/,,;
0691 $leave =~ s/[\(\)]//g;
0692
0693
0694
0695
0696
0697
0698
0699
0700 if ($leave =~ || $leave eq "" || $leave =~ /\\d/) {
0701 $leave = "others";
0702 }
0703
0704 return $leave;
0705 }
0706
0707 my @not_found;
0708
0709 sub check_file($$)
0710 {
0711 my $file_ref = shift;
0712 my $names_ref = shift;
0713 my @names = @{$names_ref};
0714 my $file = $names[0];
0715
0716 my $found_string;
0717
0718 my $leave = get_leave($file);
0719 if (!defined($leaf{$leave})) {
0720 $leave = "others";
0721 }
0722 my @expr = @{$leaf{$leave}->{expr}};
0723 die ("\rmissing rules for $leave") if (!defined($leaf{$leave}));
0724
0725 my $path = $file;
0726 $path =~ s,(.*/).*,$1,;
0727
0728 if ($search_string) {
0729 return if (!($file =~ ));
0730 $found_string = 1;
0731 }
0732
0733 for (my $i = 0; $i < @names; $i++) {
0734 if ($found_string && $hint) {
0735 if (!$i) {
0736 print STDERR "--> $names[$i]\n";
0737 } else {
0738 print STDERR " $names[$i]\n";
0739 }
0740 }
0741 foreach my $re (@expr) {
0742 print STDERR "$names[$i] =~ /^$re\$/\n" if ($debug && $dbg_undefined);
0743 if ($names[$i] =~ $re) {
0744 return;
0745 }
0746 }
0747 }
0748
0749 if ($leave ne "others") {
0750 my @expr = @{$leaf{"others"}->{expr}};
0751 for (my $i = 0; $i < @names; $i++) {
0752 foreach my $re (@expr) {
0753 print STDERR "$names[$i] =~ /^$re\$/\n" if ($debug && $dbg_undefined);
0754 if ($names[$i] =~ $re) {
0755 return;
0756 }
0757 }
0758 }
0759 }
0760
0761 push @not_found, $file if (!$search_string || $found_string);
0762
0763 if ($hint && (!$search_string || $found_string)) {
0764 my $what = $leaf{$leave}->{what};
0765 $what =~ s/\xac/\n\t/g;
0766 if ($leave ne "others") {
0767 print STDERR "\r more likely regexes:\n\t$what\n";
0768 } else {
0769 print STDERR "\r tested regexes:\n\t$what\n";
0770 }
0771 }
0772 }
0773
0774 sub check_undefined_symbols {
0775 my $num_files = scalar @files;
0776 my $next_i = 0;
0777 my $start_time = times;
0778
0779 @files = sort @files;
0780
0781 my $last_time = $start_time;
0782
0783
0784
0785 if ($hint || ($debug && $dbg_undefined)) {
0786 $next_i = $num_files;
0787 }
0788
0789 my $is_console;
0790 $is_console = 1 if (-t STDERR);
0791
0792 for (my $i = 0; $i < $num_files; $i++) {
0793 my $file_ref = $files[$i];
0794 my @names = @{$$file_ref{"__name"}};
0795
0796 check_file($file_ref, \@names);
0797
0798 my $cur_time = times;
0799
0800 if ($i == $next_i || $cur_time > $last_time + 1) {
0801 my $percent = $i * 100 / $num_files;
0802
0803 my $tm = $cur_time - $start_time;
0804 my $time = sprintf "%d:%02d", int($tm), 60 * ($tm - int($tm));
0805
0806 printf STDERR "\33[2K\r", if ($is_console);
0807 printf STDERR "%s: processing sysfs files... %i%%: $names[0]", $time, $percent;
0808 printf STDERR "\n", if (!$is_console);
0809 STDERR->flush();
0810
0811 $next_i = int (($percent + 1) * $num_files / 100);
0812 $last_time = $cur_time;
0813 }
0814 }
0815
0816 my $cur_time = times;
0817 my $tm = $cur_time - $start_time;
0818 my $time = sprintf "%d:%02d", int($tm), 60 * ($tm - int($tm));
0819
0820 printf STDERR "\33[2K\r", if ($is_console);
0821 printf STDERR "%s: processing sysfs files... done\n", $time;
0822
0823 foreach my $file (@not_found) {
0824 print "$file not found.\n";
0825 }
0826 }
0827
0828 sub undefined_symbols {
0829 print STDERR "Reading $sysfs_prefix directory contents...";
0830 find({
0831 wanted =>\&parse_existing_sysfs,
0832 preprocess =>\&dont_parse_special_attributes,
0833 no_chdir => 1
0834 }, $sysfs_prefix);
0835 print STDERR "done.\n";
0836
0837 $leaf{"others"}->{what} = "";
0838
0839 print STDERR "Converting ABI What fields into regexes...";
0840 foreach my $w (sort keys %data) {
0841 foreach my $what (split /\xac/,$w) {
0842 next if (!($what =~ ));
0843
0844
0845
0846
0847 $what =~ s/\./\xf6/g;
0848
0849
0850 $what =~ s/\[0\-9\]\+/\xff/g;
0851
0852
0853 $what =~ s/\[0\-\d+\]/\xff/g;
0854 $what =~ s/\[(\d+)\]/\xf4$1\xf5/g;
0855
0856
0857 $what =~ s/\[(\d)\-(\d)\]/\xf4$1-$2\xf5/g;
0858
0859
0860 $what =~ s/[\{\<\[]([\w_]+)(?:[,|]+([\w_]+)){1,}[\}\>\]]/($1|$2)/g;
0861
0862
0863 $what =~ s,\*,.*,g;
0864 $what =~ s,/\xf6..,/.*,g;
0865 $what =~ s/\<[^\>]+\>/.*/g;
0866 $what =~ s/\{[^\}]+\}/.*/g;
0867 $what =~ s/\[[^\]]+\]/.*/g;
0868
0869 $what =~ s/[XYZ]/.*/g;
0870
0871
0872 $what =~ s/\xf4/[/g;
0873 $what =~ s/\xf5/]/g;
0874
0875
0876 $what =~ s/\s+/ /g;
0877
0878
0879 $what =~ s/sqrt\(x^2\+y^2\+z^2\)/sqrt\(x^2\+y^2\+z^2\)/;
0880
0881
0882
0883
0884 $what =~ s,\s*\=.*$,,;
0885
0886
0887 $what =~ s/$escape_symbols/\\$1/g;
0888 $what =~ s/\\\\/\\/g;
0889 $what =~ s/\\([\[\]\(\)\|])/$1/g;
0890 $what =~ s/(\d+)\\(-\d+)/$1$2/g;
0891
0892 $what =~ s/\xff/\\d+/g;
0893
0894
0895 $what =~ s/sqrt(.*)/sqrt\(.*\)/;
0896
0897
0898 $what =~ s#(?:\.\*){2,}##g;
0899
0900
0901
0902 $what =~ s/\xf6/\./g;
0903
0904 my $leave = get_leave($what);
0905
0906 my $added = 0;
0907 foreach my $l (split /\|/, $leave) {
0908 if (defined($leaf{$l})) {
0909 next if ($leaf{$l}->{what} =~ );
0910 $leaf{$l}->{what} .= "\xac" . $what;
0911 $added = 1;
0912 } else {
0913 $leaf{$l}->{what} = $what;
0914 $added = 1;
0915 }
0916 }
0917 if ($search_string && $added) {
0918 print STDERR "What: $what\n" if ($what =~ );
0919 }
0920
0921 }
0922 }
0923
0924 foreach my $l (sort keys %leaf) {
0925 my @expr;
0926 foreach my $w(sort split /\xac/, $leaf{$l}->{what}) {
0927 push @expr, ;
0928 }
0929 $leaf{$l}->{expr} = \@expr;
0930 }
0931
0932
0933 foreach my $link (sort keys %aliases) {
0934 my $abs_file = $aliases{$link};
0935 graph_add_link($abs_file, $link);
0936 }
0937 print STDERR "done.\n";
0938
0939 check_undefined_symbols;
0940 }
0941
0942
0943
0944
0945 $prefix =~ s,/?$,/,;
0946
0947 if ($cmd eq "undefined" || $cmd eq "search") {
0948 $show_warnings = 0;
0949 }
0950
0951
0952
0953 find({wanted =>\&parse_abi, no_chdir => 1}, $prefix);
0954
0955 print STDERR Data::Dumper->Dump([\%data], []) if ($debug & $dbg_dump_abi_structs);
0956
0957
0958
0959
0960 if ($cmd eq "undefined") {
0961 undefined_symbols;
0962 } elsif ($cmd eq "search") {
0963 search_symbols;
0964 } else {
0965 if ($cmd eq "rest") {
0966 output_rest;
0967 }
0968
0969
0970 foreach my $what(sort keys %symbols) {
0971 my @files = @{$symbols{$what}->{file}};
0972
0973 next if (scalar(@files) == 1);
0974
0975 printf STDERR "Warning: $what is defined %d times: @files\n",
0976 scalar(@files);
0977 }
0978 }
0979
0980 __END__
0981
0982
0983
0984
0985
0986
0987
0988
0989
0990
0991
0992
0993
0994
0995
0996
0997
0998
0999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102