Upgrade to Devel::PPPort 3.09_02
[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#
aef0a14c 7# $Revision: 48 $
adfe19db 8# $Author: mhx $
aef0a14c 9# $Date: 2006/07/24 21:03:14 +0200 $
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) {
56093a11 71 if (exists $raw_todo{$_} and exists $raw_base{$_}) {
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;
0c96388f 128$data =~ s{__MAX_PERL__}{5.9.4}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#
aef0a14c 338# $Revision: 48 $
adfe19db 339# $Author: mhx $
aef0a14c 340# $Date: 2006/07/24 21:03:14 +0200 $
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
adfe19db 498use strict;
236afa0a 499use vars qw($VERSION $data);
adfe19db 500
aef0a14c 501$VERSION = do { my @r = '$Snapshot: /Devel-PPPort/3.09_02 $' =~ /(\d+\.\d+(?:_\d+)?)/; @r ? $r[0] : '9.99' };
adfe19db 502
4a582685 503sub _init_data
adfe19db 504{
505 $data = do { local $/; <DATA> };
506 my $now = localtime;
507 my $pkg = 'Devel::PPPort';
508 $data =~ s/__PERL_VERSION__/$]/g;
509 $data =~ s/__VERSION__/$VERSION/g;
510 $data =~ s/__DATE__/$now/g;
511 $data =~ s/__PKG__/$pkg/g;
4a582685 512 $data =~ s/^\|>//gm;
adfe19db 513}
514
515sub WriteFile
516{
517 my $file = shift || 'ppport.h';
4a582685 518 defined $data or _init_data();
adfe19db 519 my $copy = $data;
520 $copy =~ s/\bppport\.h\b/$file/g;
521
522 open F, ">$file" or return undef;
523 print F $copy;
524 close F;
525
526 return 1;
527}
528
5291;
530
531__DATA__
532#if 0
533<<'SKIP';
534#endif
535/*
536----------------------------------------------------------------------
537
4a582685 538 ppport.h -- Perl/Pollution/Portability Version __VERSION__
539
adfe19db 540 Automatically created by __PKG__ running under
541 perl __PERL_VERSION__ on __DATE__.
4a582685 542
adfe19db 543 Do NOT edit this file directly! -- Edit PPPort_pm.PL and the
544 includes in parts/inc/ instead.
4a582685 545
adfe19db 546 Use 'perldoc ppport.h' to view the documentation below.
547
548----------------------------------------------------------------------
549
550SKIP
551
4a582685 552%include ppphdoc { indent => '|>' }
adfe19db 553
554%include ppphbin
555
556__DATA__
557*/
558
559#ifndef _P_P_PORTABILITY_H_
560#define _P_P_PORTABILITY_H_
561
562#ifndef DPPP_NAMESPACE
563# define DPPP_NAMESPACE DPPP_
564#endif
565
566#define DPPP_CAT2(x,y) CAT2(x,y)
567#define DPPP_(name) DPPP_CAT2(DPPP_NAMESPACE, name)
568
569%include version
570
571%include limits
572
573%include uv
574
0d0f8426 575%include memory
576
adfe19db 577%include misc
578
0d0f8426 579%include variables
580
adfe19db 581%include threads
582
583%include mPUSH
584
585%include call
586
587%include newRV
588
589%include newCONSTSUB
590
591%include MY_CXT
592
593%include format
594
c07deaaf 595%include SvREFCNT
596
adfe19db 597%include SvPV
598
0d0f8426 599%include Sv_set
600
96ad942f 601%include sv_xpvf
602
f2ab5a41 603%include warn
604
605%include pvs
606
adfe19db 607%include magic
608
609%include cop
610
611%include grok
612
f2ab5a41 613%include snprintf
614
9132e1a3 615%include exception
616
aef0a14c 617%include strlfuncs
618
adfe19db 619#endif /* _P_P_PORTABILITY_H_ */
620
621/* End of File ppport.h */