perl/regen/embed.pl
Karl Williamson c14d142701 Make die() always expand to Perl_die_nocontext()
See 03f24b8a082948e5b437394fa33d0af08d7b80b6 for the motivation.

This commit changes plain die() to not use a thread context parameter.
It and die_nocontext() now behave identically.
2025-09-21 06:55:45 -06:00

825 lines
29 KiB
Perl
Executable File

#!/usr/bin/perl -w
#
# Regenerate (overwriting only if changed):
#
# embed.h
# embedvar.h
# proto.h
#
# from information stored in
#
# embed.fnc
# intrpvar.h
# perlvars.h
# regen/opcodes
#
# Accepts the standard regen_lib -q and -v args.
#
# This script is normally invoked from regen.pl.
require 5.004; # keep this compatible, an old perl is all we may have before
# we build the new one
use strict;
BEGIN {
# Get function prototypes
require './regen/regen_lib.pl';
require './regen/embed_lib.pl';
}
# This program has historically generated compatibility macros for a few
# functions of the form Perl_FOO(pTHX_ ...). Those macros would be named
# FOO(...), and would expand outside the core to Perl_FOO_nocontext(...)
# instead of the expected value. This was done so XS code that didn't do a
# PERL_GET_CONTEXT would continue to work unchanged after threading was
# introduced. Any new API functions that came along would require an aTHX_
# parameter; this was just to avoid breaking existing source. Hence no new
# functions need be added to the list of such macros. This is the list.
# All have varargs.
#
# N.B. If you change this list, update the copy in autodoc.pl. This is likely
# to never happen, so not worth coding automatic synchronization.
my @have_compatibility_macros = qw(
deb
form
load_module
mess
newSVpvf
sv_catpvf
sv_catpvf_mg
sv_setpvf
sv_setpvf_mg
warn
warner
);
my %has_compat_macro;
$has_compat_macro{$_} = 1 for @have_compatibility_macros;
my $unflagged_pointers;
my @az = ('a'..'z');
#
# See database of global and static function prototypes in embed.fnc
# This is used to generate prototype headers under various configurations,
# export symbols lists for different platforms, and macros to provide an
# implicit interpreter context argument.
#
my $error_count = 0;
sub die_at_end ($) { # Keeps going for now, but makes sure the regen doesn't
# succeed.
warn shift;
$error_count++;
}
sub full_name ($$) { # Returns the function name with potentially the
# prefixes 'S_' or 'Perl_'
my ($func, $flags) = @_;
if ($flags =~ /[ps]/) {
# An all uppercase macro name gets an uppercase prefix.
return (($flags =~ tr/mp// > 1) && $func !~ /[[:lower:]]/)
? "PERL_$func"
: "Perl_$func";
}
return "S_$func" if $flags =~ /[SIi]/;
return $func;
}
sub open_print_header {
my ($file, $quote) = @_;
return open_new($file, '>',
{ file => $file, style => '*', by => 'regen/embed.pl',
from => [
'embed.fnc',
'intrpvar.h',
'perlvars.h',
'regen/opcodes',
'regen/embed.pl',
'regen/embed_lib.pl',
'regen/HeaderParser.pm',
],
final => "\nEdit those files and run 'make regen_headers' to effect changes.\n",
copyright => [1993 .. 2022],
quote => $quote });
}
sub open_buf_out {
$_[0] //= "";
open my $fh,">", \$_[0]
or die "Failed to open buffer: $!";
return $fh;
}
my %type_asserts = (
# Templates for argument type checking for different argument types.
# __arg__ will be replaced by the parameter variable name
'AV*' => "SvTYPE(__arg__) == SVt_PVAV",
'HV*' => "SvTYPE(__arg__) == SVt_PVHV",
# Any CV* might point at a PVCV or PVFM
'CV*' => "SvTYPE(__arg__) == SVt_PVCV || SvTYPE(__arg__) == SVt_PVFM",
# We don't check GV*s for now because too many functions
# take non-initialised GV pointers
);
# generate proto.h
sub generate_proto_h {
my ($all)= @_;
my $pr = open_buf_out(my $proto_buffer);
my $ret;
foreach (@$all) {
if ($_->{type} ne "content") {
print $pr "$_->{line}";
next;
}
my $embed= $_->{embed}
or next;
my $level= $_->{level};
my $ind= $level ? " " : "";
$ind .= " " x ($level-1) if $level>1;
my $inner_ind= $ind ? " " : " ";
my ($flags, $retval, $plain_func, $args, $assertions ) =
@{$embed}{qw(flags return_type name args assertions)};
if ($flags =~ / ( [^ AabCDdEefFhIiMmNnOoPpRrSsTUuWXx;] ) /xx) {
die_at_end "flag $1 is not legal (for function $plain_func)";
}
my @nonnull;
my $args_assert_line = ( $flags !~ /m/ );
my $has_depth = ( $flags =~ /W/ );
my $has_context = ( $flags !~ /T/ );
my $never_returns = ( $flags =~ /r/ );
my $binarycompat = ( $flags =~ /b/ );
my $has_mflag = ( $flags =~ /m/ );
my $is_malloc = ( $flags =~ /a/ );
my $can_ignore = $flags !~ /[RP]/ && !$is_malloc;
my $extensions_only = ( $flags =~ /E/ );
my @asserts;
my $func;
if (! $can_ignore && $retval eq 'void') {
warn "It is nonsensical to require the return value of a void function ($plain_func) to be checked";
}
my $has_E_or_X = $flags =~ /[EX]/;
if ($has_E_or_X + ($flags =~ tr/AC//) > 1) {
die_at_end "$plain_func: A, C, and either E or X flags are"
. " mutually exclusive";
}
die_at_end "$plain_func: S and p flags are mutually exclusive"
if $flags =~ tr/Sp// > 1;
if ($has_mflag) {
if ($flags =~ /S/) {
die_at_end "$plain_func: m and S flags are mutually exclusive";
}
}
else {
die_at_end "$plain_func: u flag only usable with m" if $flags =~ /u/;
}
my ($static_flag, @extra_static_flags)= $flags =~/([SsIi])/g;
if (@extra_static_flags) {
my $flags_str = join ", ", $static_flag, @extra_static_flags;
$flags_str =~ s/, (\w)\z/ and $1/;
die_at_end "$plain_func: flags $flags_str are mutually exclusive\n";
}
my $static_inline = 0;
if ($static_flag) {
my $type;
if ($never_returns) {
$type = {
'S' => 'PERL_STATIC_NO_RET',
's' => 'PERL_STATIC_NO_RET',
'i' => 'PERL_STATIC_INLINE_NO_RET',
'I' => 'PERL_STATIC_FORCE_INLINE_NO_RET'
}->{$static_flag};
}
else {
$type = {
'S' => 'STATIC',
's' => 'STATIC',
'i' => 'PERL_STATIC_INLINE',
'I' => 'PERL_STATIC_FORCE_INLINE'
}->{$static_flag};
}
$retval = "$type $retval";
die_at_end "Don't declare static function '$plain_func' pure" if $flags =~ /P/;
$static_inline = $type =~ /^PERL_STATIC(?:_FORCE)?_INLINE/;
}
else {
# A publicly accessible non-static element needs to have a Perl_
# prefix available to call it with (in case of name conflicts).
die_at_end "'$plain_func' requires p flag because has A or C flag"
if $flags !~ /p/
&& $flags =~ /[AC]/
&& $plain_func !~ /[Pp]erl/;
if ($never_returns) {
$retval = "PERL_CALLCONV_NO_RET $retval";
}
else {
$retval = "PERL_CALLCONV $retval";
}
}
$func = full_name($plain_func, $flags);
die_at_end "For '$plain_func', M flag requires p flag"
if $flags =~ /M/ && $flags !~ /p/;
my $C_required_flags = '[pIimbs]';
die_at_end
"For '$plain_func', C flag requires one of $C_required_flags] flags"
if $flags =~ /C/
&& ($flags !~ /$C_required_flags/
# Notwithstanding the
# above, if the name won't
# clash with a user name,
# it's ok.
&& $plain_func !~ /^[Pp]erl/);
die_at_end "For '$plain_func', X flag requires one of [Iip] flags"
if $flags =~ /X/ && $flags !~ /[Iip]/;
die_at_end "For '$plain_func', X and m flags are mutually exclusive"
if $flags =~ /X/ && $has_mflag;
die_at_end "For '$plain_func', [Ii] with [ACX] requires p flag"
if $flags =~ /[Ii]/ && $flags =~ /[ACX]/ && $flags !~ /p/;
die_at_end "For '$plain_func', b and m flags are mutually exclusive"
. " (try M flag)" if $flags =~ /b/ && $has_mflag;
die_at_end "For '$plain_func', b flag without M flag requires D flag"
if $flags =~ /b/ && $flags !~ /M/ && $flags !~ /D/;
die_at_end "For '$plain_func', I and i flags are mutually exclusive"
if $flags =~ tr/Ii// > 1;
$ret = "";
$ret .= "$retval\n";
$ret .= "$func(";
if ( $has_context ) {
$ret .= @$args ? "pTHX_ " : "pTHX";
}
if (@$args) {
die_at_end "$plain_func: n flag is contradicted by having arguments"
if $flags =~ /n/;
my $n;
for my $arg ( @$args ) {
++$n;
if ($arg =~ / ^ " (.+) " $ /x) { # Handle literal string
my $name = $1;
# Make the string a legal C identifier; 'p' is arbitrary,
# and is because C reserves leading underscores
$name =~ s/^\W/p/a;
$name =~ s/\W/_/ag;
$arg = "const char * const $name";
die_at_end "$plain_func: func: m flag required for"
. '"literal" argument' unless $has_mflag;
}
else {
my $nn = ( $arg =~ s/\bNN\b// );
my $nz = ( $arg =~ s/\bNZ\b// );
my $nullok = ( $arg =~ s/\bNULLOK\b// );
my $nocheck = ( $arg =~ s/\bNOCHECK\b// );
# Trim $arg and remove multiple blanks
$arg =~ s/^\s+//;
$arg =~ s/\s+$//;
$arg =~ s/\s{2,}/ /g;
die_at_end ":$func: $arg Use only one of NN, NULLOK, and NZ"
if 0 + $nn + $nz + $nullok > 1;
push( @nonnull, $n ) if $nn;
# A non-pointer shouldn't have a pointer-related modifier.
# But typedefs may be pointers without our knowing it, so
# we can't check for non-pointer issues. We can only
# check for the case where the argument is definitely a
# pointer.
if ($args_assert_line && $arg =~ /\*/) {
if ($nn + $nullok == 0) {
warn "$func: $arg needs NN or NULLOK\n";
++$unflagged_pointers;
}
warn "$func: $arg should not have NZ\n" if $nz;
}
push( @nonnull, $n ) if $nn;
# Make sure each arg has at least a type and a var name.
# An arg of "int" is valid C, but want it to be "int foo".
my $argtype = ( $arg =~ m/^(\w+(?:\s*\*+)?)/ )[0];
defined $argtype and $argtype =~ s/\s+//g;
my $temp_arg = $arg;
$temp_arg =~ s/\*//g;
$temp_arg =~ s/\s*\bstruct\b\s*/ /g;
if ( ($temp_arg ne "...")
&& ($temp_arg !~ /\w+\s+(\w+)(?:\[\d+\])?\s*$/) ) {
die_at_end "$func: $arg ($n) doesn't have a name\n";
}
my $argname = $1;
if (defined $argname && (! $has_mflag || $binarycompat)) {
if ($nn||$nz) {
push @asserts, "assert($argname)";
}
if ( ! $nocheck
&& defined $argtype
&& exists $type_asserts{$argtype})
{
my $type_assert =
$type_asserts{$argtype} =~ s/__arg__/$argname/gr;
$type_assert = "!$argname || $type_assert" if $nullok;
push @asserts, "assert($type_assert)";
}
}
}
}
$ret .= join ", ", @$args;
}
else {
$ret .= "void" if !$has_context;
}
$ret .= " comma_pDEPTH" if $has_depth;
$ret .= ")";
push @asserts, @$assertions if $assertions;
my @attrs;
if ( $flags =~ /r/ ) {
push @attrs, "__attribute__noreturn__";
}
if ( $flags =~ /D/ ) {
push @attrs, "__attribute__deprecated__";
}
if ( $is_malloc ) {
push @attrs, "__attribute__malloc__";
}
if ( !$can_ignore ) {
push @attrs, "__attribute__warn_unused_result__";
}
if ( $flags =~ /P/ ) {
push @attrs, "__attribute__pure__";
}
if ( $flags =~ /I/ ) {
push @attrs, "__attribute__always_inline__";
}
# roughly the inverse of the rules used in makedef.pl
if ( $flags !~ /[AbCeIimSX]/ ) {
push @attrs, '__attribute__visibility__("hidden")'
}
if( $flags =~ /f/ ) {
my $prefix = $has_context ? 'pTHX_' : '';
my ($argc, $pat);
if (!defined $args->[1]) {
use Data::Dumper;
die Dumper($_);
}
if ($args->[-1] eq '...') {
$argc = scalar @$args;
$pat = $argc - 1;
$argc = $prefix . $argc;
}
else {
# don't check args, and guess which arg is the pattern
# (one of 'fmt', 'pat', 'f'),
$argc = 0;
my @fmts = grep $args->[$_] =~ /\b(f|pat|fmt)$/, 0..$#$args;
if (@fmts != 1) {
die "embed.pl: '$plain_func': can't determine pattern arg\n";
}
$pat = $fmts[0] + 1;
}
my $macro = grep($_ == $pat, @nonnull)
? '__attribute__format__'
: '__attribute__format__null_ok__';
if ($plain_func =~ /strftime/) {
push @attrs, sprintf "%s(__strftime__,%s1,0)", $macro, $prefix;
}
else {
push @attrs, sprintf "%s(__printf__,%s%d,%s)", $macro,
$prefix, $pat, $argc;
}
}
elsif ((grep { $_ eq '...' } @$args) && $flags !~ /F/) {
die_at_end "$plain_func: Function with '...' arguments must have"
. " f or F flag";
}
if ( @attrs ) {
$ret .= "\n";
$ret .= join( "\n", map { (" " x 8) . $_ } @attrs );
}
$ret .= ";";
$ret = "/* $ret */" if $has_mflag;
# Hide the prototype from non-authorized code. This acts kind of like
# __attribute__visibility__("hidden") for cases where that can't be
# used.
$ret = "#${ind}if defined(PERL_CORE) || defined(PERL_EXT)\n"
. $ret
. " \n#${ind}endif"
if $extensions_only;
# We don't hide the ARGS_ASSERT macro; having that defined does no
# harm, and otherwise some inline functions that are looking for it
# would fail to compile.
if ($args_assert_line || @asserts) {
$ret .= "\n#${ind}define PERL_ARGS_ASSERT_\U$plain_func\E";
if (@asserts) {
$ret .= " \\\n";
my $line = "";
while(@asserts) {
my $assert = shift @asserts;
if(length($line) + length($assert) > 78) {
$ret .= $line . "; \\\n";
$line = "";
}
$line .= " " x 8 if !length $line;
$line .= "; " if $line =~ m/\S/;
$line .= $assert;
}
$ret .= $line if length $line;
$ret .= "\n";
}
}
$ret .= "\n";
$ret = "#${ind}ifndef PERL_NO_INLINE_FUNCTIONS\n$ret\n#${ind}endif"
if $static_inline;
$ret = "#${ind}ifndef NO_MATHOMS\n$ret\n#${ind}endif"
if $binarycompat;
$ret .= @attrs ? "\n\n" : "\n";
print $pr $ret;
}
close $pr;
my $clean= normalize_group_content($proto_buffer);
my $fh = open_print_header("proto.h");
print $fh <<~"EOF";
START_EXTERN_C
$clean
#ifdef PERL_CORE
# include "pp_proto.h"
#endif
END_EXTERN_C
EOF
read_only_bottom_close_and_rename($fh) if ! $error_count;
}
{
my $hp= HeaderParser->new();
sub normalize_group_content {
open my $in, "<", \$_[0]
or die "Failed to open buffer: $!";
$hp->parse_fh($in);
my $ppc= sub {
my ($self, $line_data)= @_;
# re-align defines so that the definitions line up at the 48th col
# as much as possible.
if ($line_data->{sub_type} eq "#define") {
$line_data->{line}=~s/^(\s*#\s*define\s+\S+?(?:\([^()]*\))?\s)(\s*)(\S+)/
sprintf "%-48s%s", $1, $3/e;
}
};
my $clean= $hp->lines_as_str($hp->group_content(),$ppc);
return $clean;
}
}
sub normalize_and_print {
my ($file, $buffer)= @_;
my $fh = open_print_header($file);
print $fh normalize_group_content($buffer);
read_only_bottom_close_and_rename($fh);
}
sub readvars {
my ($file, $pre) = @_;
my $hp= HeaderParser->new()->read_file($file);
my %seen;
foreach my $line_data (@{$hp->lines}) {
#next unless $line_data->is_content;
my $line= $line_data->line;
if ($line=~m/^\s*PERLVARA?I?C?\(\s*$pre\s*,\s*(\w+)/){
$seen{$1}++
and
die_at_end "duplicate symbol $1 while processing $file line "
. ($line_data->start_line_num) . "\n"
}
}
my @keys= sort { lc($a) cmp lc($b) ||
$a cmp $b }
keys %seen;
return @keys;
}
sub add_indent {
#my ($ret, $add, $width)= @_;
my $width= $_[2] || 48;
$_[0] .= " " x ($width-length($_[0])) if length($_[0])<$width;
$_[0] .= " " unless $_[0]=~/\s\z/;
if (defined $_[1]) {
$_[0] .= $_[1];
}
return $_[0];
}
sub indent_define {
my ($from, $to, $indent, $width) = @_;
$indent = '' unless defined $indent;
my $ret= "#${indent}define $from";
add_indent($ret,"$to\n",$width);
}
sub multon {
my ($sym,$pre,$ptr,$ind) = @_;
$ind//="";
indent_define("PL_$sym", "($ptr$pre$sym)", $ind);
}
sub embed_h {
my (
$em, # file handle
$guard, # ifdef text
$funcs # functions to go into this text
) = @_;
my $lines;
foreach (@$funcs) {
if ($_->{type} ne "content") {
$lines .= $_->{line};
next;
}
my $level= $_->{level};
my $embed= $_->{embed} or next;
my ($flags,$retval,$func,$args) = @{$embed}{qw(flags return_type name args)};
my $full_name = full_name($func, $flags);
next if $full_name eq $func; # Don't output a no-op.
my $ret = "";
my $ind= $level ? " " : "";
$ind .= " " x ($level-1) if $level>1;
my $inner_ind= $ind ? " " : " ";
if ($flags =~ tr/mp// > 1) { # Has both m and p
# Yields
# #define Perl_func func
# which works when there is no thread context.
$ret = indent_define($full_name, $func, $ind);
if ($flags !~ /[T]/) {
# But when there is the possibility of a thread context
# parameter, $ret works only on non-threaded builds
my $no_thread_full_define = $ret;
# And we have to do more when there are threads. First,
# convert the input argument list to 'a', 'b' .... This keeps
# us from having to worry about all the extra stuff in the
# input list; stuff like the type declarations, things like
# NULLOK, and pointers '*'.
my $argname = 'a';
my @stripped_args;
push @stripped_args, $argname++ for $args->@*;
my $arglist = join ",", @stripped_args;
# In the threaded case, the Perl_ form is expecting an aTHX
# first argument. Use mTHX to match that, which isn't passed
# on to the short form name, as that is expecting an implicit
# aTHX. The non-threaded case just uses what we generated
# above for the /T/ flag case.
my $mTHX_ = "mTHX";
$mTHX_ .= ',' if $arglist ne "";
$ret = "#${ind}ifdef USE_THREADS\n"
. "#${ind} define $full_name($mTHX_$arglist)"
. " $func($arglist)\n"
. "#${ind}else\n"
. "$ind $no_thread_full_define" # No \n because no chomp
. "#${ind}endif\n";
}
}
elsif ($flags !~ /[omM]/) {
my $argc = scalar @$args;
if ($flags =~ /[T]/) {
$ret = indent_define($func, $full_name, $ind);
}
else {
my $use_va_list = $argc && $args->[-1] =~ /\.\.\./;
if($use_va_list) {
# CPP has trouble with empty __VA_ARGS__ and comma joining,
# so we'll have to eat an extra params here.
if($argc < 2) {
die "Cannot use ... as the only parameter to a macro ($func)\n";
}
$argc -= 2;
}
my $paramlist = join(",", @az[0..$argc-1],
$use_va_list ? ("...") : ());
my $replacelist = join(",", @az[0..$argc-1],
$use_va_list ? ("__VA_ARGS__") : ());
$ret = "#${ind}define $func($paramlist) ";
add_indent($ret,full_name($func, $flags) . "(aTHX");
if ($replacelist) {
$ret .= ($flags =~ /m/) ? "," : "_ ";
$ret .= $replacelist;
}
if ($flags =~ /W/) {
if ($replacelist) {
$ret .= " comma_aDEPTH";
} else {
die "Can't use W without other args (currently)";
}
}
$ret .= ")\n";
if($has_compat_macro{$func}) {
# Make older ones available only when !MULTIPLICITY or PERL_CORE or PERL_WANT_VARARGS
# These should not be done uncondtionally because existing
# code might call e.g. warn() without aTHX in scope.
$ret = "#${ind}if !defined(MULTIPLICITY) || defined(PERL_CORE) || defined(PERL_WANT_VARARGS)\n" .
$ret .
"#${ind}endif\n";
}
}
$ret = "#${ind}ifndef NO_MATHOMS\n$ret#${ind}endif\n" if $flags =~ /b/;
}
$lines .= $ret;
}
# remove empty blocks
1 while $lines =~ s/^#\s*if.*\n#\s*endif.*\n//mg
or $lines =~ s/^(#\s*if)\s+(.*)\n#else.*\n/$1 !($2)\n/mg;
if ($guard) {
print $em "$guard /* guard */\n";
$lines=~s/^#(\s*)/"#".(length($1)?" ":" ").$1/mge;
}
print $em $lines;
print $em "#endif\n" if $guard;
}
sub generate_embed_h {
my ($all, $api, $ext, $core)= @_;
my $em= open_buf_out(my $embed_buffer);
print $em <<~'END';
/* (Doing namespace management portably in C is really gross.) */
/* By defining PERL_NO_SHORT_NAMES (not done by default) the short forms
* (like warn instead of Perl_warn) for the API are not defined.
* Not defining the short forms is a good thing for cleaner embedding.
* BEWARE that a bunch of macros don't have long names, so either must be
* added or don't use them if you define this symbol */
#ifndef PERL_NO_SHORT_NAMES
/* Hide global symbols */
END
embed_h($em, '', $api);
embed_h($em, '#if defined(PERL_CORE) || defined(PERL_EXT)', $ext);
embed_h($em, '#if defined(PERL_CORE)', $core);
print $em <<~'END';
#endif /* #ifndef PERL_NO_SHORT_NAMES */
#if !defined(PERL_CORE)
/* Compatibility stubs. Compile extensions with -DPERL_NOCOMPAT to
* disable them.
*/
# define sv_setptrobj(rv,ptr,name) sv_setref_iv(rv,name,PTR2IV(ptr))
# define sv_setptrref(rv,ptr) sv_setref_iv(rv,NULL,PTR2IV(ptr))
#endif
#if !defined(PERL_CORE) && !defined(PERL_NOCOMPAT)
/* Compatibility for various misnamed functions. All functions
in the API that begin with "perl_" (not "Perl_") take an explicit
interpreter context pointer.
The following are not like that, but since they had a "perl_"
prefix in previous versions, we provide compatibility macros.
*/
# define perl_atexit(a,b) call_atexit(a,b)
END
foreach (@$all) {
my $embed= $_->{embed} or next;
my ($flags, $retval, $func, $args) = @{$embed}{qw(flags return_type name args)};
next unless $flags =~ /O/;
my $alist = join ",", @az[0..$#$args];
my $ret = "# define perl_$func($alist) ";
print $em add_indent($ret,"$func($alist)\n");
}
print $em <<~'END';
/* Before C99, macros could not wrap varargs functions. This
provides a set of compatibility functions that don't take an
extra argument but grab the context pointer using the macro dTHX.
*/
#if defined(MULTIPLICITY) && !defined(PERL_NO_SHORT_NAMES) && !defined(PERL_WANT_VARARGS)
END
foreach (@have_compatibility_macros) {
print $em indent_define($_, "Perl_${_}_nocontext", " ");
}
print $em <<~'END';
#endif
#endif /* !defined(PERL_CORE) && !defined(PERL_NOCOMPAT) */
#if !defined(MULTIPLICITY)
/* undefined symbols, point them back at the usual ones */
END
foreach (@have_compatibility_macros) {
print $em indent_define("Perl_${_}_nocontext", "Perl_$_", " ");
}
print $em "#endif\n";
close $em;
normalize_and_print('embed.h',$embed_buffer)
unless $error_count;
}
sub generate_embedvar_h {
my $em = open_buf_out(my $embedvar_buffer);
print $em "#if defined(MULTIPLICITY)\n",
indent_define("vTHX","aTHX"," ");
my @intrp = readvars 'intrpvar.h','I';
#my @globvar = readvars 'perlvars.h','G';
for my $sym (@intrp) {
my $ind = " ";
if ($sym eq 'sawampersand') {
print $em "# if !defined(PL_sawampersand)\n";
$ind = " ";
}
my $line = multon($sym, 'I', 'vTHX->', $ind);
print $em $line;
if ($sym eq 'sawampersand') {
print $em "# endif /* !defined(PL_sawampersand) */\n";
}
}
print $em "#endif /* MULTIPLICITY */\n";
close $em;
normalize_and_print('embedvar.h',$embedvar_buffer)
unless $error_count;
}
sub update_headers {
my ($all, $api, $ext, $core) = setup_embed(); # see regen/embed_lib.pl
generate_proto_h($all);
die_at_end "$unflagged_pointers pointer arguments to clean up\n" if $unflagged_pointers;
generate_embed_h($all, $api, $ext, $core);
generate_embedvar_h();
die "$error_count errors found" if $error_count;
}
update_headers() unless caller;
# ex: set ts=8 sts=4 sw=4 et: