#############################################################################
## Name: stdout.pm
## Purpose: Safe::World::stdout
## Author: Graciliano M. P.
## Modified by:
## Created: 08/09/2003
## RCS-ID:
## Copyright: (c) 2003 Graciliano M. P.
## Licence: This program is free software; you can redistribute it and/or
## modify it under the same terms as Perl itself
#############################################################################
package Safe::World::stdout ;
use strict qw(vars);
use vars qw($VERSION @ISA) ;
$VERSION = '0.02' ;
no warnings ;
##########
# SCOPES #
##########
use vars qw($Safe_World_NOW) ;
*Safe_World_NOW = \$Safe::World::NOW ;
######################
# CHECK_HEADSPLITTER #
######################
sub check_headsplitter {
my $this = shift ;
$this->{AUTOHEAD_DATA} .= shift ;
my $headsplitter = $this->{HEADSPLITTER} ;
my ($headers , $end) ;
if ( ref($headsplitter) eq 'CODE' ) {
($headers , $end) = &$headsplitter( $Safe_World_NOW , $this->{AUTOHEAD_DATA} ) ;
}
elsif ( $this->{AUTOHEAD_DATA} =~ /^(.*?$headsplitter)(.*)/s ) {
$headers = $1 ;
$end = $2 ;
}
delete $this->{AUTOHEAD_DATA} if $headers ne '' || $end ne '' ;
return ($headers , $end) ;
}
#####################
# HEADSPLITTER_HTML #
#####################
sub headsplitter_html {
shift ;
my $headsplitter ;
if ( $_[0] =~ /Content-Type:\s*\S+(.*?)(\015?\012\015?\012|\r?\n\r?\n)/si ) {
if ($1 !~ /<[^>]+>/s) { $headsplitter = $2 ;}
}
## Try to fix wrong headers:
if ( !$headsplitter && $_[0] =~ /^(.*?)(?:\015?\012|\r?\n)([ \t]*<[^>]+>[ \t]*)(?:\015?\012|\r?\n)/s ) {
if ($1 !~ /<[^>]+>/s) { $headsplitter = $2 ;}
}
if ( !$headsplitter && $_[0] =~ /^(.*?)(<html\s*>\s*<[^>]+>)/si ) {
if ($1 !~ /<[^>]+>/s) { $headsplitter = $2 ;}
}
if ( !$headsplitter && $_[0] =~ /^(.*?)(<[^>]+>\s*<[^>]+>)/s ) {
my ($s1 , $s2) = ($1,$2) ;
if ($s1 !~ /<[^>]+>/s && $s1 !~ /(?:^|[\r\n\015\012])[^\s:]+:[^\r\n\015\012]+$/s) {
my ($line) = ( $s1 =~ /([^\r\n\015\012]+)$/s );
$headsplitter = $line . $s2 ;
}
}
if ( !$headsplitter && $_[0] =~ /^(.*?)(\015?\012\015?\012|\r?\n\r?\n)/s ) {
if ($1 !~ /<[^>]+>/s) { $headsplitter = $2 ;}
}
my $is_all_content ;
if ( !$headsplitter && $_[0] =~ /^(?:<[^>]+>|>)+(?:\015?\012|\r?\n)/s ) { $headsplitter = $is_all_content = 1 ;}
if ( !$headsplitter && $_[0] =~ /(?:\015?\012|\r?\n)([ \t]*(?:<[^>]+>|>)+\s)/s ) { $headsplitter = $1 ;}
my ($headers , $end) ;
if ( $is_all_content ) {
$end = $_[0] ;
}
elsif ( $headsplitter ne '' && $_[0] =~ /^(.*?)\Q$headsplitter\E(.*)/s ) {
$headers = $1 ;
$end = $2 ;
if ($headsplitter !~ /^\s+$/s) { $end = "$headsplitter$end" ;}
else { $headers .= $headsplitter ;}
}
return ($headers , $end) ;
}
###########
# HEADERS #
###########
sub headers {
return '' if ref($_[0]->{HEADOUT}) ne 'SCALAR' ;
if ($#_ >= 1) { ${$_[0]->{HEADOUT}} = $_[1] ;}
my $headers = ${ $_[0]->{HEADOUT} } ;
return $headers ;
}
###############
# STDOUT_DATA #
###############
sub stdout_data {
if ( ref($_[0]->{STDOUT}) eq 'SCALAR' ) {
if ($#_ >= 1) { ${$_[0]->{STDOUT}} = $_[1] ;}
my $stdout = ${ $_[0]->{STDOUT} } ;
return $stdout ;
}
else { return '' ;}
}
###############
# BUFFER_DATA #
###############
sub buffer_data {
if ($#_ >= 1) { $_[0]->{BUFFER} = $_[1] ;}
my $buf = $_[0]->{BUFFER} ;
return $buf ;
}
#########
# BLOCK #
#########
sub block {
my $this = shift ;
$this->{BLOCKED} = 1 ;
}
###########
# UNBLOCK #
###########
sub unblock {
my $this = shift ;
$this->{BLOCKED} = undef ;
}
#########
# PRINT #
#########
sub print { &PRINT ;}
################
# PRINT_STDOUT #
################
sub print_stdout {
#print main::STDOUT "std>> $| [[$_[1]]] [[$_[0]->{BUFFER}]]\n" ;
my $this = shift ; return 1 if $_[0] eq '' ;
return if $this->{BLOCKED} ;
my $stdout = $this->{STDOUT} ;
if ( $this->{AUTOHEAD} && !$_[1] ) {
my ($headers , $end) = $this->check_headsplitter($_[0]) ;
if ($headers ne '' || $end ne '') {
$this->{AUTOHEAD} = undef ;
$this->print_headout($headers,1) if $headers ne '' ;
$this->print($end) if $end ne '' ;
return 1 ;
}
}
else {
if ( !$_[1] ) {
if ( !$this->{HEADER_CLOSED} && $this->{ONCLOSEHEADERS} ) {
#print main::STDOUT "**>> $this->{HEADER_CLOSED} && $this->{ONCLOSEHEADERS}\n" ;
$this->{HEADER_CLOSED} = 1 ;
$this->call_oncloseheaders ;
}
else { $this->{HEADER_CLOSED} = 1 ;}
}
if ( ref($stdout) eq 'SCALAR' ) { $$stdout .= $_[0] ;}
elsif ( ref($stdout) eq 'CODE' ) {
my $sel = $Safe_World_NOW->{SELECT}{PREVSTDOUT} ? &Safe::World::SELECT( $Safe_World_NOW->{SELECT}{PREVSTDOUT} ) : undef ;
&$stdout($Safe_World_NOW , $_[0]) ;
&Safe::World::SELECT($sel) if $sel ;
}
else { print $stdout $_[0] ;}
}
return 1 ;
}
#################
# PRINT_HEADOUT #
#################
sub print_headout {
my $this = shift ; return 1 if $_[0] eq '' ;
my $headout = $this->{HEADOUT} ;
return $this->print_stdout($_[0]) if !$headout ;
if ( !$_[1] && $this->{AUTOHEAD} ) {
my ($headers , $end) = $this->check_headsplitter($_[0]) ;
if ($headers ne '' || $end ne '') {
$this->{AUTOHEAD} = undef ;
$this->print_headout($headers,1) if $headers ne '' ;
$this->print($end) if $end ne '' ;
return 1 ;
}
return ;
}
if ( ref($headout) eq 'SCALAR' ) { $$headout .= $_[0] ;}
elsif ( ref($headout) eq 'CODE' ) {
my $sel = $Safe_World_NOW->{SELECT}{PREVSTDOUT} ? &Safe::World::SELECT( $Safe_World_NOW->{SELECT}{PREVSTDOUT} ) : undef ;
&$headout($Safe_World_NOW , $_[0]) ;
&Safe::World::SELECT($sel) if $sel ;
}
else { print $headout $_[0] ;}
return 1 ;
}
#################
# CLOSE_HEADERS #
#################
sub close_headers {
my $this = shift ;
##print main::STDOUT ">> $this->{AUTOHEAD} && $this->{HEADER_CLOSED} [[$this->{AUTOHEAD_DATA}]] [[$this->{BUFFER}]]\n" ;
##return if !$this->{AUTOHEAD} ;
return if (!$this->{AUTOHEAD} && $this->{HEADER_CLOSED}) || $this->{BUFFER} ne '' ;
$this->{AUTOHEAD} = undef ;
if ( $this->{AUTOHEAD_DATA} ne '' ) {
my ($headers , $end) = $this->check_headsplitter() ;
if ($headers ne '' || $end ne '') {
$this->print_headout($headers,1) if $headers ne '' ;
$this->print($end) if $end ne '' ;
}
else {
$this->print( delete $this->{AUTOHEAD_DATA} ) ;
}
}
if ( !$this->{HEADER_CLOSED} && $this->{ONCLOSEHEADERS} ) {
$this->{HEADER_CLOSED} = 1 ;
$this->call_oncloseheaders ;
}
$this->{HEADER_CLOSED} = 1 ;
return 1 ;
}
#######################
# CALL_ONCLOSEHEADERS #
#######################
sub call_oncloseheaders {
my $this = shift ;
return if !$this->{ONCLOSEHEADERS} ;
my $sel = $Safe_World_NOW->{SELECT}{PREVSTDOUT} ? &Safe::World::SELECT( $Safe_World_NOW->{SELECT}{PREVSTDOUT} ) : undef ;
my $autoflush = $this->{AUTO_FLUSH} ;
$this->{AUTO_FLUSH} = 1 ;
my $oncloseheaders = $this->{ONCLOSEHEADERS} ;
&$oncloseheaders( $Safe_World_NOW , $this->headers ) ;
$this->{AUTO_FLUSH} = $autoflush ;
&Safe::World::SELECT($sel) if $sel ;
return 1 ;
}
#########
# FLUSH #
#########
sub flush {
my $this = shift ;
if ( $this->{BUFFER} ne '' ) {
$this->print_stdout( delete $this->{BUFFER} ) ;
return 1 ;
}
return ;
}
#######################
# GET_AUTOFLUSH_VALUE #
#######################
sub get_autoflush_value {
my $this = shift ;
my $sel = select ;
my $reset ;
if ( $sel ne $this->{IO} && $sel ne 'main::STDOUT' ) { &Safe::World::SELECT($this->{IO}) ; $reset = 1 ;}
my $val = $| ;
if ($reset) { &Safe::World::SELECT($sel) ;}
return $val ;
}
#############
# TIEHANDLE #
#############
sub TIEHANDLE {
my $class = shift ;
my ($root , $stdout , $flush , $headout , $autohead , $headsplitter , $oncloseheaders) = @_ ;
my $this = {
ROOT => $root ,
STDOUT => $stdout ,
HEADOUT => $headout ,
AUTOHEAD => $autohead ,
HEADSPLITTER => $headsplitter ,
ONCLOSEHEADERS => $oncloseheaders ,
AUTO_FLUSH => $flush ,
IO => "$root\::STDOUT" ,
} ;
bless($this , $class) ;
return( $this ) ;
}
sub PRINT {
my $this = shift ;
if ( $this->{REDIRECT} ) {
${$this->{REDIRECT}} .= join("", (@_[0..$#_])) ;
}
else {
if ( !$this->{AUTO_FLUSH} && !$this->{AUTOHEAD} && !$| ) {
#print main::STDOUT "BUF>> !$autoflus_val && !$this->{AUTO_FLUSH} && !$this->{AUTOHEAD} \n" ;
$this->{BUFFER} .= join("", (@_[0..$#_])) ;
}
else {
#print main::STDOUT "PRT>> !$autoflus_val && !$this->{AUTO_FLUSH} && !$this->{AUTOHEAD} [[$_[0]]]\n" ;
$this->flush if $this->{BUFFER} ne '' ;
$this->print_stdout( join("", (@_[0..$#_])) ) ;
}
}
return 1 ;
}
sub PRINTF { &PRINT($_[0],sprintf($_[1],@_[2..$#_])) ;}
sub READ {}
sub READLINE {}
sub GETC {}
sub WRITE {}
sub FILENO {
#my $this = shift ;
#my $n = $this + 1 ;
#return $n ;
}
sub CLOSE {
my $this = shift ;
$this->{AUTO_FLUSH} = 1 ;
$this->close_headers ;
$this->flush ;
}
sub STORE {
my $this = shift ;
my $stdout = shift ;
if ( !ref($stdout) ) {
$stdout =~ s/^\*// ;
$stdout = \*{$stdout} ;
}
$this->{STDOUT} = $stdout ;
}
sub FETCH {}
sub DESTROY {
&CLOSE ;
}
#######
# END #
#######
1;