2020-11-23 17:15:33 +03:00
#!/usr/bin/env perl
2019-06-20 20:23:10 +03:00
# SPDX-License-Identifier: GPL-2.0
2019-06-20 20:22:55 +03:00
2021-09-27 16:49:51 +03:00
BEGIN { $ Pod:: Usage:: Formatter = 'Pod::Text::Termcap' ; }
2019-06-20 20:22:55 +03:00
use strict ;
2020-10-30 10:40:24 +03:00
use warnings ;
2020-10-30 10:40:29 +03:00
use utf8 ;
2021-09-27 16:49:51 +03:00
use Pod::Usage qw( pod2usage ) ;
2019-06-20 20:22:55 +03:00
use Getopt::Long ;
use File::Find ;
2021-09-28 13:14:03 +03:00
use IO::Handle ;
2019-06-20 20:22:55 +03:00
use Fcntl ':mode' ;
2021-09-18 12:52:13 +03:00
use Cwd 'abs_path' ;
2021-09-23 18:41:14 +03:00
use Data::Dumper ;
2019-06-20 20:22:55 +03:00
2020-10-30 10:40:24 +03:00
my $ help = 0 ;
2021-09-18 12:52:13 +03:00
my $ hint = 0 ;
2020-10-30 10:40:24 +03:00
my $ man = 0 ;
my $ debug = 0 ;
my $ enable_lineno = 0 ;
2021-09-18 12:52:12 +03:00
my $ show_warnings = 1 ;
2019-06-20 20:22:59 +03:00
my $ prefix = "Documentation/ABI" ;
2021-09-18 12:52:12 +03:00
my $ sysfs_prefix = "/sys" ;
2021-09-18 12:52:14 +03:00
my $ search_string ;
2019-06-20 20:22:55 +03:00
2021-09-23 18:41:14 +03:00
# Debug options
my $ dbg_what_parsing = 1 ;
my $ dbg_what_open = 2 ;
my $ dbg_dump_abi_structs = 4 ;
2021-09-23 18:41:18 +03:00
my $ dbg_undefined = 8 ;
2021-09-23 18:41:14 +03:00
2021-09-27 16:49:49 +03:00
$ Data:: Dumper:: Indent = 1 ;
$ Data:: Dumper:: Terse = 1 ;
2020-10-30 10:40:20 +03:00
#
# If true, assumes that the description is formatted with ReST
#
2020-10-30 10:40:58 +03:00
my $ description_is_rst = 1 ;
2020-10-30 10:40:20 +03:00
2019-06-20 20:22:55 +03:00
GetOptions (
2021-09-23 18:41:14 +03:00
"debug=i" = > \ $ debug ,
2020-10-30 10:40:22 +03:00
"enable-lineno" = > \ $ enable_lineno ,
2020-10-30 10:40:20 +03:00
"rst-source!" = > \ $ description_is_rst ,
2019-06-20 20:22:59 +03:00
"dir=s" = > \ $ prefix ,
2019-06-20 20:22:55 +03:00
'help|?' = > \ $ help ,
2021-09-18 12:52:13 +03:00
"show-hints" = > \ $ hint ,
2021-09-18 12:52:14 +03:00
"search-string=s" = > \ $ search_string ,
2019-06-20 20:22:55 +03:00
man = > \ $ man
) or pod2usage ( 2 ) ;
pod2usage ( 1 ) if $ help ;
2021-09-27 16:49:51 +03:00
pod2usage ( - exitstatus = > 0 , - noperldoc , - verbose = > 2 ) if $ man ;
2019-06-20 20:22:55 +03:00
2019-06-20 20:22:59 +03:00
pod2usage ( 2 ) if ( scalar @ ARGV < 1 || @ ARGV > 2 ) ;
2019-06-20 20:22:55 +03:00
2019-06-20 20:22:59 +03:00
my ( $ cmd , $ arg ) = @ ARGV ;
2021-09-18 12:52:12 +03:00
pod2usage ( 2 ) if ( $ cmd ne "search" && $ cmd ne "rest" && $ cmd ne "validate" && $ cmd ne "undefined" ) ;
2019-06-20 20:22:59 +03:00
pod2usage ( 2 ) if ( $ cmd eq "search" && ! $ arg ) ;
2019-06-20 20:22:55 +03:00
2021-09-23 18:41:14 +03:00
require Data::Dumper if ( $ debug & $ dbg_dump_abi_structs ) ;
2019-06-20 20:22:55 +03:00
my % data ;
2020-10-30 10:40:24 +03:00
my % symbols ;
2019-06-20 20:22:55 +03:00
#
# Displays an error message, printing file name and line
#
sub parse_error ($$$$) {
my ( $ file , $ ln , $ msg , $ data ) = @ _ ;
2021-09-18 12:52:12 +03:00
return if ( ! $ show_warnings ) ;
2020-10-30 10:40:45 +03:00
$ 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" ;
}
2019-06-20 20:22:55 +03:00
}
#
# 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 , ) ;
2022-01-29 03:50:18 +03:00
return if ( $ file =~ m , / \ . , ) ;
2019-06-20 20:22:55 +03:00
my $ name = $ file ;
$ name =~ s , . * / , , ;
2020-10-30 10:40:27 +03:00
my $ fn = $ file ;
$ fn =~ s , Documentation /ABI/ , , ;
my $ nametag = "File $fn" ;
2019-06-20 20:22:58 +03:00
$ data { $ nametag } - > { what } = "File $name" ;
$ data { $ nametag } - > { type } = "File" ;
$ data { $ nametag } - > { file } = $ name ;
2019-06-20 20:22:59 +03:00
$ data { $ nametag } - > { filepath } = $ file ;
2019-06-20 20:22:58 +03:00
$ data { $ nametag } - > { is_file } = 1 ;
2020-10-30 10:40:22 +03:00
$ data { $ nametag } - > { line_no } = 1 ;
2019-06-20 20:22:58 +03:00
2019-06-20 20:22:55 +03:00
my $ type = $ file ;
$ type =~ s , . * /(.*)/ . * , $ 1 , ;
my $ what ;
my $ new_what ;
2020-10-30 10:40:24 +03:00
my $ tag = "" ;
2019-06-20 20:22:55 +03:00
my $ ln ;
2019-06-20 20:22:56 +03:00
my $ xrefs ;
2019-06-20 20:22:57 +03:00
my $ space ;
2019-06-20 20:22:58 +03:00
my @ labels ;
2020-10-30 10:40:24 +03:00
my $ label = "" ;
2019-06-20 20:22:55 +03:00
2021-09-23 18:41:14 +03:00
print STDERR "Opening $file\n" if ( $ debug & $ dbg_what_open ) ;
2019-06-20 20:22:55 +03:00
open IN , $ file ;
while ( <IN> ) {
$ ln + + ;
2019-06-20 20:22:57 +03:00
if ( m/^(\S+)(:\s*)(.*)/i ) {
2019-06-20 20:22:55 +03:00
my $ new_tag = lc ( $ 1 ) ;
2019-06-20 20:22:57 +03:00
my $ sep = $ 2 ;
my $ content = $ 3 ;
2019-06-20 20:22:55 +03:00
2019-06-20 20:23:04 +03:00
if ( ! ( $ new_tag =~ m/(what|where|date|kernelversion|contact|description|users)/ ) ) {
2019-06-20 20:22:55 +03:00
if ( $ tag eq "description" ) {
2019-06-20 20:22:57 +03:00
# New "tag" is actually part of
# description. Don't consider it a tag
$ new_tag = "" ;
2019-06-20 20:23:01 +03:00
} elsif ( $ tag ne "" ) {
2019-06-20 20:22:55 +03:00
parse_error ( $ file , $ ln , "tag '$tag' is invalid" , $ _ ) ;
}
}
2019-06-20 20:23:03 +03:00
# Invalid, but it is a common mistake
if ( $ new_tag eq "where" ) {
2020-10-30 10:40:45 +03:00
parse_error ( $ file , $ ln , "tag 'Where' is invalid. Should be 'What:' instead" , "" ) ;
2019-06-20 20:23:03 +03:00
$ new_tag = "what" ;
}
2019-06-20 20:22:55 +03:00
if ( $ new_tag =~ m/what/ ) {
2019-06-20 20:22:57 +03:00
$ space = "" ;
2020-10-30 10:40:24 +03:00
$ content =~ s/[,.;]$// ;
2020-10-30 10:40:25 +03:00
push @ { $ symbols { $ content } - > { file } } , " $file:" . ( $ ln - 1 ) ;
2019-06-20 20:22:55 +03:00
if ( $ tag =~ m/what/ ) {
2021-09-18 12:52:11 +03:00
$ what . = "\xac" . $ content ;
2019-06-20 20:22:55 +03:00
} else {
2020-10-30 10:40:24 +03:00
if ( $ what ) {
parse_error ( $ file , $ ln , "What '$what' doesn't have a description" , "" ) if ( ! $ data { $ what } - > { description } ) ;
2021-09-18 12:52:11 +03:00
foreach my $ w ( split /\xac/ , $ what ) {
2020-10-30 10:40:25 +03:00
$ symbols { $ w } - > { xref } = $ what ;
2020-10-30 10:40:24 +03:00
} ;
}
2019-06-20 20:22:57 +03:00
2019-06-20 20:22:55 +03:00
$ what = $ content ;
2019-06-20 20:22:58 +03:00
$ label = $ content ;
2019-06-20 20:22:55 +03:00
$ new_what = 1 ;
}
2019-06-20 20:22:58 +03:00
push @ labels , [ ( $ content , $ label ) ] ;
2019-06-20 20:22:55 +03:00
$ tag = $ new_tag ;
2019-06-20 20:22:56 +03:00
2020-10-30 10:40:24 +03:00
push @ { $ data { $ nametag } - > { symbols } } , $ content if ( $ data { $ nametag } - > { what } ) ;
2019-06-20 20:22:55 +03:00
next ;
}
2019-06-20 20:23:01 +03:00
if ( $ tag ne "" && $ new_tag ) {
2019-06-20 20:22:57 +03:00
$ tag = $ new_tag ;
2019-06-20 20:22:55 +03:00
2019-06-20 20:22:57 +03:00
if ( $ new_what ) {
2020-10-30 10:40:24 +03:00
@ { $ data { $ what } - > { label_list } } = @ labels if ( $ data { $ nametag } - > { what } ) ;
2019-06-20 20:22:58 +03:00
@ labels = ( ) ;
$ label = "" ;
2019-06-20 20:22:57 +03:00
$ new_what = 0 ;
2019-06-20 20:22:55 +03:00
2019-06-20 20:22:57 +03:00
$ data { $ what } - > { type } = $ type ;
2020-10-30 10:40:25 +03:00
if ( ! defined ( $ data { $ what } - > { file } ) ) {
$ data { $ what } - > { file } = $ name ;
$ data { $ what } - > { filepath } = $ file ;
} else {
2021-09-27 14:10:50 +03:00
$ data { $ what } - > { description } . = "\n\n" if ( defined ( $ data { $ what } - > { description } ) ) ;
2020-10-30 10:40:25 +03:00
if ( $ name ne $ data { $ what } - > { file } ) {
$ data { $ what } - > { file } . = " " . $ name ;
$ data { $ what } - > { filepath } . = " " . $ file ;
}
}
2021-09-23 18:41:14 +03:00
print STDERR "\twhat: $what\n" if ( $ debug & $ dbg_what_parsing ) ;
2020-10-30 10:40:25 +03:00
$ data { $ what } - > { line_no } = $ ln ;
} else {
$ data { $ what } - > { line_no } = $ ln if ( ! defined ( $ data { $ what } - > { line_no } ) ) ;
2019-06-20 20:22:57 +03:00
}
2019-06-20 20:22:55 +03:00
2019-06-20 20:22:57 +03:00
if ( ! $ what ) {
parse_error ( $ file , $ ln , "'What:' should come first:" , $ _ ) ;
next ;
}
2020-10-30 10:40:23 +03:00
if ( $ new_tag eq "description" ) {
$ sep =~ s , : , , ;
2020-10-30 10:40:20 +03:00
$ content = ' ' x length ( $ new_tag ) . $ sep . $ content ;
2020-10-30 10:40:23 +03:00
while ( $ content =~ s/\t+/' ' x (length($&) * 8 - length($`) % 8)/e ) { }
if ( $ content =~ m/^(\s*)(\S.*)$/ ) {
# Preserve initial spaces for the first line
2020-10-30 10:40:20 +03:00
$ space = $ 1 ;
2020-10-30 10:40:23 +03:00
$ content = "$2\n" ;
$ data { $ what } - > { $ tag } . = $ content ;
} else {
undef ( $ space ) ;
2019-06-20 20:22:57 +03:00
}
2020-10-30 10:40:21 +03:00
2019-06-20 20:22:57 +03:00
} else {
$ data { $ what } - > { $ tag } = $ content ;
}
2019-06-20 20:22:55 +03:00
next ;
}
}
2019-06-20 20:22:57 +03:00
# Store any contents before tags at the database
2019-06-20 20:22:58 +03:00
if ( ! $ tag && $ data { $ nametag } - > { what } ) {
$ data { $ nametag } - > { description } . = $ _ ;
2019-06-20 20:22:56 +03:00
next ;
}
2019-06-20 20:22:55 +03:00
2019-06-20 20:22:57 +03:00
if ( $ tag eq "description" ) {
2020-10-30 10:40:21 +03:00
my $ content = $ _ ;
while ( $ content =~ s/\t+/' ' x (length($&) * 8 - length($`) % 8)/e ) { }
2020-10-30 10:40:23 +03:00
if ( m/^\s*\n/ ) {
$ data { $ what } - > { $ tag } . = "\n" ;
next ;
}
if ( ! defined ( $ space ) ) {
2020-10-30 10:40:21 +03:00
# Preserve initial spaces for the first line
2020-10-30 10:40:23 +03:00
if ( $ content =~ m/^(\s*)(\S.*)$/ ) {
2020-10-30 10:40:21 +03:00
$ space = $ 1 ;
2020-10-30 10:40:23 +03:00
$ content = "$2\n" ;
2019-06-20 20:22:57 +03:00
}
} else {
$ space = "" if ( ! ( $ content =~ s/^($space)// ) ) ;
}
2020-10-30 10:40:23 +03:00
$ data { $ what } - > { $ tag } . = $ content ;
2019-06-20 20:22:57 +03:00
next ;
}
2019-06-20 20:22:55 +03:00
if ( m/^\s*(.*)/ ) {
$ data { $ what } - > { $ tag } . = "\n$1" ;
$ data { $ what } - > { $ tag } =~ s/\n+$// ;
next ;
}
# Everything else is error
2020-10-30 10:40:45 +03:00
parse_error ( $ file , $ ln , "Unexpected content" , $ _ ) ;
2019-06-20 20:22:55 +03:00
}
2020-10-30 10:40:24 +03:00
$ data { $ nametag } - > { description } =~ s/^\n+// if ( $ data { $ nametag } - > { description } ) ;
if ( $ what ) {
parse_error ( $ file , $ ln , "What '$what' doesn't have a description" , "" ) if ( ! $ data { $ what } - > { description } ) ;
2021-09-18 12:52:11 +03:00
foreach my $ w ( split /\xac/ , $ what ) {
2020-10-30 10:40:25 +03:00
$ symbols { $ w } - > { xref } = $ what ;
2020-10-30 10:40:24 +03:00
} ;
}
2019-06-20 20:22:55 +03:00
close IN ;
}
2020-10-30 10:40:24 +03:00
sub create_labels {
my % labels ;
2019-06-20 20:22:55 +03:00
2020-10-30 10:40:24 +03:00
foreach my $ what ( keys % data ) {
next if ( $ data { $ what } - > { file } eq "File" ) ;
2019-06-20 20:22:57 +03:00
2020-10-30 10:40:24 +03:00
foreach my $ p ( @ { $ data { $ what } - > { label_list } } ) {
2019-06-20 20:22:58 +03:00
my ( $ content , $ label ) = @ { $ p } ;
$ label = "abi_" . $ label . " " ;
$ label =~ tr /A-Z/ a - z / ;
# Convert special chars to "_"
$ label =~ s/([\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\xff])/_/g ;
$ label =~ s , _ + , _ , g ;
$ label =~ s , _ $, , ;
2019-06-20 20:23:02 +03:00
# Avoid duplicated labels
while ( defined ( $ labels { $ label } ) ) {
my @ chars = ( "A" .. "Z" , "a" .. "z" ) ;
$ label . = $ chars [ rand @ chars ] ;
}
$ labels { $ label } = 1 ;
2020-10-30 10:40:24 +03:00
$ data { $ what } - > { label } = $ label ;
2019-06-20 20:22:58 +03:00
# only one label is enough
last ;
2019-06-20 20:22:56 +03:00
}
2020-10-30 10:40:24 +03:00
}
}
#
# Outputs the book on ReST format
#
2021-03-25 13:38:24 +03:00
# \b doesn't work well with paths. So, we need to define something else:
# Boundaries are punct characters, spaces and end-of-line
my $ start = qr {(^|\s|\() } x ;
my $ bondary = qr { ( [ , . : ; \ ) \ s ] | \ z ) } x ;
2021-03-25 13:38:25 +03:00
my $ xref_match = qr { $ start ( \ / ( sys | config | proc | dev | kvd ) \ / [ ^ , . : ; \ ) \ s ] + ) $ bondary } x ;
2021-03-25 13:38:22 +03:00
my $ symbols = qr { ( [ \ x01 - \ x08 \ x0e - \ x1f \ x21 - \ x2f \ x3a - \ x40 \ x7b - \ xff ] ) } x ;
2020-10-30 10:40:29 +03:00
2020-10-30 10:40:24 +03:00
sub output_rest {
create_labels ( ) ;
2020-11-02 13:32:16 +03:00
my $ part = "" ;
2020-10-30 10:40:24 +03:00
foreach my $ what ( sort {
( $ data { $ a } - > { type } eq "File" ) cmp ( $ data { $ b } - > { type } eq "File" ) ||
$ a cmp $ b
} keys % data ) {
my $ type = $ data { $ what } - > { type } ;
2020-10-30 10:40:25 +03:00
my @ file = split / / , $ data { $ what } - > { file } ;
my @ filepath = split / / , $ data { $ what } - > { filepath } ;
2020-10-30 10:40:24 +03:00
if ( $ enable_lineno ) {
2022-03-26 13:27:23 +03:00
printf ".. LINENO %s%s#%s\n\n" ,
2020-10-30 10:40:25 +03:00
$ prefix , $ file [ 0 ] ,
2020-10-30 10:40:24 +03:00
$ data { $ what } - > { line_no } ;
}
2019-06-20 20:22:56 +03:00
2020-10-30 10:40:24 +03:00
my $ w = $ what ;
2019-06-20 20:22:56 +03:00
2020-10-30 10:40:25 +03:00
if ( $ type ne "File" ) {
2020-11-02 13:32:16 +03:00
my $ cur_part = $ what ;
if ( $ what =~ '/' ) {
if ( $ what =~ m #^(\/?(?:[\w\-]+\/?){1,2})#) {
$ cur_part = "Symbols under $1" ;
$ cur_part =~ s , / $, , ;
}
}
if ( $ cur_part ne "" && $ part ne $ cur_part ) {
$ part = $ cur_part ;
my $ bar = $ part ;
$ bar =~ s/./-/g ;
print "$part\n$bar\n\n" ;
}
2020-10-30 10:40:24 +03:00
printf ".. _%s:\n\n" , $ data { $ what } - > { label } ;
2019-06-20 20:23:00 +03:00
2021-09-18 12:52:11 +03:00
my @ names = split /\xac/ , $ w ;
2019-06-20 20:23:00 +03:00
my $ len = 0 ;
foreach my $ name ( @ names ) {
2021-03-25 13:38:22 +03:00
$ name =~ s/$symbols/\\$1/g ;
2020-10-30 10:40:28 +03:00
$ name = "**$name**" ;
2019-06-20 20:23:00 +03:00
$ len = length ( $ name ) if ( length ( $ name ) > $ len ) ;
}
print "+-" . "-" x $ len . "-+\n" ;
foreach my $ name ( @ names ) {
printf "| %s" , $ name . " " x ( $ len - length ( $ name ) ) . " |\n" ;
print "+-" . "-" x $ len . "-+\n" ;
}
2020-10-30 10:40:25 +03:00
print "\n" ;
}
for ( my $ i = 0 ; $ i < scalar ( @ filepath ) ; $ i + + ) {
my $ path = $ filepath [ $ i ] ;
my $ f = $ file [ $ i ] ;
$ path =~ s , . * /(.*/ . * ) , $ 1 , ; ;
$ path =~ s , [ / \ - ] , _ , g ; ;
my $ fileref = "abi_file_" . $ path ;
if ( $ type eq "File" ) {
print ".. _$fileref:\n\n" ;
} else {
print "Defined on file :ref:`$f <$fileref>`\n\n" ;
}
2020-10-30 10:40:24 +03:00
}
2019-06-20 20:22:55 +03:00
2020-10-30 10:40:27 +03:00
if ( $ type eq "File" ) {
my $ bar = $ w ;
$ bar =~ s/./-/g ;
print "$w\n$bar\n\n" ;
}
2020-10-30 10:40:24 +03:00
my $ desc = "" ;
$ desc = $ data { $ what } - > { description } if ( defined ( $ data { $ what } - > { description } ) ) ;
$ desc =~ s/\s+$/\n/ ;
2019-06-20 20:22:55 +03:00
2019-06-20 20:22:57 +03:00
if ( ! ( $ desc =~ /^\s*$/ ) ) {
2020-10-30 10:40:20 +03:00
if ( $ description_is_rst ) {
2020-11-02 13:32:15 +03:00
# Remove title markups from the description
# Having titles inside ABI files will only work if extra
# care would be taken in order to strictly follow the same
# level order for each markup.
$ desc =~ s/\n[\-\*\=\^\~]+\n/\n\n/g ;
2020-10-30 10:40:29 +03:00
# Enrich text by creating cross-references
2021-03-25 13:38:26 +03:00
my $ new_desc = "" ;
2021-03-25 13:38:27 +03:00
my $ init_indent = - 1 ;
my $ literal_indent = - 1 ;
2021-03-25 13:38:26 +03:00
open ( my $ fh , "+<" , \ $ desc ) ;
while ( my $ d = <$fh> ) {
2021-03-25 13:38:27 +03:00
my $ indent = $ d =~ m/^(\s+)/ ;
my $ spaces = length ( $ indent ) ;
$ init_indent = $ indent if ( $ init_indent < 0 ) ;
if ( $ literal_indent >= 0 ) {
if ( $ spaces > $ literal_indent ) {
$ new_desc . = $ d ;
next ;
} else {
$ literal_indent = - 1 ;
}
} else {
if ( $ d =~ /()::$/ && ! ( $ d =~ /^\s*\.\./ ) ) {
$ literal_indent = $ spaces ;
}
}
2021-03-25 13:38:26 +03:00
$ d =~ s , Documentation /(?!devicetree)(\S+)\.rst,:doc:`/ $ 1 ` , g ;
my @ matches = $ d =~ m , Documentation /ABI/ ( [ \ w \ / \ - ] + ) , g ;
foreach my $ f ( @ matches ) {
my $ xref = $ f ;
my $ path = $ f ;
$ path =~ s , . * /(.*/ . * ) , $ 1 , ; ;
$ path =~ s , [ / \ - ] , _ , g ; ;
$ xref . = " <abi_file_" . $ path . ">" ;
$ d =~ s , \ bDocumentation /ABI/ $ f \ b , : ref : `$xref` , g ;
}
2020-10-30 10:40:29 +03:00
2021-03-25 13:38:26 +03:00
# Seek for cross reference symbols like /sys/...
@ matches = $ d =~ m/$xref_match/g ;
2020-10-30 10:40:29 +03:00
2021-03-25 13:38:26 +03:00
foreach my $ s ( @ matches ) {
next if ( ! ( $ s =~ m , / , ) ) ;
if ( defined ( $ data { $ s } ) && defined ( $ data { $ s } - > { label } ) ) {
my $ xref = $ s ;
2020-10-30 10:40:29 +03:00
2021-03-25 13:38:26 +03:00
$ xref =~ s/$symbols/\\$1/g ;
$ xref = ":ref:`$xref <" . $ data { $ s } - > { label } . ">`" ;
2020-10-30 10:40:29 +03:00
2021-03-25 13:38:26 +03:00
$ d =~ s , $ start $ s $ bondary , $ 1 $ xref $ 2 , g ;
}
2020-10-30 10:40:29 +03:00
}
2021-03-25 13:38:26 +03:00
$ new_desc . = $ d ;
2020-10-30 10:40:29 +03:00
}
2021-03-25 13:38:26 +03:00
close $ fh ;
2020-10-30 10:40:29 +03:00
2021-03-25 13:38:26 +03:00
print "$new_desc\n\n" ;
2019-06-20 20:22:57 +03:00
} else {
2020-10-30 10:40:20 +03:00
$ desc =~ s/^\s+// ;
2019-06-20 20:22:55 +03:00
2020-10-30 10:40:20 +03:00
# Remove title markups from the description, as they won't work
$ desc =~ s/\n[\-\*\=\^\~]+\n/\n\n/g ;
if ( $ desc =~ m/\:\n/ || $ desc =~ m/\n[\t ]+/ || $ desc =~ m/[\x00-\x08\x0b-\x1f\x7b-\xff]/ ) {
# put everything inside a code block
$ desc =~ s/\n/\n /g ;
print "::\n\n" ;
print " $desc\n\n" ;
} else {
# Escape any special chars from description
$ desc =~ s/([\x00-\x08\x0b-\x1f\x21-\x2a\x2d\x2f\x3c-\x40\x5c\x5e-\x60\x7b-\xff])/\\$1/g ;
print "$desc\n\n" ;
}
2019-06-20 20:22:57 +03:00
}
2019-06-20 20:22:55 +03:00
} else {
2019-06-20 20:22:58 +03:00
print "DESCRIPTION MISSING for $what\n\n" if ( ! $ data { $ what } - > { is_file } ) ;
2019-06-20 20:22:55 +03:00
}
2019-06-20 20:22:56 +03:00
2020-10-30 10:40:24 +03:00
if ( $ data { $ what } - > { symbols } ) {
2019-06-20 20:22:58 +03:00
printf "Has the following ABI:\n\n" ;
2020-10-30 10:40:24 +03:00
foreach my $ content ( @ { $ data { $ what } - > { symbols } } ) {
2020-10-30 10:40:25 +03:00
my $ label = $ data { $ symbols { $ content } - > { xref } } - > { label } ;
2019-06-20 20:22:58 +03:00
# Escape special chars from content
$ content =~ s/([\x00-\x1f\x21-\x2f\x3a-\x40\x7b-\xff])/\\$1/g ;
print "- :ref:`$content <$label>`\n\n" ;
}
}
2020-10-30 10:40:26 +03:00
if ( defined ( $ data { $ what } - > { users } ) ) {
my $ users = $ data { $ what } - > { users } ;
$ users =~ s/\n/\n\t/g ;
printf "Users:\n\t%s\n\n" , $ users if ( $ users ne "" ) ;
}
2019-06-20 20:22:55 +03:00
}
}
2019-06-20 20:22:59 +03:00
#
# Searches for ABI symbols
#
sub search_symbols {
foreach my $ what ( sort keys % data ) {
next if ( ! ( $ what =~ m/($arg)/ ) ) ;
my $ type = $ data { $ what } - > { type } ;
next if ( $ type eq "File" ) ;
my $ file = $ data { $ what } - > { filepath } ;
2021-09-23 18:41:12 +03:00
$ what =~ s/\xac/, /g ;
2019-06-20 20:22:59 +03:00
my $ bar = $ what ;
$ bar =~ s/./-/g ;
print "\n$what\n$bar\n\n" ;
2020-10-30 10:40:24 +03:00
my $ kernelversion = $ data { $ what } - > { kernelversion } if ( defined ( $ data { $ what } - > { kernelversion } ) ) ;
my $ contact = $ data { $ what } - > { contact } if ( defined ( $ data { $ what } - > { contact } ) ) ;
my $ users = $ data { $ what } - > { users } if ( defined ( $ data { $ what } - > { users } ) ) ;
my $ date = $ data { $ what } - > { date } if ( defined ( $ data { $ what } - > { date } ) ) ;
my $ desc = $ data { $ what } - > { description } if ( defined ( $ data { $ what } - > { description } ) ) ;
$ kernelversion =~ s/^\s+// if ( $ kernelversion ) ;
$ contact =~ s/^\s+// if ( $ contact ) ;
if ( $ users ) {
$ users =~ s/^\s+// ;
$ users =~ s/\n//g ;
}
$ date =~ s/^\s+// if ( $ date ) ;
$ desc =~ s/^\s+// if ( $ desc ) ;
2019-06-20 20:22:59 +03:00
printf "Kernel version:\t\t%s\n" , $ kernelversion if ( $ kernelversion ) ;
printf "Date:\t\t\t%s\n" , $ date if ( $ date ) ;
printf "Contact:\t\t%s\n" , $ contact if ( $ contact ) ;
printf "Users:\t\t\t%s\n" , $ users if ( $ users ) ;
2020-10-30 10:40:25 +03:00
print "Defined on file(s):\t$file\n\n" ;
2019-06-20 20:22:59 +03:00
print "Description:\n\n$desc" ;
}
}
2021-09-18 12:52:12 +03:00
# Exclude /sys/kernel/debug and /sys/kernel/tracing from the search path
2021-09-18 12:52:13 +03:00
sub dont_parse_special_attributes {
2021-09-18 12:52:12 +03:00
if ( ( $ File:: Find:: dir =~ m , ^ /sys/ kernel , ) ) {
return grep { ! /(debug|tracing)/ } @ _ ;
}
if ( ( $ File:: Find:: dir =~ m , ^ /sys/ fs , ) ) {
return grep { ! /(pstore|bpf|fuse)/ } @ _ ;
}
return @ _
}
my % leaf ;
2021-09-18 12:52:13 +03:00
my % aliases ;
my @ files ;
2021-09-18 12:52:17 +03:00
my % root ;
sub graph_add_file {
my $ file = shift ;
my $ type = shift ;
my $ dir = $ file ;
$ dir =~ s , ^ ( . * / ) . * , $ 1 , ;
$ file =~ s , . * / , , ;
my $ name ;
my $ file_ref = \ % root ;
foreach my $ edge ( split "/" , $ dir ) {
$ name . = "$edge/" ;
if ( ! defined $ { $ file_ref } { $ edge } ) {
$ { $ file_ref } { $ edge } = { } ;
}
$ file_ref = \ % { $$ file_ref { $ edge } } ;
$ { $ file_ref } { "__name" } = [ $ name ] ;
}
$ name . = "$file" ;
$ { $ file_ref } { $ file } = {
"__name" = > [ $ name ]
} ;
return \ % { $$ file_ref { $ file } } ;
}
sub graph_add_link {
my $ file = shift ;
my $ link = shift ;
# Traverse graph to find the reference
my $ file_ref = \ % root ;
foreach my $ edge ( split "/" , $ file ) {
$ file_ref = \ % { $$ file_ref { $ edge } } || die "Missing node!" ;
}
# do a BFS
my @ queue ;
my % seen ;
my $ st ;
push @ queue , $ file_ref ;
$ seen { $ start } + + ;
while ( @ queue ) {
my $ v = shift @ queue ;
my @ child = keys ( % { $ v } ) ;
foreach my $ c ( @ child ) {
next if $ seen { $$ v { $ c } } ;
next if ( $ c eq "__name" ) ;
2021-09-27 16:49:49 +03:00
if ( ! defined ( $$ v { $ c } { "__name" } ) ) {
printf STDERR "Error: Couldn't find a non-empty name on a children of $file/.*: " ;
print STDERR Dumper ( % { $ v } ) ;
exit ;
}
2021-09-18 12:52:17 +03:00
# Add new name
my $ name = @ { $$ v { $ c } { "__name" } } [ 0 ] ;
if ( $ name =~ s #^$file/#$link/#) {
push @ { $$ v { $ c } { "__name" } } , $ name ;
}
# Add child to the queue and mark as seen
push @ queue , $$ v { $ c } ;
$ seen { $ c } + + ;
}
}
}
2021-09-18 12:52:12 +03:00
2021-09-18 12:52:13 +03:00
my $ escape_symbols = qr { ( [ \ x01 - \ x08 \ x0e - \ x1f \ x21 - \ x29 \ x2b - \ x2d \ x3a - \ x40 \ x7b - \ xfe ] ) } x ;
2021-09-18 12:52:12 +03:00
sub parse_existing_sysfs {
my $ file = $ File:: Find:: name ;
2021-09-18 12:52:16 +03:00
2021-09-27 16:49:50 +03:00
my $ mode = ( lstat ( $ file ) ) [ 2 ] ;
my $ abs_file = abs_path ( $ file ) ;
2021-09-18 12:52:16 +03:00
2021-09-27 16:49:50 +03:00
my @ tmp ;
push @ tmp , $ file ;
push @ tmp , $ abs_file if ( $ abs_file ne $ file ) ;
2021-09-23 18:41:16 +03:00
2021-09-27 16:49:50 +03:00
foreach my $ f ( @ tmp ) {
# Ignore cgroup, as this is big and has zero docs under ABI
return if ( $ f =~ m #^/sys/fs/cgroup/#);
2021-09-23 18:41:16 +03:00
2021-09-27 16:49:50 +03:00
# Ignore firmware as it is documented elsewhere
# Either ACPI or under Documentation/devicetree/bindings/
return if ( $ f =~ m #^/sys/firmware/#);
# Ignore some sysfs nodes that aren't actually part of ABI
return if ( $ f =~ m #/sections|notes/#);
# Would need to check at
# Documentation/admin-guide/kernel-parameters.txt, but this
# is not easily parseable.
return if ( $ f =~ m #/parameters/#);
}
2021-09-18 12:52:12 +03:00
2021-09-18 12:52:13 +03:00
if ( S_ISLNK ( $ mode ) ) {
$ aliases { $ file } = $ abs_file ;
return ;
}
return if ( S_ISDIR ( $ mode ) ) ;
2021-09-18 12:52:12 +03:00
2021-09-18 12:52:13 +03:00
# Trivial: file is defined exactly the same way at ABI What:
return if ( defined ( $ data { $ file } ) ) ;
return if ( defined ( $ data { $ abs_file } ) ) ;
2021-09-18 12:52:12 +03:00
2021-09-18 12:52:17 +03:00
push @ files , graph_add_file ( $ abs_file , "file" ) ;
}
sub get_leave ($)
{
my $ what = shift ;
my $ leave ;
my $ l = $ what ;
my $ stop = 1 ;
$ leave = $ l ;
$ leave =~ s , / $, , ;
$ leave =~ s , . * / , , ;
$ leave =~ s/[\(\)]//g ;
# $leave is used to improve search performance at
# check_undefined_symbols, as the algorithm there can seek
# for a small number of "what". It also allows giving a
# hint about a leave with the same name somewhere else.
# However, there are a few occurences where the leave is
# either a wildcard or a number. Just group such cases
# altogether.
2021-09-23 18:41:15 +03:00
if ( $ leave =~ m/\.\*/ || $ leave eq "" || $ leave =~ /\\d/ ) {
2021-09-18 12:52:17 +03:00
$ leave = "others" ;
}
return $ leave ;
2021-09-18 12:52:13 +03:00
}
2021-09-18 12:52:12 +03:00
2021-09-28 13:14:03 +03:00
my @ not_found ;
sub check_file ($$)
{
my $ file_ref = shift ;
my $ names_ref = shift ;
my @ names = @ { $ names_ref } ;
my $ file = $ names [ 0 ] ;
2021-09-18 12:52:12 +03:00
2021-09-28 13:14:03 +03:00
my $ found_string ;
2021-09-18 12:52:12 +03:00
2021-09-28 13:14:03 +03:00
my $ leave = get_leave ( $ file ) ;
if ( ! defined ( $ leaf { $ leave } ) ) {
$ leave = "others" ;
}
my @ expr = @ { $ leaf { $ leave } - > { expr } } ;
die ( "\rmissing rules for $leave" ) if ( ! defined ( $ leaf { $ leave } ) ) ;
my $ path = $ file ;
$ path =~ s , ( . * / ) . * , $ 1 , ;
2021-09-18 12:52:13 +03:00
2021-09-28 13:14:03 +03:00
if ( $ search_string ) {
return if ( ! ( $ file =~ m #$search_string#));
$ found_string = 1 ;
}
2021-09-18 12:52:13 +03:00
2021-09-28 13:14:03 +03:00
for ( my $ i = 0 ; $ i < @ names ; $ i + + ) {
if ( $ found_string && $ hint ) {
if ( ! $ i ) {
print STDERR "--> $names[$i]\n" ;
} else {
print STDERR " $names[$i]\n" ;
}
2021-09-18 12:52:14 +03:00
}
2021-09-28 13:14:03 +03:00
foreach my $ re ( @ expr ) {
print STDERR "$names[$i] =~ /^$re\$/\n" if ( $ debug && $ dbg_undefined ) ;
if ( $ names [ $ i ] =~ $ re ) {
return ;
}
}
}
2021-09-18 12:52:14 +03:00
2021-09-28 13:14:03 +03:00
if ( $ leave ne "others" ) {
2021-09-30 12:39:59 +03:00
my @ expr = @ { $ leaf { "others" } - > { expr } } ;
2021-09-23 18:41:18 +03:00
for ( my $ i = 0 ; $ i < @ names ; $ i + + ) {
foreach my $ re ( @ expr ) {
2021-09-28 13:14:03 +03:00
print STDERR "$names[$i] =~ /^$re\$/\n" if ( $ debug && $ dbg_undefined ) ;
2021-09-23 18:41:18 +03:00
if ( $ names [ $ i ] =~ $ re ) {
2021-09-28 13:14:03 +03:00
return ;
2021-09-18 12:52:13 +03:00
}
2021-09-18 12:52:12 +03:00
}
}
2021-09-28 13:14:03 +03:00
}
push @ not_found , $ file if ( ! $ search_string || $ found_string ) ;
2021-09-18 12:52:12 +03:00
2021-09-28 13:14:03 +03:00
if ( $ hint && ( ! $ search_string || $ found_string ) ) {
my $ what = $ leaf { $ leave } - > { what } ;
$ what =~ s/\xac/\n\t/g ;
2021-09-23 18:41:19 +03:00
if ( $ leave ne "others" ) {
2021-09-28 13:14:03 +03:00
print STDERR "\r more likely regexes:\n\t$what\n" ;
} else {
print STDERR "\r tested regexes:\n\t$what\n" ;
2021-09-23 18:41:19 +03:00
}
2021-09-28 13:14:03 +03:00
}
}
2021-09-23 18:41:19 +03:00
2021-09-28 13:14:03 +03:00
sub check_undefined_symbols {
my $ num_files = scalar @ files ;
my $ next_i = 0 ;
my $ start_time = times ;
2021-09-28 13:14:02 +03:00
2021-09-29 00:51:32 +03:00
@ files = sort @ files ;
2021-09-28 13:14:03 +03:00
my $ last_time = $ start_time ;
# When either debug or hint is enabled, there's no sense showing
# progress, as the progress will be overriden.
if ( $ hint || ( $ debug && $ dbg_undefined ) ) {
$ next_i = $ num_files ;
}
my $ is_console ;
$ is_console = 1 if ( - t STDERR ) ;
for ( my $ i = 0 ; $ i < $ num_files ; $ i + + ) {
my $ file_ref = $ files [ $ i ] ;
my @ names = @ { $$ file_ref { "__name" } } ;
check_file ( $ file_ref , \ @ names ) ;
my $ cur_time = times ;
if ( $ i == $ next_i || $ cur_time > $ last_time + 1 ) {
my $ percent = $ i * 100 / $ num_files ;
my $ tm = $ cur_time - $ start_time ;
my $ time = sprintf "%d:%02d" , int ( $ tm ) , 60 * ( $ tm - int ( $ tm ) ) ;
printf STDERR "\33[2K\r" , if ( $ is_console ) ;
printf STDERR "%s: processing sysfs files... %i%%: $names[0]" , $ time , $ percent ;
printf STDERR "\n" , if ( ! $ is_console ) ;
STDERR - > flush ( ) ;
$ next_i = int ( ( $ percent + 1 ) * $ num_files / 100 ) ;
$ last_time = $ cur_time ;
2021-09-18 12:52:13 +03:00
}
}
2021-09-28 13:14:03 +03:00
my $ cur_time = times ;
my $ tm = $ cur_time - $ start_time ;
my $ time = sprintf "%d:%02d" , int ( $ tm ) , 60 * ( $ tm - int ( $ tm ) ) ;
printf STDERR "\33[2K\r" , if ( $ is_console ) ;
printf STDERR "%s: processing sysfs files... done\n" , $ time ;
foreach my $ file ( @ not_found ) {
print "$file not found.\n" ;
}
2021-09-18 12:52:12 +03:00
}
sub undefined_symbols {
2021-09-28 13:14:03 +03:00
print STDERR "Reading $sysfs_prefix directory contents..." ;
2021-09-18 12:52:13 +03:00
find ( {
wanted = > \ & parse_existing_sysfs ,
preprocess = > \ & dont_parse_special_attributes ,
no_chdir = > 1
} , $ sysfs_prefix ) ;
2021-09-28 13:14:03 +03:00
print STDERR "done.\n" ;
2021-09-18 12:52:13 +03:00
2021-09-23 18:41:18 +03:00
$ leaf { "others" } - > { what } = "" ;
2021-09-18 12:52:17 +03:00
2021-09-28 13:14:03 +03:00
print STDERR "Converting ABI What fields into regexes..." ;
2021-09-18 12:52:12 +03:00
foreach my $ w ( sort keys % data ) {
2021-09-18 12:52:17 +03:00
foreach my $ what ( split /\xac/ , $ w ) {
2021-09-18 12:52:13 +03:00
next if ( ! ( $ what =~ m/^$sysfs_prefix/ ) ) ;
# Convert what into regular expressions
2021-09-30 12:40:00 +03:00
# Escape dot characters
$ what =~ s/\./\xf6/g ;
2021-09-18 12:52:13 +03:00
# Temporarily change [0-9]+ type of patterns
$ what =~ s/\[0\-9\]\+/\xff/g ;
# Temporarily change [\d+-\d+] type of patterns
$ what =~ s/\[0\-\d+\]/\xff/g ;
$ what =~ s/\[(\d+)\]/\xf4$1\xf5/g ;
# Temporarily change [0-9] type of patterns
$ what =~ s/\[(\d)\-(\d)\]/\xf4$1-$2\xf5/g ;
# Handle multiple option patterns
$ what =~ s/[\{\<\[]([\w_]+)(?:[,|]+([\w_]+)){1,}[\}\>\]]/($1|$2)/g ;
# Handle wildcards
2021-09-30 12:40:00 +03:00
$ what =~ s , \ * , . * , g ;
$ what =~ s , /\xf6..,/ . * , g ;
2021-09-18 12:52:13 +03:00
$ what =~ s/\<[^\>]+\>/.*/g ;
$ what =~ s/\{[^\}]+\}/.*/g ;
$ what =~ s/\[[^\]]+\]/.*/g ;
$ what =~ s/[XYZ]/.*/g ;
# Recover [0-9] type of patterns
$ what =~ s/\xf4/[/g ;
$ what =~ s/\xf5/]/g ;
# Remove duplicated spaces
$ what =~ s/\s+/ /g ;
# Special case: this ABI has a parenthesis on it
$ what =~ s/sqrt\(x^2\+y^2\+z^2\)/sqrt\(x^2\+y^2\+z^2\)/ ;
# Special case: drop comparition as in:
# What: foo = <something>
# (this happens on a few IIO definitions)
$ what =~ s , \ s * \= . * $, , ;
# Escape all other symbols
$ what =~ s/$escape_symbols/\\$1/g ;
$ what =~ s/\\\\/\\/g ;
$ what =~ s/\\([\[\]\(\)\|])/$1/g ;
$ what =~ s/(\d+)\\(-\d+)/$1$2/g ;
2021-09-18 12:52:14 +03:00
$ what =~ s/\xff/\\d+/g ;
# Special case: IIO ABI which a parenthesis.
$ what =~ s/sqrt(.*)/sqrt\(.*\)/ ;
2021-09-30 12:40:00 +03:00
# Simplify regexes with multiple .*
$ what =~ s #(?:\.\*){2,}##g;
# $what =~ s#\.\*/\.\*#.*#g;
# Recover dot characters
$ what =~ s/\xf6/\./g ;
2021-09-23 18:41:13 +03:00
my $ leave = get_leave ( $ what ) ;
2021-09-23 18:41:18 +03:00
2021-09-18 12:52:14 +03:00
my $ added = 0 ;
2021-09-18 12:52:13 +03:00
foreach my $ l ( split /\|/ , $ leave ) {
if ( defined ( $ leaf { $ l } ) ) {
2021-09-23 18:41:18 +03:00
next if ( $ leaf { $ l } - > { what } =~ m/\b$what\b/ ) ;
$ leaf { $ l } - > { what } . = "\xac" . $ what ;
2021-09-18 12:52:14 +03:00
$ added = 1 ;
2021-09-18 12:52:13 +03:00
} else {
2021-09-23 18:41:18 +03:00
$ leaf { $ l } - > { what } = $ what ;
2021-09-18 12:52:14 +03:00
$ added = 1 ;
2021-09-18 12:52:13 +03:00
}
2021-09-18 12:52:12 +03:00
}
2021-09-18 12:52:14 +03:00
if ( $ search_string && $ added ) {
2021-09-28 13:14:02 +03:00
print STDERR "What: $what\n" if ( $ what =~ m #$search_string#);
2021-09-18 12:52:14 +03:00
}
2021-09-18 12:52:12 +03:00
}
}
2021-09-23 18:41:18 +03:00
# Compile regexes
2021-09-29 00:51:32 +03:00
foreach my $ l ( sort keys % leaf ) {
2021-09-23 18:41:18 +03:00
my @ expr ;
2021-09-29 00:51:32 +03:00
foreach my $ w ( sort split /\xac/ , $ leaf { $ l } - > { what } ) {
2021-09-23 18:41:18 +03:00
push @ expr , qr /^$w$/ ;
}
$ leaf { $ l } - > { expr } = \ @ expr ;
}
2021-09-18 12:52:17 +03:00
# Take links into account
2021-09-29 00:51:32 +03:00
foreach my $ link ( sort keys % aliases ) {
2021-09-18 12:52:17 +03:00
my $ abs_file = $ aliases { $ link } ;
graph_add_link ( $ abs_file , $ link ) ;
}
2021-09-28 13:14:03 +03:00
print STDERR "done.\n" ;
2021-09-18 12:52:13 +03:00
check_undefined_symbols ;
2021-09-18 12:52:12 +03:00
}
2020-10-30 10:40:22 +03:00
# Ensure that the prefix will always end with a slash
# While this is not needed for find, it makes the patch nicer
# with --enable-lineno
$ prefix =~ s , /?$,/ , ;
2019-06-20 20:22:59 +03:00
2021-09-18 12:52:12 +03:00
if ( $ cmd eq "undefined" || $ cmd eq "search" ) {
$ show_warnings = 0 ;
}
2019-06-20 20:22:55 +03:00
#
# Parses all ABI files located at $prefix dir
#
find ( { wanted = > \ & parse_abi , no_chdir = > 1 } , $ prefix ) ;
2021-09-23 18:41:14 +03:00
print STDERR Data::Dumper - > Dump ( [ \ % data ] , [ qw( *data ) ] ) if ( $ debug & $ dbg_dump_abi_structs ) ;
2019-06-20 20:22:55 +03:00
#
2019-06-20 20:22:59 +03:00
# Handles the command
2019-06-20 20:22:55 +03:00
#
2021-09-18 12:52:12 +03:00
if ( $ cmd eq "undefined" ) {
undefined_symbols ;
} elsif ( $ cmd eq "search" ) {
2019-06-20 20:22:59 +03:00
search_symbols ;
2020-10-30 10:40:25 +03:00
} else {
if ( $ cmd eq "rest" ) {
output_rest ;
}
# Warn about duplicated ABI entries
foreach my $ what ( sort keys % symbols ) {
my @ files = @ { $ symbols { $ what } - > { file } } ;
next if ( scalar ( @ files ) == 1 ) ;
2019-06-20 20:22:55 +03:00
2020-10-30 10:40:25 +03:00
printf STDERR "Warning: $what is defined %d times: @files\n" ,
scalar ( @ files ) ;
}
}
2019-06-20 20:22:55 +03:00
__END__
= head1 NAME
2022-04-19 15:16:36 +03:00
get_abi . pl - parse the Linux ABI files and produce a ReST book .
2019-06-20 20:22:55 +03:00
= head1 SYNOPSIS
2022-04-19 15:16:36 +03:00
B <get_abi.pl> [ - - debug <level> ] [ - - enable - lineno ] [ - - man ] [ - - help ]
2021-09-18 12:52:13 +03:00
[ - - ( no - ) rst - source ] [ - - dir = <dir> ] [ - - show - hints ]
2021-09-18 12:52:14 +03:00
[ - - search - string <regex> ]
2022-02-25 14:40:08 +03:00
<COMMAND> [ <ARGUMENT> ]
2019-06-20 20:22:59 +03:00
2021-09-27 16:49:51 +03:00
Where B <COMMAND> can be:
2019-06-20 20:22:59 +03:00
= over 8
2021-09-27 16:49:51 +03:00
B <search> I <SEARCH_REGEX> - search for I <SEARCH_REGEX> inside ABI
2019-06-20 20:22:59 +03:00
2021-09-27 16:49:51 +03:00
B <rest> - output the ABI in ReST markup language
2019-06-20 20:23:04 +03:00
2021-09-27 16:49:51 +03:00
B <validate> - validate the ABI contents
2019-06-20 20:22:59 +03:00
2021-09-27 16:49:51 +03:00
B <undefined> - existing symbols at the system that aren ' t
defined at Documentation / ABI
2021-09-18 12:52:12 +03:00
2019-06-20 20:22:59 +03:00
= back
2019-06-20 20:22:55 +03:00
= head1 OPTIONS
= over 8
2019-06-20 20:22:59 +03:00
= item B <--dir>
Changes the location of the ABI search . By default , it uses
the Documentation / ABI directory .
2020-10-30 10:40:20 +03:00
= item B <--rst-source> and B <--no-rst-source>
The input file may be using ReST syntax or not . Those two options allow
2021-09-27 16:49:51 +03:00
selecting between a rst - compliant source ABI ( B <--rst-source> ) , or a
2020-10-30 10:40:20 +03:00
plain text that may be violating ReST spec , so it requres some escaping
2021-09-27 16:49:51 +03:00
logic ( B <--no-rst-source> ) .
2020-10-30 10:40:20 +03:00
2020-10-30 10:40:22 +03:00
= item B <--enable-lineno>
2022-03-26 13:27:23 +03:00
Enable output of .. LINENO lines .
2020-10-30 10:40:22 +03:00
2021-09-23 18:41:14 +03:00
= item B <--debug> I < debug level >
Print debug information according with the level , which is given by the
following bitmask:
2019-06-20 20:22:55 +03:00
2021-09-23 18:41:14 +03:00
- 1 : Debug parsing What entries from ABI files ;
- 2 : Shows what files are opened from ABI files ;
- 4 : Dump the structs used to store the contents of the ABI files .
2019-06-20 20:22:55 +03:00
2021-09-18 12:52:13 +03:00
= item B <--show-hints>
Show hints about possible definitions for the missing ABI symbols .
Used only when B <undefined> .
2021-09-27 16:49:51 +03:00
= item B <--search-string> I < regex string >
2021-09-18 12:52:14 +03:00
Show only occurences that match a search string .
Used only when B <undefined> .
2019-06-20 20:22:55 +03:00
= item B <--help>
Prints a brief help message and exits .
= item B <--man>
Prints the manual page and exits .
= back
= head1 DESCRIPTION
2019-06-20 20:22:59 +03:00
Parse the Linux ABI files from ABI DIR ( usually located at Documentation / ABI ) ,
allowing to search for ABI symbols or to produce a ReST book containing
the Linux ABI documentation .
= head1 EXAMPLES
Search for all stable symbols with the word "usb" :
= over 8
$ scripts /get_abi.pl search usb --dir Documentation/ ABI / stable
= back
Search for all symbols that match the regex expression "usb.*cap" :
= over 8
$ scripts / get_abi . pl search usb . * cap
= back
Output all obsoleted symbols in ReST format
= over 8
$ scripts /get_abi.pl rest --dir Documentation/ ABI / obsolete
= back
2019-06-20 20:22:55 +03:00
= head1 BUGS
2021-09-27 16:49:51 +03:00
Report bugs to Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
2019-06-20 20:22:55 +03:00
= head1 COPYRIGHT
2021-09-27 16:49:51 +03:00
Copyright ( c ) 2016 - 2021 by Mauro Carvalho Chehab <mchehab+huawei@kernel.org> .
2019-06-20 20:22:55 +03:00
License GPLv2: GNU GPL version 2 <http://gnu.org/licenses/gpl.html> .
This is free software: you are free to change and redistribute it .
There is NO WARRANTY , to the extent permitted by law .
= cut