blob: f7c9944a833c2316d561f204969082216f8586fc [file] [log] [blame]
Mauro Carvalho Chehabbbc249f2019-06-20 14:22:55 -03001#!/usr/bin/perl
2
3use strict;
4use Pod::Usage;
5use Getopt::Long;
6use File::Find;
7use Fcntl ':mode';
8
9my $help;
10my $man;
11my $debug;
12
13GetOptions(
14 "debug|d+" => \$debug,
15 'help|?' => \$help,
16 man => \$man
17) or pod2usage(2);
18
19pod2usage(1) if $help;
20pod2usage(-exitstatus => 0, -verbose => 2) if $man;
21
22pod2usage(2) if (scalar @ARGV != 1);
23
24my ($prefix) = @ARGV;
25
26require Data::Dumper if ($debug);
27
28my %data;
29
30#
31# Displays an error message, printing file name and line
32#
33sub parse_error($$$$) {
34 my ($file, $ln, $msg, $data) = @_;
35
36 print STDERR "file $file#$ln: $msg at\n\t$data";
37}
38
39#
40# Parse an ABI file, storing its contents at %data
41#
42sub parse_abi {
43 my $file = $File::Find::name;
44
45 my $mode = (stat($file))[2];
46 return if ($mode & S_IFDIR);
47 return if ($file =~ m,/README,);
48
49 my $name = $file;
50 $name =~ s,.*/,,;
51
52 my $type = $file;
53 $type =~ s,.*/(.*)/.*,$1,;
54
55 my $what;
56 my $new_what;
57 my $tag;
58 my $ln;
59
60 print STDERR "Opening $file\n" if ($debug > 1);
61 open IN, $file;
62 while(<IN>) {
63 $ln++;
64 if (m/^(\S+):\s*(.*)/i) {
65 my $new_tag = lc($1);
66 my $content = $2;
67
68 if (!($new_tag =~ m/(what|date|kernelversion|contact|description|users)/)) {
69 if ($tag eq "description") {
70 $data{$what}->{$tag} .= "\n$content";;
71 $data{$what}->{$tag} =~ s/\n+$//;
72 next;
73 } else {
74 parse_error($file, $ln, "tag '$tag' is invalid", $_);
75 }
76 }
77
78 if ($new_tag =~ m/what/) {
79 if ($tag =~ m/what/) {
80 $what .= ", " . $content;
81 } else {
82 $what = $content;
83 $new_what = 1;
84 }
85 $tag = $new_tag;
86 next;
87 }
88
89 $tag = $new_tag;
90
91 if ($new_what) {
92 $new_what = 0;
93
94 $data{$what}->{type} = $type;
95 $data{$what}->{file} = $name;
96 print STDERR "\twhat: $what\n" if ($debug > 1);
97 }
98
99 if (!$what) {
100 parse_error($file, $ln, "'What:' should come first:", $_);
101 next;
102 }
103 $data{$what}->{$tag} = $content;
104 next;
105 }
106
107 # Silently ignore any headers before the database
108 next if (!$tag);
109
110 if (m/^\s*(.*)/) {
111 $data{$what}->{$tag} .= "\n$1";
112 $data{$what}->{$tag} =~ s/\n+$//;
113 next;
114 }
115
116 # Everything else is error
117 parse_error($file, $ln, "Unexpected line:", $_);
118 }
119 close IN;
120}
121
122# Outputs the output on ReST format
123sub output_rest {
124 foreach my $what (sort keys %data) {
125 my $type = $data{$what}->{type};
126 my $file = $data{$what}->{file};
127
128 my $w = $what;
129 $w =~ s/([\(\)\_\-\*\=\^\~\\])/\\$1/g;
130
131 print "$w\n\n";
132 print "- defined on file $file (type: $type)\n\n::\n\n";
133
134 my $desc = $data{$what}->{description};
135 $desc =~ s/^\s+//;
136
137 # Remove title markups from the description, as they won't work
138 $desc =~ s/\n[\-\*\=\^\~]+\n/\n/g;
139
140 # put everything inside a code block
141 $desc =~ s/\n/\n /g;
142
143
144 if (!($desc =~ /^\s*$/)) {
145 print " $desc\n\n";
146 } else {
147 print " DESCRIPTION MISSING\n\n";
148 }
149 }
150}
151
152#
153# Parses all ABI files located at $prefix dir
154#
155find({wanted =>\&parse_abi, no_chdir => 1}, $prefix);
156
157print STDERR Data::Dumper->Dump([\%data], [qw(*data)]) if ($debug);
158
159#
160# Outputs an ReST file with the ABI contents
161#
162output_rest
163
164
165__END__
166
167=head1 NAME
168
169abi_book.pl - parse the Linux ABI files and produce a ReST book.
170
171=head1 SYNOPSIS
172
173B<abi_book.pl> [--debug] <ABI_DIR>]
174
175=head1 OPTIONS
176
177=over 8
178
179=item B<--debug>
180
181Put the script in verbose mode, useful for debugging. Can be called multiple
182times, to increase verbosity.
183
184=item B<--help>
185
186Prints a brief help message and exits.
187
188=item B<--man>
189
190Prints the manual page and exits.
191
192=back
193
194=head1 DESCRIPTION
195
196Parse the Linux ABI files from ABI DIR (usually located at Documentation/ABI)
197and produce a ReST book containing the Linux ABI.
198
199=head1 BUGS
200
201Report bugs to Mauro Carvalho Chehab <mchehab@s-opensource.com>
202
203=head1 COPYRIGHT
204
205Copyright (c) 2016 by Mauro Carvalho Chehab <mchehab@s-opensource.com>.
206
207License GPLv2: GNU GPL version 2 <http://gnu.org/licenses/gpl.html>.
208
209This is free software: you are free to change and redistribute it.
210There is NO WARRANTY, to the extent permitted by law.
211
212=cut