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