Upgrade to Devel::PPPort 3.07
[p5sagit/p5-mst-13.2.git] / ext / Devel / PPPort / PPPort_pm.PL
CommitLineData
adfe19db 1################################################################################
2#
3# PPPort_pm.PL -- generate PPPort.pm
4#
5################################################################################
6#
0d0f8426 7# $Revision: 41 $
adfe19db 8# $Author: mhx $
0d0f8426 9# $Date: 2006/01/14 18:07:56 +0100 $
adfe19db 10#
11################################################################################
12#
0d0f8426 13# Version 3.x, Copyright (C) 2004-2006, Marcus Holland-Moritz.
adfe19db 14# Version 2.x, Copyright (C) 2001, Paul Marquess.
15# Version 1.x, Copyright (C) 1999, Kenneth Albanowski.
16#
17# This program is free software; you can redistribute it and/or
18# modify it under the same terms as Perl itself.
19#
20################################################################################
21
22use strict;
23$^W = 1;
24require "parts/ppptools.pl";
25
26my $INCLUDE = 'parts/inc';
27my $DPPP = 'DPPP_';
28
29my %embed = map { ( $_->{name} => $_ ) }
30 parse_embed(qw(parts/embed.fnc parts/apidoc.fnc));
31
32my(%provides, %prototypes, %explicit);
33
34my $data = do { local $/; <DATA> };
35$data =~ s{^\%(include)\s+(\w+)((?:[^\S\r\n]+.*?)?)\s*$}
36 {eval "$1('$2', $3)" or die $@}gem;
37
38$data = expand($data);
39
40my @api = sort { lc $a cmp lc $b } keys %provides;
41
42$data =~ s{^(.*)__PROVIDED_API__(\s*?)^}
43 {join '', map "$1$_\n", @api}gem;
44
45{
46 my $len = 0;
47 for (keys %explicit) {
48 length > $len and $len = length;
49 }
4a582685 50 my $format = sprintf '%%-%ds %%-%ds %%s', $len+2, $len+5;
adfe19db 51 $len = 3*$len + 23;
52
0d0f8426 53$data =~ s!^(.*)__EXPLICIT_API__(\s*?)^!
54 sprintf("$1$format\n", 'Function / Variable', 'Static Request', 'Global Request') .
adfe19db 55 $1 . '-'x$len . "\n" .
0d0f8426 56 join('', map { sprintf "$1$format\n", $explicit{$_} eq 'var' ? $_ : "$_()", "NEED_$_", "NEED_${_}_GLOBAL" }
adfe19db 57 sort keys %explicit)
0d0f8426 58 !gem;
adfe19db 59}
60
61my %raw_base = %{&parse_todo('parts/base')};
62my %raw_todo = %{&parse_todo('parts/todo')};
63
64my %todo;
65for (keys %raw_todo) {
66 push @{$todo{$raw_todo{$_}}}, $_;
67}
68
69# check consistency
70for (@api) {
71 if (exists $raw_todo{$_}) {
96ad942f 72 if ($raw_base{$_} eq $raw_todo{$_}) {
73 warn "$INCLUDE/$provides{$_} provides $_, which is still marked "
74 . "todo for " . format_version($raw_todo{$_}) . "\n";
75 }
76 else {
77 check(2, "$_ was ported back to " . format_version($raw_todo{$_}) .
78 " (baseline revision: " . format_version($raw_base{$_}) . ").");
79 }
adfe19db 80 }
81}
82
83my @perl_api;
84for (keys %provides) {
85 next if exists $embed{$_};
86 push @perl_api, $_;
87 check(2, "No API definition for provided element $_ found.");
88}
89
90push @perl_api, keys %embed;
91
92for (@perl_api) {
93 if (exists $provides{$_} && !exists $raw_base{$_}) {
94 check(2, "Mmmh, $_ doesn't seem to need backporting.");
95 }
96 my $line = "$_|" . (exists $provides{$_} && exists $raw_base{$_} ? $raw_base{$_} : '') . '|';
97 $line .= ($raw_todo{$_} || '') . '|';
98 $line .= 'p' if exists $provides{$_};
99 if (exists $embed{$_}) {
100 my $e = $embed{$_};
101 if (exists $e->{flags}{p}) {
102 my $args = $e->{args};
103 $line .= 'v' if @$args && $args->[-1][0] eq '...';
104 }
105 $line .= 'n' if exists $e->{flags}{n};
106 }
107 $_ = $line;
108}
109
110$data =~ s/^([\t ]*)__PERL_API__(\s*?)$/
111 join "\n", map "$1$_", sort @perl_api
112 /gem;
113
114my @todo;
115for (reverse sort keys %todo) {
116 my $ver = format_version($_);
117 my $todo = "=item perl $ver\n\n";
118 for (sort @{$todo{$_}}) {
119 $todo .= " $_\n";
120 }
121 push @todo, $todo;
122}
123
124$data =~ s{^__UNSUPPORTED_API__(\s*?)^}
125 {join "\n", @todo}gem;
126
127$data =~ s{__MIN_PERL__}{5.003}g;
4a582685 128$data =~ s{__MAX_PERL__}{5.9.3}g;
adfe19db 129
130open FH, ">PPPort.pm" or die "PPPort.pm: $!\n";
131print FH $data;
132close FH;
133
134exit 0;
135
136sub include
137{
138 my($file, $opt) = @_;
139
140 print "including $file\n";
141
142 my $data = parse_partspec("$INCLUDE/$file");
143
144 for (@{$data->{provides}}) {
145 if (exists $provides{$_}) {
146 if ($provides{$_} ne $file) {
147 warn "$file: $_ already provided by $provides{$_}\n";
148 }
149 }
150 else {
151 $provides{$_} = $file;
152 }
153 }
154
155 for (keys %{$data->{prototypes}}) {
156 $prototypes{$_} = $data->{prototypes}{$_};
96ad942f 157 $data->{implementation} =~ s/^$_(?=\s*\()/$DPPP(my_$_)/mg;
adfe19db 158 }
159
160 my $out = $data->{implementation};
161
162 if (exists $opt->{indent}) {
163 $out =~ s/^/$opt->{indent}/gm;
164 }
165
166 return $out;
167}
168
169sub expand
170{
171 my $code = shift;
172 $code =~ s{^(\s*#\s*(?:el)?if\s+)(.*)$}{$1.expand_pp_expressions($2)}gem;
173 $code =~ s{^\s*
174 __UNDEFINED__
175 \s+
176 (
177 ( \w+ )
178 (?: \( [^)]* \) )?
179 )
180 [^\r\n\S]*
181 (
182 (?:[^\r\n\\]|\\[^\r\n])*
183 (?:
184 \\
185 (?:\r\n|[\r\n])
186 (?:[^\r\n\\]|\\[^\r\n])*
187 )*
188 )
189 \s*$}
190 {expand_undefined($2, $1, $3)}gemx;
0d0f8426 191 $code =~ s{^([^\S\r\n]*)__NEED_VAR__\s+(.*?)\s+(\w+)(?:\s*=\s*([^;]+?)\s*;\s*)?$}
192 {expand_need_var($1, $3, $2, $4)}gem;
193 return $code;
194}
195
196sub expand_need_var
197{
198 my($indent, $var, $type, $init) = @_;
199
200 $explicit{$var} = 'var';
201
202 my $myvar = "$DPPP(my_$var)";
203
204 my $code = <<ENDCODE;
205#if defined(NEED_$var)
206static $type $myvar = $init;
207#elif defined(NEED_${var}_GLOBAL)
208$type $myvar = $init;
209#else
210extern $type $myvar;
211#endif
212#define $var $myvar
213ENDCODE
214
215 $code =~ s/^/$indent/mg;
216
adfe19db 217 return $code;
218}
219
220sub expand_undefined
221{
222 my($macro, $withargs, $def) = @_;
223 my $rv = "#ifndef $macro\n# define ";
224
4a582685 225 if (defined $def && $def =~ /\S/) {
adfe19db 226 $rv .= sprintf "%-30s %s", $withargs, $def;
227 }
228 else {
229 $rv .= $withargs;
230 }
231
232 $rv .= "\n#endif\n";
233
234 return $rv;
235}
236
237sub expand_pp_expressions
238{
239 my $pp = shift;
240 $pp =~ s/\{([^\}]+)\}/expand_pp_expr($1)/ge;
241 return $pp;
242}
243
244sub expand_pp_expr
245{
246 my $expr = shift;
247
0d0f8426 248 if ($expr =~ /^\s*need\s+(\w+)\s*$/i) {
adfe19db 249 my $func = $1;
250 my $e = $embed{$func} or die "unknown API function '$func' in NEED\n";
251 my $proto = make_prototype($e);
252 if (exists $prototypes{$func}) {
253 if (compare_prototypes($proto, $prototypes{$func})) {
254 check(1, "differing prototypes for $func:\n API: $proto\n PPP: $prototypes{$func}");
255 $proto = $prototypes{$func};
256 }
257 }
258 else {
259 warn "found no prototype for $func\n";;
260 }
261
0d0f8426 262 $explicit{$func} = 'func';
adfe19db 263
96ad942f 264 $proto =~ s/\b$func(?=\s*\()/$DPPP(my_$func)/;
adfe19db 265 my $embed = make_embed($e);
266
267 return "defined(NEED_$func)\n"
268 . "static $proto;\n"
269 . "static\n"
270 . "#else\n"
271 . "extern $proto;\n"
272 . "#endif\n"
273 . "\n"
274 . "$embed\n"
275 . "\n"
96ad942f 276 . "#if defined(NEED_$func) || defined(NEED_${func}_GLOBAL)";
adfe19db 277 }
278
adfe19db 279 die "cannot expand preprocessor expression '$expr'\n";
280}
281
282sub make_embed
283{
284 my $f = shift;
285 my $n = $f->{name};
286 my $a = do { my $x = 'a'; join ',', map { $x++ } 1 .. @{$f->{args}} };
287
288 if ($f->{flags}{n}) {
289 if ($f->{flags}{p}) {
96ad942f 290 return "#define $n $DPPP(my_$n)\n" .
291 "#define Perl_$n $DPPP(my_$n)";
adfe19db 292 }
293 else {
96ad942f 294 return "#define $n $DPPP(my_$n)";
adfe19db 295 }
296 }
297 else {
298 my $undef = <<UNDEF;
299#ifdef $n
300# undef $n
301#endif
302UNDEF
303 if ($f->{flags}{p}) {
96ad942f 304 if ($f->{flags}{f}) {
305 return "#define Perl_$n $DPPP(my_$n)";
306 }
307 else {
308 return $undef . "#define $n($a) $DPPP(my_$n)(aTHX_ $a)\n" .
309 "#define Perl_$n $DPPP(my_$n)";
310 }
adfe19db 311 }
312 else {
96ad942f 313 return $undef . "#define $n($a) $DPPP(my_$n)(aTHX_ $a)";
adfe19db 314 }
315 }
316}
317
318sub check
319{
320 my $level = shift;
321
322 if (exists $ENV{DPPP_CHECK_LEVEL} and $ENV{DPPP_CHECK_LEVEL} >= $level) {
323 print STDERR @_, "\n";
324 }
325}
326
327__DATA__
328################################################################################
329#
330# !!!!! Do NOT edit this file directly! -- Edit PPPort_pm.PL instead. !!!!!
331#
332################################################################################
333#
334# Perl/Pollution/Portability
335#
336################################################################################
337#
0d0f8426 338# $Revision: 41 $
adfe19db 339# $Author: mhx $
0d0f8426 340# $Date: 2006/01/14 18:07:56 +0100 $
adfe19db 341#
342################################################################################
343#
0d0f8426 344# Version 3.x, Copyright (C) 2004-2006, Marcus Holland-Moritz.
adfe19db 345# Version 2.x, Copyright (C) 2001, Paul Marquess.
346# Version 1.x, Copyright (C) 1999, Kenneth Albanowski.
347#
348# This program is free software; you can redistribute it and/or
349# modify it under the same terms as Perl itself.
350#
351################################################################################
352
353=head1 NAME
354
355Devel::PPPort - Perl/Pollution/Portability
356
357=head1 SYNOPSIS
358
359 Devel::PPPort::WriteFile(); # defaults to ./ppport.h
360 Devel::PPPort::WriteFile('someheader.h');
361
362=head1 DESCRIPTION
363
364Perl's API has changed over time, gaining new features, new functions,
365increasing its flexibility, and reducing the impact on the C namespace
366environment (reduced pollution). The header file written by this module,
367typically F<ppport.h>, attempts to bring some of the newer Perl API
368features to older versions of Perl, so that you can worry less about
369keeping track of old releases, but users can still reap the benefit.
370
371C<Devel::PPPort> contains a single function, called C<WriteFile>. Its
372only purpose is to write the F<ppport.h> C header file. This file
373contains a series of macros and, if explicitly requested, functions that
374allow XS modules to be built using older versions of Perl. Currently,
375Perl versions from __MIN_PERL__ to __MAX_PERL__ are supported.
376
4a582685 377This module is used by C<h2xs> to write the file F<ppport.h>.
adfe19db 378
379=head2 Why use ppport.h?
4a582685 380
adfe19db 381You should use F<ppport.h> in modern code so that your code will work
382with the widest range of Perl interpreters possible, without significant
383additional work.
384
385You should attempt older code to fully use F<ppport.h>, because the
386reduced pollution of newer Perl versions is an important thing. It's so
387important that the old polluting ways of original Perl modules will not be
388supported very far into the future, and your module will almost certainly
389break! By adapting to it now, you'll gain compatibility and a sense of
390having done the electronic ecology some good.
391
392=head2 How to use ppport.h
393
394Don't direct the users of your module to download C<Devel::PPPort>.
395They are most probably no XS writers. Also, don't make F<ppport.h>
396optional. Rather, just take the most recent copy of F<ppport.h> that
397you can find (e.g. by generating it with the latest C<Devel::PPPort>
398release from CPAN), copy it into your project, adjust your project to
4a582685 399use it, and distribute the header along with your module.
adfe19db 400
401=head2 Running ppport.h
402
403But F<ppport.h> is more than just a C header. It's also a Perl script
404that can check your source code. It will suggest hints and portability
405notes, and can even make suggestions on how to change your code. You
406can run it like any other Perl program:
407
9132e1a3 408 perl ppport.h [options] [files]
adfe19db 409
410It also has embedded documentation, so you can use
411
412 perldoc ppport.h
413
414to find out more about how to use it.
415
416=head1 FUNCTIONS
417
418=head2 WriteFile
419
420C<WriteFile> takes one optional argument. When called with one
421argument, it expects to be passed a filename. When called with
422no arguments, it defaults to the filename F<ppport.h>.
423
424The function returns a true value if the file was written successfully.
425Otherwise it returns a false value.
426
427=head1 COMPATIBILITY
428
429F<ppport.h> supports Perl versions from __MIN_PERL__ to __MAX_PERL__
430in threaded and non-threaded configurations.
431
432=head2 Provided Perl compatibility API
433
434The header file written by this module, typically F<ppport.h>, provides
435access to the following elements of the Perl API that is not available
436in older Perl releases:
437
438 __PROVIDED_API__
439
440=head2 Perl API not supported by ppport.h
441
442There is still a big part of the API not supported by F<ppport.h>.
443Either because it doesn't make sense to back-port that part of the API,
444or simply because it hasn't been implemented yet. Patches welcome!
445
446Here's a list of the currently unsupported API, and also the version of
447Perl below which it is unsupported:
448
449=over 4
450
451__UNSUPPORTED_API__
452
453=back
454
455=head1 BUGS
456
457If you find any bugs, C<Devel::PPPort> doesn't seem to build on your
458system or any of its tests fail, please use the CPAN Request Tracker
459at L<http://rt.cpan.org/> to create a ticket for the module.
460
461=head1 AUTHORS
462
463=over 2
464
465=item *
466
467Version 1.x of Devel::PPPort was written by Kenneth Albanowski.
468
469=item *
470
471Version 2.x was ported to the Perl core by Paul Marquess.
472
473=item *
474
475Version 3.x was ported back to CPAN by Marcus Holland-Moritz.
476
477=back
478
479=head1 COPYRIGHT
480
0d0f8426 481Version 3.x, Copyright (C) 2004-2006, Marcus Holland-Moritz.
adfe19db 482
483Version 2.x, Copyright (C) 2001, Paul Marquess.
484
485Version 1.x, Copyright (C) 1999, Kenneth Albanowski.
486
487This program is free software; you can redistribute it and/or
488modify it under the same terms as Perl itself.
489
490=head1 SEE ALSO
491
492See L<h2xs>, L<ppport.h>.
493
494=cut
495
496package Devel::PPPort;
497
498require DynaLoader;
499use strict;
500use vars qw($VERSION @ISA $data);
501
0d0f8426 502$VERSION = do { my @r = '$Snapshot: /Devel-PPPort/3.07 $' =~ /(\d+\.\d+(?:_\d+)?)/; @r ? $r[0] : '9.99' };
adfe19db 503
504@ISA = qw(DynaLoader);
505
506bootstrap Devel::PPPort;
507
4a582685 508sub _init_data
adfe19db 509{
510 $data = do { local $/; <DATA> };
511 my $now = localtime;
512 my $pkg = 'Devel::PPPort';
513 $data =~ s/__PERL_VERSION__/$]/g;
514 $data =~ s/__VERSION__/$VERSION/g;
515 $data =~ s/__DATE__/$now/g;
516 $data =~ s/__PKG__/$pkg/g;
4a582685 517 $data =~ s/^\|>//gm;
adfe19db 518}
519
520sub WriteFile
521{
522 my $file = shift || 'ppport.h';
4a582685 523 defined $data or _init_data();
adfe19db 524 my $copy = $data;
525 $copy =~ s/\bppport\.h\b/$file/g;
526
527 open F, ">$file" or return undef;
528 print F $copy;
529 close F;
530
531 return 1;
532}
533
5341;
535
536__DATA__
537#if 0
538<<'SKIP';
539#endif
540/*
541----------------------------------------------------------------------
542
4a582685 543 ppport.h -- Perl/Pollution/Portability Version __VERSION__
544
adfe19db 545 Automatically created by __PKG__ running under
546 perl __PERL_VERSION__ on __DATE__.
4a582685 547
adfe19db 548 Do NOT edit this file directly! -- Edit PPPort_pm.PL and the
549 includes in parts/inc/ instead.
4a582685 550
adfe19db 551 Use 'perldoc ppport.h' to view the documentation below.
552
553----------------------------------------------------------------------
554
555SKIP
556
4a582685 557%include ppphdoc { indent => '|>' }
adfe19db 558
559%include ppphbin
560
561__DATA__
562*/
563
564#ifndef _P_P_PORTABILITY_H_
565#define _P_P_PORTABILITY_H_
566
567#ifndef DPPP_NAMESPACE
568# define DPPP_NAMESPACE DPPP_
569#endif
570
571#define DPPP_CAT2(x,y) CAT2(x,y)
572#define DPPP_(name) DPPP_CAT2(DPPP_NAMESPACE, name)
573
574%include version
575
576%include limits
577
578%include uv
579
0d0f8426 580%include memory
581
adfe19db 582%include misc
583
0d0f8426 584%include variables
585
adfe19db 586%include threads
587
588%include mPUSH
589
590%include call
591
592%include newRV
593
594%include newCONSTSUB
595
596%include MY_CXT
597
598%include format
599
600%include SvPV
601
0d0f8426 602%include Sv_set
603
96ad942f 604%include sv_xpvf
605
adfe19db 606%include magic
607
608%include cop
609
610%include grok
611
9132e1a3 612%include exception
613
adfe19db 614#endif /* _P_P_PORTABILITY_H_ */
615
616/* End of File ppport.h */