1################################################################################ 2# 3# PPPort_pm.PL -- generate PPPort.pm 4# 5# Set the environment variable DPPP_CHECK_LEVEL to more than zero for some 6# extra checking. 1 or 2 currently 7 8################################################################################ 9# 10# Version 3.x, Copyright (C) 2004-2013, Marcus Holland-Moritz. 11# Copyright (C) 2018, The perl5 porters 12# Version 2.x, Copyright (C) 2001, Paul Marquess. 13# Version 1.x, Copyright (C) 1999, Kenneth Albanowski. 14# 15# This program is free software; you can redistribute it and/or 16# modify it under the same terms as Perl itself. 17# 18################################################################################ 19 20use strict; 21BEGIN { $^W = 1; } 22require "./parts/ppptools.pl"; 23require "./parts/inc/inctools"; 24 25my $INCLUDE = 'parts/inc'; 26my $DPPP = 'DPPP_'; 27 28# The keys of %embed are the names of the items found in all the .fnc files, 29# and each value is all the information parse_embed returns for that item. 30my %embed = map { ( $_->{name} => $_ ) } 31 parse_embed(qw(parts/embed.fnc parts/apidoc.fnc parts/ppport.fnc)); 32 33my(%provides, %prototypes, %explicit); 34 35my $data = do { local $/; <DATA> }; 36 37# Call include(file, params) for every line that begins with %include 38# These fill in %provides and %prototypes. 39# The keys of %provides are the items provided by Devel::PPPort, and each 40# value is the name of the file (in parts/inc/) that has the code to provide 41# it. 42# An entry in %prototypes looks like: 43# 'grok_bin' => 'UV grok_bin(pTHX_ const char * start, STRLEN * len_p, I32 * flags, NV * result)', 44 45$data =~ s{^\%(include)\s+(\w+)((?:[^\S\r\n]+.*?)?)\s*$} 46 {eval "$1('$2', $3)" or die $@}gem; 47 48# And expand it. 49$data = expand($data); 50 51# Just the list of provided items. 52my @provided = sort dictionary_order keys %provides; 53 54# which further expands $data. 55$data =~ s{^(.*)__PROVIDED_API__(\s*?)^} 56 {join '', map "$1$_\n", @provided}gem; 57 58{ 59 my $len = 0; 60 for (keys %explicit) { 61 length > $len and $len = length; 62 } 63 my $format = sprintf '%%-%ds %%-%ds %%s', $len+2, $len+5; 64 $len = 3*$len + 23; 65 66$data =~ s!^(.*)__EXPLICIT_API__(\s*?)^! 67 sprintf("$1$format\n", 'Function / Variable', 'Static Request', 'Global Request') . 68 $1 . '-'x$len . "\n" . 69 join('', map { sprintf "$1$format\n", $explicit{$_} eq 'var' ? $_ : "$_()", "NEED_$_", "NEED_${_}_GLOBAL" } 70 sort dictionary_order keys %explicit) 71 !gem; 72} 73 74# These hashes look like: 75# { ... 'gv_check' => '5.003007', 76# 'gv_const_sv' => '5.009003', 77# 'gv_dump' => '5.006000', 78# ... }, 79 80# What's provided when without ppport.h, as far as we've been able to 81# determine 82my %raw_base = %{&parse_todo('parts/base')}; 83 84# What's provided when using ppport.h, as far as we've been able to 85# determine 86my %raw_todo = %{&parse_todo('parts/todo')}; 87 88# The items defined by config.h are found instead by scanprov which currently 89# doesn't write them to the todo files. Instead add them here. All such have 90# the K code, and we know certain things about them, so set their flags 91# accordingly. 92for (keys %raw_base) { 93 if ( exists $raw_base{$_}{code} 94 && $raw_base{$_}{code} eq 'K') 95 { 96 $embed{$_}->{flags}{'A'} = 1; 97 $embed{$_}->{flags}{'m'} = 1; 98 $embed{$_}->{flags}{'d'} = 1; 99 $embed{$_}->{flags}{'T'} = 1; 100 # 101 # Don't override any existing 102 $raw_todo{$_} = $raw_base{$_} unless exists $raw_todo{$_}; 103 } 104} 105 106# Invert so each key is the 7 digit version number, and its value is an array 107# of all symbols within it, like: 108# '5005003' => [ 109# 'POPpx', 110# 'get_vtbl', 111# 'save_generic_svref' 112# ], 113my %todo; 114for (keys %raw_todo) { 115 push @{$todo{int_parse_version($raw_todo{$_}{version})}}, $_; 116} 117 118# Most recent first 119my @todo_list = reverse sort keys %todo; 120 121# Here, @todo_list contains the integer version numbers that have support. 122# The first and final elements give the extremes of the supported versions. 123# (Use defaults that were reasonable at the time of this commit if the 124# directories are empty (which should only happen during regeneration of the 125# base and todo files).). Actually the final element is for blead (at the 126# time things were regenerated), which is 1 beyond the max version supported. 127my $INT_MAX_PERL = (@todo_list) ? $todo_list[0] - 1 : '5038000'; # used for __MAX_PERL__ 128my $MAX_PERL = format_version($INT_MAX_PERL); 129my $INT_MIN_PERL = (@todo_list) ? $todo_list[-1] : 5003007; 130my $MIN_PERL = format_version($INT_MIN_PERL); 131 132# Get rid of blead. It contains the things marked as todo, meaning they 133# don't compile at all, and not getting rid of it would mean they would be 134# listed as working but introduced in blead. 135shift @todo_list if @todo_list && $todo_list[0] > $INT_MAX_PERL; 136 137# check consistency between our list of everything provided, and our lists of 138# what got provided when 139for (@provided) { 140 if ( exists $raw_todo{$_} 141 && $raw_todo{$_}{version} > $INT_MIN_PERL # INT_MIN_PERL contents are real 142 # symbols, not something to do 143 && $raw_todo{$_}{version} <= $INT_MAX_PERL # Above this would be things that 144 # don't compile in blead 145 && exists $raw_base{$_}) 146 { 147 if ($raw_base{$_}{version} == $raw_todo{$_}{version}) { 148 warn "$INCLUDE/$provides{$_} provides $_, which is still marked " 149 . "todo for " . format_version($raw_todo{$_}) . "\n"; 150 } 151 else { 152 check(2, "$_ was ported back to " . format_version($raw_todo{$_}{version}) 153 . " (baseline revision: " . format_version($raw_base{$_}{version}) 154 . ")."); 155 } 156 } 157} 158 159my %perl_api; 160for (@provided) { 161 next if /^Perl_(.*)/ && exists $embed{$1}; 162 next if exists $embed{$_}; 163 $perl_api{$_} = 1; 164 check(2, "No API definition for provided element $_ found."); 165} 166 167# At this point the keys of %perl_api give the list of things we provide that 168# weren't found in the .fnc files. 169my @prototype_unknown = keys %perl_api; 170 171# Add in the .fnc file definitions. 172for (keys %embed) { 173 $perl_api{$_} = 1; 174} 175 176# Finally, scanprov has found macros of various types 177my @scanprov_found_macros = grep { $raw_base{$_}{code} =~ /[KMZ]/ } keys %raw_base; 178for (@scanprov_found_macros) { 179 $perl_api{$_} = 1; 180} 181 182my @perl_api = sort dictionary_order keys %perl_api; 183 184for (@perl_api) { # $_ is the item name 185 if (exists $provides{$_} && !exists $raw_base{$_}) { 186 check(2, "Mmmh, $_ doesn't seem to need backporting."); 187 } 188 189 # Create the lines that ppport.h reads. These look like 190 # CopyD|5.009002|5.003007|p 191 my $line = "$_|"; 192 $line .= $raw_base{$_}{version} if exists $raw_base{$_} 193 # If is above the max, it means it never actually got defined 194 && int_parse_version($raw_base{$_}{version}) <= $INT_MAX_PERL; 195 $line .= '|'; 196 $line .= $raw_todo{$_}{version} 197 if exists $raw_todo{$_} 198 && int_parse_version($raw_todo{$_}{version}) <= $INT_MAX_PERL; 199 $line .= '|'; 200 $line .= 'p' if exists $provides{$_}; 201 my $e; 202 $e = $embed{$_} if exists $embed{$_}; 203 my $is_documented = 0; 204 my $is_accessible = 0; 205 my $has_thread = 1; 206 if (defined $e) { 207 if (exists $e->{flags}{'p'}) { # Has 'Perl_' prefix 208 my $args = $e->{args}; 209 $line .= 'v' if @$args && $args->[-1][0] eq '...'; 210 } 211 $line .= 'o' if exists $e->{ppport_fnc}; 212 $line .= 'd' if exists $e->{flags}{'D'}; # deprecated 213 $line .= 'x' if exists $e->{flags}{'x'}; # experimental 214 $line .= 'c' if exists $e->{flags}{'C'} # core-only 215 || ( exists $e->{flags}{'X'} 216 && (exists $e->{flags}{'E'} || ! exists $e->{flags}{'m'})); 217 $has_thread = 0 if exists $e->{flags}{'T'}; # No thread context parameter 218 $is_accessible = 1 if exists $e->{flags}{'A'} 219 || exists $e->{flags}{'C'} 220 || ( exists $e->{flags}{'X'} 221 && ! exists $e->{flags}{'E'} 222 && exists $e->{flags}{'m'}); 223 $is_documented = 1 if exists $e->{flags}{'d'}; 224 } 225 226 # scanprov adds several flags: 227 # F is for functions we didn't find in testing (usually because they are 228 # hidden behind ifdefs, like USE_THREADS if built on unthreaded perls, 229 # or vice-versa. 230 # K for config.h #defines. These are considered provided and are 231 # documented in config.h (mnemonic: K is like c in config) 232 # M for provided, undocumented macros. If they were documented, they 233 # would have been found before scanprov was run. 234 # Z for macros that aren't documented or provided. (mnemonic: 235 # 'Zecret'). Some of these may be hidden behind an #ifdef PERL_CORE. 236 # None of these were verified by compilation 237 if (exists $raw_base{$_}{code}) { 238 $line .= 'V' if $raw_base{$_}{code} =~ /[FKMXZ]/; 239 $is_accessible = 1 if $raw_base{$_}{code} =~ /M/; 240 } 241 $line .= 'n' unless $has_thread; 242 $line .= 'i' unless $is_accessible; 243 $line .= 'u' unless $is_documented; 244 245 $_ = $line; 246} 247 248$data =~ s/^([\t ]*)__ALL_ELEMENTS__(\s*?)$/ 249 join "\n", map "$1$_", sort dictionary_order @perl_api 250 /gem; 251 252my $undocumented = "(undocumented)"; 253 254my @todo; 255for (@todo_list) { 256 my $ver = format_version($_); 257 $ver .= " (or maybe earlier)" if $_ == $todo_list[-1]; 258 my $todo = "=item perl $ver\n\n"; 259 for (sort dictionary_order @{$todo{$_}}) { 260 $todo .= " $_"; 261 $todo .= " (DEPRECATED)" if $embed{$_}->{flags}{'D'}; 262 $todo .= " (marked experimental)" if $embed{$_}->{flags}{'x'}; 263 $todo .= " $undocumented" unless $embed{$_}->{flags}{'d'}; 264 $todo .= "\n"; 265 } 266 push @todo, $todo; 267} 268 269if (@prototype_unknown) { 270 my $todo = "=item Backported version unknown\n\n"; 271 for (sort dictionary_order @prototype_unknown) { 272 $todo .= " $_ $undocumented\n"; 273 } 274 push @todo, $todo; 275} 276 277$data =~ s{^__UNSUPPORTED_API__(\s*?)^} 278 {join "\n", @todo}gem; 279 280$data =~ s{__MIN_PERL__}{$MIN_PERL}g; 281$data =~ s{__MAX_PERL__}{$MAX_PERL}g; 282 283open FH, ">PPPort.pm" or die "PPPort.pm: $!\n"; 284print FH $data; 285close FH; 286 287exit 0; 288 289sub include 290{ 291 my($file, $opt) = @_; 292 293 print "including $file\n"; 294 295 my $data = parse_partspec("$INCLUDE/$file"); 296 297 for (@{$data->{provides}}) { 298 if (exists $provides{$_}) { 299 if ($provides{$_} ne $file) { 300 warn "$file: $_ already provided by $provides{$_}\n"; 301 } 302 } 303 else { 304 $provides{$_} = $file; 305 } 306 } 307 308 for (keys %{$data->{prototypes}}) { 309 $prototypes{$_} = $data->{prototypes}{$_}; 310 $prototypes{$_} = normalize_prototype($data->{prototypes}{$_}); 311 $data->{implementation} =~ s/^$_(?=\s*\()/$DPPP(my_$_)/mg; 312 } 313 314 my $out = $data->{implementation}; 315 316 if (exists $opt->{indent}) { 317 $out =~ s/^/$opt->{indent}/gm; 318 } 319 320 return $out; 321} 322 323sub expand 324{ 325 my $code = shift; 326 $code =~ s{^(\s*#\s*(?:el)?if\s+)(.*)$}{$1.expand_pp_expressions($2)}gem; 327 $code =~ s{^\s* 328 __(?:UNDEFINED|UNDEF_NOT_PROVIDED)__ 329 \s+ 330 ( 331 ( \w+ ) 332 (?: \( [^)]* \) )? 333 ) 334 [^\r\n\S]* 335 ( 336 (?:[^\r\n\\]|\\[^\r\n])* 337 (?: 338 \\ 339 (?:\r\n|[\r\n]) 340 (?:[^\r\n\\]|\\[^\r\n])* 341 )* 342 ) 343 \s*$} 344 {expand_undefined($2, $1, $3)}gemx; 345 $code =~ s{^([^\S\r\n]*)__NEED_VAR__\s+(.*?)\s+(\w+)(?:\s*=\s*([^;]+?))?\s*;\s*$} 346 {expand_need_var($1, $3, $2, $4)}gem; 347 $code =~ s{^([^\S\r\n]*)__NEED_DUMMY_VAR__\s+(.*?)\s+(\w+)(?:\s*=\s*([^;]+?))?\s*;\s*$} 348 {expand_need_dummy_var($1, $3, $2, $4)}gem; 349 return $code; 350} 351 352sub expand_need_var 353{ 354 my($indent, $var, $type, $init) = @_; 355 356 $explicit{$var} = 'var'; 357 358 my $myvar = "$DPPP(my_$var)"; 359 $init = defined $init ? " = $init" : ""; 360 361 my $code = <<ENDCODE; 362#if defined(NEED_$var) 363static $type $myvar$init; 364#elif defined(NEED_${var}_GLOBAL) 365$type $myvar$init; 366#else 367extern $type $myvar; 368#endif 369#define $var $myvar 370ENDCODE 371 372 $code =~ s/^/$indent/mg; 373 374 return $code; 375} 376 377sub expand_need_dummy_var 378{ 379 my($indent, $var, $type, $init) = @_; 380 381 $explicit{$var} = 'var'; 382 383 my $myvar = "$DPPP(dummy_$var)"; 384 $init = defined $init ? " = $init" : ""; 385 386 my $code = <<ENDCODE; 387#if defined(NEED_$var) 388static $type $myvar$init; 389#elif defined(NEED_${var}_GLOBAL) 390$type $myvar$init; 391#else 392extern $type $myvar; 393#endif 394ENDCODE 395 396 $code =~ s/^/$indent/mg; 397 398 return $code; 399} 400 401sub expand_undefined 402{ 403 my($macro, $withargs, $def) = @_; 404 my $rv = "#ifndef $macro\n# define "; 405 406 if (defined $def && $def =~ /\S/) { 407 $rv .= sprintf "%-30s %s", $withargs, $def; 408 } 409 else { 410 $rv .= $withargs; 411 } 412 413 $rv .= "\n#endif\n"; 414 415 return $rv; 416} 417 418sub expand_pp_expressions 419{ 420 my $pp = shift; 421 $pp =~ s/\{([^\}]+)\}/expand_pp_expr($1)/ge; 422 return $pp; 423} 424 425sub expand_pp_expr 426{ 427 my $expr = shift; 428 429 if ($expr =~ /^\s*need\s+(\w+)\s*$/i) { 430 my $func = $1; 431 my $e = $embed{$func} or die "unknown API function '$func' in NEED\n"; 432 my $proto = make_prototype($e); 433 if (exists $prototypes{$func}) { 434 if (compare_prototypes($proto, $prototypes{$func})) { 435 my $proto_no_pTHX = $proto; 436 $proto_no_pTHX =~ s/pTHX_\s*//; 437 if (compare_prototypes($proto_no_pTHX, $prototypes{$func})) { 438 check(1, "differing prototypes for $func:\n API: $proto\n PPP: $prototypes{$func}"); 439 } 440 else { 441 check(1, "prototypes differ in pTHX_ for $func:\n API: $proto\n PPP: $prototypes{$func}"); 442 } 443 $proto = $prototypes{$func}; 444 } 445 } 446 else { 447 warn "found no prototype for $func\n";; 448 } 449 450 $explicit{$func} = 'func'; 451 452 $proto =~ s/\b$func(?=\s*\()/$DPPP(my_$func)/; 453 my $embed = make_embed($e); 454 455 return "defined(NEED_$func)\n" 456 . "static $proto;\n" 457 . "static\n" 458 . "#else\n" 459 . "extern $proto;\n" 460 . "#endif\n" 461 . "\n" 462 . "#if defined(NEED_$func) || defined(NEED_${func}_GLOBAL)\n" 463 . "\n" 464 . "$embed\n"; 465 } 466 467 die "cannot expand preprocessor expression '$expr'\n"; 468} 469 470sub make_embed 471{ 472 my $f = shift; 473 my $n = $f->{name}; 474 my $a = do { my $x = 'a'; join ',', map { $x++ } 1 .. @{$f->{args}} }; 475 my $lastarg = ${$f->{args}}[-1]; 476 477 if ($f->{flags}{'T'}) { 478 if ($f->{flags}{'p'}) { 479 return "#define $n $DPPP(my_$n)\n" . 480 "#define Perl_$n $DPPP(my_$n)"; 481 } 482 else { 483 return "#define $n $DPPP(my_$n)"; 484 } 485 } 486 else { 487 my $undef = <<UNDEF; 488#ifdef $n 489# undef $n 490#endif 491UNDEF 492 if ($f->{flags}{'p'}) { 493 if ($f->{flags}{'f'}) { 494 return "#define Perl_$n $DPPP(my_$n)"; 495 } 496 elsif (@$lastarg && $lastarg->[0] =~ /\.\.\./) { 497 return $undef . "#define $n $DPPP(my_$n)\n" . 498 "#define Perl_$n $DPPP(my_$n)"; 499 } 500 else { 501 return $undef . "#define $n($a) $DPPP(my_$n)(aTHX_ $a)\n" . 502 "#define Perl_$n $DPPP(my_$n)"; 503 } 504 } 505 else { 506 return $undef . "#define $n($a) $DPPP(my_$n)(aTHX_ $a)"; 507 } 508 } 509} 510 511sub check 512{ 513 my $level = shift; 514 515 if (exists $ENV{DPPP_CHECK_LEVEL} and $ENV{DPPP_CHECK_LEVEL} >= $level) { 516 print STDERR @_, "\n"; 517 } 518} 519 520__DATA__ 521################################################################################ 522# 523# !!!!! Do NOT edit this file directly! -- Edit PPPort_pm.PL instead. !!!!! 524# 525# This file was automatically generated from the definition files in the 526# parts/inc/ subdirectory by PPPort_pm.PL. To learn more about how all this 527# works, please read the L<HACKERS> file that came with this distribution. 528# 529################################################################################ 530# 531# Perl/Pollution/Portability 532# 533################################################################################ 534# 535# Version 3.x, Copyright (C) 2004-2013, Marcus Holland-Moritz. 536# Copyright (C) 2018, The perl5 porters 537# Version 2.x, Copyright (C) 2001, Paul Marquess. 538# Version 1.x, Copyright (C) 1999, Kenneth Albanowski. 539# 540# This program is free software; you can redistribute it and/or 541# modify it under the same terms as Perl itself. 542# 543################################################################################ 544 545=head1 NAME 546 547Devel::PPPort - Perl/Pollution/Portability 548 549=head1 SYNOPSIS 550 551 Devel::PPPort::WriteFile(); # defaults to ./ppport.h 552 Devel::PPPort::WriteFile('someheader.h'); 553 554 # Same as above but retrieve contents rather than write file 555 my $contents = Devel::PPPort::GetFileContents(); 556 my $contents = Devel::PPPort::GetFileContents('someheader.h'); 557 558=head1 Start using Devel::PPPort for XS projects 559 560 $ cpan Devel::PPPort 561 $ perl -MDevel::PPPort -e'Devel::PPPort::WriteFile' 562 $ perl ppport.h --compat-version=5.6.1 --patch=diff.patch *.xs 563 $ patch -p0 < diff.patch 564 $ echo ppport.h >>MANIFEST 565 566=head1 DESCRIPTION 567 568Perl's API has changed over time, gaining new features, new functions, 569increasing its flexibility, and reducing the impact on the C namespace 570environment (reduced pollution). The header file written by this module, 571typically F<ppport.h>, attempts to bring some of the newer Perl API 572features to older versions of Perl, so that you can worry less about 573keeping track of old releases, but users can still reap the benefit. 574 575C<Devel::PPPort> contains two functions, C<WriteFile> and C<GetFileContents>. 576C<WriteFile>'s only purpose is to write the F<ppport.h> C header file. 577This file contains a series of macros and, if explicitly requested, functions 578that allow XS modules to be built using older versions of Perl. Currently, 579Perl versions from __MIN_PERL__ to __MAX_PERL__ are supported. 580 581C<GetFileContents> can be used to retrieve the file contents rather than 582writing it out. 583 584This module is used by C<h2xs> to write the file F<ppport.h>. 585 586=head2 Why use ppport.h? 587 588You should use F<ppport.h> in modern code so that your code will work 589with the widest range of Perl interpreters possible, without significant 590additional work. 591 592You should attempt to get older code to fully use F<ppport.h>, because the 593reduced pollution of newer Perl versions is an important thing. It's so 594important that the old polluting ways of original Perl modules will not be 595supported very far into the future, and your module will almost certainly 596break! By adapting to it now, you'll gain compatibility and a sense of 597having done the electronic ecology some good. 598 599=head2 How to use ppport.h 600 601Don't direct the users of your module to download C<Devel::PPPort>. 602They are most probably not XS writers. Also, don't make F<ppport.h> 603optional. Rather, just take the most recent copy of F<ppport.h> that 604you can find (e.g. by generating it with the latest C<Devel::PPPort> 605release from CPAN), copy it into your project, adjust your project to 606use it, test it, and distribute the header along with your module. 607 608It is important to use the most recent version of F<ppport.h>. You do need to 609test before shipping a newer version than you already had. One possible 610failure is that someone had to convert a backported element from a macro into 611a function, and actual functions must be enabled with a NEED macro to minimize 612the possibility of namespace pollution. See L<HACKERS> for details. The 613developers of C<Devel::PPPort> want to hear if there are other problems that 614arise from using a later F<ppport.h>. Use 615L<https://github.com/Dual-Life/Devel-PPPort/issues> to report any. 616 617=head2 Running ppport.h 618 619But F<ppport.h> is more than just a C header. It's also a Perl script 620that can check your source code. It will suggest hints and portability 621notes, and can even make suggestions on how to change your code. You 622can run it like any other Perl program: 623 624 perl ppport.h [options] [files] 625 626It also has embedded documentation, so you can use 627 628 perldoc ppport.h 629 630to find out more about how to use it. 631 632=head1 FUNCTIONS 633 634=head2 WriteFile 635 636C<WriteFile> takes one optional argument. When called with one 637argument, it expects to be passed a filename. When called with 638no arguments, it defaults to the filename F<ppport.h>. 639 640The function returns a true value if the file was written successfully. 641Otherwise it returns a false value. 642 643=head2 GetFileContents 644 645C<GetFileContents> behaves like C<WriteFile> above, but returns the contents 646of the would-be file rather than writing it out. 647 648=head1 COMPATIBILITY 649 650F<ppport.h> supports Perl versions from __MIN_PERL__ to __MAX_PERL__ 651in threaded and non-threaded configurations. 652 653=head2 Provided Perl compatibility API 654 655The header file written by this module, typically F<ppport.h>, provides access 656to the following elements of the Perl API that are not otherwise available in 657Perl releases older than when the elements were first introduced. (Note that 658many of these are not supported all the way back to __MIN_PERL__, but it may 659be that they are supported back as far as you need; see L</Supported Perl API, 660sorted by version> for that information.) 661 662 __PROVIDED_API__ 663 664=head2 Supported Perl API, sorted by version 665 666The table in this section lists all the Perl API elements available, sorted by 667the version in which support starts. This includes all the elements that 668F<ppport.h> helps out with, as well as those elements that it doesn't. 669 670In some cases, it doesn't make practical sense for elements to be supported 671earlier than they already are. For example, UTF-8 functionality isn't 672provided prior to the release where it was first introduced. 673 674But in other cases, it just is that no one has implemented support yet. 675Patches welcome! Some elements are ported backward for some releases, but not 676all the way to __MIN_PERL__. 677 678If an element, call it ELEMENT, is not on this list, try using this command to 679find out why: 680 681 perl ppport.h --api-info=ELEMENT 682 683A few of the entries in the list below are marked as DEPRECATED. You should 684not use these for new code, and should be converting existing uses to use 685something better. 686 687Some of the entries in the list are marked as "experimental". This means 688these should not generally be used. They may be removed or changed without 689notice. You can ask why they are experimental by sending email to 690L<mailto:perl5-porters@perl.org>. 691 692And some of the entries are marked as "undocumented". This means that they 693aren't necessarily considered stable, and could be changed or removed in some 694future release without warning. It is therefore a bad idea to use them 695without further checking. It could be that these are considered to be for 696perl core use only; or it could be, though, that C<Devel::PPPort> doesn't know 697where to find their documentation, or that it's just an oversight that they 698haven't been documented. If you want to use one, and potentially have it 699backported, first send mail to L<mailto:perl5-porters@perl.org>. 700 701=over 4 702 703__UNSUPPORTED_API__ 704 705=back 706 707=head1 BUGS 708 709If you find any bugs, C<Devel::PPPort> doesn't seem to build on your 710system, or any of its tests fail, please send a bug report to 711L<https://github.com/Dual-Life/Devel-PPPort/issues/new>. 712 713=head1 AUTHORS 714 715=over 2 716 717=item * 718 719Version 1.x of Devel::PPPort was written by Kenneth Albanowski. 720 721=item * 722 723Version 2.x was ported to the Perl core by Paul Marquess. 724 725=item * 726 727Version 3.x was ported back to CPAN by Marcus Holland-Moritz. 728 729=item * 730 731Versions >= 3.22 are maintained by perl5 porters 732 733=back 734 735=head1 COPYRIGHT 736 737Version 3.x, Copyright (C) 2004-2013, Marcus Holland-Moritz. 738 739 Copyright (C) 2018-2020, The perl5 porters 740 741Version 2.x, Copyright (C) 2001, Paul Marquess. 742 743Version 1.x, Copyright (C) 1999, Kenneth Albanowski. 744 745This program is free software; you can redistribute it and/or 746modify it under the same terms as Perl itself. 747 748=head1 SEE ALSO 749 750See L<h2xs>, F<ppport.h>. 751 752=cut 753 754package Devel::PPPort; 755 756use strict; 757use vars qw($VERSION $data); 758 759$VERSION = '3.72'; 760 761sub _init_data 762{ 763 $data = do { local $/; <DATA> }; 764 my $pkg = 'Devel::PPPort'; 765 $data =~ s/__PERL_VERSION__/$]/g; 766 $data =~ s/__VERSION__/$VERSION/g; 767 $data =~ s/__PKG__/$pkg/g; 768 $data =~ s/^\|>//gm; 769} 770 771sub GetFileContents { 772 my $file = shift || 'ppport.h'; 773 defined $data or _init_data(); 774 my $copy = $data; 775 $copy =~ s/\bppport\.h\b/$file/g; 776 777 return $copy; 778} 779 780sub WriteFile 781{ 782 my $file = shift || 'ppport.h'; 783 my $data = GetFileContents($file); 784 open F, ">$file" or return undef; 785 print F $data; 786 close F; 787 788 return 1; 789} 790 7911; 792 793__DATA__ 794#if 0 795my $void = <<'SKIP'; 796#endif 797/* 798---------------------------------------------------------------------- 799 800 ppport.h -- Perl/Pollution/Portability Version __VERSION__ 801 802 Automatically created by __PKG__ running under perl __PERL_VERSION__. 803 804 Do NOT edit this file directly! -- Edit PPPort_pm.PL and the 805 includes in parts/inc/ instead. 806 807 Use 'perldoc ppport.h' to view the documentation below. 808 809---------------------------------------------------------------------- 810 811SKIP 812 813%include ppphdoc { indent => '|>' } 814 815%include inctools 816 817%include ppphbin 818 819__DATA__ 820*/ 821 822#ifndef _P_P_PORTABILITY_H_ 823#define _P_P_PORTABILITY_H_ 824 825#ifndef DPPP_NAMESPACE 826# define DPPP_NAMESPACE DPPP_ 827#endif 828 829#define DPPP_CAT2(x,y) CAT2(x,y) 830#define DPPP_(name) DPPP_CAT2(DPPP_NAMESPACE, name) 831 832%include version 833 834%include threads 835 836%include limits 837 838%include variables 839 840%include subparse 841 842%include newCONSTSUB 843 844%include magic_defs 845 846%include misc 847 848%include sv_xpvf 849 850%include SvPV 851 852%include warn 853 854%include format 855 856%include uv 857 858%include memory 859 860%include mess 861 862%include mPUSH 863 864%include call 865 866%include newRV 867 868%include MY_CXT 869 870%include SvREFCNT 871 872%include newSV_type 873 874%include newSVpv 875 876%include Sv_set 877 878%include shared_pv 879 880%include HvNAME 881 882%include gv 883 884%include pvs 885 886%include magic 887 888%include cop 889 890%include grok 891 892%include snprintf 893 894%include sprintf 895 896%include exception 897 898%include strlfuncs 899 900%include utf8 901 902%include pv_tools 903 904%include locale 905 906#endif /* _P_P_PORTABILITY_H_ */ 907 908/* End of File ppport.h */ 909