1 | #!/usr/bin/perl |
---|
2 | |
---|
3 | use strict; |
---|
4 | use warnings; |
---|
5 | |
---|
6 | my $ARBHOME = $ENV{ARBHOME}; |
---|
7 | defined $ARBHOME || die "Expected environment variable ARBHOME to be defined"; |
---|
8 | -d $ARBHOME || die "Expected directory '$ARBHOME' (from environment variable ARBHOME)"; |
---|
9 | |
---|
10 | my $ARBPERLDIR = $ARBHOME.'/PERL2ARB'; |
---|
11 | -d $ARBPERLDIR || die "Expected directory '$ARBPERLDIR'"; |
---|
12 | |
---|
13 | my %method = (); # ARB::name or BIO::name (value=1) |
---|
14 | my %name = (); # key = method, value = name only |
---|
15 | |
---|
16 | sub parsePerlMethods() { |
---|
17 | my $arb_c = $ARBPERLDIR.'/ARB.c'; |
---|
18 | open(CSRC, '<'.$arb_c) || die "failed to read '$arb_c' (Reason: $!)"; |
---|
19 | |
---|
20 | my $line; |
---|
21 | my $reg = qr/(newXSproto|newXSproto_portable).*\"(ARB|BIO)::([a-zA-Z0-9_]+)\"/o; |
---|
22 | while (defined($line=<CSRC>)) { |
---|
23 | if ($line =~ $reg) { |
---|
24 | my ($package,$name) = ($2,$3); |
---|
25 | my $method = $package.'::'.$name; |
---|
26 | if (exists $method{$method}) { |
---|
27 | die "duplicated method '$method'"; |
---|
28 | } |
---|
29 | $method{$method} = 1; |
---|
30 | $name{$method} = $name; |
---|
31 | } |
---|
32 | } |
---|
33 | |
---|
34 | close(CSRC); |
---|
35 | if (scalar(keys %method)<1) { |
---|
36 | die "No 'ARB perl interface'-functions detected in '$arb_c' (parsing error?)"; |
---|
37 | } |
---|
38 | } |
---|
39 | |
---|
40 | my %prototype = (); # key = c++ method name, value=full prototype OR 0 (if duplicated) |
---|
41 | my %file = (); # key = method name, value=filename OR undef (if duplicated) |
---|
42 | |
---|
43 | sub parsePrototypes() { |
---|
44 | my $proto_h = $ARBPERLDIR.'/proto.h'; |
---|
45 | open(PROTO, '<'.$proto_h) || die "failed to read '$proto_h' (Reason: $!)"; |
---|
46 | |
---|
47 | my $line; |
---|
48 | my $reg_file_start = qr/\/\*\s*([^\s]+)\s*\*\//o; |
---|
49 | my $reg_prototype = qr/([a-zA-Z0-9_]+)\(/o; |
---|
50 | |
---|
51 | my $current_file = undef; |
---|
52 | |
---|
53 | while (defined($line=<PROTO>)) { |
---|
54 | if ($line =~ $reg_prototype) { |
---|
55 | my $name = $1; |
---|
56 | chomp($line); |
---|
57 | if (exists $prototype{$name}) { |
---|
58 | $prototype{$name} = 0; # duplicated function name |
---|
59 | $file{$name} = undef; |
---|
60 | } |
---|
61 | else { |
---|
62 | $prototype{$name} = $line; |
---|
63 | $file{$name} = $current_file; |
---|
64 | } |
---|
65 | } |
---|
66 | elsif ($line =~ $reg_file_start) { |
---|
67 | my ($file) = $1; |
---|
68 | if ($file =~ /\.cxx$/o) { $current_file = $file; } |
---|
69 | # else { print "ignored file '$file'\n"; } |
---|
70 | } |
---|
71 | } |
---|
72 | |
---|
73 | close(PROTO); |
---|
74 | if (scalar(keys %prototype)<1) { |
---|
75 | die "No 'ARB perl interface'-functions detected in '$proto_h' (parsing error?)"; |
---|
76 | } |
---|
77 | |
---|
78 | # hardcoded methods: |
---|
79 | $prototype{GB_await_error} = 'GB_ERROR GB_await_error(void);'; |
---|
80 | $file{GB_await_error} = '../CORE/arb_msg.cxx'; |
---|
81 | |
---|
82 | $prototype{GBP_prepare_to_die} = 'void GBP_prepare_to_die()'; |
---|
83 | $file{GBP_prepare_to_die} = 'adperl.cxx'; |
---|
84 | } |
---|
85 | |
---|
86 | my %cpp_method = (); # key = perl method (full), value=C++ method |
---|
87 | |
---|
88 | sub linkMethods() { |
---|
89 | my $reg_cpp_method = qr/^([^_]+)_(.*)$/o; |
---|
90 | |
---|
91 | # see also ../PERLTOOLS/arb_proto_2_xsub.cxx@PREFIX_HANDLING |
---|
92 | my %ppackage = |
---|
93 | ( |
---|
94 | 'GB' => 'ARB', |
---|
95 | 'GBP' => 'ARB', |
---|
96 | 'GBT' => 'BIO', |
---|
97 | 'GEN' => 'BIO', |
---|
98 | ); |
---|
99 | |
---|
100 | foreach my $cpp_method (sort keys %prototype) { |
---|
101 | if ($cpp_method =~ $reg_cpp_method) { |
---|
102 | my ($prefix,$name) = ($1,$2); |
---|
103 | my $package = $ppackage{$prefix}; |
---|
104 | if (defined $package) { |
---|
105 | my $perl_method = $package.'::'.$name; |
---|
106 | if (exists $method{$perl_method}) { |
---|
107 | if (exists $cpp_method{$perl_method}) { |
---|
108 | die "ambiguous function suffix matches for '$perl_method': $cpp_method and ".$cpp_method{$perl_method}; |
---|
109 | } |
---|
110 | $cpp_method{$perl_method} = $cpp_method; |
---|
111 | } |
---|
112 | # else { print STDERR "Note: Found no perl-method for prototype '$cpp_method'\n"; } # shows unused prototypes |
---|
113 | } |
---|
114 | # else { print STDERR "Note: no package defined for prefix '$prefix' (cpp_method=$cpp_method)\n"; } |
---|
115 | } |
---|
116 | else { |
---|
117 | die "cannot parse method name: '$cpp_method'"; |
---|
118 | } |
---|
119 | } |
---|
120 | |
---|
121 | foreach my $perl_method (sort keys %method) { |
---|
122 | if (not exists $cpp_method{$perl_method}) { |
---|
123 | die "failed to detect c++-function for '$perl_method'"; |
---|
124 | # print "Error: failed to detect c++-function for '$perl_method'\n"; |
---|
125 | } |
---|
126 | } |
---|
127 | } |
---|
128 | |
---|
129 | my $HEADER = <<'END_HEADER'; |
---|
130 | # |
---|
131 | # The list below contains information about the functions provided by the arb PERL interface. |
---|
132 | # |
---|
133 | # The columns contain the following information: |
---|
134 | # - function name (used to sort; not unique), |
---|
135 | # - fully qualified name of perl function (unique), |
---|
136 | # - name of C++ function and |
---|
137 | # - name of C++ file where function is located. |
---|
138 | # |
---|
139 | # The list is automatically updated while arb is build. |
---|
140 | # |
---|
141 | # To find specific information for single C++ functions, refer to |
---|
142 | # http://dev.arb-home.de/source_doc/globals_func_g.html#index_g |
---|
143 | # look there for the C++ function name (3rd column below) and |
---|
144 | # click on one of the links behind the name. |
---|
145 | # |
---|
146 | # If no documentation is shown then, please also click on the line number at |
---|
147 | # "Definition at line ### of file MODULE.cxx." |
---|
148 | # to look into the source code, which may contain documenting comments. |
---|
149 | # |
---|
150 | END_HEADER |
---|
151 | |
---|
152 | sub dumpMethods() { |
---|
153 | my @sorted_method = sort { |
---|
154 | my $cmp = $name{$a} cmp $name{$b}; |
---|
155 | if ($cmp == 0) { |
---|
156 | $cmp = $a cmp $b; |
---|
157 | } |
---|
158 | $cmp; |
---|
159 | } keys %method; |
---|
160 | |
---|
161 | my $name_width = 47; |
---|
162 | my $full_width = $name_width + 5; |
---|
163 | my $cpp_width = $name_width + 3 + 1; |
---|
164 | |
---|
165 | print $HEADER; |
---|
166 | |
---|
167 | foreach my $perl_method (@sorted_method) { |
---|
168 | my $name = $name{$perl_method}; |
---|
169 | my $name_length = length($name); |
---|
170 | if ($name_length > $name_width) { die "bad formatting: name_width < $name_length"; } |
---|
171 | |
---|
172 | my $cpp = $cpp_method{$perl_method}; |
---|
173 | my $cpp_length = length($cpp); |
---|
174 | if ($cpp_length > $cpp_width) { die "bad formatting: cpp_width < $cpp_length"; } |
---|
175 | |
---|
176 | my $file = $file{$cpp}; |
---|
177 | |
---|
178 | if (not defined $file) { |
---|
179 | die "Error: ambiguous function definition for '$cpp' (overloaded method exported to perl?)\n"; |
---|
180 | } |
---|
181 | else { |
---|
182 | print sprintf('%-'.$name_width.'s %-'.$full_width.'s %-'.$cpp_width.'s %s'."\n", $name, $perl_method, $cpp, $file); |
---|
183 | } |
---|
184 | } |
---|
185 | } |
---|
186 | |
---|
187 | sub main() { |
---|
188 | parsePerlMethods(); |
---|
189 | parsePrototypes(); |
---|
190 | linkMethods(); |
---|
191 | |
---|
192 | dumpMethods(); |
---|
193 | } |
---|
194 | |
---|
195 | main(); |
---|