]>
Commit | Line | Data |
---|---|---|
dabf8be3 MCC |
1 | #!/usr/bin/perl |
2 | use strict; | |
3 | use Text::Tabs; | |
327f5a75 MCC |
4 | use Getopt::Long; |
5 | use Pod::Usage; | |
dabf8be3 | 6 | |
327f5a75 MCC |
7 | my $debug; |
8 | my $help; | |
9 | my $man; | |
dabf8be3 | 10 | |
327f5a75 MCC |
11 | GetOptions( |
12 | "debug" => \$debug, | |
c3396656 MCC |
13 | 'usage|?' => \$help, |
14 | 'help' => \$man | |
327f5a75 | 15 | ) or pod2usage(2); |
bcec7c21 | 16 | |
327f5a75 MCC |
17 | pod2usage(1) if $help; |
18 | pod2usage(-exitstatus => 0, -verbose => 2) if $man; | |
19 | pod2usage(2) if (scalar @ARGV < 2 || scalar @ARGV > 3); | |
dabf8be3 MCC |
20 | |
21 | my ($file_in, $file_out, $file_exceptions) = @ARGV; | |
22 | ||
23 | my $data; | |
24 | my %ioctls; | |
25 | my %defines; | |
26 | my %typedefs; | |
27 | my %enums; | |
28 | my %enum_symbols; | |
29 | my %structs; | |
30 | ||
327f5a75 MCC |
31 | require Data::Dumper if ($debug); |
32 | ||
dabf8be3 MCC |
33 | # |
34 | # read the file and get identifiers | |
35 | # | |
36 | ||
37 | my $is_enum = 0; | |
034e6c8e | 38 | my $is_comment = 0; |
dabf8be3 MCC |
39 | open IN, $file_in or die "Can't open $file_in"; |
40 | while (<IN>) { | |
034e6c8e MCC |
41 | $data .= $_; |
42 | ||
9afe5112 | 43 | my $ln = $_; |
034e6c8e MCC |
44 | if (!$is_comment) { |
45 | $ln =~ s,/\*.*(\*/),,g; | |
9afe5112 | 46 | |
034e6c8e MCC |
47 | $is_comment = 1 if ($ln =~ s,/\*.*,,); |
48 | } else { | |
49 | if ($ln =~ s,^(.*\*/),,) { | |
50 | $is_comment = 0; | |
51 | } else { | |
52 | next; | |
53 | } | |
54 | } | |
dabf8be3 | 55 | |
9c80c745 | 56 | if ($is_enum && $ln =~ m/^\s*([_\w][\w\d_]+)\s*[\,=]?/) { |
dabf8be3 MCC |
57 | my $s = $1; |
58 | my $n = $1; | |
59 | $n =~ tr/A-Z/a-z/; | |
60 | $n =~ tr/_/-/; | |
61 | ||
22c40033 | 62 | $enum_symbols{$s} = "\\ :ref:`$s <$n>`\\ "; |
dabf8be3 MCC |
63 | |
64 | $is_enum = 0 if ($is_enum && m/\}/); | |
65 | next; | |
66 | } | |
67 | $is_enum = 0 if ($is_enum && m/\}/); | |
68 | ||
9c80c745 | 69 | if ($ln =~ m/^\s*#\s*define\s+([_\w][\w\d_]+)\s+_IO/) { |
dabf8be3 MCC |
70 | my $s = $1; |
71 | my $n = $1; | |
72 | $n =~ tr/A-Z/a-z/; | |
73 | ||
22c40033 | 74 | $ioctls{$s} = "\\ :ref:`$s <$n>`\\ "; |
dabf8be3 MCC |
75 | next; |
76 | } | |
77 | ||
9c80c745 | 78 | if ($ln =~ m/^\s*#\s*define\s+([_\w][\w\d_]+)\s+/) { |
dabf8be3 MCC |
79 | my $s = $1; |
80 | my $n = $1; | |
81 | $n =~ tr/A-Z/a-z/; | |
82 | $n =~ tr/_/-/; | |
83 | ||
22c40033 | 84 | $defines{$s} = "\\ :ref:`$s <$n>`\\ "; |
dabf8be3 MCC |
85 | next; |
86 | } | |
87 | ||
22c40033 MCC |
88 | if ($ln =~ m/^\s*typedef\s+([_\w][\w\d_]+)\s+(.*)\s+([_\w][\w\d_]+);/) { |
89 | my $s = $2; | |
90 | my $n = $3; | |
dabf8be3 | 91 | |
22c40033 | 92 | $typedefs{$n} = "\\ :c:type:`$n <$s>`\\ "; |
dabf8be3 MCC |
93 | next; |
94 | } | |
9c80c745 | 95 | if ($ln =~ m/^\s*enum\s+([_\w][\w\d_]+)\s+\{/ |
6c4c7dad MCC |
96 | || $ln =~ m/^\s*enum\s+([_\w][\w\d_]+)$/ |
97 | || $ln =~ m/^\s*typedef\s*enum\s+([_\w][\w\d_]+)\s+\{/ | |
98 | || $ln =~ m/^\s*typedef\s*enum\s+([_\w][\w\d_]+)$/) { | |
dabf8be3 | 99 | my $s = $1; |
dabf8be3 | 100 | |
22c40033 | 101 | $enums{$s} = "enum :c:type:`$s`\\ "; |
dabf8be3 MCC |
102 | |
103 | $is_enum = $1; | |
104 | next; | |
105 | } | |
9c80c745 | 106 | if ($ln =~ m/^\s*struct\s+([_\w][\w\d_]+)\s+\{/ |
6c4c7dad MCC |
107 | || $ln =~ m/^\s*struct\s+([[_\w][\w\d_]+)$/ |
108 | || $ln =~ m/^\s*typedef\s*struct\s+([_\w][\w\d_]+)\s+\{/ | |
109 | || $ln =~ m/^\s*typedef\s*struct\s+([[_\w][\w\d_]+)$/ | |
110 | ) { | |
dabf8be3 | 111 | my $s = $1; |
dabf8be3 | 112 | |
22c40033 | 113 | $structs{$s} = "struct :c:type:`$s`\\ "; |
dabf8be3 MCC |
114 | next; |
115 | } | |
116 | } | |
117 | close IN; | |
118 | ||
119 | # | |
120 | # Handle multi-line typedefs | |
121 | # | |
122 | ||
4ff916a0 MCC |
123 | my @matches = ($data =~ m/typedef\s+struct\s+\S+?\s*\{[^\}]+\}\s*(\S+)\s*\;/g, |
124 | $data =~ m/typedef\s+enum\s+\S+?\s*\{[^\}]+\}\s*(\S+)\s*\;/g,); | |
dabf8be3 | 125 | foreach my $m (@matches) { |
22c40033 | 126 | my $s = $m; |
dabf8be3 | 127 | |
22c40033 | 128 | $typedefs{$s} = "\\ :c:type:`$s`\\ "; |
dabf8be3 MCC |
129 | next; |
130 | } | |
131 | ||
132 | # | |
133 | # Handle exceptions, if any | |
134 | # | |
135 | ||
22c40033 MCC |
136 | my %def_reftype = ( |
137 | "ioctl" => ":ref", | |
138 | "define" => ":ref", | |
139 | "symbol" => ":ref", | |
140 | "typedef" => ":c:type", | |
141 | "enum" => ":c:type", | |
142 | "struct" => ":c:type", | |
143 | ); | |
144 | ||
dabf8be3 MCC |
145 | if ($file_exceptions) { |
146 | open IN, $file_exceptions or die "Can't read $file_exceptions"; | |
147 | while (<IN>) { | |
148 | next if (m/^\s*$/ || m/^\s*#/); | |
149 | ||
150 | # Parsers to ignore a symbol | |
151 | ||
152 | if (m/^ignore\s+ioctl\s+(\S+)/) { | |
153 | delete $ioctls{$1} if (exists($ioctls{$1})); | |
154 | next; | |
155 | } | |
156 | if (m/^ignore\s+define\s+(\S+)/) { | |
157 | delete $defines{$1} if (exists($defines{$1})); | |
158 | next; | |
159 | } | |
160 | if (m/^ignore\s+typedef\s+(\S+)/) { | |
161 | delete $typedefs{$1} if (exists($typedefs{$1})); | |
162 | next; | |
163 | } | |
164 | if (m/^ignore\s+enum\s+(\S+)/) { | |
165 | delete $enums{$1} if (exists($enums{$1})); | |
166 | next; | |
167 | } | |
168 | if (m/^ignore\s+struct\s+(\S+)/) { | |
169 | delete $structs{$1} if (exists($structs{$1})); | |
170 | next; | |
171 | } | |
526b8848 MCC |
172 | if (m/^ignore\s+symbol\s+(\S+)/) { |
173 | delete $enum_symbols{$1} if (exists($enum_symbols{$1})); | |
174 | next; | |
175 | } | |
dabf8be3 MCC |
176 | |
177 | # Parsers to replace a symbol | |
22c40033 | 178 | my ($type, $old, $new, $reftype); |
dabf8be3 | 179 | |
22c40033 MCC |
180 | if (m/^replace\s+(\S+)\s+(\S+)\s+(\S+)/) { |
181 | $type = $1; | |
182 | $old = $2; | |
183 | $new = $3; | |
184 | } else { | |
185 | die "Can't parse $file_exceptions: $_"; | |
186 | } | |
187 | ||
188 | if ($new =~ m/^\:c\:(data|func|macro|type)\:\`(.+)\`/) { | |
189 | $reftype = ":c:$1"; | |
190 | $new = $2; | |
191 | } elsif ($new =~ m/\:ref\:\`(.+)\`/) { | |
192 | $reftype = ":ref"; | |
193 | $new = $1; | |
194 | } else { | |
195 | $reftype = $def_reftype{$type}; | |
196 | } | |
197 | $new = "$reftype:`$old <$new>`"; | |
198 | ||
199 | if ($type eq "ioctl") { | |
200 | $ioctls{$old} = $new if (exists($ioctls{$old})); | |
dabf8be3 MCC |
201 | next; |
202 | } | |
22c40033 MCC |
203 | if ($type eq "define") { |
204 | $defines{$old} = $new if (exists($defines{$old})); | |
dabf8be3 MCC |
205 | next; |
206 | } | |
22c40033 MCC |
207 | if ($type eq "symbol") { |
208 | $enum_symbols{$old} = $new if (exists($enum_symbols{$old})); | |
dabf8be3 MCC |
209 | next; |
210 | } | |
22c40033 MCC |
211 | if ($type eq "typedef") { |
212 | $typedefs{$old} = $new if (exists($typedefs{$old})); | |
dabf8be3 MCC |
213 | next; |
214 | } | |
22c40033 MCC |
215 | if ($type eq "enum") { |
216 | $enums{$old} = $new if (exists($enums{$old})); | |
dabf8be3 MCC |
217 | next; |
218 | } | |
22c40033 MCC |
219 | if ($type eq "struct") { |
220 | $structs{$old} = $new if (exists($structs{$old})); | |
dabf8be3 MCC |
221 | next; |
222 | } | |
223 | ||
224 | die "Can't parse $file_exceptions: $_"; | |
225 | } | |
226 | } | |
227 | ||
228 | if ($debug) { | |
229 | print Data::Dumper->Dump([\%ioctls], [qw(*ioctls)]) if (%ioctls); | |
230 | print Data::Dumper->Dump([\%typedefs], [qw(*typedefs)]) if (%typedefs); | |
231 | print Data::Dumper->Dump([\%enums], [qw(*enums)]) if (%enums); | |
232 | print Data::Dumper->Dump([\%structs], [qw(*structs)]) if (%structs); | |
233 | print Data::Dumper->Dump([\%defines], [qw(*defines)]) if (%defines); | |
234 | print Data::Dumper->Dump([\%enum_symbols], [qw(*enum_symbols)]) if (%enum_symbols); | |
235 | } | |
236 | ||
237 | # | |
238 | # Align block | |
239 | # | |
240 | $data = expand($data); | |
241 | $data = " " . $data; | |
242 | $data =~ s/\n/\n /g; | |
243 | $data =~ s/\n\s+$/\n/g; | |
244 | $data =~ s/\n\s+\n/\n\n/g; | |
245 | ||
246 | # | |
247 | # Add escape codes for special characters | |
248 | # | |
999d998e | 249 | $data =~ s,([\_\`\*\<\>\&\\\\:\/\|\%\$\#\{\}\~\^]),\\$1,g; |
dabf8be3 | 250 | |
7d95fa8d MCC |
251 | $data =~ s,DEPRECATED,**DEPRECATED**,g; |
252 | ||
dabf8be3 MCC |
253 | # |
254 | # Add references | |
255 | # | |
256 | ||
6fe79d1e MCC |
257 | my $start_delim = "[ \n\t\(\=\*\@]"; |
258 | my $end_delim = "(\\s|,|\\\\=|\\\\:|\\;|\\\)|\\}|\\{)"; | |
dabf8be3 MCC |
259 | |
260 | foreach my $r (keys %ioctls) { | |
22c40033 | 261 | my $s = $ioctls{$r}; |
dabf8be3 MCC |
262 | |
263 | $r =~ s,([\_\`\*\<\>\&\\\\:\/]),\\\\$1,g; | |
264 | ||
265 | print "$r -> $s\n" if ($debug); | |
266 | ||
6fe79d1e | 267 | $data =~ s/($start_delim)($r)$end_delim/$1$s$3/g; |
dabf8be3 MCC |
268 | } |
269 | ||
270 | foreach my $r (keys %defines) { | |
22c40033 | 271 | my $s = $defines{$r}; |
dabf8be3 MCC |
272 | |
273 | $r =~ s,([\_\`\*\<\>\&\\\\:\/]),\\\\$1,g; | |
274 | ||
275 | print "$r -> $s\n" if ($debug); | |
276 | ||
6fe79d1e | 277 | $data =~ s/($start_delim)($r)$end_delim/$1$s$3/g; |
dabf8be3 MCC |
278 | } |
279 | ||
280 | foreach my $r (keys %enum_symbols) { | |
22c40033 | 281 | my $s = $enum_symbols{$r}; |
dabf8be3 MCC |
282 | |
283 | $r =~ s,([\_\`\*\<\>\&\\\\:\/]),\\\\$1,g; | |
284 | ||
285 | print "$r -> $s\n" if ($debug); | |
286 | ||
6fe79d1e | 287 | $data =~ s/($start_delim)($r)$end_delim/$1$s$3/g; |
dabf8be3 MCC |
288 | } |
289 | ||
290 | foreach my $r (keys %enums) { | |
22c40033 | 291 | my $s = $enums{$r}; |
dabf8be3 MCC |
292 | |
293 | $r =~ s,([\_\`\*\<\>\&\\\\:\/]),\\\\$1,g; | |
294 | ||
295 | print "$r -> $s\n" if ($debug); | |
296 | ||
6fe79d1e | 297 | $data =~ s/enum\s+($r)$end_delim/$s$2/g; |
dabf8be3 MCC |
298 | } |
299 | ||
300 | foreach my $r (keys %structs) { | |
22c40033 | 301 | my $s = $structs{$r}; |
dabf8be3 MCC |
302 | |
303 | $r =~ s,([\_\`\*\<\>\&\\\\:\/]),\\\\$1,g; | |
304 | ||
305 | print "$r -> $s\n" if ($debug); | |
306 | ||
6fe79d1e | 307 | $data =~ s/struct\s+($r)$end_delim/$s$2/g; |
dabf8be3 MCC |
308 | } |
309 | ||
310 | foreach my $r (keys %typedefs) { | |
22c40033 | 311 | my $s = $typedefs{$r}; |
dabf8be3 MCC |
312 | |
313 | $r =~ s,([\_\`\*\<\>\&\\\\:\/]),\\\\$1,g; | |
314 | ||
315 | print "$r -> $s\n" if ($debug); | |
6fe79d1e | 316 | $data =~ s/($start_delim)($r)$end_delim/$1$s$3/g; |
dabf8be3 MCC |
317 | } |
318 | ||
22c40033 | 319 | $data =~ s/\\ ([\n\s])/\1/g; |
fb6fc6c9 | 320 | |
dabf8be3 MCC |
321 | # |
322 | # Generate output file | |
323 | # | |
324 | ||
325 | my $title = $file_in; | |
326 | $title =~ s,.*/,,; | |
327 | ||
328 | open OUT, "> $file_out" or die "Can't open $file_out"; | |
329 | print OUT ".. -*- coding: utf-8; mode: rst -*-\n\n"; | |
330 | print OUT "$title\n"; | |
331 | print OUT "=" x length($title); | |
332 | print OUT "\n\n.. parsed-literal::\n\n"; | |
333 | print OUT $data; | |
334 | close OUT; | |
327f5a75 MCC |
335 | |
336 | __END__ | |
337 | ||
338 | =head1 NAME | |
339 | ||
340 | parse_headers.pl - parse a C file, in order to identify functions, structs, | |
341 | enums and defines and create cross-references to a Sphinx book. | |
342 | ||
343 | =head1 SYNOPSIS | |
344 | ||
345 | B<parse_headers.pl> [<options>] <C_FILE> <OUT_FILE> [<EXCEPTIONS_FILE>] | |
346 | ||
347 | Where <options> can be: --debug, --help or --man. | |
348 | ||
349 | =head1 OPTIONS | |
350 | ||
351 | =over 8 | |
352 | ||
353 | =item B<--debug> | |
354 | ||
355 | Put the script in verbose mode, useful for debugging. | |
356 | ||
c3396656 | 357 | =item B<--usage> |
327f5a75 MCC |
358 | |
359 | Prints a brief help message and exits. | |
360 | ||
c3396656 | 361 | =item B<--help> |
327f5a75 | 362 | |
c3396656 | 363 | Prints a more detailed help message and exits. |
327f5a75 MCC |
364 | |
365 | =back | |
366 | ||
367 | =head1 DESCRIPTION | |
368 | ||
369 | Convert a C header or source file (C_FILE), into a ReStructured Text | |
370 | included via ..parsed-literal block with cross-references for the | |
371 | documentation files that describe the API. It accepts an optional | |
372 | EXCEPTIONS_FILE with describes what elements will be either ignored or | |
373 | be pointed to a non-default reference. | |
374 | ||
375 | The output is written at the (OUT_FILE). | |
376 | ||
377 | It is capable of identifying defines, functions, structs, typedefs, | |
378 | enums and enum symbols and create cross-references for all of them. | |
379 | It is also capable of distinguish #define used for specifying a Linux | |
380 | ioctl. | |
381 | ||
c3396656 MCC |
382 | The EXCEPTIONS_FILE contain two rules to allow ignoring a symbol or |
383 | to replace the default references by a custom one. | |
327f5a75 | 384 | |
c3396656 MCC |
385 | Please read Documentation/doc-guide/parse-headers.rst at the Kernel's |
386 | tree for more details. | |
327f5a75 MCC |
387 | |
388 | =head1 BUGS | |
389 | ||
32590819 | 390 | Report bugs to Mauro Carvalho Chehab <mchehab@kernel.org> |
327f5a75 MCC |
391 | |
392 | =head1 COPYRIGHT | |
393 | ||
32590819 | 394 | Copyright (c) 2016 by Mauro Carvalho Chehab <mchehab+samsung@kernel.org>. |
327f5a75 MCC |
395 | |
396 | License GPLv2: GNU GPL version 2 <http://gnu.org/licenses/gpl.html>. | |
397 | ||
398 | This is free software: you are free to change and redistribute it. | |
399 | There is NO WARRANTY, to the extent permitted by law. | |
400 | ||
401 | =cut |