#!/usr/bin/env perl
# SPDX-License-Identifier: GPL-2.0
BEGIN { $Pod::Usage::Formatter = 'Pod::Text::Termcap'; }
use strict;
use warnings;
use utf8;
use Pod::Usage qw(pod2usage);
use Getopt::Long;
use File::Find;
use IO::Handle;
use Fcntl ':mode';
use Cwd 'abs_path';
use Data::Dumper;
my $help = 0;
my $hint = 0;
my $man = 0;
my $debug = 0;
my $enable_lineno = 0;
my $show_warnings = 1;
my $prefix="Documentation/ABI";
my $sysfs_prefix="/sys";
my $search_string;
# Debug options
my $dbg_what_parsing = 1;
my $dbg_what_open = 2;
my $dbg_dump_abi_structs = 4;
my $dbg_undefined = 8;
$Data::Dumper::Indent = 1;
$Data::Dumper::Terse = 1;
#
# If true, assumes that the description is formatted with ReST
#
my $description_is_rst = 1;
GetOptions(
"debug=i" => \$debug,
"enable-lineno" => \$enable_lineno,
"rst-source!" => \$description_is_rst,
"dir=s" => \$prefix,
'help|?' => \$help,
"show-hints" => \$hint,
"search-string=s" => \$search_string,
man => \$man
) or pod2usage(2);
pod2usage(1) if $help;
pod2usage(-exitstatus => 0, -noperldoc, -verbose => 2) if $man;
pod2usage(2) if (scalar @ARGV < 1 || @ARGV > 2);
my ($cmd, $arg) = @ARGV;
pod2usage(2) if ($cmd ne "search" && $cmd ne "rest" && $cmd ne "validate" && $cmd ne "undefined");
pod2usage(2) if ($cmd eq "search" && !$arg);
require Data::Dumper if ($debug & $dbg_dump_abi_structs);
my %data;
my %symbols;
#
# Displays an error message, printing file name and line
#
sub parse_error($$$$) {
my ($file, $ln, $msg, $data) = @_;
return if (!$show_warnings);
$data =~ s/\s+$/\n/;
print STDERR "Warning: file $file#$ln:\n\t$msg";
if ($data ne "") {
print STDERR ". Line\n\t\t$data";
} else {
print STDERR "\n";
}
}
#
# Parse an ABI file, storing its contents at %data
#
sub parse_abi {
my $file = $File::Find::name;
my $mode = (stat($file))[2];
return if ($mode & S_IFDIR);
return if ($file =~ m,/README,);
return if ($file =~ m,/\.,);
return if ($file =~ m,\.(rej|org|orig|bak)$,);
my $name = $file;
$name =~ s,.*/,,;
my $fn = $file;
$fn =~ s,.*Documentation/ABI/,,;
my $nametag = "File $fn";
$data{$nametag}->{what} = "File $name";
$data{$nametag}->{type} = "File";
$data{$nametag}->{file} = $name;
$data{$nametag}->{filepath} = $file;
$data{$nametag}->{is_file} = 1;
$data{$nametag}->{line_no} = 1;
my $type = $file;
$type =~ s,.*/(.*)/.*,$1,;
my $what;
my $new_what;
my $tag = "";
my $ln;
my $xrefs;
my $space;
my @labels;
my $label = "";
print STDERR "Opening $file\n" if ($debug & $dbg_what_open);
open IN, $file;
while(<IN>) {
$ln++;
if (m/^(\S+)(:\s*)(.*)/i) {
my $new_tag = lc($1);
my $sep = $2;
my $content = $3;
if (!($new_tag =~ m/(what|where|date|kernelversion|contact|description|users)/)) {
if ($tag eq "description") {
# New "tag" is actually part of
# description. Don't consider it a tag
$new_tag = "";
} elsif ($tag ne "") {
parse_error($file, $ln, "tag '$tag' is invalid", $_);
}
}
# Invalid, but it is a common mistake
if ($new_tag eq "where") {
parse_error($file, $ln, "tag 'Where' is invalid. Should be 'What:' instead", "");
$new_tag = "what";
}
if ($new_tag =~ m/what/) {
$space = "";
$content =~ s/[,.;]$//;
push @{$s