📄 typemap.pm
字号:
# Copyright 2001-2005 The Apache Software Foundation## Licensed under the Apache License, Version 2.0 (the "License");# you may not use this file except in compliance with the License.# You may obtain a copy of the License at## http://www.apache.org/licenses/LICENSE-2.0## Unless required by applicable law or agreed to in writing, software# distributed under the License is distributed on an "AS IS" BASIS,# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.# See the License for the specific language governing permissions and# limitations under the License.#package ModPerl::TypeMap;use strict;use warnings FATAL => 'all';use ModPerl::FunctionMap ();use ModPerl::StructureMap ();use ModPerl::MapUtil qw(list_first);our @ISA = qw(ModPerl::MapBase);sub new { my $class = shift; my $self = bless { INCLUDE => [], struct => [], typedef => [], }, $class; $self->{function_map} = ModPerl::FunctionMap->new, $self->{structure_map} = ModPerl::StructureMap->new, $self->get; $self;}my %special = map { $_, 1 } qw(UNDEFINED NOTIMPL CALLBACK);sub special { my ($self, $class) = @_; return $special{$class};}sub function_map { shift->{function_map}->get }sub structure_map { shift->{structure_map}->get }sub parse { my ($self, $fh, $map) = @_; while ($fh->readline) { if (/E=/) { my %args = $self->parse_keywords($_); while (my ($key,$val) = each %args) { push @{ $self->{$key} }, $val; } next; } my @aliases; my ($type, $class) = (split /\s*\|\s*/, $_)[0,1]; $class ||= 'UNDEFINED'; if ($type =~ s/^(struct|typedef)\s+(.*)/$2/) { my $typemap = $1; push @aliases, $type; if ($typemap eq 'struct') { push @aliases, "const $type", "$type *", "const $type *", "struct $type *", "const struct $type *", "$type **"; } my $cname = $class; if ($cname =~ s/::/__/g) { push @{ $self->{$typemap} }, [$type, $cname]; } } elsif ($type =~ /_t$/) { push @aliases, $type, "$type *", "const $type *"; } else { push @aliases, $type; } for (@aliases) { $map->{$_} = $class; } }}sub get { my $self = shift; $self->{map} ||= $self->parse_map_files;}my $ignore = join '|', qw{ap_LINK ap_HOOK _ UINT union._union.block_hdr cleanup process_chainiovec struct.rlimit Sigfunc in_addr_t};sub should_ignore { my ($self, $type) = @_; return 1 if $type =~ /^($ignore)/o;}sub is_callback { my ($self, $type) = @_; return 1 if $type =~ /\(/ and $type =~ /\)/; #XXX: callback}sub exists { my ($self, $type) = @_; return 1 if $self->is_callback($type) || $self->should_ignore($type); $type =~ s/\[\d+\]$//; #char foo[64] return exists $self->get->{$type};}sub map_type { my ($self, $type) = @_; my $class = $self->get->{$type}; return unless $class and ! $self->special($class);# return if $type =~ /\*\*$/; #XXX if ($class =~ /::/) { return $class; } else { return $type; }}sub null_type { my ($self, $type) = @_; my $class = $self->get->{$type}; if ($class =~ /^[INU]V/) { return '0'; } else { return 'NULL'; }}sub can_map { my $self = shift; my $map = shift; return 1 if $map->{argspec}; for (@_) { return (0, $_) unless $self->map_type($_); } return 1;}sub map_arg { my ($self, $arg) = @_; my $map_type = $self->map_type($arg->{type}); die "unknown typemap: '$arg->{type}'" unless defined $map_type; return { name => $arg->{name}, default => $arg->{default}, type => $map_type, rtype => $arg->{type}, }}sub map_args { my ($self, $func) = @_; my $entry = $self->function_map->{ $func->{name} }; my $argspec = $entry->{argspec}; my $args = []; if ($argspec) { $entry->{orig_args} = [ map $_->{name}, @{ $func->{args} } ]; for my $arg (@$argspec) { my $default; ($arg, $default) = split /=/, $arg, 2; my ($type, $name) = split ':', $arg, 2; if ($type and $name) { push @$args, { name => $name, type => $type, default => $default, }; } else { my $e = list_first { $_->{name} eq $arg } @{ $func->{args} }; if ($e) { push @$args, { %$e, default => $default }; } elsif ($arg eq '...') { push @$args, { name => '...', type => 'SV *' }; } else { warn "bad argspec: $func->{name} ($arg)\n"; } } } } else { $args = $func->{args}; } return [ map $self->map_arg($_), @$args ]}#this is needed for modperl-only functions#unlike apache/apr functions which are remapped to a mpxs_ functionsub thx_fixup { my ($self, $func) = @_; my $first = $func->{args}->[0]; return unless $first; if ($first->{type} =~ /PerlInterpreter/) { shift @{ $func->{args} }; $func->{thx} = 1; }}sub map_function { my ($self, $func) = @_; my $map = $self->function_map->{ $func->{name} }; return unless $map; $self->thx_fixup($func); my ($status, $failed_type) = $self->can_map($map, $func->{return_type}, map $_->{type}, @{ $func->{args} }); unless ($status) { warn "unknown typemap: '$failed_type' (skipping $func->{name})\n"; return; } my $type = $map->{return_type} || $func->{return_type} || 'void'; my $map_type = $self->map_type($type); die "unknown typemap: '$type'" unless defined $map_type; my $mf = { name => $func->{name}, return_type => $map_type, args => $self->map_args($func), perl_name => $map->{name}, thx => $func->{thx}, }; for (qw(dispatch argspec orig_args prefix)) { $mf->{$_} = $map->{$_}; } unless ($mf->{class}) { $mf->{class} = $map->{class} || $self->first_class($mf); #print "GUESS class=$mf->{class} for $mf->{name}\n"; } $mf->{prefix} ||= ModPerl::FunctionMap::guess_prefix($mf); $mf->{module} = $map->{module} || $mf->{class}; $mf;}sub map_structure { my ($self, $struct) = @_; my ($class, @elts); my $stype = $struct->{type}; return unless $class = $self->map_type($stype); for my $e (@{ $struct->{elts} }) { my ($name, $type) = ($e->{name}, $e->{type}); my $rtype; # ro/rw/r+w_startup/undef(disabled) my $access_mode = $self->structure_map->{$stype}->{$name}; next unless $access_mode; next unless $rtype = $self->map_type($type); push @elts, { name => $name, type => $rtype, default => $self->null_type($type), pool => $self->class_pool($class), class => $self->{map}->{$type} || "", access_mode => $access_mode, }; } return { module => $self->{structure_map}->{MODULES}->{$stype} || $class, class => $class, type => $stype, elts => \@elts, };}sub destructor { my ($self, $prefix) = @_; $self->function_map->{$prefix . 'DESTROY'};}sub first_class { my ($self, $func) = @_; for my $e (@{ $func->{args} }) { next unless $e->{type} =~ /::/; #there are alot of util functions that take an APR::Pool #that do not belong in the APR::Pool class next if $e->{type} eq 'APR::Pool' and $func->{name} !~ /^apr_pool/; return $e->{type}; } return $func->{name} =~ /^apr_/ ? 'APR' : 'Apache2';}sub check { my $self = shift; my (@types, @missing, %seen); require Apache2::StructureTable; for my $entry (@$Apache2::StructureTable) { push @types, map $_->{type}, @{ $entry->{elts} }; } for my $entry (@$Apache2::FunctionTable) { push @types, grep { not $seen{$_}++ } ($entry->{return_type}, map $_->{type}, @{ $entry->{args} }) } #printf "%d types\n", scalar @types; for my $type (@types) { push @missing, $type unless $self->exists($type); } return @missing ? \@missing : undef;}#look for Apache/APR structures that do not exist in structure.mapmy %ignore_check = map { $_,1 } qw{module_struct cmd_how kill_conditionsregex_t regmatch_t pthread_mutex_tunsigned void va_list ... iovec char int long constgid_t uid_t time_t pid_t size_tsockaddr hostentSV};sub check_exists { my $self = shift; my %structures = map { $_->{type}, 1 } @{ $self->structure_table() }; my @missing = (); my %seen; for my $name (keys %{ $self->{map} }) { 1 while $name =~ s/^\w+\s+(\w+)/$1/; $name =~ s/\s+\**.*$//; next if $seen{$name}++ or $structures{$name} or $ignore_check{$name}; push @missing, $name; } return @missing ? \@missing : undef;}#XXX: generate thismy %class_pools = map { (my $f = "mpxs_${_}_pool") =~ s/:/_/g; $_, $f;} qw{ Apache2::RequestRec Apache2::Connection Apache2::URI APR::URI};sub class_pool : lvalue { my ($self, $class) = @_; $class_pools{$class};}#anything needed that mod_perl.h does not already include#XXX: .maps should INCLUDE= thesemy @includes = qw{apr_uuid.hapr_sha1.hapr_md5.hapr_base64.hapr_getopt.hapr_hash.hapr_lib.hapr_general.hapr_signal.hutil_script.h};sub h_wrap { my ($self, $file, $code) = @_; $file = 'modperl_xs_' . $file; my $h_def = uc "${file}_h"; my $preamble = "\#ifndef $h_def\n\#define $h_def\n\n"; my $postamble = "\n\#endif /* $h_def */\n"; return ("$file.h", $preamble . $code . $postamble);}sub typedefs_code { my $self = shift; my $map = $self->get; my %seen; my $file = 'modperl_xs_typedefs'; my $h_def = uc "${file}_h"; my $code = ""; for (@includes, @{ $self->{INCLUDE} }) { $code .= qq{\#include "$_"\n} } for my $t (@{ $self->{struct} }) { next if $seen{ $t->[1] }++; $code .= "typedef $t->[0] * $t->[1];\n"; } for my $t (@{ $self->{typedef} }) { next if $seen{ $t->[1] }++; $code .= "typedef $t->[0] $t->[1];\n"; } $self->h_wrap('typedefs', $code);}my %convert_alias = ( Apache2__RequestRec => 'r', Apache2__Server => 'server', Apache2__Connection => 'connection', APR__Table => 'table', APR__UUID => 'uuid', apr_status_t => 'status',);sub sv_convert_code { my $self = shift; my $map = $self->get; my %seen; my $code = ""; while (my ($ctype, $ptype) = each %$map) { next if $self->special($ptype); next if $ctype =~ /\s/; my $class = $ptype; if ($ptype =~ s/:/_/g) { next if $seen{$ptype}++; my $alias; my $expect = "expecting an $class derived object"; my $croak = "argument is not a blessed reference"; #Perl -> C my $define = "mp_xs_sv2_$ptype"; $code .= <<EOF;#define $define(sv) \\((SvROK(sv) && (SvTYPE(SvRV(sv)) == SVt_PVMG)) \\|| (Perl_croak(aTHX_ "$croak ($expect)"),0) ? \\INT2PTR($ctype *, SvIV((SV*)SvRV(sv))) : ($ctype *)NULL)EOF if ($alias = $convert_alias{$ptype}) { $code .= "#define mp_xs_sv2_$alias $define\n\n"; } #C -> Perl $define = "mp_xs_${ptype}_2obj"; $code .= <<EOF;#define $define(ptr) \\sv_setref_pv(sv_newmortal(), "$class", (void*)ptr)EOF if ($alias) { $code .= "#define mp_xs_${alias}_2obj $define\n\n"; } } else { if ($ptype =~ /^(\wV)$/) { my $class = $1; my $define = "mp_xs_sv2_$ctype"; $code .= "#define $define(sv) ($ctype)Sv$class(sv)\n\n"; if (my $alias = $convert_alias{$ctype}) { $code .= "#define mp_xs_sv2_$alias $define\n\n"; } } } } $self->h_wrap('sv_convert', $code);}1;__END__
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -