2016-07-07 04:58:54 +03:00
#!/usr/bin/perl
use strict ;
use Text::Tabs ;
my $ debug = 0 ;
2016-08-31 12:41:40 +03:00
while ( $ ARGV [ 0 ] =~ m/^-(.*)/ ) {
my $ cmd = shift @ ARGV ;
if ( $ cmd eq "--debug" ) {
require Data::Dumper ;
$ debug = 1 ;
next ;
}
die "argument $cmd unknown" ;
}
2016-07-07 04:58:54 +03:00
if ( scalar @ ARGV < 2 || scalar @ ARGV > 3 ) {
die "Usage:\n\t$0 <file in> <file out> [<exceptions file>]\n" ;
}
my ( $ file_in , $ file_out , $ file_exceptions ) = @ ARGV ;
my $ data ;
my % ioctls ;
my % defines ;
my % typedefs ;
my % enums ;
my % enum_symbols ;
my % structs ;
#
# read the file and get identifiers
#
my $ is_enum = 0 ;
2016-07-07 20:13:12 +03:00
my $ is_comment = 0 ;
2016-07-07 04:58:54 +03:00
open IN , $ file_in or die "Can't open $file_in" ;
while ( <IN> ) {
2016-07-07 20:13:12 +03:00
$ data . = $ _ ;
2016-07-07 12:52:10 +03:00
my $ ln = $ _ ;
2016-07-07 20:13:12 +03:00
if ( ! $ is_comment ) {
$ ln =~ s , /\*.*(\*/ ) , , g ;
2016-07-07 12:52:10 +03:00
2016-07-07 20:13:12 +03:00
$ is_comment = 1 if ( $ ln =~ s , / \ * . * , , ) ;
} else {
if ( $ ln =~ s , ^ ( . * \ * / ) , , ) {
$ is_comment = 0 ;
} else {
next ;
}
}
2016-07-07 04:58:54 +03:00
2016-07-07 13:06:05 +03:00
if ( $ is_enum && $ ln =~ m/^\s*([_\w][\w\d_]+)\s*[\,=]?/ ) {
2016-07-07 04:58:54 +03:00
my $ s = $ 1 ;
my $ n = $ 1 ;
$ n =~ tr /A-Z/ a - z / ;
$ n =~ tr /_/ - / ;
2016-08-31 12:44:21 +03:00
$ enum_symbols { $ s } = "\\ :ref:`$s <$n>`\\ " ;
2016-07-07 04:58:54 +03:00
$ is_enum = 0 if ( $ is_enum && m/\}/ ) ;
next ;
}
$ is_enum = 0 if ( $ is_enum && m/\}/ ) ;
2016-07-07 13:06:05 +03:00
if ( $ ln =~ m/^\s*#\s*define\s+([_\w][\w\d_]+)\s+_IO/ ) {
2016-07-07 04:58:54 +03:00
my $ s = $ 1 ;
my $ n = $ 1 ;
$ n =~ tr /A-Z/ a - z / ;
2016-08-31 12:44:21 +03:00
$ ioctls { $ s } = "\\ :ref:`$s <$n>`\\ " ;
2016-07-07 04:58:54 +03:00
next ;
}
2016-07-07 13:06:05 +03:00
if ( $ ln =~ m/^\s*#\s*define\s+([_\w][\w\d_]+)\s+/ ) {
2016-07-07 04:58:54 +03:00
my $ s = $ 1 ;
my $ n = $ 1 ;
$ n =~ tr /A-Z/ a - z / ;
$ n =~ tr /_/ - / ;
2016-08-31 12:44:21 +03:00
$ defines { $ s } = "\\ :ref:`$s <$n>`\\ " ;
2016-07-07 04:58:54 +03:00
next ;
}
2016-08-31 12:44:21 +03:00
if ( $ ln =~ m/^\s*typedef\s+([_\w][\w\d_]+)\s+(.*)\s+([_\w][\w\d_]+);/ ) {
my $ s = $ 2 ;
my $ n = $ 3 ;
2016-07-07 04:58:54 +03:00
2016-08-31 12:44:21 +03:00
$ typedefs { $ n } = "\\ :c:type:`$n <$s>`\\ " ;
2016-07-07 04:58:54 +03:00
next ;
}
2016-07-07 13:06:05 +03:00
if ( $ ln =~ m/^\s*enum\s+([_\w][\w\d_]+)\s+\{/
2016-07-07 13:20:27 +03:00
|| $ ln =~ m/^\s*enum\s+([_\w][\w\d_]+)$/
|| $ ln =~ m/^\s*typedef\s*enum\s+([_\w][\w\d_]+)\s+\{/
|| $ ln =~ m/^\s*typedef\s*enum\s+([_\w][\w\d_]+)$/ ) {
2016-07-07 04:58:54 +03:00
my $ s = $ 1 ;
2016-08-31 12:44:21 +03:00
$ enums { $ s } = "enum :c:type:`$s`\\ " ;
2016-07-07 04:58:54 +03:00
$ is_enum = $ 1 ;
next ;
}
2016-07-07 13:06:05 +03:00
if ( $ ln =~ m/^\s*struct\s+([_\w][\w\d_]+)\s+\{/
2016-07-07 13:20:27 +03:00
|| $ ln =~ m/^\s*struct\s+([[_\w][\w\d_]+)$/
|| $ ln =~ m/^\s*typedef\s*struct\s+([_\w][\w\d_]+)\s+\{/
|| $ ln =~ m/^\s*typedef\s*struct\s+([[_\w][\w\d_]+)$/
) {
2016-07-07 04:58:54 +03:00
my $ s = $ 1 ;
2016-08-31 12:44:21 +03:00
$ structs { $ s } = "struct :c:type:`$s`\\ " ;
2016-07-07 04:58:54 +03:00
next ;
}
}
close IN ;
#
# Handle multi-line typedefs
#
2016-07-07 14:09:37 +03:00
my @ matches = ( $ data =~ m/typedef\s+struct\s+\S+?\s*\{[^\}]+\}\s*(\S+)\s*\;/g ,
$ data =~ m/typedef\s+enum\s+\S+?\s*\{[^\}]+\}\s*(\S+)\s*\;/g , ) ;
2016-07-07 04:58:54 +03:00
foreach my $ m ( @ matches ) {
2016-08-31 12:44:21 +03:00
my $ s = $ m ;
2016-07-07 04:58:54 +03:00
2016-08-31 12:44:21 +03:00
$ typedefs { $ s } = "\\ :c:type:`$s`\\ " ;
2016-07-07 04:58:54 +03:00
next ;
}
#
# Handle exceptions, if any
#
2016-08-31 12:44:21 +03:00
my % def_reftype = (
"ioctl" = > ":ref" ,
"define" = > ":ref" ,
"symbol" = > ":ref" ,
"typedef" = > ":c:type" ,
"enum" = > ":c:type" ,
"struct" = > ":c:type" ,
) ;
2016-07-07 04:58:54 +03:00
if ( $ file_exceptions ) {
open IN , $ file_exceptions or die "Can't read $file_exceptions" ;
while ( <IN> ) {
next if ( m/^\s*$/ || m/^\s*#/ ) ;
# Parsers to ignore a symbol
if ( m/^ignore\s+ioctl\s+(\S+)/ ) {
delete $ ioctls { $ 1 } if ( exists ( $ ioctls { $ 1 } ) ) ;
next ;
}
if ( m/^ignore\s+define\s+(\S+)/ ) {
delete $ defines { $ 1 } if ( exists ( $ defines { $ 1 } ) ) ;
next ;
}
if ( m/^ignore\s+typedef\s+(\S+)/ ) {
delete $ typedefs { $ 1 } if ( exists ( $ typedefs { $ 1 } ) ) ;
next ;
}
if ( m/^ignore\s+enum\s+(\S+)/ ) {
delete $ enums { $ 1 } if ( exists ( $ enums { $ 1 } ) ) ;
next ;
}
if ( m/^ignore\s+struct\s+(\S+)/ ) {
delete $ structs { $ 1 } if ( exists ( $ structs { $ 1 } ) ) ;
next ;
}
2016-07-07 20:26:51 +03:00
if ( m/^ignore\s+symbol\s+(\S+)/ ) {
delete $ enum_symbols { $ 1 } if ( exists ( $ enum_symbols { $ 1 } ) ) ;
next ;
}
2016-07-07 04:58:54 +03:00
# Parsers to replace a symbol
2016-08-31 12:44:21 +03:00
my ( $ type , $ old , $ new , $ reftype ) ;
2016-07-07 04:58:54 +03:00
2016-08-31 12:44:21 +03:00
if ( m/^replace\s+(\S+)\s+(\S+)\s+(\S+)/ ) {
$ type = $ 1 ;
$ old = $ 2 ;
$ new = $ 3 ;
} else {
die "Can't parse $file_exceptions: $_" ;
}
if ( $ new =~ m/^\:c\:(data|func|macro|type)\:\`(.+)\`/ ) {
$ reftype = ":c:$1" ;
$ new = $ 2 ;
} elsif ( $ new =~ m/\:ref\:\`(.+)\`/ ) {
$ reftype = ":ref" ;
$ new = $ 1 ;
} else {
$ reftype = $ def_reftype { $ type } ;
}
$ new = "$reftype:`$old <$new>`" ;
if ( $ type eq "ioctl" ) {
$ ioctls { $ old } = $ new if ( exists ( $ ioctls { $ old } ) ) ;
2016-07-07 04:58:54 +03:00
next ;
}
2016-08-31 12:44:21 +03:00
if ( $ type eq "define" ) {
$ defines { $ old } = $ new if ( exists ( $ defines { $ old } ) ) ;
2016-07-07 04:58:54 +03:00
next ;
}
2016-08-31 12:44:21 +03:00
if ( $ type eq "symbol" ) {
$ enum_symbols { $ old } = $ new if ( exists ( $ enum_symbols { $ old } ) ) ;
2016-07-07 04:58:54 +03:00
next ;
}
2016-08-31 12:44:21 +03:00
if ( $ type eq "typedef" ) {
$ typedefs { $ old } = $ new if ( exists ( $ typedefs { $ old } ) ) ;
2016-07-07 04:58:54 +03:00
next ;
}
2016-08-31 12:44:21 +03:00
if ( $ type eq "enum" ) {
$ enums { $ old } = $ new if ( exists ( $ enums { $ old } ) ) ;
2016-07-07 04:58:54 +03:00
next ;
}
2016-08-31 12:44:21 +03:00
if ( $ type eq "struct" ) {
$ structs { $ old } = $ new if ( exists ( $ structs { $ old } ) ) ;
2016-07-07 04:58:54 +03:00
next ;
}
die "Can't parse $file_exceptions: $_" ;
}
}
if ( $ debug ) {
print Data::Dumper - > Dump ( [ \ % ioctls ] , [ qw( *ioctls ) ] ) if ( % ioctls ) ;
print Data::Dumper - > Dump ( [ \ % typedefs ] , [ qw( *typedefs ) ] ) if ( % typedefs ) ;
print Data::Dumper - > Dump ( [ \ % enums ] , [ qw( *enums ) ] ) if ( % enums ) ;
print Data::Dumper - > Dump ( [ \ % structs ] , [ qw( *structs ) ] ) if ( % structs ) ;
print Data::Dumper - > Dump ( [ \ % defines ] , [ qw( *defines ) ] ) if ( % defines ) ;
print Data::Dumper - > Dump ( [ \ % enum_symbols ] , [ qw( *enum_symbols ) ] ) if ( % enum_symbols ) ;
}
#
# Align block
#
$ data = expand ( $ data ) ;
$ data = " " . $ data ;
$ data =~ s/\n/\n /g ;
$ data =~ s/\n\s+$/\n/g ;
$ data =~ s/\n\s+\n/\n\n/g ;
#
# Add escape codes for special characters
#
2016-08-16 19:25:41 +03:00
$ data =~ s , ( [ \ _ \ ` \ * \ <\> \ & \ \ \ \ : \ / \ | \ % \ $ \ # \ { \ } \ ~ \ ^ ] ) , \ \ $ 1 , g ;
2016-07-07 04:58:54 +03:00
2016-07-07 12:31:21 +03:00
$ data =~ s , DEPRECATED , ** DEPRECATED ** , g ;
2016-07-07 04:58:54 +03:00
#
# Add references
#
2016-07-07 12:27:54 +03:00
my $ start_delim = "[ \n\t\(\=\*\@]" ;
my $ end_delim = "(\\s|,|\\\\=|\\\\:|\\;|\\\)|\\}|\\{)" ;
2016-07-07 04:58:54 +03:00
foreach my $ r ( keys % ioctls ) {
2016-08-31 12:44:21 +03:00
my $ s = $ ioctls { $ r } ;
2016-07-07 04:58:54 +03:00
$ r =~ s , ( [ \ _ \ ` \ * \ <\> \ & \ \ \ \ : \ / ] ) , \ \ \ \ $ 1 , g ;
print "$r -> $s\n" if ( $ debug ) ;
2016-07-07 12:27:54 +03:00
$ data =~ s/($start_delim)($r)$end_delim/$1$s$3/g ;
2016-07-07 04:58:54 +03:00
}
foreach my $ r ( keys % defines ) {
2016-08-31 12:44:21 +03:00
my $ s = $ defines { $ r } ;
2016-07-07 04:58:54 +03:00
$ r =~ s , ( [ \ _ \ ` \ * \ <\> \ & \ \ \ \ : \ / ] ) , \ \ \ \ $ 1 , g ;
print "$r -> $s\n" if ( $ debug ) ;
2016-07-07 12:27:54 +03:00
$ data =~ s/($start_delim)($r)$end_delim/$1$s$3/g ;
2016-07-07 04:58:54 +03:00
}
foreach my $ r ( keys % enum_symbols ) {
2016-08-31 12:44:21 +03:00
my $ s = $ enum_symbols { $ r } ;
2016-07-07 04:58:54 +03:00
$ r =~ s , ( [ \ _ \ ` \ * \ <\> \ & \ \ \ \ : \ / ] ) , \ \ \ \ $ 1 , g ;
print "$r -> $s\n" if ( $ debug ) ;
2016-07-07 12:27:54 +03:00
$ data =~ s/($start_delim)($r)$end_delim/$1$s$3/g ;
2016-07-07 04:58:54 +03:00
}
foreach my $ r ( keys % enums ) {
2016-08-31 12:44:21 +03:00
my $ s = $ enums { $ r } ;
2016-07-07 04:58:54 +03:00
$ r =~ s , ( [ \ _ \ ` \ * \ <\> \ & \ \ \ \ : \ / ] ) , \ \ \ \ $ 1 , g ;
print "$r -> $s\n" if ( $ debug ) ;
2016-07-07 12:27:54 +03:00
$ data =~ s/enum\s+($r)$end_delim/$s$2/g ;
2016-07-07 04:58:54 +03:00
}
foreach my $ r ( keys % structs ) {
2016-08-31 12:44:21 +03:00
my $ s = $ structs { $ r } ;
2016-07-07 04:58:54 +03:00
$ r =~ s , ( [ \ _ \ ` \ * \ <\> \ & \ \ \ \ : \ / ] ) , \ \ \ \ $ 1 , g ;
print "$r -> $s\n" if ( $ debug ) ;
2016-07-07 12:27:54 +03:00
$ data =~ s/struct\s+($r)$end_delim/$s$2/g ;
2016-07-07 04:58:54 +03:00
}
foreach my $ r ( keys % typedefs ) {
2016-08-31 12:44:21 +03:00
my $ s = $ typedefs { $ r } ;
2016-07-07 04:58:54 +03:00
$ r =~ s , ( [ \ _ \ ` \ * \ <\> \ & \ \ \ \ : \ / ] ) , \ \ \ \ $ 1 , g ;
print "$r -> $s\n" if ( $ debug ) ;
2016-07-07 12:27:54 +03:00
$ data =~ s/($start_delim)($r)$end_delim/$1$s$3/g ;
2016-07-07 04:58:54 +03:00
}
2016-08-31 12:44:21 +03:00
$ data =~ s/\\ ([\n\s])/\1/g ;
2016-07-09 15:35:34 +03:00
2016-07-07 04:58:54 +03:00
#
# Generate output file
#
my $ title = $ file_in ;
$ title =~ s , . * / , , ;
open OUT , "> $file_out" or die "Can't open $file_out" ;
print OUT ".. -*- coding: utf-8; mode: rst -*-\n\n" ;
print OUT "$title\n" ;
print OUT "=" x length ( $ title ) ;
print OUT "\n\n.. parsed-literal::\n\n" ;
print OUT $ data ;
close OUT ;