doc-rst: fix parsing comments and '{' on a separate line
[linux-2.6-block.git] / Documentation / sphinx / parse-headers.pl
1 #!/usr/bin/perl
2 use strict;
3 use Text::Tabs;
4
5 # Uncomment if debug is needed
6 #use Data::Dumper;
7
8 # change to 1 to generate some debug prints
9 my $debug = 0;
10
11 if (scalar @ARGV < 2 || scalar @ARGV > 3) {
12         die "Usage:\n\t$0 <file in> <file out> [<exceptions file>]\n";
13 }
14
15 my ($file_in, $file_out, $file_exceptions) = @ARGV;
16
17 my $data;
18 my %ioctls;
19 my %defines;
20 my %typedefs;
21 my %enums;
22 my %enum_symbols;
23 my %structs;
24
25 #
26 # read the file and get identifiers
27 #
28
29 my $is_enum = 0;
30 open IN, $file_in or die "Can't open $file_in";
31 while (<IN>) {
32         my $ln = $_;
33         $ln =~ s,/\*.*\*/,,;
34
35         $data .= $_;
36
37         if ($is_enum && $ln =~ m/^\s*([_A-Z][^\s\}\,\=]+)\s*[\,=]?/) {
38                 my $s = $1;
39                 my $n = $1;
40                 $n =~ tr/A-Z/a-z/;
41                 $n =~ tr/_/-/;
42
43                 $enum_symbols{$s} = $n;
44
45                 $is_enum = 0 if ($is_enum && m/\}/);
46                 next;
47         }
48         $is_enum = 0 if ($is_enum && m/\}/);
49
50         if ($ln =~ m/^\s*#\s*define\s+([_A-Z]\S+)\s+_IO/) {
51                 my $s = $1;
52                 my $n = $1;
53                 $n =~ tr/A-Z/a-z/;
54
55                 $ioctls{$s} = $n;
56                 next;
57         }
58
59         if ($ln =~ m/^\s*#\s*define\s+([_A-Z]\S+)\s+/) {
60                 my $s = $1;
61                 my $n = $1;
62                 $n =~ tr/A-Z/a-z/;
63                 $n =~ tr/_/-/;
64
65                 $defines{$s} = $n;
66                 next;
67         }
68
69         if ($ln =~ m/^\s*typedef\s+.*\s+([_\w]\S+);/) {
70                 my $s = $1;
71                 my $n = $1;
72                 $n =~ tr/A-Z/a-z/;
73                 $n =~ tr/_/-/;
74
75                 $typedefs{$s} = $n;
76                 next;
77         }
78         if ($ln =~ m/^\s*enum\s+(\S+)\s+\{/
79             || $ln =~ m/^\s*enum\s+(\S+)$/) {
80                 my $s = $1;
81                 my $n = $1;
82                 $n =~ tr/A-Z/a-z/;
83                 $n =~ tr/_/-/;
84
85                 $enums{$s} = $n;
86
87                 $is_enum = $1;
88                 next;
89         }
90         if ($ln =~ m/^\s*struct\s+([_A-Za-z_]\S+)\s+\{/
91             || $ln =~ m/^\s*struct\s+([A-Za-z_]\S+)$/) {
92                 my $s = $1;
93                 my $n = $1;
94                 $n =~ tr/A-Z/a-z/;
95                 $n =~ tr/_/-/;
96
97                 $structs{$s} = $n;
98                 next;
99         }
100 }
101 close IN;
102
103 #
104 # Handle multi-line typedefs
105 #
106
107 my @matches = $data =~ m/typedef\s+struct\s+\S+\s*\{[^\}]+\}\s*(\S+)\s*\;/g;
108 foreach my $m (@matches) {
109                 my $s = $1;
110                 my $n = $1;
111                 $n =~ tr/A-Z/a-z/;
112                 $n =~ tr/_/-/;
113
114                 $typedefs{$s} = $n;
115         next;
116 }
117
118 #
119 # Handle exceptions, if any
120 #
121
122 if ($file_exceptions) {
123         open IN, $file_exceptions or die "Can't read $file_exceptions";
124         while (<IN>) {
125                 next if (m/^\s*$/ || m/^\s*#/);
126
127                 # Parsers to ignore a symbol
128
129                 if (m/^ignore\s+ioctl\s+(\S+)/) {
130                         delete $ioctls{$1} if (exists($ioctls{$1}));
131                         next;
132                 }
133                 if (m/^ignore\s+define\s+(\S+)/) {
134                         delete $defines{$1} if (exists($defines{$1}));
135                         next;
136                 }
137                 if (m/^ignore\s+typedef\s+(\S+)/) {
138                         delete $typedefs{$1} if (exists($typedefs{$1}));
139                         next;
140                 }
141                 if (m/^ignore\s+enum\s+(\S+)/) {
142                         delete $enums{$1} if (exists($enums{$1}));
143                         next;
144                 }
145                 if (m/^ignore\s+struct\s+(\S+)/) {
146                         delete $structs{$1} if (exists($structs{$1}));
147                         next;
148                 }
149
150                 # Parsers to replace a symbol
151
152                 if (m/^replace\s+ioctl\s+(\S+)\s+(\S+)/) {
153                         $ioctls{$1} = $2 if (exists($ioctls{$1}));
154                         next;
155                 }
156                 if (m/^replace\s+define\s+(\S+)\s+(\S+)/) {
157                         $defines{$1} = $2 if (exists($defines{$1}));
158                         next;
159                 }
160                 if (m/^replace\s+typedef\s+(\S+)\s+(\S+)/) {
161                         $typedefs{$1} = $2 if (exists($typedefs{$1}));
162                         next;
163                 }
164                 if (m/^replace\s+enum\s+(\S+)\s+(\S+)/) {
165                         $enums{$1} = $2 if (exists($enums{$1}));
166                         next;
167                 }
168                 if (m/^replace\s+symbol\s+(\S+)\s+(\S+)/) {
169                         $enum_symbols{$1} = $2 if (exists($enum_symbols{$1}));
170                         next;
171                 }
172                 if (m/^replace\s+struct\s+(\S+)\s+(\S+)/) {
173                         $structs{$1} = $2 if (exists($structs{$1}));
174                         next;
175                 }
176
177                 die "Can't parse $file_exceptions: $_";
178         }
179 }
180
181 if ($debug) {
182         print Data::Dumper->Dump([\%ioctls], [qw(*ioctls)]) if (%ioctls);
183         print Data::Dumper->Dump([\%typedefs], [qw(*typedefs)]) if (%typedefs);
184         print Data::Dumper->Dump([\%enums], [qw(*enums)]) if (%enums);
185         print Data::Dumper->Dump([\%structs], [qw(*structs)]) if (%structs);
186         print Data::Dumper->Dump([\%defines], [qw(*defines)]) if (%defines);
187         print Data::Dumper->Dump([\%enum_symbols], [qw(*enum_symbols)]) if (%enum_symbols);
188 }
189
190 #
191 # Align block
192 #
193 $data = expand($data);
194 $data = "    " . $data;
195 $data =~ s/\n/\n    /g;
196 $data =~ s/\n\s+$/\n/g;
197 $data =~ s/\n\s+\n/\n\n/g;
198
199 #
200 # Add escape codes for special characters
201 #
202 $data =~ s,([\_\`\*\<\>\&\\\\:\/]),\\$1,g;
203
204 $data =~ s,DEPRECATED,**DEPRECATED**,g;
205
206 #
207 # Add references
208 #
209
210 my $start_delim = "[ \n\t\(\=\*\@]";
211 my $end_delim = "(\\s|,|\\\\=|\\\\:|\\;|\\\)|\\}|\\{)";
212
213 foreach my $r (keys %ioctls) {
214         my $n = $ioctls{$r};
215
216         my $s = "\\ :ref:`$r <$n>`\\ ";
217
218         $r =~ s,([\_\`\*\<\>\&\\\\:\/]),\\\\$1,g;
219
220         print "$r -> $s\n" if ($debug);
221
222         $data =~ s/($start_delim)($r)$end_delim/$1$s$3/g;
223 }
224
225 foreach my $r (keys %defines) {
226         my $n = $defines{$r};
227
228         my $s = "\\ :ref:`$r <$n>`\\ ";
229
230         $r =~ s,([\_\`\*\<\>\&\\\\:\/]),\\\\$1,g;
231
232         print "$r -> $s\n" if ($debug);
233
234         $data =~ s/($start_delim)($r)$end_delim/$1$s$3/g;
235 }
236
237 foreach my $r (keys %enum_symbols) {
238         my $n = $enum_symbols{$r};
239
240         my $s = "\\ :ref:`$r <$n>`\\ ";
241
242         $r =~ s,([\_\`\*\<\>\&\\\\:\/]),\\\\$1,g;
243
244         print "$r -> $s\n" if ($debug);
245
246         $data =~ s/($start_delim)($r)$end_delim/$1$s$3/g;
247 }
248
249 foreach my $r (keys %enums) {
250         my $n = $enums{$r};
251
252         my $s = "\\ :ref:`enum $r <$n>`\\ ";
253
254         $r =~ s,([\_\`\*\<\>\&\\\\:\/]),\\\\$1,g;
255
256         print "$r -> $s\n" if ($debug);
257
258         $data =~ s/enum\s+($r)$end_delim/$s$2/g;
259 }
260
261 foreach my $r (keys %structs) {
262         my $n = $structs{$r};
263
264         my $s = "\\ :ref:`struct $r <$n>`\\ ";
265
266         $r =~ s,([\_\`\*\<\>\&\\\\:\/]),\\\\$1,g;
267
268         print "$r -> $s\n" if ($debug);
269
270         $data =~ s/struct\s+($r)$end_delim/$s$2/g;
271 }
272
273 foreach my $r (keys %typedefs) {
274         my $n = $typedefs{$r};
275
276         my $s = "\\ :ref:`$r <$n>`\\ ";
277
278         $r =~ s,([\_\`\*\<\>\&\\\\:\/]),\\\\$1,g;
279
280         print "$r -> $s\n" if ($debug);
281
282         $data =~ s/($start_delim)($r)$end_delim/$1$s$3/g;
283 }
284
285 #
286 # Generate output file
287 #
288
289 my $title = $file_in;
290 $title =~ s,.*/,,;
291
292 open OUT, "> $file_out" or die "Can't open $file_out";
293 print OUT ".. -*- coding: utf-8; mode: rst -*-\n\n";
294 print OUT "$title\n";
295 print OUT "=" x length($title);
296 print OUT "\n\n.. parsed-literal::\n\n";
297 print OUT $data;
298 close OUT;