File Coverage

blib/lib/ExtUtils/DynaGlue.pm
Criterion Covered Total %
statement 16 30 53.3
branch 0 4 0.0
condition 0 5 0.0
subroutine 6 8 75.0
pod n/a
total 22 47 46.8


line stmt bran cond sub pod time code
1             package ExtUtils::DynaGlue;
2              
3 1     1   800 use strict;
  1         1  
  1         33  
4 1     1   5 use vars qw($VERSION @xs_sections @pm_sections);
  1         1  
  1         57  
5              
6 1     1   860 use IO::File ();
  1         13382  
  1         26  
7 1     1   8 use Config;
  1         1  
  1         563  
8              
9             #$Id: DynaGlue.pm,v 1.10 1996/11/27 19:31:16 dougm Exp $
10             $VERSION = (qw$Revision: 1.10 $)[1] . "a";
11              
12             sub new {
13 0     0     my $class = shift;
14 0 0         my $self = bless {
15             TEMPLATE_VERSION => '0.01',
16             EXT => (-d 'ext' ? 'ext/' : '') ,
17             AUTHOR => _author(),
18             EMAIL => _email(),
19             PREFIX => undef,
20             CONST_XSUBS => undef,
21             CONST_XSUBS_HASH => {},
22             CONST_NAMES => [],
23             PREFIX_NAMES => {},
24             XS_SECTIONS => [],
25             PM_SECTIONS => [],
26             NAME => "",
27             FULLPATH => undef,
28             FLAGS => undef,
29             PATH_H => undef,
30             SCAN => {
31             },
32             DO_SCAN => 0,
33             @_,
34             } => $class;
35              
36 0 0         $self->path_h($self->{PATH_H}, $self->{DO_SCAN})
37             if $self->{PATH_H};
38 0   0       $self->name($self->{NAME} || $self->{PATH_H});
39 0           $self->module($self->name);
40 0           $self->modparts($self->name);
41 0           $self;
42             }
43              
44             sub _author {
45 0   0 0     my $name = (getpwuid($>))[6] || $ENV{NAME} || "A. U. Thor";
46 0           $name =~ s/,.*//;
47 0           while($name =~ s/\([^\(]*\)//) { 1; }
  0            
48 0           $name;
49             }
50              
51             {
52 1     1   5 no strict;
  1         2  
  1         43  
53 1     1   2033 eval { use Mail::Util qw(mailaddress); };
  0            
  0            
54             *mailaddress = sub {'a.u.thor@a.galaxy.far.far.away'} if $@;
55             }
56              
57             sub _email {
58             return mailaddress();
59             }
60              
61             sub author { shift->_elem('AUTHOR', @_) }
62             sub email { shift->_elem('EMAIL', @_) }
63             sub do_scan { shift->_elem('DO_SCAN', @_) }
64             sub no_xs { shift->_elem('NO_XS', @_) }
65             sub no_const { shift->_elem('NO_CONST', @_) }
66             sub no_auto { shift->_elem('NO_AUTO', @_) }
67             sub no_pod { shift->_elem('NO_POD', @_) }
68             sub module { shift->_elem('MODULE', @_) }
69             sub prefix { shift->_elem('PREFIX', @_) }
70             sub modfname { shift->_elem('modfname', @_) }
71             sub fullpath { shift->_elem('FULLPATH', @_) }
72             sub flags { shift->_elem('FLAGS', @_) }
73             sub extralibs { shift->_elem('EXTRALIBS', @_) }
74             sub ext { shift->_elem('EXT', @_) }
75             sub template_version { shift->_elem('TEMPLATE_VERSION', $_[0] || '0.01') }
76              
77             sub const_xsubs {
78             my $self = shift;
79             my $subs = $_[0] || $self->{CONST_XSUBS};
80             if($subs) {
81             unless(ref $subs) {
82             $subs = [split /,+/, $subs];
83             }
84             $self->{CONST_XSUBS_HASH} = { map {$_,1} @$subs };
85             }
86             $self->{CONST_XSUBS_HASH};
87             }
88              
89             sub path_h {
90             my $self = shift;
91             my($path_h, $do_scan) = @_;
92             $do_scan ||= $self->{DO_SCAN};
93             my(@idx) = ('PATH_H');
94             push @idx, 'FULLPATH' if wantarray;
95             return (@{$self}{@idx}) unless $path_h;
96             $path_h .= ".h" unless $path_h =~ /\.h$/;
97              
98             my $fullpath = $path_h;
99             $path_h =~ s/,.*$// if $do_scan;
100             if ($^O eq 'VMS') { # Consider overrides of default location
101             if ($path_h !~ m![:>\[]!) {
102             my($hadsys) = ($path_h =~ s!^sys/!!i);
103             if ($ENV{'DECC$System_Include'}) { $path_h = "DECC\$System_Include:$path_h"; }
104             elsif ($ENV{'DECC$Library_Include'}) { $path_h = "DECC\$Library_Include:$path_h"; }
105             elsif ($ENV{'GNU_CC_Include'}) { $path_h = 'GNU_CC_Include:' .
106             ($hadsys ? '[vms]' : '[000000]') . $path_h; }
107             elsif ($ENV{'VAXC$Include'}) { $path_h = "VAXC\$_Include:$path_h"; }
108             else { $path_h = "Sys\$Library:$path_h"; }
109             }
110             }
111             elsif ($^O eq 'os2') {
112             $path_h = "/usr/include/$path_h"
113             if $path_h !~ m#^([a-z]:)?[./]#i and -r "/usr/include/$path_h";
114             }
115             else {
116             $path_h = "/usr/include/$path_h"
117             if $path_h !~ m#^[./]# and -r "/usr/include/$path_h";
118             }
119             $self->{PATH_H} = $path_h;
120             $self->{FULLPATH} = $fullpath;
121             return(@{$self}{@idx});
122             }
123              
124             sub constants {
125             my($self, $path_h, $opt_p) = @_;
126             unless($self->{SCANNED}++) {
127             $path_h ||= $self->path_h;
128             }
129             return($self->{CONST_NAMES}, $self->{PREFIX_NAMES}) unless $path_h;
130             $opt_p ||= $self->prefix;
131             my(%const_names, %prefix);
132             # Scan the header file (we should deal with nested header files)
133             # Record the names of simple #define constants into const_names
134             # Function prototypes are not (currently) processed.
135             local *CH;
136             open(CH, "<$path_h") || die "Can't open $path_h: $!\n";
137              
138             local($/) = "\n";
139             while () {
140             if (/^#[ \t]*define\s+([\$\w]+)\b\s*[^("]/) {
141             #print "Matched $_ ($1)\n" if $opt_d;
142             $_ = $1;
143             next if /^_.*_h_*$/i; # special case, but for what?
144             if (defined $opt_p) {
145             if (!/^$opt_p(\d)/) {
146             ++$self->{PREFIX_NAMES}{$_} if s/^$opt_p//;
147             }
148             else {
149             warn "can't remove $opt_p prefix from '$_'!\n";
150             }
151             }
152             $const_names{$_}++;
153             }
154             }
155             close(CH);
156             $self->{CONST_NAMES} = [sort keys %const_names];
157              
158             return($self->{CONST_NAMES}, $self->{PREFIX_NAMES});
159             }
160              
161             sub name {
162             my($self, $name) = @_;
163             return $self->{NAME} unless $name;
164             $name =~ s/\.h$//;
165             if( $name !~ /::/ ){
166             $name =~ s#^.*/##;
167             $name = "\u$name";
168             }
169             $self->{NAME} = $name;
170             }
171              
172             sub modparts {
173             my($self, $module) = @_;
174             $module ||= $self->module;
175             my($nested, @modparts, $modfname, $modpname);
176             if( $module =~ /::/ ){
177             $nested = 1;
178             @modparts = split(/::/,$module);
179             $modfname = $modparts[-1];
180             $modpname = join('/',@modparts);
181             }
182             else {
183             $nested = 0;
184             @modparts = ();
185             $modfname = $modpname = $module;
186             }
187             @{$self}{qw(modfname modpname modparts)} =
188             ($modfname, $modpname, [@modparts]);
189             }
190              
191             sub mkdirs {
192             my($self, $modpname, $modparts) = @_;
193             if( scalar @$modparts ){
194             my $modpath = "";
195             foreach (@$modparts){
196             mkdir("$modpath$_", 0777);
197             $modpath .= "$_/";
198             }
199             }
200             mkdir($modpname, 0777);
201             }
202              
203             sub function_scan {
204             my($self, $fullpath, $addflags) = @_;
205             return($self->fdecls, $self->parsed_fdecls) unless $fullpath;
206             require C::Scan; # Run-time directive
207             require Config; # Run-time directive
208             #warn "Scanning typemaps...\n";
209             $self->get_typemap();
210             my $c;
211             my $filter;
212             my $filename = $self->path_h;
213             $addflags ||= '';
214             if ($fullpath =~ /,/) {
215             $filename = $`;
216             $filter = $';
217             }
218             #warn "Scanning $filename for functions...\n";
219             my $c = new C::Scan 'filename' => $filename, 'filename_filter' => $filter,
220             'add_cppflags' => $addflags;
221             $c->set('includeDirs' => ["$Config::Config{archlib}/CORE"]);
222            
223             ($self->{SCAN}{fdecls}, $self->{SCAN}{parsed_fdecls}) =
224             ($c->get('fdecls'), $c->get('parsed_fdecls'));
225             }
226              
227             sub fdecls { $_[0]->{SCAN}{fdecls} }
228             sub parsed_fdecls { $_[0]->{SCAN}{parsed_fdecls} }
229              
230             # Should be called before any actual call to normalize_type().
231             sub get_typemap {
232             my($self) = @_;
233             $self->{SCAN}{std_types} = {};
234             $self->{SCAN}{types_seen} = {};
235             # We do not want to read ./typemap by obvios reasons.
236             my @tm = qw(../../../typemap ../../typemap ../typemap);
237             my $stdtypemap = "$Config::Config{privlib}/ExtUtils/typemap";
238             unshift @tm, $stdtypemap;
239             my $proto_re = "[" . quotemeta('\$%&*@;') . "]" ;
240             my($image, $typemap, $type);
241             local *TYPEMAP;
242              
243             foreach $typemap (@tm) {
244             next unless -e $typemap ;
245             # skip directories, binary files etc.
246             warn " Scanning $typemap\n";
247             warn("Warning: ignoring non-text typemap file '$typemap'\n"), next
248             unless -T $typemap ;
249             open(TYPEMAP, $typemap)
250             or warn ("Warning: could not open typemap file '$typemap': $!\n"), next;
251             my $mode = 'Typemap';
252             while () {
253             next if /^\s*\#/;
254             if (/^INPUT\s*$/) { $mode = 'Input'; next; }
255             elsif (/^OUTPUT\s*$/) { $mode = 'Output'; next; }
256             elsif (/^TYPEMAP\s*$/) { $mode = 'Typemap'; next; }
257             elsif ($mode eq 'Typemap') {
258             next if /^\s*($|\#)/ ;
259             if ( ($type, $image) =
260             /^\s*(.*?\S)\s+(\S+)\s*($proto_re*)\s*$/o
261             # This may reference undefined functions:
262             and not ($image eq 'T_PACKED' and $typemap eq $stdtypemap)) {
263             $self->normalize_type($type);
264             }
265             }
266             }
267             close(TYPEMAP) or die "Cannot close $typemap: $!";
268             }
269             %{$self->{SCAN}{std_types}} = %{$self->{SCAN}{types_seen}};
270             %{$self->{SCAN}{types_seen}} = ();
271             }
272              
273             sub normalize_type {
274             my($self, $type) = @_;
275             my $ignore_mods = '(?:\b(?:__const__|static|inline|__inline__)\b\s*)*';
276             $type =~ s/$ignore_mods//go;
277             $type =~ s/([\]\[()])/ \1 /g;
278             $type =~ s/\s+/ /g;
279             $type =~ s/\s+$//;
280             $type =~ s/^\s+//;
281             $type =~ s/\b\*/ */g;
282             $type =~ s/\*\b/* /g;
283             $type =~ s/\*\s+(?=\*)/*/g;
284             $self->{SCAN}{types_seen}{$type}++
285             unless $type eq '...' or $type eq 'void' or $self->{SCAN}{std_types}{$type};
286             $type;
287             }
288              
289             sub print_decl {
290             my $self = shift;
291             #my $fh = shift;
292             my $decl = shift;
293             my ($type, $name, $args) = @$decl;
294             my $retval;
295             return if $self->{seen_decl}{$name}++; # Need to do the same for docs as well?
296              
297             my @argnames = map {$_->[1]} @$args;
298             my @argtypes = map { $self->normalize_type( $_->[0] ) } @$args;
299             my @argarrays = map { $_->[4] || '' } @$args;
300             my $numargs = @$args;
301             if ($numargs and $argtypes[-1] eq '...') {
302             $numargs--;
303             $argnames[-1] = '...';
304             }
305             local $" = ', ';
306             $type = $self->normalize_type($type);
307            
308             $retval .= <<"EOP";
309              
310             $type
311             $name(@argnames)
312             EOP
313             my $arg;
314             for $arg (0 .. $numargs - 1) {
315             $retval .= <<"EOP";
316             $argtypes[$arg] $argnames[$arg]$argarrays[$arg]
317             EOP
318             }
319             return $retval;
320             }
321              
322             sub pm_open {
323             my($self, $file) = @_;
324             $file ||= join '.', $self->modfname, "pm";
325             warn "Writing $file for module $self->{MODULE}\n" if $self->{VERBOSE};
326             return new IO::File ">$file";
327             }
328              
329             sub pm_top_sec {
330             my($self) = @_;
331             my $module = $self->module;
332              
333             return <<"END";
334             package $module;
335              
336             use strict;
337              
338             END
339             }
340              
341             sub pm_use_vars_sec {
342             my($self, @vars) = @_;
343             my $use_carp;
344             if( $self->no_xs || $self->no_const || $self->no_auto ) {
345             # we won't have our own AUTOLOAD(), so won't have $AUTOLOAD
346             unshift @vars, qw($VERSION @ISA @EXPORT);
347             }
348             else {
349             unshift @vars, qw($VERSION @ISA @EXPORT $AUTOLOAD);
350             $use_carp = "use Carp;\n";
351             }
352             return <<"END";
353             ${use_carp}use vars qw(@vars);
354             END
355             }
356              
357             sub pm_requires {
358             my($self, @requires) = @_;
359            
360             unshift @requires, 'Exporter';
361             unshift @requires, 'DynaLoader' unless $self->no_xs;
362              
363             # require autoloader if XS is disabled.
364             # if XS is enabled, require autoloader unless autoloading is disabled.
365             unshift @requires, 'AutoLoader' if( $self->no_xs || (! $self->no_auto) );
366            
367             [@requires];
368             }
369              
370             sub pm_requires_sec {
371             join "\n", (map { "require $_;" } @{ shift->pm_requires(@_) }), "";
372             }
373              
374             sub pm_isa {
375             my($self, @isa) = @_;
376             if( $self->no_xs || ($self->no_const && ! $self->no_auto) ){
377             # we won't have our own AUTOLOAD(), so we'll inherit it.
378             if(! $self->no_xs ) { # use DynaLoader, unless XS was disabled
379             push @isa, qw(Exporter AutoLoader DynaLoader);
380             }
381             else {
382             push @isa, qw(Exporter AutoLoader);
383             }
384             }
385             else {
386             # 1) we have our own AUTOLOAD(), so don't need to inherit it.
387             # or
388             # 2) we don't want autoloading mentioned.
389             if( ! $self->no_xs ){ # use DynaLoader, unless XS was disabled
390             push @isa, qw(Exporter DynaLoader);
391             }
392             else{
393             push @isa, qw(Exporter);
394             }
395             }
396             [@isa];
397             }
398              
399             sub pm_isa_sec {
400             "\n\n\@ISA = qw(@{ shift->pm_isa(@_) });\n";
401             }
402              
403             sub pm_export {
404             my($self, @export) = @_;
405             my($const, $prefix) = $self->constants;
406             push @$const, @export;
407             $const;
408             }
409              
410             sub pm_export_sec {
411             my($self) = shift;
412             local($") = "\n\t";
413             my(@export) = @{ $self->pm_export(@_) };
414              
415             return <<"END";
416              
417             # Items to export into callers namespace by default. Note: do not export
418             # names by default without a very good reason. Use EXPORT_OK instead.
419             # Do not simply export all your public functions/methods/constants.
420              
421             \@EXPORT = qw(
422             @export
423             );
424              
425             END
426             }
427              
428             sub pm_version {
429             my($self) = @_;
430             $self->{VERSION} || $self->template_version;
431             };
432              
433             sub pm_version_sec {
434             my($self) = @_;
435             my $version = $self->pm_version;
436             return <<"END";
437              
438             \$VERSION = '$version';
439              
440             END
441             }
442              
443             sub pm_autoload_sec {
444             my($self) = @_;
445              
446             my $module = $self->module;
447             return if $self->no_const or $self->no_xs;
448             return <<"END";
449             sub AUTOLOAD {
450             # This AUTOLOAD is used to 'autoload' constants from the constant()
451             # XS function. If a constant is not found then control is passed
452             # to the AUTOLOAD in AutoLoader.
453              
454             my \$constname;
455             (\$constname = \$AUTOLOAD) =~ s/.*:://;
456             my \$val = constant(\$constname, \@_ ? \$_[0] : 0);
457             if (\$! != 0) {
458             if (\$! =~ /Invalid/) {
459             \$AutoLoader::AUTOLOAD = \$AUTOLOAD;
460             goto &AutoLoader::AUTOLOAD;
461             }
462             else {
463             croak "Your vendor has not defined $module macro \$constname";
464             }
465             }
466             eval "sub \$AUTOLOAD () { \$val }";
467             goto &\$AUTOLOAD;
468             }
469              
470             END
471             }
472              
473             sub pm_bootstrap_sec {
474             my($self) = @_;
475             my $module = $self->module;
476              
477             return if $self->no_xs;
478             # print bootstrap, unless XS is disabled
479             return <<"END";
480              
481             bootstrap $module \$VERSION;
482             END
483             }
484              
485              
486             sub pm_bottom_sec {
487             my($self) = @_;
488             my $after;
489             if( $self->no_pod ){ # if POD is disabled
490             $after = '__END__';
491             }
492             else {
493             $after = '=cut';
494             }
495            
496             return <<"END";
497              
498             # Preloaded methods go here.
499              
500             # Autoload methods go after $after, and are processed by the autosplit program.
501              
502             1;
503             __END__