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