This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Upgrade to CGI.pm-3.33. There are still differences between the
[perl5.git] / ext / Devel / PPPort / PPPort_pm.PL
CommitLineData
adfe19db
MHM
1################################################################################
2#
3# PPPort_pm.PL -- generate PPPort.pm
4#
5################################################################################
6#
aab9a3b6 7# $Revision: 57 $
adfe19db 8# $Author: mhx $
aab9a3b6 9# $Date: 2007/09/11 23:28:24 +0200 $
adfe19db
MHM
10#
11################################################################################
12#
d2dacc4f 13# Version 3.x, Copyright (C) 2004-2007, Marcus Holland-Moritz.
adfe19db
MHM
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
MHM
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
MHM
51 $len = 3*$len + 23;
52
0d0f8426
MHM
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
MHM
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
MHM
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
MHM
80 }
81}
82
83my @perl_api;
84for (keys %provides) {
aab9a3b6 85 next if /^Perl_(.*)/ && exists $embed{$1};
adfe19db
MHM
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
MHM
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
MHM
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
MHM
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
MHM
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
MHM
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
MHM
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
MHM
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
MHM
278 }
279
adfe19db
MHM
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
MHM
289
290 if ($f->{flags}{n}) {
291 if ($f->{flags}{p}) {
96ad942f
MHM
292 return "#define $n $DPPP(my_$n)\n" .
293 "#define Perl_$n $DPPP(my_$n)";
adfe19db
MHM
294 }
295 else {
96ad942f 296 return "#define $n $DPPP(my_$n)";
adfe19db
MHM
297 }
298 }
299 else {
300 my $undef = <<UNDEF;
301#ifdef $n
302# undef $n
303#endif
304UNDEF
305 if ($f->{flags}{p}) {
96ad942f
MHM
306 if ($f->{flags}{f}) {
307 return "#define Perl_$n $DPPP(my_$n)";
308 }
a89b7ab8
MHM
309 elsif (@$lastarg && $lastarg->[0] =~ /\.\.\./) {
310 return $undef . "#define $n $DPPP(my_$n)\n" .
311 "#define Perl_$n $DPPP(my_$n)";
312 }
96ad942f
MHM
313 else {
314 return $undef . "#define $n($a) $DPPP(my_$n)(aTHX_ $a)\n" .
315 "#define Perl_$n $DPPP(my_$n)";
316 }
adfe19db
MHM
317 }
318 else {
96ad942f 319 return $undef . "#define $n($a) $DPPP(my_$n)(aTHX_ $a)";
adfe19db
MHM
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
MHM
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
MHM
342################################################################################
343#
344# Perl/Pollution/Portability
345#
346################################################################################
347#
aab9a3b6 348# $Revision: 57 $
adfe19db 349# $Author: mhx $
aab9a3b6 350# $Date: 2007/09/11 23:28:24 +0200 $
adfe19db
MHM
351#
352################################################################################
353#
d2dacc4f 354# Version 3.x, Copyright (C) 2004-2007, Marcus Holland-Moritz.
adfe19db
MHM
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
MHM
388
389=head2 Why use ppport.h?
4a582685 390
adfe19db
MHM
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
MHM
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
MHM
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
d2dacc4f 491Version 3.x, Copyright (C) 2004-2007, Marcus Holland-Moritz.
adfe19db
MHM
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
c58e738a 511$VERSION = do { my @r = '$Snapshot: /Devel-PPPort/3.13 $' =~ /(\d+\.\d+(?:_\d+)?)/; @r ? $r[0] : '9.99' };
adfe19db 512
4a582685 513sub _init_data
adfe19db
MHM
514{
515 $data = do { local $/; <DATA> };
adfe19db
MHM
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
MHM
521}
522
523sub WriteFile
524{
525 my $file = shift || 'ppport.h';
4a582685 526 defined $data or _init_data();
adfe19db
MHM
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
NC
546 ppport.h -- Perl/Pollution/Portability Version __VERSION__
547
d31fb070 548 Automatically created by __PKG__ running under perl __PERL_VERSION__.
4a582685 549
adfe19db
MHM
550 Do NOT edit this file directly! -- Edit PPPort_pm.PL and the
551 includes in parts/inc/ instead.
4a582685 552
adfe19db
MHM
553 Use 'perldoc ppport.h' to view the documentation below.
554
555----------------------------------------------------------------------
556
557SKIP
558
4a582685 559%include ppphdoc { indent => '|>' }
adfe19db
MHM
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
MHM
582%include memory
583
adfe19db
MHM
584%include misc
585
0d0f8426
MHM
586%include variables
587
adfe19db
MHM
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
MHM
602%include SvREFCNT
603
adfe19db
MHM
604%include SvPV
605
0d0f8426
MHM
606%include Sv_set
607
96ad942f
MHM
608%include sv_xpvf
609
c83e6f19
MHM
610%include shared_pv
611
f2ab5a41
MHM
612%include warn
613
614%include pvs
615
adfe19db
MHM
616%include magic
617
618%include cop
619
620%include grok
621
f2ab5a41
MHM
622%include snprintf
623
9132e1a3
MHM
624%include exception
625
aef0a14c
MHM
626%include strlfuncs
627
adfe19db
MHM
628#endif /* _P_P_PORTABILITY_H_ */
629
630/* End of File ppport.h */