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