| 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(); |
|---|