Viewing File: /usr/local/cpanel/3rdparty/perl/536/cpanel-lib/x86_64-linux/B/C/Save.pm
package B::C::Save;
use B::C::Std;
use B::C::Debug qw/debug/;
use B::C::File qw( xpvmgsect decl init const cowpv );
use B::C::Helpers qw/strlen_flags cstring_cow cow_strlen_flags/;
use Exporter ();
our @ISA = qw(Exporter);
our @EXPORT_OK = qw/savecowpv/;
my %strtable;
my %cowtable;
my %COW_map;
use constant C_DECLARATION_FOR_COW_PV => q{Static const char allCOWPVs[]};
sub savecowpv ($pv) {
my ( $cstring, $cur, $len, $utf8 ) = cow_strlen_flags($pv);
return @{ $cowtable{$cstring} } if defined $cowtable{$cstring};
if ( cowpv->index <= 0 ) {
# the 0 entry is special
cowpv->add( C_DECLARATION_FOR_COW_PV . qq{ = "";\n} );
}
my $ix = cowpv->add(qq[/* placeholder: filled later */]);
my $pvsym = sprintf( q{COWPV%d}, $ix );
$COW_map{$pvsym} = [ $ix, $len, $cstring, $pv ]; # consider removing the cstring
# local cache for this function
$cowtable{$cstring} = [ $pvsym, $cur, $len, $utf8 ];
# NOTE: $cur is total size of the perl string. len would be the length of the C string.
return ( $pvsym, $cur, $len, $utf8 );
}
#
# Run later when all our COWPV strings are setup
#
sub cowpv_setup() {
my $total_len = 0;
my @all_syms = keys %COW_map; # shuffle the list
if ( defined $ENV{BC_COWPV_SHUFFLE} && $ENV{BC_COWPV_SHUFFLE} eq 0 ) {
warn "### WARNING: BC_COWPV_SHUFFLE=0\n";
@all_syms = sort { $COW_map{$a}->[0] <=> $COW_map{$b}->[0] } @all_syms;
}
my @all_pvs;
foreach my $pvsym (@all_syms) {
my ( $ix, $len, $cstring, $pv ) = $COW_map{$pvsym}->@*;
my $comment = _comment_str($cstring);
my @cchars = cchars($pv);
# do not use the 'cstring' but split the char directly and encode it
push @all_pvs, [
cchars($pv), '0x00', '0xff',
"/* $pvsym=$comment */\n"
];
cowpv->supdate(
$ix,
q{#define %s (char*) allCOWPVs+%d /* %s */},
$pvsym,
$total_len,
$comment
);
$total_len += $len;
}
# update definition...
my $str = '';
foreach my $pv (@all_pvs) {
$str .= ( " " x 20 ) . join( ', ', @$pv );
}
my $declaration = sprintf(
C_DECLARATION_FOR_COW_PV . qq[ = {\n%s\n};\n],
$str
);
cowpv->update( 0, $declaration );
cowpv()->{_total_len} = $total_len;
return;
}
sub cchars ($pv) {
# ensure to use a different PV
$pv = $pv . "_";
chop $pv;
# "\x{100}" becomes "\xc4\x80"
utf8::encode($pv) if utf8::is_utf8($pv);
my @chars = split( '', $pv );
my @cchars = ( map { sprintf( q[0x%02x], ord($_) ) } @chars );
if ( grep { hex($_) > 255 } @cchars ) {
warn "PV: $pv";
warn "CCHARS: @cchars";
require Devel::Peek;
Devel::Peek::Dump($pv);
die qq[PV contains some unexpected characters];
}
return @cchars;
}
sub _comment_str ($str) {
$str =~ s{\Q/*\E}{??}g;
$str =~ s{\Q*/\E}{??}g;
$str =~ s{\Q\000\377\E"$}{"}; # remove the cow part
$str =~ s{\n}{\\n}g;
return $str;
}
sub _caller_comment {
return '' unless debug('stack');
my $s = stack_flat(+1);
return qq{/* $s */};
}
sub stack {
my @stack;
foreach my $level ( 0 .. 100 ) {
my @caller = grep { defined } caller($level);
@caller = map { $_ =~ s{/usr/local/cpanel/3rdparty/perl/5[0-9]+/lib64/perl5/cpanel_lib/x86_64-linux-64int/}{lib/}; $_ } @caller;
last if !scalar @caller or !defined $caller[0];
push @stack, join( ' ', @caller );
}
return \@stack;
}
sub stack_flat ( $remove = 0 ) {
$remove += 2;
my @stack = @{ stack() };
splice( @stack, 0, $remove ); # shift the first X elements
return join "\n", @stack;
}
1;
Back to Directory
File Manager