18c2ecf20Sopenharmony_ci#!/usr/bin/env perl 28c2ecf20Sopenharmony_ci# SPDX-License-Identifier: GPL-2.0 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ciuse strict; 58c2ecf20Sopenharmony_ciuse warnings; 68c2ecf20Sopenharmony_ciuse utf8; 78c2ecf20Sopenharmony_ciuse Pod::Usage; 88c2ecf20Sopenharmony_ciuse Getopt::Long; 98c2ecf20Sopenharmony_ciuse File::Find; 108c2ecf20Sopenharmony_ciuse Fcntl ':mode'; 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_cimy $help = 0; 138c2ecf20Sopenharmony_cimy $man = 0; 148c2ecf20Sopenharmony_cimy $debug = 0; 158c2ecf20Sopenharmony_cimy $enable_lineno = 0; 168c2ecf20Sopenharmony_cimy $prefix="Documentation/ABI"; 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci# 198c2ecf20Sopenharmony_ci# If true, assumes that the description is formatted with ReST 208c2ecf20Sopenharmony_ci# 218c2ecf20Sopenharmony_cimy $description_is_rst = 1; 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ciGetOptions( 248c2ecf20Sopenharmony_ci "debug|d+" => \$debug, 258c2ecf20Sopenharmony_ci "enable-lineno" => \$enable_lineno, 268c2ecf20Sopenharmony_ci "rst-source!" => \$description_is_rst, 278c2ecf20Sopenharmony_ci "dir=s" => \$prefix, 288c2ecf20Sopenharmony_ci 'help|?' => \$help, 298c2ecf20Sopenharmony_ci man => \$man 308c2ecf20Sopenharmony_ci) or pod2usage(2); 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cipod2usage(1) if $help; 338c2ecf20Sopenharmony_cipod2usage(-exitstatus => 0, -verbose => 2) if $man; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cipod2usage(2) if (scalar @ARGV < 1 || @ARGV > 2); 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cimy ($cmd, $arg) = @ARGV; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cipod2usage(2) if ($cmd ne "search" && $cmd ne "rest" && $cmd ne "validate"); 408c2ecf20Sopenharmony_cipod2usage(2) if ($cmd eq "search" && !$arg); 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cirequire Data::Dumper if ($debug); 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cimy %data; 458c2ecf20Sopenharmony_cimy %symbols; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci# 488c2ecf20Sopenharmony_ci# Displays an error message, printing file name and line 498c2ecf20Sopenharmony_ci# 508c2ecf20Sopenharmony_cisub parse_error($$$$) { 518c2ecf20Sopenharmony_ci my ($file, $ln, $msg, $data) = @_; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci $data =~ s/\s+$/\n/; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci print STDERR "Warning: file $file#$ln:\n\t$msg"; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci if ($data ne "") { 588c2ecf20Sopenharmony_ci print STDERR ". Line\n\t\t$data"; 598c2ecf20Sopenharmony_ci } else { 608c2ecf20Sopenharmony_ci print STDERR "\n"; 618c2ecf20Sopenharmony_ci } 628c2ecf20Sopenharmony_ci} 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci# 658c2ecf20Sopenharmony_ci# Parse an ABI file, storing its contents at %data 668c2ecf20Sopenharmony_ci# 678c2ecf20Sopenharmony_cisub parse_abi { 688c2ecf20Sopenharmony_ci my $file = $File::Find::name; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci my $mode = (stat($file))[2]; 718c2ecf20Sopenharmony_ci return if ($mode & S_IFDIR); 728c2ecf20Sopenharmony_ci return if ($file =~ m,/README,); 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci my $name = $file; 758c2ecf20Sopenharmony_ci $name =~ s,.*/,,; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci my $fn = $file; 788c2ecf20Sopenharmony_ci $fn =~ s,.*Documentation/ABI/,,; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci my $nametag = "File $fn"; 818c2ecf20Sopenharmony_ci $data{$nametag}->{what} = "File $name"; 828c2ecf20Sopenharmony_ci $data{$nametag}->{type} = "File"; 838c2ecf20Sopenharmony_ci $data{$nametag}->{file} = $name; 848c2ecf20Sopenharmony_ci $data{$nametag}->{filepath} = $file; 858c2ecf20Sopenharmony_ci $data{$nametag}->{is_file} = 1; 868c2ecf20Sopenharmony_ci $data{$nametag}->{line_no} = 1; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci my $type = $file; 898c2ecf20Sopenharmony_ci $type =~ s,.*/(.*)/.*,$1,; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci my $what; 928c2ecf20Sopenharmony_ci my $new_what; 938c2ecf20Sopenharmony_ci my $tag = ""; 948c2ecf20Sopenharmony_ci my $ln; 958c2ecf20Sopenharmony_ci my $xrefs; 968c2ecf20Sopenharmony_ci my $space; 978c2ecf20Sopenharmony_ci my @labels; 988c2ecf20Sopenharmony_ci my $label = ""; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci print STDERR "Opening $file\n" if ($debug > 1); 1018c2ecf20Sopenharmony_ci open IN, $file; 1028c2ecf20Sopenharmony_ci while(<IN>) { 1038c2ecf20Sopenharmony_ci $ln++; 1048c2ecf20Sopenharmony_ci if (m/^(\S+)(:\s*)(.*)/i) { 1058c2ecf20Sopenharmony_ci my $new_tag = lc($1); 1068c2ecf20Sopenharmony_ci my $sep = $2; 1078c2ecf20Sopenharmony_ci my $content = $3; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci if (!($new_tag =~ m/(what|where|date|kernelversion|contact|description|users)/)) { 1108c2ecf20Sopenharmony_ci if ($tag eq "description") { 1118c2ecf20Sopenharmony_ci # New "tag" is actually part of 1128c2ecf20Sopenharmony_ci # description. Don't consider it a tag 1138c2ecf20Sopenharmony_ci $new_tag = ""; 1148c2ecf20Sopenharmony_ci } elsif ($tag ne "") { 1158c2ecf20Sopenharmony_ci parse_error($file, $ln, "tag '$tag' is invalid", $_); 1168c2ecf20Sopenharmony_ci } 1178c2ecf20Sopenharmony_ci } 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci # Invalid, but it is a common mistake 1208c2ecf20Sopenharmony_ci if ($new_tag eq "where") { 1218c2ecf20Sopenharmony_ci parse_error($file, $ln, "tag 'Where' is invalid. Should be 'What:' instead", ""); 1228c2ecf20Sopenharmony_ci $new_tag = "what"; 1238c2ecf20Sopenharmony_ci } 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci if ($new_tag =~ m/what/) { 1268c2ecf20Sopenharmony_ci $space = ""; 1278c2ecf20Sopenharmony_ci $content =~ s/[,.;]$//; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci push @{$symbols{$content}->{file}}, " $file:" . ($ln - 1); 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci if ($tag =~ m/what/) { 1328c2ecf20Sopenharmony_ci $what .= ", " . $content; 1338c2ecf20Sopenharmony_ci } else { 1348c2ecf20Sopenharmony_ci if ($what) { 1358c2ecf20Sopenharmony_ci parse_error($file, $ln, "What '$what' doesn't have a description", "") if (!$data{$what}->{description}); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci foreach my $w(split /, /, $what) { 1388c2ecf20Sopenharmony_ci $symbols{$w}->{xref} = $what; 1398c2ecf20Sopenharmony_ci }; 1408c2ecf20Sopenharmony_ci } 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci $what = $content; 1438c2ecf20Sopenharmony_ci $label = $content; 1448c2ecf20Sopenharmony_ci $new_what = 1; 1458c2ecf20Sopenharmony_ci } 1468c2ecf20Sopenharmony_ci push @labels, [($content, $label)]; 1478c2ecf20Sopenharmony_ci $tag = $new_tag; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci push @{$data{$nametag}->{symbols}}, $content if ($data{$nametag}->{what}); 1508c2ecf20Sopenharmony_ci next; 1518c2ecf20Sopenharmony_ci } 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci if ($tag ne "" && $new_tag) { 1548c2ecf20Sopenharmony_ci $tag = $new_tag; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci if ($new_what) { 1578c2ecf20Sopenharmony_ci @{$data{$what}->{label_list}} = @labels if ($data{$nametag}->{what}); 1588c2ecf20Sopenharmony_ci @labels = (); 1598c2ecf20Sopenharmony_ci $label = ""; 1608c2ecf20Sopenharmony_ci $new_what = 0; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci $data{$what}->{type} = $type; 1638c2ecf20Sopenharmony_ci if (!defined($data{$what}->{file})) { 1648c2ecf20Sopenharmony_ci $data{$what}->{file} = $name; 1658c2ecf20Sopenharmony_ci $data{$what}->{filepath} = $file; 1668c2ecf20Sopenharmony_ci } else { 1678c2ecf20Sopenharmony_ci if ($name ne $data{$what}->{file}) { 1688c2ecf20Sopenharmony_ci $data{$what}->{file} .= " " . $name; 1698c2ecf20Sopenharmony_ci $data{$what}->{filepath} .= " " . $file; 1708c2ecf20Sopenharmony_ci } 1718c2ecf20Sopenharmony_ci } 1728c2ecf20Sopenharmony_ci print STDERR "\twhat: $what\n" if ($debug > 1); 1738c2ecf20Sopenharmony_ci $data{$what}->{line_no} = $ln; 1748c2ecf20Sopenharmony_ci } else { 1758c2ecf20Sopenharmony_ci $data{$what}->{line_no} = $ln if (!defined($data{$what}->{line_no})); 1768c2ecf20Sopenharmony_ci } 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci if (!$what) { 1798c2ecf20Sopenharmony_ci parse_error($file, $ln, "'What:' should come first:", $_); 1808c2ecf20Sopenharmony_ci next; 1818c2ecf20Sopenharmony_ci } 1828c2ecf20Sopenharmony_ci if ($new_tag eq "description") { 1838c2ecf20Sopenharmony_ci $sep =~ s,:, ,; 1848c2ecf20Sopenharmony_ci $content = ' ' x length($new_tag) . $sep . $content; 1858c2ecf20Sopenharmony_ci while ($content =~ s/\t+/' ' x (length($&) * 8 - length($`) % 8)/e) {} 1868c2ecf20Sopenharmony_ci if ($content =~ m/^(\s*)(\S.*)$/) { 1878c2ecf20Sopenharmony_ci # Preserve initial spaces for the first line 1888c2ecf20Sopenharmony_ci $space = $1; 1898c2ecf20Sopenharmony_ci $content = "$2\n"; 1908c2ecf20Sopenharmony_ci $data{$what}->{$tag} .= $content; 1918c2ecf20Sopenharmony_ci } else { 1928c2ecf20Sopenharmony_ci undef($space); 1938c2ecf20Sopenharmony_ci } 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci } else { 1968c2ecf20Sopenharmony_ci $data{$what}->{$tag} = $content; 1978c2ecf20Sopenharmony_ci } 1988c2ecf20Sopenharmony_ci next; 1998c2ecf20Sopenharmony_ci } 2008c2ecf20Sopenharmony_ci } 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci # Store any contents before tags at the database 2038c2ecf20Sopenharmony_ci if (!$tag && $data{$nametag}->{what}) { 2048c2ecf20Sopenharmony_ci $data{$nametag}->{description} .= $_; 2058c2ecf20Sopenharmony_ci next; 2068c2ecf20Sopenharmony_ci } 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci if ($tag eq "description") { 2098c2ecf20Sopenharmony_ci my $content = $_; 2108c2ecf20Sopenharmony_ci while ($content =~ s/\t+/' ' x (length($&) * 8 - length($`) % 8)/e) {} 2118c2ecf20Sopenharmony_ci if (m/^\s*\n/) { 2128c2ecf20Sopenharmony_ci $data{$what}->{$tag} .= "\n"; 2138c2ecf20Sopenharmony_ci next; 2148c2ecf20Sopenharmony_ci } 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci if (!defined($space)) { 2178c2ecf20Sopenharmony_ci # Preserve initial spaces for the first line 2188c2ecf20Sopenharmony_ci if ($content =~ m/^(\s*)(\S.*)$/) { 2198c2ecf20Sopenharmony_ci $space = $1; 2208c2ecf20Sopenharmony_ci $content = "$2\n"; 2218c2ecf20Sopenharmony_ci } 2228c2ecf20Sopenharmony_ci } else { 2238c2ecf20Sopenharmony_ci $space = "" if (!($content =~ s/^($space)//)); 2248c2ecf20Sopenharmony_ci } 2258c2ecf20Sopenharmony_ci $data{$what}->{$tag} .= $content; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci next; 2288c2ecf20Sopenharmony_ci } 2298c2ecf20Sopenharmony_ci if (m/^\s*(.*)/) { 2308c2ecf20Sopenharmony_ci $data{$what}->{$tag} .= "\n$1"; 2318c2ecf20Sopenharmony_ci $data{$what}->{$tag} =~ s/\n+$//; 2328c2ecf20Sopenharmony_ci next; 2338c2ecf20Sopenharmony_ci } 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci # Everything else is error 2368c2ecf20Sopenharmony_ci parse_error($file, $ln, "Unexpected content", $_); 2378c2ecf20Sopenharmony_ci } 2388c2ecf20Sopenharmony_ci $data{$nametag}->{description} =~ s/^\n+// if ($data{$nametag}->{description}); 2398c2ecf20Sopenharmony_ci if ($what) { 2408c2ecf20Sopenharmony_ci parse_error($file, $ln, "What '$what' doesn't have a description", "") if (!$data{$what}->{description}); 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci foreach my $w(split /, /,$what) { 2438c2ecf20Sopenharmony_ci $symbols{$w}->{xref} = $what; 2448c2ecf20Sopenharmony_ci }; 2458c2ecf20Sopenharmony_ci } 2468c2ecf20Sopenharmony_ci close IN; 2478c2ecf20Sopenharmony_ci} 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_cisub create_labels { 2508c2ecf20Sopenharmony_ci my %labels; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci foreach my $what (keys %data) { 2538c2ecf20Sopenharmony_ci next if ($data{$what}->{file} eq "File"); 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci foreach my $p (@{$data{$what}->{label_list}}) { 2568c2ecf20Sopenharmony_ci my ($content, $label) = @{$p}; 2578c2ecf20Sopenharmony_ci $label = "abi_" . $label . " "; 2588c2ecf20Sopenharmony_ci $label =~ tr/A-Z/a-z/; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci # Convert special chars to "_" 2618c2ecf20Sopenharmony_ci $label =~s/([\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\xff])/_/g; 2628c2ecf20Sopenharmony_ci $label =~ s,_+,_,g; 2638c2ecf20Sopenharmony_ci $label =~ s,_$,,; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci # Avoid duplicated labels 2668c2ecf20Sopenharmony_ci while (defined($labels{$label})) { 2678c2ecf20Sopenharmony_ci my @chars = ("A".."Z", "a".."z"); 2688c2ecf20Sopenharmony_ci $label .= $chars[rand @chars]; 2698c2ecf20Sopenharmony_ci } 2708c2ecf20Sopenharmony_ci $labels{$label} = 1; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci $data{$what}->{label} = $label; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci # only one label is enough 2758c2ecf20Sopenharmony_ci last; 2768c2ecf20Sopenharmony_ci } 2778c2ecf20Sopenharmony_ci } 2788c2ecf20Sopenharmony_ci} 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci# 2818c2ecf20Sopenharmony_ci# Outputs the book on ReST format 2828c2ecf20Sopenharmony_ci# 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci# \b doesn't work well with paths. So, we need to define something else 2858c2ecf20Sopenharmony_cimy $bondary = qr { (?<![\w\/\`\{])(?=[\w\/\`\{])|(?<=[\w\/\`\{])(?![\w\/\`\{]) }x; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_cisub output_rest { 2888c2ecf20Sopenharmony_ci create_labels(); 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci my $part = ""; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci foreach my $what (sort { 2938c2ecf20Sopenharmony_ci ($data{$a}->{type} eq "File") cmp ($data{$b}->{type} eq "File") || 2948c2ecf20Sopenharmony_ci $a cmp $b 2958c2ecf20Sopenharmony_ci } keys %data) { 2968c2ecf20Sopenharmony_ci my $type = $data{$what}->{type}; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci my @file = split / /, $data{$what}->{file}; 2998c2ecf20Sopenharmony_ci my @filepath = split / /, $data{$what}->{filepath}; 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci if ($enable_lineno) { 3028c2ecf20Sopenharmony_ci printf "#define LINENO %s%s#%s\n\n", 3038c2ecf20Sopenharmony_ci $prefix, $file[0], 3048c2ecf20Sopenharmony_ci $data{$what}->{line_no}; 3058c2ecf20Sopenharmony_ci } 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci my $w = $what; 3088c2ecf20Sopenharmony_ci $w =~ s/([\(\)\_\-\*\=\^\~\\])/\\$1/g; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci if ($type ne "File") { 3118c2ecf20Sopenharmony_ci my $cur_part = $what; 3128c2ecf20Sopenharmony_ci if ($what =~ '/') { 3138c2ecf20Sopenharmony_ci if ($what =~ m#^(\/?(?:[\w\-]+\/?){1,2})#) { 3148c2ecf20Sopenharmony_ci $cur_part = "Symbols under $1"; 3158c2ecf20Sopenharmony_ci $cur_part =~ s,/$,,; 3168c2ecf20Sopenharmony_ci } 3178c2ecf20Sopenharmony_ci } 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci if ($cur_part ne "" && $part ne $cur_part) { 3208c2ecf20Sopenharmony_ci $part = $cur_part; 3218c2ecf20Sopenharmony_ci my $bar = $part; 3228c2ecf20Sopenharmony_ci $bar =~ s/./-/g; 3238c2ecf20Sopenharmony_ci print "$part\n$bar\n\n"; 3248c2ecf20Sopenharmony_ci } 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci printf ".. _%s:\n\n", $data{$what}->{label}; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci my @names = split /, /,$w; 3298c2ecf20Sopenharmony_ci my $len = 0; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci foreach my $name (@names) { 3328c2ecf20Sopenharmony_ci $name = "**$name**"; 3338c2ecf20Sopenharmony_ci $len = length($name) if (length($name) > $len); 3348c2ecf20Sopenharmony_ci } 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci print "+-" . "-" x $len . "-+\n"; 3378c2ecf20Sopenharmony_ci foreach my $name (@names) { 3388c2ecf20Sopenharmony_ci printf "| %s", $name . " " x ($len - length($name)) . " |\n"; 3398c2ecf20Sopenharmony_ci print "+-" . "-" x $len . "-+\n"; 3408c2ecf20Sopenharmony_ci } 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci print "\n"; 3438c2ecf20Sopenharmony_ci } 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci for (my $i = 0; $i < scalar(@filepath); $i++) { 3468c2ecf20Sopenharmony_ci my $path = $filepath[$i]; 3478c2ecf20Sopenharmony_ci my $f = $file[$i]; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci $path =~ s,.*/(.*/.*),$1,;; 3508c2ecf20Sopenharmony_ci $path =~ s,[/\-],_,g;; 3518c2ecf20Sopenharmony_ci my $fileref = "abi_file_".$path; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci if ($type eq "File") { 3548c2ecf20Sopenharmony_ci print ".. _$fileref:\n\n"; 3558c2ecf20Sopenharmony_ci } else { 3568c2ecf20Sopenharmony_ci print "Defined on file :ref:`$f <$fileref>`\n\n"; 3578c2ecf20Sopenharmony_ci } 3588c2ecf20Sopenharmony_ci } 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci if ($type eq "File") { 3618c2ecf20Sopenharmony_ci my $bar = $w; 3628c2ecf20Sopenharmony_ci $bar =~ s/./-/g; 3638c2ecf20Sopenharmony_ci print "$w\n$bar\n\n"; 3648c2ecf20Sopenharmony_ci } 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci my $desc = ""; 3678c2ecf20Sopenharmony_ci $desc = $data{$what}->{description} if (defined($data{$what}->{description})); 3688c2ecf20Sopenharmony_ci $desc =~ s/\s+$/\n/; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci if (!($desc =~ /^\s*$/)) { 3718c2ecf20Sopenharmony_ci if ($description_is_rst) { 3728c2ecf20Sopenharmony_ci # Remove title markups from the description 3738c2ecf20Sopenharmony_ci # Having titles inside ABI files will only work if extra 3748c2ecf20Sopenharmony_ci # care would be taken in order to strictly follow the same 3758c2ecf20Sopenharmony_ci # level order for each markup. 3768c2ecf20Sopenharmony_ci $desc =~ s/\n[\-\*\=\^\~]+\n/\n\n/g; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci # Enrich text by creating cross-references 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci $desc =~ s,Documentation/(?!devicetree)(\S+)\.rst,:doc:`/$1`,g; 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci my @matches = $desc =~ m,Documentation/ABI/([\w\/\-]+),; 3838c2ecf20Sopenharmony_ci foreach my $f (@matches) { 3848c2ecf20Sopenharmony_ci my $xref = $f; 3858c2ecf20Sopenharmony_ci my $path = $f; 3868c2ecf20Sopenharmony_ci $path =~ s,.*/(.*/.*),$1,;; 3878c2ecf20Sopenharmony_ci $path =~ s,[/\-],_,g;; 3888c2ecf20Sopenharmony_ci $xref .= " <abi_file_" . $path . ">"; 3898c2ecf20Sopenharmony_ci $desc =~ s,\bDocumentation/ABI/$f\b,:ref:`$xref`,g; 3908c2ecf20Sopenharmony_ci } 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci @matches = $desc =~ m,$bondary(/sys/[^\s\.\,\;\:\*\s\`\'\(\)]+)$bondary,; 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci foreach my $s (@matches) { 3958c2ecf20Sopenharmony_ci if (defined($data{$s}) && defined($data{$s}->{label})) { 3968c2ecf20Sopenharmony_ci my $xref = $s; 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci $xref =~ s/([\x00-\x1f\x21-\x2f\x3a-\x40\x7b-\xff])/\\$1/g; 3998c2ecf20Sopenharmony_ci $xref = ":ref:`$xref <" . $data{$s}->{label} . ">`"; 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci $desc =~ s,$bondary$s$bondary,$xref,g; 4028c2ecf20Sopenharmony_ci } 4038c2ecf20Sopenharmony_ci } 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci print "$desc\n\n"; 4068c2ecf20Sopenharmony_ci } else { 4078c2ecf20Sopenharmony_ci $desc =~ s/^\s+//; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci # Remove title markups from the description, as they won't work 4108c2ecf20Sopenharmony_ci $desc =~ s/\n[\-\*\=\^\~]+\n/\n\n/g; 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci if ($desc =~ m/\:\n/ || $desc =~ m/\n[\t ]+/ || $desc =~ m/[\x00-\x08\x0b-\x1f\x7b-\xff]/) { 4138c2ecf20Sopenharmony_ci # put everything inside a code block 4148c2ecf20Sopenharmony_ci $desc =~ s/\n/\n /g; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci print "::\n\n"; 4178c2ecf20Sopenharmony_ci print " $desc\n\n"; 4188c2ecf20Sopenharmony_ci } else { 4198c2ecf20Sopenharmony_ci # Escape any special chars from description 4208c2ecf20Sopenharmony_ci $desc =~s/([\x00-\x08\x0b-\x1f\x21-\x2a\x2d\x2f\x3c-\x40\x5c\x5e-\x60\x7b-\xff])/\\$1/g; 4218c2ecf20Sopenharmony_ci print "$desc\n\n"; 4228c2ecf20Sopenharmony_ci } 4238c2ecf20Sopenharmony_ci } 4248c2ecf20Sopenharmony_ci } else { 4258c2ecf20Sopenharmony_ci print "DESCRIPTION MISSING for $what\n\n" if (!$data{$what}->{is_file}); 4268c2ecf20Sopenharmony_ci } 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci if ($data{$what}->{symbols}) { 4298c2ecf20Sopenharmony_ci printf "Has the following ABI:\n\n"; 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci foreach my $content(@{$data{$what}->{symbols}}) { 4328c2ecf20Sopenharmony_ci my $label = $data{$symbols{$content}->{xref}}->{label}; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci # Escape special chars from content 4358c2ecf20Sopenharmony_ci $content =~s/([\x00-\x1f\x21-\x2f\x3a-\x40\x7b-\xff])/\\$1/g; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci print "- :ref:`$content <$label>`\n\n"; 4388c2ecf20Sopenharmony_ci } 4398c2ecf20Sopenharmony_ci } 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci if (defined($data{$what}->{users})) { 4428c2ecf20Sopenharmony_ci my $users = $data{$what}->{users}; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci $users =~ s/\n/\n\t/g; 4458c2ecf20Sopenharmony_ci printf "Users:\n\t%s\n\n", $users if ($users ne ""); 4468c2ecf20Sopenharmony_ci } 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci } 4498c2ecf20Sopenharmony_ci} 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci# 4528c2ecf20Sopenharmony_ci# Searches for ABI symbols 4538c2ecf20Sopenharmony_ci# 4548c2ecf20Sopenharmony_cisub search_symbols { 4558c2ecf20Sopenharmony_ci foreach my $what (sort keys %data) { 4568c2ecf20Sopenharmony_ci next if (!($what =~ m/($arg)/)); 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci my $type = $data{$what}->{type}; 4598c2ecf20Sopenharmony_ci next if ($type eq "File"); 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci my $file = $data{$what}->{filepath}; 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci my $bar = $what; 4648c2ecf20Sopenharmony_ci $bar =~ s/./-/g; 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci print "\n$what\n$bar\n\n"; 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci my $kernelversion = $data{$what}->{kernelversion} if (defined($data{$what}->{kernelversion})); 4698c2ecf20Sopenharmony_ci my $contact = $data{$what}->{contact} if (defined($data{$what}->{contact})); 4708c2ecf20Sopenharmony_ci my $users = $data{$what}->{users} if (defined($data{$what}->{users})); 4718c2ecf20Sopenharmony_ci my $date = $data{$what}->{date} if (defined($data{$what}->{date})); 4728c2ecf20Sopenharmony_ci my $desc = $data{$what}->{description} if (defined($data{$what}->{description})); 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci $kernelversion =~ s/^\s+// if ($kernelversion); 4758c2ecf20Sopenharmony_ci $contact =~ s/^\s+// if ($contact); 4768c2ecf20Sopenharmony_ci if ($users) { 4778c2ecf20Sopenharmony_ci $users =~ s/^\s+//; 4788c2ecf20Sopenharmony_ci $users =~ s/\n//g; 4798c2ecf20Sopenharmony_ci } 4808c2ecf20Sopenharmony_ci $date =~ s/^\s+// if ($date); 4818c2ecf20Sopenharmony_ci $desc =~ s/^\s+// if ($desc); 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci printf "Kernel version:\t\t%s\n", $kernelversion if ($kernelversion); 4848c2ecf20Sopenharmony_ci printf "Date:\t\t\t%s\n", $date if ($date); 4858c2ecf20Sopenharmony_ci printf "Contact:\t\t%s\n", $contact if ($contact); 4868c2ecf20Sopenharmony_ci printf "Users:\t\t\t%s\n", $users if ($users); 4878c2ecf20Sopenharmony_ci print "Defined on file(s):\t$file\n\n"; 4888c2ecf20Sopenharmony_ci print "Description:\n\n$desc"; 4898c2ecf20Sopenharmony_ci } 4908c2ecf20Sopenharmony_ci} 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci# Ensure that the prefix will always end with a slash 4938c2ecf20Sopenharmony_ci# While this is not needed for find, it makes the patch nicer 4948c2ecf20Sopenharmony_ci# with --enable-lineno 4958c2ecf20Sopenharmony_ci$prefix =~ s,/?$,/,; 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci# 4988c2ecf20Sopenharmony_ci# Parses all ABI files located at $prefix dir 4998c2ecf20Sopenharmony_ci# 5008c2ecf20Sopenharmony_cifind({wanted =>\&parse_abi, no_chdir => 1}, $prefix); 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ciprint STDERR Data::Dumper->Dump([\%data], [qw(*data)]) if ($debug); 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci# 5058c2ecf20Sopenharmony_ci# Handles the command 5068c2ecf20Sopenharmony_ci# 5078c2ecf20Sopenharmony_ciif ($cmd eq "search") { 5088c2ecf20Sopenharmony_ci search_symbols; 5098c2ecf20Sopenharmony_ci} else { 5108c2ecf20Sopenharmony_ci if ($cmd eq "rest") { 5118c2ecf20Sopenharmony_ci output_rest; 5128c2ecf20Sopenharmony_ci } 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci # Warn about duplicated ABI entries 5158c2ecf20Sopenharmony_ci foreach my $what(sort keys %symbols) { 5168c2ecf20Sopenharmony_ci my @files = @{$symbols{$what}->{file}}; 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci next if (scalar(@files) == 1); 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci printf STDERR "Warning: $what is defined %d times: @files\n", 5218c2ecf20Sopenharmony_ci scalar(@files); 5228c2ecf20Sopenharmony_ci } 5238c2ecf20Sopenharmony_ci} 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci__END__ 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci=head1 NAME 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ciabi_book.pl - parse the Linux ABI files and produce a ReST book. 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci=head1 SYNOPSIS 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ciB<abi_book.pl> [--debug] [--enable-lineno] [--man] [--help] 5348c2ecf20Sopenharmony_ci [--(no-)rst-source] [--dir=<dir>] <COMAND> [<ARGUMENT>] 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ciWhere <COMMAND> can be: 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci=over 8 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ciB<search> [SEARCH_REGEX] - search for [SEARCH_REGEX] inside ABI 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ciB<rest> - output the ABI in ReST markup language 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ciB<validate> - validate the ABI contents 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci=back 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci=head1 OPTIONS 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci=over 8 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci=item B<--dir> 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ciChanges the location of the ABI search. By default, it uses 5558c2ecf20Sopenharmony_cithe Documentation/ABI directory. 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci=item B<--rst-source> and B<--no-rst-source> 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ciThe input file may be using ReST syntax or not. Those two options allow 5608c2ecf20Sopenharmony_ciselecting between a rst-compliant source ABI (--rst-source), or a 5618c2ecf20Sopenharmony_ciplain text that may be violating ReST spec, so it requres some escaping 5628c2ecf20Sopenharmony_cilogic (--no-rst-source). 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci=item B<--enable-lineno> 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ciEnable output of #define LINENO lines. 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci=item B<--debug> 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ciPut the script in verbose mode, useful for debugging. Can be called multiple 5718c2ecf20Sopenharmony_citimes, to increase verbosity. 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci=item B<--help> 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ciPrints a brief help message and exits. 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci=item B<--man> 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ciPrints the manual page and exits. 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci=back 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci=head1 DESCRIPTION 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ciParse the Linux ABI files from ABI DIR (usually located at Documentation/ABI), 5868c2ecf20Sopenharmony_ciallowing to search for ABI symbols or to produce a ReST book containing 5878c2ecf20Sopenharmony_cithe Linux ABI documentation. 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci=head1 EXAMPLES 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ciSearch for all stable symbols with the word "usb": 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci=over 8 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci$ scripts/get_abi.pl search usb --dir Documentation/ABI/stable 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci=back 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ciSearch for all symbols that match the regex expression "usb.*cap": 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci=over 8 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci$ scripts/get_abi.pl search usb.*cap 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci=back 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ciOutput all obsoleted symbols in ReST format 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci=over 8 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci$ scripts/get_abi.pl rest --dir Documentation/ABI/obsolete 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci=back 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci=head1 BUGS 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ciReport bugs to Mauro Carvalho Chehab <mchehab+samsung@kernel.org> 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci=head1 COPYRIGHT 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ciCopyright (c) 2016-2019 by Mauro Carvalho Chehab <mchehab+samsung@kernel.org>. 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ciLicense GPLv2: GNU GPL version 2 <http://gnu.org/licenses/gpl.html>. 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ciThis is free software: you are free to change and redistribute it. 6268c2ecf20Sopenharmony_ciThere is NO WARRANTY, to the extent permitted by law. 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci=cut 629