parse-headers.pl 6.7 KB

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