/usr/local/CPAN/VCS-LibCVS/VCS/LibCVS/Client/LoggingIOHandle.pm


#
# Copyright (c) 2003,2004,2005 Alexander Taler (dissent@0--0.org)
#
# All rights reserved. This program is free software; you can redistribute it
# and/or modify it under the same terms as Perl itself.
#

package VCS::LibCVS::Client::LoggingIOHandle;

use strict;
use IO::Handle;

#
# An IO::Handle which logs everything that goes through it.  Useful for
# debugging protcol implementations
#

###############################################################################
# Class constants
###############################################################################

use constant REVISION => '$Header: /cvsroot/libcvs-perl/libcvs-perl/VCS/LibCVS/Client/LoggingIOHandle.pm,v 1.5 2005/10/10 12:52:11 dissent Exp $ ';

use vars ('@ISA');
@ISA = ("IO::Handle");

###############################################################################
# Private variables
###############################################################################

# $self->{next}        The wrapped IOHandle, to which calls are forwarded
# $self->{Prefix}      String to prepend to each line
# $self->{LogOutput}   IOHandle where output is duplicated, with optional prefix
# $self->{NotNewLine}  False when a new line has just been printed, so the next
#                      line can be prepended with the prefix.

###############################################################################
# Class routines
###############################################################################

# A new LoggingIOHandle is built around an existing IO::Handle.  The
# constructor takes one arg, which is an IO::Handle.
sub new {
  my $class = shift;
  my $ioh   = shift;

  my $that = bless {}, $class;
  $that->{next} = $ioh;
  $that->logfile();
  $that->{NotNewLine} = 0;
  return $that;
}

###############################################################################
# Instance routines
###############################################################################

# It doesn't put the prefix on each line of multiple line prints
# and doesn't handle multiple line prints properly
sub print {
  my $self = shift;
  if ($self->{Prefix} && (!$self->{NotNewLine})) {
    $self->{LogOutput}->print($self->{Prefix});
  }

  # Set NotNewLine
  if (!$self->{NotNewLine}) {
    $self->{NotNewLine} = 1;
  }
  map { $self->{NotNewLine} = 0 if /\n/ } @_;

  $self->{LogOutput}->print(@_);
  $self->{LogOutput}->flush;

  return $self->{next}->print(@_);
}

sub getc {
  my $self = shift;
  my $char = $self->{next}->getc();

  if (($self->{Prefix}) && (!$self->{NotNewLine})) {
    $self->{LogOutput}->print($self->{Prefix});
  }

  $self->{NotNewLine} = ($char ne "\n");
  $self->{LogOutput}->print($char);
  $self->{LogOutput}->flush();

  return $char;
}

sub getline {
  my $self = shift;
  my $line = $self->{next}->getline();

  if (($self->{Prefix}) && (!$self->{NotNewLine})) {
    $self->{LogOutput}->print($self->{Prefix});
  }

  $self->{NotNewLine} = 0;
  $self->{LogOutput}->print($line);
  $self->{LogOutput}->flush();

  return $line;
}

sub read {
  my $self = shift;
  return $self->{next}->read(@_);
}

# set and get the prefix to use
# Undefined means don't print a prefix
sub prefix {
  my ($self, $new_prefix) = @_;
  $self->{Prefix} = $new_prefix if (defined $new_prefix);
  return $self->{Prefix};
}

# set the output filename
# If it's undefined, STDERR is used
sub logfile {
  my ($self, $filename) = @_;
  if (defined $filename) {
    $self->{LogOutput} = IO::File->new(">> $filename");
  } else {
    $self->{LogOutput} = IO::Handle->new_from_fd(fileno(STDERR), ">>");
  }
}

###############################################################################
# Private routines
###############################################################################

1;