162306a36Sopenharmony_ci#!/usr/bin/env perl 262306a36Sopenharmony_ci# SPDX-License-Identifier: GPL-2.0 362306a36Sopenharmony_ci 462306a36Sopenharmony_ciBEGIN { $Pod::Usage::Formatter = 'Pod::Text::Termcap'; } 562306a36Sopenharmony_ci 662306a36Sopenharmony_ciuse strict; 762306a36Sopenharmony_ciuse warnings; 862306a36Sopenharmony_ciuse utf8; 962306a36Sopenharmony_ciuse Pod::Usage qw(pod2usage); 1062306a36Sopenharmony_ciuse Getopt::Long; 1162306a36Sopenharmony_ciuse File::Find; 1262306a36Sopenharmony_ciuse IO::Handle; 1362306a36Sopenharmony_ciuse Fcntl ':mode'; 1462306a36Sopenharmony_ciuse Cwd 'abs_path'; 1562306a36Sopenharmony_ciuse Data::Dumper; 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_cimy $help = 0; 1862306a36Sopenharmony_cimy $hint = 0; 1962306a36Sopenharmony_cimy $man = 0; 2062306a36Sopenharmony_cimy $debug = 0; 2162306a36Sopenharmony_cimy $enable_lineno = 0; 2262306a36Sopenharmony_cimy $show_warnings = 1; 2362306a36Sopenharmony_cimy $prefix="Documentation/ABI"; 2462306a36Sopenharmony_cimy $sysfs_prefix="/sys"; 2562306a36Sopenharmony_cimy $search_string; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci# Debug options 2862306a36Sopenharmony_cimy $dbg_what_parsing = 1; 2962306a36Sopenharmony_cimy $dbg_what_open = 2; 3062306a36Sopenharmony_cimy $dbg_dump_abi_structs = 4; 3162306a36Sopenharmony_cimy $dbg_undefined = 8; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci$Data::Dumper::Indent = 1; 3462306a36Sopenharmony_ci$Data::Dumper::Terse = 1; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci# 3762306a36Sopenharmony_ci# If true, assumes that the description is formatted with ReST 3862306a36Sopenharmony_ci# 3962306a36Sopenharmony_cimy $description_is_rst = 1; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ciGetOptions( 4262306a36Sopenharmony_ci "debug=i" => \$debug, 4362306a36Sopenharmony_ci "enable-lineno" => \$enable_lineno, 4462306a36Sopenharmony_ci "rst-source!" => \$description_is_rst, 4562306a36Sopenharmony_ci "dir=s" => \$prefix, 4662306a36Sopenharmony_ci 'help|?' => \$help, 4762306a36Sopenharmony_ci "show-hints" => \$hint, 4862306a36Sopenharmony_ci "search-string=s" => \$search_string, 4962306a36Sopenharmony_ci man => \$man 5062306a36Sopenharmony_ci) or pod2usage(2); 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_cipod2usage(1) if $help; 5362306a36Sopenharmony_cipod2usage(-exitstatus => 0, -noperldoc, -verbose => 2) if $man; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cipod2usage(2) if (scalar @ARGV < 1 || @ARGV > 2); 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_cimy ($cmd, $arg) = @ARGV; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_cipod2usage(2) if ($cmd ne "search" && $cmd ne "rest" && $cmd ne "validate" && $cmd ne "undefined"); 6062306a36Sopenharmony_cipod2usage(2) if ($cmd eq "search" && !$arg); 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_cirequire Data::Dumper if ($debug & $dbg_dump_abi_structs); 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cimy %data; 6562306a36Sopenharmony_cimy %symbols; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci# 6862306a36Sopenharmony_ci# Displays an error message, printing file name and line 6962306a36Sopenharmony_ci# 7062306a36Sopenharmony_cisub parse_error($$$$) { 7162306a36Sopenharmony_ci my ($file, $ln, $msg, $data) = @_; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci return if (!$show_warnings); 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci $data =~ s/\s+$/\n/; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci print STDERR "Warning: file $file#$ln:\n\t$msg"; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci if ($data ne "") { 8062306a36Sopenharmony_ci print STDERR ". Line\n\t\t$data"; 8162306a36Sopenharmony_ci } else { 8262306a36Sopenharmony_ci print STDERR "\n"; 8362306a36Sopenharmony_ci } 8462306a36Sopenharmony_ci} 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci# 8762306a36Sopenharmony_ci# Parse an ABI file, storing its contents at %data 8862306a36Sopenharmony_ci# 8962306a36Sopenharmony_cisub parse_abi { 9062306a36Sopenharmony_ci my $file = $File::Find::name; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci my $mode = (stat($file))[2]; 9362306a36Sopenharmony_ci return if ($mode & S_IFDIR); 9462306a36Sopenharmony_ci return if ($file =~ m,/README,); 9562306a36Sopenharmony_ci return if ($file =~ m,/\.,); 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci my $name = $file; 9862306a36Sopenharmony_ci $name =~ s,.*/,,; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci my $fn = $file; 10162306a36Sopenharmony_ci $fn =~ s,.*Documentation/ABI/,,; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci my $nametag = "File $fn"; 10462306a36Sopenharmony_ci $data{$nametag}->{what} = "File $name"; 10562306a36Sopenharmony_ci $data{$nametag}->{type} = "File"; 10662306a36Sopenharmony_ci $data{$nametag}->{file} = $name; 10762306a36Sopenharmony_ci $data{$nametag}->{filepath} = $file; 10862306a36Sopenharmony_ci $data{$nametag}->{is_file} = 1; 10962306a36Sopenharmony_ci $data{$nametag}->{line_no} = 1; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci my $type = $file; 11262306a36Sopenharmony_ci $type =~ s,.*/(.*)/.*,$1,; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci my $what; 11562306a36Sopenharmony_ci my $new_what; 11662306a36Sopenharmony_ci my $tag = ""; 11762306a36Sopenharmony_ci my $ln; 11862306a36Sopenharmony_ci my $xrefs; 11962306a36Sopenharmony_ci my $space; 12062306a36Sopenharmony_ci my @labels; 12162306a36Sopenharmony_ci my $label = ""; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci print STDERR "Opening $file\n" if ($debug & $dbg_what_open); 12462306a36Sopenharmony_ci open IN, $file; 12562306a36Sopenharmony_ci while(<IN>) { 12662306a36Sopenharmony_ci $ln++; 12762306a36Sopenharmony_ci if (m/^(\S+)(:\s*)(.*)/i) { 12862306a36Sopenharmony_ci my $new_tag = lc($1); 12962306a36Sopenharmony_ci my $sep = $2; 13062306a36Sopenharmony_ci my $content = $3; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci if (!($new_tag =~ m/(what|where|date|kernelversion|contact|description|users)/)) { 13362306a36Sopenharmony_ci if ($tag eq "description") { 13462306a36Sopenharmony_ci # New "tag" is actually part of 13562306a36Sopenharmony_ci # description. Don't consider it a tag 13662306a36Sopenharmony_ci $new_tag = ""; 13762306a36Sopenharmony_ci } elsif ($tag ne "") { 13862306a36Sopenharmony_ci parse_error($file, $ln, "tag '$tag' is invalid", $_); 13962306a36Sopenharmony_ci } 14062306a36Sopenharmony_ci } 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci # Invalid, but it is a common mistake 14362306a36Sopenharmony_ci if ($new_tag eq "where") { 14462306a36Sopenharmony_ci parse_error($file, $ln, "tag 'Where' is invalid. Should be 'What:' instead", ""); 14562306a36Sopenharmony_ci $new_tag = "what"; 14662306a36Sopenharmony_ci } 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci if ($new_tag =~ m/what/) { 14962306a36Sopenharmony_ci $space = ""; 15062306a36Sopenharmony_ci $content =~ s/[,.;]$//; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci push @{$symbols{$content}->{file}}, " $file:" . ($ln - 1); 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci if ($tag =~ m/what/) { 15562306a36Sopenharmony_ci $what .= "\xac" . $content; 15662306a36Sopenharmony_ci } else { 15762306a36Sopenharmony_ci if ($what) { 15862306a36Sopenharmony_ci parse_error($file, $ln, "What '$what' doesn't have a description", "") if (!$data{$what}->{description}); 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci foreach my $w(split /\xac/, $what) { 16162306a36Sopenharmony_ci $symbols{$w}->{xref} = $what; 16262306a36Sopenharmony_ci }; 16362306a36Sopenharmony_ci } 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci $what = $content; 16662306a36Sopenharmony_ci $label = $content; 16762306a36Sopenharmony_ci $new_what = 1; 16862306a36Sopenharmony_ci } 16962306a36Sopenharmony_ci push @labels, [($content, $label)]; 17062306a36Sopenharmony_ci $tag = $new_tag; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci push @{$data{$nametag}->{symbols}}, $content if ($data{$nametag}->{what}); 17362306a36Sopenharmony_ci next; 17462306a36Sopenharmony_ci } 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci if ($tag ne "" && $new_tag) { 17762306a36Sopenharmony_ci $tag = $new_tag; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci if ($new_what) { 18062306a36Sopenharmony_ci @{$data{$what}->{label_list}} = @labels if ($data{$nametag}->{what}); 18162306a36Sopenharmony_ci @labels = (); 18262306a36Sopenharmony_ci $label = ""; 18362306a36Sopenharmony_ci $new_what = 0; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci $data{$what}->{type} = $type; 18662306a36Sopenharmony_ci if (!defined($data{$what}->{file})) { 18762306a36Sopenharmony_ci $data{$what}->{file} = $name; 18862306a36Sopenharmony_ci $data{$what}->{filepath} = $file; 18962306a36Sopenharmony_ci } else { 19062306a36Sopenharmony_ci $data{$what}->{description} .= "\n\n" if (defined($data{$what}->{description})); 19162306a36Sopenharmony_ci if ($name ne $data{$what}->{file}) { 19262306a36Sopenharmony_ci $data{$what}->{file} .= " " . $name; 19362306a36Sopenharmony_ci $data{$what}->{filepath} .= " " . $file; 19462306a36Sopenharmony_ci } 19562306a36Sopenharmony_ci } 19662306a36Sopenharmony_ci print STDERR "\twhat: $what\n" if ($debug & $dbg_what_parsing); 19762306a36Sopenharmony_ci $data{$what}->{line_no} = $ln; 19862306a36Sopenharmony_ci } else { 19962306a36Sopenharmony_ci $data{$what}->{line_no} = $ln if (!defined($data{$what}->{line_no})); 20062306a36Sopenharmony_ci } 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci if (!$what) { 20362306a36Sopenharmony_ci parse_error($file, $ln, "'What:' should come first:", $_); 20462306a36Sopenharmony_ci next; 20562306a36Sopenharmony_ci } 20662306a36Sopenharmony_ci if ($new_tag eq "description") { 20762306a36Sopenharmony_ci $sep =~ s,:, ,; 20862306a36Sopenharmony_ci $content = ' ' x length($new_tag) . $sep . $content; 20962306a36Sopenharmony_ci while ($content =~ s/\t+/' ' x (length($&) * 8 - length($`) % 8)/e) {} 21062306a36Sopenharmony_ci if ($content =~ m/^(\s*)(\S.*)$/) { 21162306a36Sopenharmony_ci # Preserve initial spaces for the first line 21262306a36Sopenharmony_ci $space = $1; 21362306a36Sopenharmony_ci $content = "$2\n"; 21462306a36Sopenharmony_ci $data{$what}->{$tag} .= $content; 21562306a36Sopenharmony_ci } else { 21662306a36Sopenharmony_ci undef($space); 21762306a36Sopenharmony_ci } 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci } else { 22062306a36Sopenharmony_ci $data{$what}->{$tag} = $content; 22162306a36Sopenharmony_ci } 22262306a36Sopenharmony_ci next; 22362306a36Sopenharmony_ci } 22462306a36Sopenharmony_ci } 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci # Store any contents before tags at the database 22762306a36Sopenharmony_ci if (!$tag && $data{$nametag}->{what}) { 22862306a36Sopenharmony_ci $data{$nametag}->{description} .= $_; 22962306a36Sopenharmony_ci next; 23062306a36Sopenharmony_ci } 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci if ($tag eq "description") { 23362306a36Sopenharmony_ci my $content = $_; 23462306a36Sopenharmony_ci while ($content =~ s/\t+/' ' x (length($&) * 8 - length($`) % 8)/e) {} 23562306a36Sopenharmony_ci if (m/^\s*\n/) { 23662306a36Sopenharmony_ci $data{$what}->{$tag} .= "\n"; 23762306a36Sopenharmony_ci next; 23862306a36Sopenharmony_ci } 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci if (!defined($space)) { 24162306a36Sopenharmony_ci # Preserve initial spaces for the first line 24262306a36Sopenharmony_ci if ($content =~ m/^(\s*)(\S.*)$/) { 24362306a36Sopenharmony_ci $space = $1; 24462306a36Sopenharmony_ci $content = "$2\n"; 24562306a36Sopenharmony_ci } 24662306a36Sopenharmony_ci } else { 24762306a36Sopenharmony_ci $space = "" if (!($content =~ s/^($space)//)); 24862306a36Sopenharmony_ci } 24962306a36Sopenharmony_ci $data{$what}->{$tag} .= $content; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci next; 25262306a36Sopenharmony_ci } 25362306a36Sopenharmony_ci if (m/^\s*(.*)/) { 25462306a36Sopenharmony_ci $data{$what}->{$tag} .= "\n$1"; 25562306a36Sopenharmony_ci $data{$what}->{$tag} =~ s/\n+$//; 25662306a36Sopenharmony_ci next; 25762306a36Sopenharmony_ci } 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci # Everything else is error 26062306a36Sopenharmony_ci parse_error($file, $ln, "Unexpected content", $_); 26162306a36Sopenharmony_ci } 26262306a36Sopenharmony_ci $data{$nametag}->{description} =~ s/^\n+// if ($data{$nametag}->{description}); 26362306a36Sopenharmony_ci if ($what) { 26462306a36Sopenharmony_ci parse_error($file, $ln, "What '$what' doesn't have a description", "") if (!$data{$what}->{description}); 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci foreach my $w(split /\xac/,$what) { 26762306a36Sopenharmony_ci $symbols{$w}->{xref} = $what; 26862306a36Sopenharmony_ci }; 26962306a36Sopenharmony_ci } 27062306a36Sopenharmony_ci close IN; 27162306a36Sopenharmony_ci} 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_cisub create_labels { 27462306a36Sopenharmony_ci my %labels; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci foreach my $what (keys %data) { 27762306a36Sopenharmony_ci next if ($data{$what}->{file} eq "File"); 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci foreach my $p (@{$data{$what}->{label_list}}) { 28062306a36Sopenharmony_ci my ($content, $label) = @{$p}; 28162306a36Sopenharmony_ci $label = "abi_" . $label . " "; 28262306a36Sopenharmony_ci $label =~ tr/A-Z/a-z/; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci # Convert special chars to "_" 28562306a36Sopenharmony_ci $label =~s/([\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\xff])/_/g; 28662306a36Sopenharmony_ci $label =~ s,_+,_,g; 28762306a36Sopenharmony_ci $label =~ s,_$,,; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci # Avoid duplicated labels 29062306a36Sopenharmony_ci while (defined($labels{$label})) { 29162306a36Sopenharmony_ci my @chars = ("A".."Z", "a".."z"); 29262306a36Sopenharmony_ci $label .= $chars[rand @chars]; 29362306a36Sopenharmony_ci } 29462306a36Sopenharmony_ci $labels{$label} = 1; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci $data{$what}->{label} = $label; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci # only one label is enough 29962306a36Sopenharmony_ci last; 30062306a36Sopenharmony_ci } 30162306a36Sopenharmony_ci } 30262306a36Sopenharmony_ci} 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci# 30562306a36Sopenharmony_ci# Outputs the book on ReST format 30662306a36Sopenharmony_ci# 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci# \b doesn't work well with paths. So, we need to define something else: 30962306a36Sopenharmony_ci# Boundaries are punct characters, spaces and end-of-line 31062306a36Sopenharmony_cimy $start = qr {(^|\s|\() }x; 31162306a36Sopenharmony_cimy $bondary = qr { ([,.:;\)\s]|\z) }x; 31262306a36Sopenharmony_cimy $xref_match = qr { $start(\/(sys|config|proc|dev|kvd)\/[^,.:;\)\s]+)$bondary }x; 31362306a36Sopenharmony_cimy $symbols = qr { ([\x01-\x08\x0e-\x1f\x21-\x2f\x3a-\x40\x7b-\xff]) }x; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_cisub output_rest { 31662306a36Sopenharmony_ci create_labels(); 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci my $part = ""; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci foreach my $what (sort { 32162306a36Sopenharmony_ci ($data{$a}->{type} eq "File") cmp ($data{$b}->{type} eq "File") || 32262306a36Sopenharmony_ci $a cmp $b 32362306a36Sopenharmony_ci } keys %data) { 32462306a36Sopenharmony_ci my $type = $data{$what}->{type}; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci my @file = split / /, $data{$what}->{file}; 32762306a36Sopenharmony_ci my @filepath = split / /, $data{$what}->{filepath}; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci if ($enable_lineno) { 33062306a36Sopenharmony_ci printf ".. LINENO %s%s#%s\n\n", 33162306a36Sopenharmony_ci $prefix, $file[0], 33262306a36Sopenharmony_ci $data{$what}->{line_no}; 33362306a36Sopenharmony_ci } 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci my $w = $what; 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci if ($type ne "File") { 33862306a36Sopenharmony_ci my $cur_part = $what; 33962306a36Sopenharmony_ci if ($what =~ '/') { 34062306a36Sopenharmony_ci if ($what =~ m#^(\/?(?:[\w\-]+\/?){1,2})#) { 34162306a36Sopenharmony_ci $cur_part = "Symbols under $1"; 34262306a36Sopenharmony_ci $cur_part =~ s,/$,,; 34362306a36Sopenharmony_ci } 34462306a36Sopenharmony_ci } 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci if ($cur_part ne "" && $part ne $cur_part) { 34762306a36Sopenharmony_ci $part = $cur_part; 34862306a36Sopenharmony_ci my $bar = $part; 34962306a36Sopenharmony_ci $bar =~ s/./-/g; 35062306a36Sopenharmony_ci print "$part\n$bar\n\n"; 35162306a36Sopenharmony_ci } 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci printf ".. _%s:\n\n", $data{$what}->{label}; 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci my @names = split /\xac/,$w; 35662306a36Sopenharmony_ci my $len = 0; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci foreach my $name (@names) { 35962306a36Sopenharmony_ci $name =~ s/$symbols/\\$1/g; 36062306a36Sopenharmony_ci $name = "**$name**"; 36162306a36Sopenharmony_ci $len = length($name) if (length($name) > $len); 36262306a36Sopenharmony_ci } 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci print "+-" . "-" x $len . "-+\n"; 36562306a36Sopenharmony_ci foreach my $name (@names) { 36662306a36Sopenharmony_ci printf "| %s", $name . " " x ($len - length($name)) . " |\n"; 36762306a36Sopenharmony_ci print "+-" . "-" x $len . "-+\n"; 36862306a36Sopenharmony_ci } 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci print "\n"; 37162306a36Sopenharmony_ci } 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci for (my $i = 0; $i < scalar(@filepath); $i++) { 37462306a36Sopenharmony_ci my $path = $filepath[$i]; 37562306a36Sopenharmony_ci my $f = $file[$i]; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci $path =~ s,.*/(.*/.*),$1,;; 37862306a36Sopenharmony_ci $path =~ s,[/\-],_,g;; 37962306a36Sopenharmony_ci my $fileref = "abi_file_".$path; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci if ($type eq "File") { 38262306a36Sopenharmony_ci print ".. _$fileref:\n\n"; 38362306a36Sopenharmony_ci } else { 38462306a36Sopenharmony_ci print "Defined on file :ref:`$f <$fileref>`\n\n"; 38562306a36Sopenharmony_ci } 38662306a36Sopenharmony_ci } 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci if ($type eq "File") { 38962306a36Sopenharmony_ci my $bar = $w; 39062306a36Sopenharmony_ci $bar =~ s/./-/g; 39162306a36Sopenharmony_ci print "$w\n$bar\n\n"; 39262306a36Sopenharmony_ci } 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci my $desc = ""; 39562306a36Sopenharmony_ci $desc = $data{$what}->{description} if (defined($data{$what}->{description})); 39662306a36Sopenharmony_ci $desc =~ s/\s+$/\n/; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci if (!($desc =~ /^\s*$/)) { 39962306a36Sopenharmony_ci if ($description_is_rst) { 40062306a36Sopenharmony_ci # Remove title markups from the description 40162306a36Sopenharmony_ci # Having titles inside ABI files will only work if extra 40262306a36Sopenharmony_ci # care would be taken in order to strictly follow the same 40362306a36Sopenharmony_ci # level order for each markup. 40462306a36Sopenharmony_ci $desc =~ s/\n[\-\*\=\^\~]+\n/\n\n/g; 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci # Enrich text by creating cross-references 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci my $new_desc = ""; 40962306a36Sopenharmony_ci my $init_indent = -1; 41062306a36Sopenharmony_ci my $literal_indent = -1; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci open(my $fh, "+<", \$desc); 41362306a36Sopenharmony_ci while (my $d = <$fh>) { 41462306a36Sopenharmony_ci my $indent = $d =~ m/^(\s+)/; 41562306a36Sopenharmony_ci my $spaces = length($indent); 41662306a36Sopenharmony_ci $init_indent = $indent if ($init_indent < 0); 41762306a36Sopenharmony_ci if ($literal_indent >= 0) { 41862306a36Sopenharmony_ci if ($spaces > $literal_indent) { 41962306a36Sopenharmony_ci $new_desc .= $d; 42062306a36Sopenharmony_ci next; 42162306a36Sopenharmony_ci } else { 42262306a36Sopenharmony_ci $literal_indent = -1; 42362306a36Sopenharmony_ci } 42462306a36Sopenharmony_ci } else { 42562306a36Sopenharmony_ci if ($d =~ /()::$/ && !($d =~ /^\s*\.\./)) { 42662306a36Sopenharmony_ci $literal_indent = $spaces; 42762306a36Sopenharmony_ci } 42862306a36Sopenharmony_ci } 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci $d =~ s,Documentation/(?!devicetree)(\S+)\.rst,:doc:`/$1`,g; 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci my @matches = $d =~ m,Documentation/ABI/([\w\/\-]+),g; 43362306a36Sopenharmony_ci foreach my $f (@matches) { 43462306a36Sopenharmony_ci my $xref = $f; 43562306a36Sopenharmony_ci my $path = $f; 43662306a36Sopenharmony_ci $path =~ s,.*/(.*/.*),$1,;; 43762306a36Sopenharmony_ci $path =~ s,[/\-],_,g;; 43862306a36Sopenharmony_ci $xref .= " <abi_file_" . $path . ">"; 43962306a36Sopenharmony_ci $d =~ s,\bDocumentation/ABI/$f\b,:ref:`$xref`,g; 44062306a36Sopenharmony_ci } 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci # Seek for cross reference symbols like /sys/... 44362306a36Sopenharmony_ci @matches = $d =~ m/$xref_match/g; 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci foreach my $s (@matches) { 44662306a36Sopenharmony_ci next if (!($s =~ m,/,)); 44762306a36Sopenharmony_ci if (defined($data{$s}) && defined($data{$s}->{label})) { 44862306a36Sopenharmony_ci my $xref = $s; 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci $xref =~ s/$symbols/\\$1/g; 45162306a36Sopenharmony_ci $xref = ":ref:`$xref <" . $data{$s}->{label} . ">`"; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci $d =~ s,$start$s$bondary,$1$xref$2,g; 45462306a36Sopenharmony_ci } 45562306a36Sopenharmony_ci } 45662306a36Sopenharmony_ci $new_desc .= $d; 45762306a36Sopenharmony_ci } 45862306a36Sopenharmony_ci close $fh; 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci print "$new_desc\n\n"; 46262306a36Sopenharmony_ci } else { 46362306a36Sopenharmony_ci $desc =~ s/^\s+//; 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci # Remove title markups from the description, as they won't work 46662306a36Sopenharmony_ci $desc =~ s/\n[\-\*\=\^\~]+\n/\n\n/g; 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci if ($desc =~ m/\:\n/ || $desc =~ m/\n[\t ]+/ || $desc =~ m/[\x00-\x08\x0b-\x1f\x7b-\xff]/) { 46962306a36Sopenharmony_ci # put everything inside a code block 47062306a36Sopenharmony_ci $desc =~ s/\n/\n /g; 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci print "::\n\n"; 47362306a36Sopenharmony_ci print " $desc\n\n"; 47462306a36Sopenharmony_ci } else { 47562306a36Sopenharmony_ci # Escape any special chars from description 47662306a36Sopenharmony_ci $desc =~s/([\x00-\x08\x0b-\x1f\x21-\x2a\x2d\x2f\x3c-\x40\x5c\x5e-\x60\x7b-\xff])/\\$1/g; 47762306a36Sopenharmony_ci print "$desc\n\n"; 47862306a36Sopenharmony_ci } 47962306a36Sopenharmony_ci } 48062306a36Sopenharmony_ci } else { 48162306a36Sopenharmony_ci print "DESCRIPTION MISSING for $what\n\n" if (!$data{$what}->{is_file}); 48262306a36Sopenharmony_ci } 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci if ($data{$what}->{symbols}) { 48562306a36Sopenharmony_ci printf "Has the following ABI:\n\n"; 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci foreach my $content(@{$data{$what}->{symbols}}) { 48862306a36Sopenharmony_ci my $label = $data{$symbols{$content}->{xref}}->{label}; 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci # Escape special chars from content 49162306a36Sopenharmony_ci $content =~s/([\x00-\x1f\x21-\x2f\x3a-\x40\x7b-\xff])/\\$1/g; 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci print "- :ref:`$content <$label>`\n\n"; 49462306a36Sopenharmony_ci } 49562306a36Sopenharmony_ci } 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci if (defined($data{$what}->{users})) { 49862306a36Sopenharmony_ci my $users = $data{$what}->{users}; 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci $users =~ s/\n/\n\t/g; 50162306a36Sopenharmony_ci printf "Users:\n\t%s\n\n", $users if ($users ne ""); 50262306a36Sopenharmony_ci } 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci } 50562306a36Sopenharmony_ci} 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci# 50862306a36Sopenharmony_ci# Searches for ABI symbols 50962306a36Sopenharmony_ci# 51062306a36Sopenharmony_cisub search_symbols { 51162306a36Sopenharmony_ci foreach my $what (sort keys %data) { 51262306a36Sopenharmony_ci next if (!($what =~ m/($arg)/)); 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci my $type = $data{$what}->{type}; 51562306a36Sopenharmony_ci next if ($type eq "File"); 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci my $file = $data{$what}->{filepath}; 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci $what =~ s/\xac/, /g; 52062306a36Sopenharmony_ci my $bar = $what; 52162306a36Sopenharmony_ci $bar =~ s/./-/g; 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci print "\n$what\n$bar\n\n"; 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci my $kernelversion = $data{$what}->{kernelversion} if (defined($data{$what}->{kernelversion})); 52662306a36Sopenharmony_ci my $contact = $data{$what}->{contact} if (defined($data{$what}->{contact})); 52762306a36Sopenharmony_ci my $users = $data{$what}->{users} if (defined($data{$what}->{users})); 52862306a36Sopenharmony_ci my $date = $data{$what}->{date} if (defined($data{$what}->{date})); 52962306a36Sopenharmony_ci my $desc = $data{$what}->{description} if (defined($data{$what}->{description})); 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci $kernelversion =~ s/^\s+// if ($kernelversion); 53262306a36Sopenharmony_ci $contact =~ s/^\s+// if ($contact); 53362306a36Sopenharmony_ci if ($users) { 53462306a36Sopenharmony_ci $users =~ s/^\s+//; 53562306a36Sopenharmony_ci $users =~ s/\n//g; 53662306a36Sopenharmony_ci } 53762306a36Sopenharmony_ci $date =~ s/^\s+// if ($date); 53862306a36Sopenharmony_ci $desc =~ s/^\s+// if ($desc); 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci printf "Kernel version:\t\t%s\n", $kernelversion if ($kernelversion); 54162306a36Sopenharmony_ci printf "Date:\t\t\t%s\n", $date if ($date); 54262306a36Sopenharmony_ci printf "Contact:\t\t%s\n", $contact if ($contact); 54362306a36Sopenharmony_ci printf "Users:\t\t\t%s\n", $users if ($users); 54462306a36Sopenharmony_ci print "Defined on file(s):\t$file\n\n"; 54562306a36Sopenharmony_ci print "Description:\n\n$desc"; 54662306a36Sopenharmony_ci } 54762306a36Sopenharmony_ci} 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci# Exclude /sys/kernel/debug and /sys/kernel/tracing from the search path 55062306a36Sopenharmony_cisub dont_parse_special_attributes { 55162306a36Sopenharmony_ci if (($File::Find::dir =~ m,^/sys/kernel,)) { 55262306a36Sopenharmony_ci return grep {!/(debug|tracing)/ } @_; 55362306a36Sopenharmony_ci } 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci if (($File::Find::dir =~ m,^/sys/fs,)) { 55662306a36Sopenharmony_ci return grep {!/(pstore|bpf|fuse)/ } @_; 55762306a36Sopenharmony_ci } 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci return @_ 56062306a36Sopenharmony_ci} 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_cimy %leaf; 56362306a36Sopenharmony_cimy %aliases; 56462306a36Sopenharmony_cimy @files; 56562306a36Sopenharmony_cimy %root; 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_cisub graph_add_file { 56862306a36Sopenharmony_ci my $file = shift; 56962306a36Sopenharmony_ci my $type = shift; 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci my $dir = $file; 57262306a36Sopenharmony_ci $dir =~ s,^(.*/).*,$1,; 57362306a36Sopenharmony_ci $file =~ s,.*/,,; 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci my $name; 57662306a36Sopenharmony_ci my $file_ref = \%root; 57762306a36Sopenharmony_ci foreach my $edge(split "/", $dir) { 57862306a36Sopenharmony_ci $name .= "$edge/"; 57962306a36Sopenharmony_ci if (!defined ${$file_ref}{$edge}) { 58062306a36Sopenharmony_ci ${$file_ref}{$edge} = { }; 58162306a36Sopenharmony_ci } 58262306a36Sopenharmony_ci $file_ref = \%{$$file_ref{$edge}}; 58362306a36Sopenharmony_ci ${$file_ref}{"__name"} = [ $name ]; 58462306a36Sopenharmony_ci } 58562306a36Sopenharmony_ci $name .= "$file"; 58662306a36Sopenharmony_ci ${$file_ref}{$file} = { 58762306a36Sopenharmony_ci "__name" => [ $name ] 58862306a36Sopenharmony_ci }; 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci return \%{$$file_ref{$file}}; 59162306a36Sopenharmony_ci} 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_cisub graph_add_link { 59462306a36Sopenharmony_ci my $file = shift; 59562306a36Sopenharmony_ci my $link = shift; 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci # Traverse graph to find the reference 59862306a36Sopenharmony_ci my $file_ref = \%root; 59962306a36Sopenharmony_ci foreach my $edge(split "/", $file) { 60062306a36Sopenharmony_ci $file_ref = \%{$$file_ref{$edge}} || die "Missing node!"; 60162306a36Sopenharmony_ci } 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci # do a BFS 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci my @queue; 60662306a36Sopenharmony_ci my %seen; 60762306a36Sopenharmony_ci my $st; 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci push @queue, $file_ref; 61062306a36Sopenharmony_ci $seen{$start}++; 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci while (@queue) { 61362306a36Sopenharmony_ci my $v = shift @queue; 61462306a36Sopenharmony_ci my @child = keys(%{$v}); 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci foreach my $c(@child) { 61762306a36Sopenharmony_ci next if $seen{$$v{$c}}; 61862306a36Sopenharmony_ci next if ($c eq "__name"); 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci if (!defined($$v{$c}{"__name"})) { 62162306a36Sopenharmony_ci printf STDERR "Error: Couldn't find a non-empty name on a children of $file/.*: "; 62262306a36Sopenharmony_ci print STDERR Dumper(%{$v}); 62362306a36Sopenharmony_ci exit; 62462306a36Sopenharmony_ci } 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci # Add new name 62762306a36Sopenharmony_ci my $name = @{$$v{$c}{"__name"}}[0]; 62862306a36Sopenharmony_ci if ($name =~ s#^$file/#$link/#) { 62962306a36Sopenharmony_ci push @{$$v{$c}{"__name"}}, $name; 63062306a36Sopenharmony_ci } 63162306a36Sopenharmony_ci # Add child to the queue and mark as seen 63262306a36Sopenharmony_ci push @queue, $$v{$c}; 63362306a36Sopenharmony_ci $seen{$c}++; 63462306a36Sopenharmony_ci } 63562306a36Sopenharmony_ci } 63662306a36Sopenharmony_ci} 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_cimy $escape_symbols = qr { ([\x01-\x08\x0e-\x1f\x21-\x29\x2b-\x2d\x3a-\x40\x7b-\xfe]) }x; 63962306a36Sopenharmony_cisub parse_existing_sysfs { 64062306a36Sopenharmony_ci my $file = $File::Find::name; 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci my $mode = (lstat($file))[2]; 64362306a36Sopenharmony_ci my $abs_file = abs_path($file); 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci my @tmp; 64662306a36Sopenharmony_ci push @tmp, $file; 64762306a36Sopenharmony_ci push @tmp, $abs_file if ($abs_file ne $file); 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci foreach my $f(@tmp) { 65062306a36Sopenharmony_ci # Ignore cgroup, as this is big and has zero docs under ABI 65162306a36Sopenharmony_ci return if ($f =~ m#^/sys/fs/cgroup/#); 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci # Ignore firmware as it is documented elsewhere 65462306a36Sopenharmony_ci # Either ACPI or under Documentation/devicetree/bindings/ 65562306a36Sopenharmony_ci return if ($f =~ m#^/sys/firmware/#); 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci # Ignore some sysfs nodes that aren't actually part of ABI 65862306a36Sopenharmony_ci return if ($f =~ m#/sections|notes/#); 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci # Would need to check at 66162306a36Sopenharmony_ci # Documentation/admin-guide/kernel-parameters.txt, but this 66262306a36Sopenharmony_ci # is not easily parseable. 66362306a36Sopenharmony_ci return if ($f =~ m#/parameters/#); 66462306a36Sopenharmony_ci } 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci if (S_ISLNK($mode)) { 66762306a36Sopenharmony_ci $aliases{$file} = $abs_file; 66862306a36Sopenharmony_ci return; 66962306a36Sopenharmony_ci } 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci return if (S_ISDIR($mode)); 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci # Trivial: file is defined exactly the same way at ABI What: 67462306a36Sopenharmony_ci return if (defined($data{$file})); 67562306a36Sopenharmony_ci return if (defined($data{$abs_file})); 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci push @files, graph_add_file($abs_file, "file"); 67862306a36Sopenharmony_ci} 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_cisub get_leave($) 68162306a36Sopenharmony_ci{ 68262306a36Sopenharmony_ci my $what = shift; 68362306a36Sopenharmony_ci my $leave; 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci my $l = $what; 68662306a36Sopenharmony_ci my $stop = 1; 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci $leave = $l; 68962306a36Sopenharmony_ci $leave =~ s,/$,,; 69062306a36Sopenharmony_ci $leave =~ s,.*/,,; 69162306a36Sopenharmony_ci $leave =~ s/[\(\)]//g; 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci # $leave is used to improve search performance at 69462306a36Sopenharmony_ci # check_undefined_symbols, as the algorithm there can seek 69562306a36Sopenharmony_ci # for a small number of "what". It also allows giving a 69662306a36Sopenharmony_ci # hint about a leave with the same name somewhere else. 69762306a36Sopenharmony_ci # However, there are a few occurences where the leave is 69862306a36Sopenharmony_ci # either a wildcard or a number. Just group such cases 69962306a36Sopenharmony_ci # altogether. 70062306a36Sopenharmony_ci if ($leave =~ m/\.\*/ || $leave eq "" || $leave =~ /\\d/) { 70162306a36Sopenharmony_ci $leave = "others"; 70262306a36Sopenharmony_ci } 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci return $leave; 70562306a36Sopenharmony_ci} 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_cimy @not_found; 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_cisub check_file($$) 71062306a36Sopenharmony_ci{ 71162306a36Sopenharmony_ci my $file_ref = shift; 71262306a36Sopenharmony_ci my $names_ref = shift; 71362306a36Sopenharmony_ci my @names = @{$names_ref}; 71462306a36Sopenharmony_ci my $file = $names[0]; 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci my $found_string; 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci my $leave = get_leave($file); 71962306a36Sopenharmony_ci if (!defined($leaf{$leave})) { 72062306a36Sopenharmony_ci $leave = "others"; 72162306a36Sopenharmony_ci } 72262306a36Sopenharmony_ci my @expr = @{$leaf{$leave}->{expr}}; 72362306a36Sopenharmony_ci die ("\rmissing rules for $leave") if (!defined($leaf{$leave})); 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci my $path = $file; 72662306a36Sopenharmony_ci $path =~ s,(.*/).*,$1,; 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci if ($search_string) { 72962306a36Sopenharmony_ci return if (!($file =~ m#$search_string#)); 73062306a36Sopenharmony_ci $found_string = 1; 73162306a36Sopenharmony_ci } 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci for (my $i = 0; $i < @names; $i++) { 73462306a36Sopenharmony_ci if ($found_string && $hint) { 73562306a36Sopenharmony_ci if (!$i) { 73662306a36Sopenharmony_ci print STDERR "--> $names[$i]\n"; 73762306a36Sopenharmony_ci } else { 73862306a36Sopenharmony_ci print STDERR " $names[$i]\n"; 73962306a36Sopenharmony_ci } 74062306a36Sopenharmony_ci } 74162306a36Sopenharmony_ci foreach my $re (@expr) { 74262306a36Sopenharmony_ci print STDERR "$names[$i] =~ /^$re\$/\n" if ($debug && $dbg_undefined); 74362306a36Sopenharmony_ci if ($names[$i] =~ $re) { 74462306a36Sopenharmony_ci return; 74562306a36Sopenharmony_ci } 74662306a36Sopenharmony_ci } 74762306a36Sopenharmony_ci } 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci if ($leave ne "others") { 75062306a36Sopenharmony_ci my @expr = @{$leaf{"others"}->{expr}}; 75162306a36Sopenharmony_ci for (my $i = 0; $i < @names; $i++) { 75262306a36Sopenharmony_ci foreach my $re (@expr) { 75362306a36Sopenharmony_ci print STDERR "$names[$i] =~ /^$re\$/\n" if ($debug && $dbg_undefined); 75462306a36Sopenharmony_ci if ($names[$i] =~ $re) { 75562306a36Sopenharmony_ci return; 75662306a36Sopenharmony_ci } 75762306a36Sopenharmony_ci } 75862306a36Sopenharmony_ci } 75962306a36Sopenharmony_ci } 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci push @not_found, $file if (!$search_string || $found_string); 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci if ($hint && (!$search_string || $found_string)) { 76462306a36Sopenharmony_ci my $what = $leaf{$leave}->{what}; 76562306a36Sopenharmony_ci $what =~ s/\xac/\n\t/g; 76662306a36Sopenharmony_ci if ($leave ne "others") { 76762306a36Sopenharmony_ci print STDERR "\r more likely regexes:\n\t$what\n"; 76862306a36Sopenharmony_ci } else { 76962306a36Sopenharmony_ci print STDERR "\r tested regexes:\n\t$what\n"; 77062306a36Sopenharmony_ci } 77162306a36Sopenharmony_ci } 77262306a36Sopenharmony_ci} 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_cisub check_undefined_symbols { 77562306a36Sopenharmony_ci my $num_files = scalar @files; 77662306a36Sopenharmony_ci my $next_i = 0; 77762306a36Sopenharmony_ci my $start_time = times; 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci @files = sort @files; 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci my $last_time = $start_time; 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci # When either debug or hint is enabled, there's no sense showing 78462306a36Sopenharmony_ci # progress, as the progress will be overriden. 78562306a36Sopenharmony_ci if ($hint || ($debug && $dbg_undefined)) { 78662306a36Sopenharmony_ci $next_i = $num_files; 78762306a36Sopenharmony_ci } 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci my $is_console; 79062306a36Sopenharmony_ci $is_console = 1 if (-t STDERR); 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci for (my $i = 0; $i < $num_files; $i++) { 79362306a36Sopenharmony_ci my $file_ref = $files[$i]; 79462306a36Sopenharmony_ci my @names = @{$$file_ref{"__name"}}; 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci check_file($file_ref, \@names); 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci my $cur_time = times; 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci if ($i == $next_i || $cur_time > $last_time + 1) { 80162306a36Sopenharmony_ci my $percent = $i * 100 / $num_files; 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci my $tm = $cur_time - $start_time; 80462306a36Sopenharmony_ci my $time = sprintf "%d:%02d", int($tm), 60 * ($tm - int($tm)); 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci printf STDERR "\33[2K\r", if ($is_console); 80762306a36Sopenharmony_ci printf STDERR "%s: processing sysfs files... %i%%: $names[0]", $time, $percent; 80862306a36Sopenharmony_ci printf STDERR "\n", if (!$is_console); 80962306a36Sopenharmony_ci STDERR->flush(); 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci $next_i = int (($percent + 1) * $num_files / 100); 81262306a36Sopenharmony_ci $last_time = $cur_time; 81362306a36Sopenharmony_ci } 81462306a36Sopenharmony_ci } 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci my $cur_time = times; 81762306a36Sopenharmony_ci my $tm = $cur_time - $start_time; 81862306a36Sopenharmony_ci my $time = sprintf "%d:%02d", int($tm), 60 * ($tm - int($tm)); 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci printf STDERR "\33[2K\r", if ($is_console); 82162306a36Sopenharmony_ci printf STDERR "%s: processing sysfs files... done\n", $time; 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci foreach my $file (@not_found) { 82462306a36Sopenharmony_ci print "$file not found.\n"; 82562306a36Sopenharmony_ci } 82662306a36Sopenharmony_ci} 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_cisub undefined_symbols { 82962306a36Sopenharmony_ci print STDERR "Reading $sysfs_prefix directory contents..."; 83062306a36Sopenharmony_ci find({ 83162306a36Sopenharmony_ci wanted =>\&parse_existing_sysfs, 83262306a36Sopenharmony_ci preprocess =>\&dont_parse_special_attributes, 83362306a36Sopenharmony_ci no_chdir => 1 83462306a36Sopenharmony_ci }, $sysfs_prefix); 83562306a36Sopenharmony_ci print STDERR "done.\n"; 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci $leaf{"others"}->{what} = ""; 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci print STDERR "Converting ABI What fields into regexes..."; 84062306a36Sopenharmony_ci foreach my $w (sort keys %data) { 84162306a36Sopenharmony_ci foreach my $what (split /\xac/,$w) { 84262306a36Sopenharmony_ci next if (!($what =~ m/^$sysfs_prefix/)); 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci # Convert what into regular expressions 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci # Escape dot characters 84762306a36Sopenharmony_ci $what =~ s/\./\xf6/g; 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci # Temporarily change [0-9]+ type of patterns 85062306a36Sopenharmony_ci $what =~ s/\[0\-9\]\+/\xff/g; 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci # Temporarily change [\d+-\d+] type of patterns 85362306a36Sopenharmony_ci $what =~ s/\[0\-\d+\]/\xff/g; 85462306a36Sopenharmony_ci $what =~ s/\[(\d+)\]/\xf4$1\xf5/g; 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci # Temporarily change [0-9] type of patterns 85762306a36Sopenharmony_ci $what =~ s/\[(\d)\-(\d)\]/\xf4$1-$2\xf5/g; 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci # Handle multiple option patterns 86062306a36Sopenharmony_ci $what =~ s/[\{\<\[]([\w_]+)(?:[,|]+([\w_]+)){1,}[\}\>\]]/($1|$2)/g; 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci # Handle wildcards 86362306a36Sopenharmony_ci $what =~ s,\*,.*,g; 86462306a36Sopenharmony_ci $what =~ s,/\xf6..,/.*,g; 86562306a36Sopenharmony_ci $what =~ s/\<[^\>]+\>/.*/g; 86662306a36Sopenharmony_ci $what =~ s/\{[^\}]+\}/.*/g; 86762306a36Sopenharmony_ci $what =~ s/\[[^\]]+\]/.*/g; 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ci $what =~ s/[XYZ]/.*/g; 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci # Recover [0-9] type of patterns 87262306a36Sopenharmony_ci $what =~ s/\xf4/[/g; 87362306a36Sopenharmony_ci $what =~ s/\xf5/]/g; 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci # Remove duplicated spaces 87662306a36Sopenharmony_ci $what =~ s/\s+/ /g; 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci # Special case: this ABI has a parenthesis on it 87962306a36Sopenharmony_ci $what =~ s/sqrt\(x^2\+y^2\+z^2\)/sqrt\(x^2\+y^2\+z^2\)/; 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci # Special case: drop comparition as in: 88262306a36Sopenharmony_ci # What: foo = <something> 88362306a36Sopenharmony_ci # (this happens on a few IIO definitions) 88462306a36Sopenharmony_ci $what =~ s,\s*\=.*$,,; 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci # Escape all other symbols 88762306a36Sopenharmony_ci $what =~ s/$escape_symbols/\\$1/g; 88862306a36Sopenharmony_ci $what =~ s/\\\\/\\/g; 88962306a36Sopenharmony_ci $what =~ s/\\([\[\]\(\)\|])/$1/g; 89062306a36Sopenharmony_ci $what =~ s/(\d+)\\(-\d+)/$1$2/g; 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci $what =~ s/\xff/\\d+/g; 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_ci # Special case: IIO ABI which a parenthesis. 89562306a36Sopenharmony_ci $what =~ s/sqrt(.*)/sqrt\(.*\)/; 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci # Simplify regexes with multiple .* 89862306a36Sopenharmony_ci $what =~ s#(?:\.\*){2,}##g; 89962306a36Sopenharmony_ci# $what =~ s#\.\*/\.\*#.*#g; 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci # Recover dot characters 90262306a36Sopenharmony_ci $what =~ s/\xf6/\./g; 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci my $leave = get_leave($what); 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_ci my $added = 0; 90762306a36Sopenharmony_ci foreach my $l (split /\|/, $leave) { 90862306a36Sopenharmony_ci if (defined($leaf{$l})) { 90962306a36Sopenharmony_ci next if ($leaf{$l}->{what} =~ m/\b$what\b/); 91062306a36Sopenharmony_ci $leaf{$l}->{what} .= "\xac" . $what; 91162306a36Sopenharmony_ci $added = 1; 91262306a36Sopenharmony_ci } else { 91362306a36Sopenharmony_ci $leaf{$l}->{what} = $what; 91462306a36Sopenharmony_ci $added = 1; 91562306a36Sopenharmony_ci } 91662306a36Sopenharmony_ci } 91762306a36Sopenharmony_ci if ($search_string && $added) { 91862306a36Sopenharmony_ci print STDERR "What: $what\n" if ($what =~ m#$search_string#); 91962306a36Sopenharmony_ci } 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ci } 92262306a36Sopenharmony_ci } 92362306a36Sopenharmony_ci # Compile regexes 92462306a36Sopenharmony_ci foreach my $l (sort keys %leaf) { 92562306a36Sopenharmony_ci my @expr; 92662306a36Sopenharmony_ci foreach my $w(sort split /\xac/, $leaf{$l}->{what}) { 92762306a36Sopenharmony_ci push @expr, qr /^$w$/; 92862306a36Sopenharmony_ci } 92962306a36Sopenharmony_ci $leaf{$l}->{expr} = \@expr; 93062306a36Sopenharmony_ci } 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci # Take links into account 93362306a36Sopenharmony_ci foreach my $link (sort keys %aliases) { 93462306a36Sopenharmony_ci my $abs_file = $aliases{$link}; 93562306a36Sopenharmony_ci graph_add_link($abs_file, $link); 93662306a36Sopenharmony_ci } 93762306a36Sopenharmony_ci print STDERR "done.\n"; 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ci check_undefined_symbols; 94062306a36Sopenharmony_ci} 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_ci# Ensure that the prefix will always end with a slash 94362306a36Sopenharmony_ci# While this is not needed for find, it makes the patch nicer 94462306a36Sopenharmony_ci# with --enable-lineno 94562306a36Sopenharmony_ci$prefix =~ s,/?$,/,; 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ciif ($cmd eq "undefined" || $cmd eq "search") { 94862306a36Sopenharmony_ci $show_warnings = 0; 94962306a36Sopenharmony_ci} 95062306a36Sopenharmony_ci# 95162306a36Sopenharmony_ci# Parses all ABI files located at $prefix dir 95262306a36Sopenharmony_ci# 95362306a36Sopenharmony_cifind({wanted =>\&parse_abi, no_chdir => 1}, $prefix); 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_ciprint STDERR Data::Dumper->Dump([\%data], [qw(*data)]) if ($debug & $dbg_dump_abi_structs); 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci# 95862306a36Sopenharmony_ci# Handles the command 95962306a36Sopenharmony_ci# 96062306a36Sopenharmony_ciif ($cmd eq "undefined") { 96162306a36Sopenharmony_ci undefined_symbols; 96262306a36Sopenharmony_ci} elsif ($cmd eq "search") { 96362306a36Sopenharmony_ci search_symbols; 96462306a36Sopenharmony_ci} else { 96562306a36Sopenharmony_ci if ($cmd eq "rest") { 96662306a36Sopenharmony_ci output_rest; 96762306a36Sopenharmony_ci } 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci # Warn about duplicated ABI entries 97062306a36Sopenharmony_ci foreach my $what(sort keys %symbols) { 97162306a36Sopenharmony_ci my @files = @{$symbols{$what}->{file}}; 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci next if (scalar(@files) == 1); 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ci printf STDERR "Warning: $what is defined %d times: @files\n", 97662306a36Sopenharmony_ci scalar(@files); 97762306a36Sopenharmony_ci } 97862306a36Sopenharmony_ci} 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_ci__END__ 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_ci=head1 NAME 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ciget_abi.pl - parse the Linux ABI files and produce a ReST book. 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_ci=head1 SYNOPSIS 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ciB<get_abi.pl> [--debug <level>] [--enable-lineno] [--man] [--help] 98962306a36Sopenharmony_ci [--(no-)rst-source] [--dir=<dir>] [--show-hints] 99062306a36Sopenharmony_ci [--search-string <regex>] 99162306a36Sopenharmony_ci <COMMAND> [<ARGUMENT>] 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_ciWhere B<COMMAND> can be: 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ci=over 8 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ciB<search> I<SEARCH_REGEX> - search for I<SEARCH_REGEX> inside ABI 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_ciB<rest> - output the ABI in ReST markup language 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_ciB<validate> - validate the ABI contents 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ciB<undefined> - existing symbols at the system that aren't 100462306a36Sopenharmony_ci defined at Documentation/ABI 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_ci=back 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci=head1 OPTIONS 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci=over 8 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ci=item B<--dir> 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ciChanges the location of the ABI search. By default, it uses 101562306a36Sopenharmony_cithe Documentation/ABI directory. 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_ci=item B<--rst-source> and B<--no-rst-source> 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ciThe input file may be using ReST syntax or not. Those two options allow 102062306a36Sopenharmony_ciselecting between a rst-compliant source ABI (B<--rst-source>), or a 102162306a36Sopenharmony_ciplain text that may be violating ReST spec, so it requres some escaping 102262306a36Sopenharmony_cilogic (B<--no-rst-source>). 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_ci=item B<--enable-lineno> 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_ciEnable output of .. LINENO lines. 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ci=item B<--debug> I<debug level> 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_ciPrint debug information according with the level, which is given by the 103162306a36Sopenharmony_cifollowing bitmask: 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci - 1: Debug parsing What entries from ABI files; 103462306a36Sopenharmony_ci - 2: Shows what files are opened from ABI files; 103562306a36Sopenharmony_ci - 4: Dump the structs used to store the contents of the ABI files. 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ci=item B<--show-hints> 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_ciShow hints about possible definitions for the missing ABI symbols. 104062306a36Sopenharmony_ciUsed only when B<undefined>. 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_ci=item B<--search-string> I<regex string> 104362306a36Sopenharmony_ci 104462306a36Sopenharmony_ciShow only occurences that match a search string. 104562306a36Sopenharmony_ciUsed only when B<undefined>. 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_ci=item B<--help> 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_ciPrints a brief help message and exits. 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_ci=item B<--man> 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_ciPrints the manual page and exits. 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci=back 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_ci=head1 DESCRIPTION 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_ciParse the Linux ABI files from ABI DIR (usually located at Documentation/ABI), 106062306a36Sopenharmony_ciallowing to search for ABI symbols or to produce a ReST book containing 106162306a36Sopenharmony_cithe Linux ABI documentation. 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_ci=head1 EXAMPLES 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_ciSearch for all stable symbols with the word "usb": 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_ci=over 8 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci$ scripts/get_abi.pl search usb --dir Documentation/ABI/stable 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_ci=back 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_ciSearch for all symbols that match the regex expression "usb.*cap": 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci=over 8 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_ci$ scripts/get_abi.pl search usb.*cap 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_ci=back 108062306a36Sopenharmony_ci 108162306a36Sopenharmony_ciOutput all obsoleted symbols in ReST format 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci=over 8 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_ci$ scripts/get_abi.pl rest --dir Documentation/ABI/obsolete 108662306a36Sopenharmony_ci 108762306a36Sopenharmony_ci=back 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_ci=head1 BUGS 109062306a36Sopenharmony_ci 109162306a36Sopenharmony_ciReport bugs to Mauro Carvalho Chehab <mchehab+huawei@kernel.org> 109262306a36Sopenharmony_ci 109362306a36Sopenharmony_ci=head1 COPYRIGHT 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_ciCopyright (c) 2016-2021 by Mauro Carvalho Chehab <mchehab+huawei@kernel.org>. 109662306a36Sopenharmony_ci 109762306a36Sopenharmony_ciLicense GPLv2: GNU GPL version 2 <http://gnu.org/licenses/gpl.html>. 109862306a36Sopenharmony_ci 109962306a36Sopenharmony_ciThis is free software: you are free to change and redistribute it. 110062306a36Sopenharmony_ciThere is NO WARRANTY, to the extent permitted by law. 110162306a36Sopenharmony_ci 110262306a36Sopenharmony_ci=cut 1103