# Copyright (c) 2003, Dick Munroe (munroe@csworks.com),
#                     Cottage Software Works, Inc.
#                     All rights reserved.
#
# This program, comes with ABSOLUTELY NO WARRANTY.
# This is free software, and you are welcome to redistribute it
# under the conditions of the GNU GENERAL PUBLIC LICENSE, version 2.
#
# Specialize the behavior of VMS::Librarian for Text files.
#
# Revision History:
#
#   1.00    06-May-2003	Dick Munroe (munroe@csworks.com)
#	    Initial Version Created.
#
#   1.01    11-May-2003 Dick Munroe (munroe@csworks.com)
#	    Allow get_module to return a concatenated string.
#	    Allow add_module to accept a string as a data
#	    argument.  Break the string into appropriately delimited
#	    pieces.
#
#   1.02    11-May-2003 Dick Munroe (munroe@csworks.com)
#	    Fix a bug in replace_module.
#	    Add documentation.
#
#   1.03    13-May-2003	Dick Munroe (munroe@csworks.com)
#	    Add write_module for text modules.
#
#   1.04    13-May-2003 Dick Munroe (munroe@csworks.com)
#	    Fix carriage control in read_module.
#	    Add write_module.
#

package VMS::Librarian::Text ;

$VERSION = "1.04" ;

use strict ;
use 5.6.1 ;

use FileHandle ;
use VMS::Librarian qw(VLIB_CRE_MACTXTCAS VLIB_TEXT) ;
use VMS::Stdio qw(:CONSTANTS :FUNCTIONS) ;

@VMS::Librarian::Text::ISA = qw(VMS::Librarian) ;

sub creopt
{
    my $self = shift ;

    return $self->SUPER::creopt(
	TYPE=>VLIB_TEXT,
	IDXOPT=>VLIB_CRE_MACTXTCAS,
	KEYLEN=>39,
	ENTALL=>11,
	@_) ;
}

#
# Text in Perl is usually terminated with a new line.  The data
# inside OpenVMS Text Libraries is not.  This subtracts the newlines
# from the module data.
#

sub add_module
{
    my $self = shift ;
    my %theParams = @_ ;

    if (ref($theParams{DATA}))
    {
	foreach (@{$theParams{DATA}})
	{
	    chomp $_ ;
	}
    }
    else
    {
	#
	# Assume that it's a string with embedded new lines and
	# split it.
	#

	my @theLines = split /\n/,$theParams{DATA} ;

	if (@theLines)
	{
	    $theParams{DATA} = \@theLines ;
	}
    }

    return $self->SUPER::add_module(%theParams) ;
}

#
# Text in Perl is usually terminated with a new line.  The data
# inside OpenVMS Text Libraries is not.  This adds the newlines
# to the module data.
#

sub get_module
{
    my $self = shift ;

    return (wantarray() ? (map { $_ .= "\n" } $self->SUPER::get_module(@_))
			: ((join "\n",$self->SUPER::get_module(@_)) . "\n")) ;
}

sub new
{
    my $thePackage = shift ;

    return $thePackage->SUPER::new(@_,TYPE=>VLIB_TEXT) ;
}


#
# Read a module from a file.
#
# Input is in text mode.
# sysread treats EOF as a 0 length record.  Therefore no binary
# file may have a 0 length record or the code will think its
# at eof when the file hasn't been fully processed.
#

sub read_module {
    my $self = shift;
    my %theParams = @_;
    my $theStatus;

    my $theDebug = $self->_debug_($theParams{DEBUG}) ;

    if ($theDebug & 1) {
	print "Entering read_module";
	display (\%theParams, "read_module called with:");
    }

    die "FILENAME required in read_module" unless (defined($theParams{FILENAME})) ;

    my @theData ;
    my $theFileHandle = new FileHandle $theParams{FILENAME}, "r" ;

    if ($theFileHandle)
    {
	my $theDataRead ;

	while ($theDataRead = $theFileHandle->getline())
	{
	    push @theData, $theDataRead ;
	}
    }

    if (! defined($theFileHandle)) 
    {
	if ($theDebug & 1) { print "Error [$!][$^E] in read_module; returning undef\n" }
    }

    undef $theFileHandle ;

    if ($theDebug & 1) {
	display (\%theParams, "read_module returned with:");
	print "exiting read_module";
    }

    return (wantarray() ? (@theData)
			: (join "",@theData)) ;
}

#
# Text in Perl is usually terminated with a new line.  The data
# inside OpenVMS Text Libraries is not.  This subtracts the newlines
# from the module data.
#

sub replace_module
{
    my $self = shift ;
    my %theParams = @_ ;

    if (ref($theParams{DATA}))
    {
	foreach (@{$theParams{DATA}})
	{
	    chomp $_ ;
	}
    }
    else
    {
	#
	# Assume that it's a string with embedded new lines and
	# split it.
	#

	my @theLines = split /\n/,$theParams{DATA} ;

	if (@theLines)
	{
	    $theParams{DATA} = \@theLines ;
	}
    }

    return $self->SUPER::replace_module(%theParams) ;
}

sub write_module {
    my $self = shift;
    my %theParams = @_;
    my $theStatus;

    my $theDebug = $self->_debug_($theParams{DEBUG}) ;

    if ($theDebug & 1) {
	print "Entering write_module";
	display (\%theParams, "write_module called with:");
    }

    die "FILENAME required in write_module" unless (defined($theParams{FILENAME})) ;
    die "DATA required in write_module" unless (defined($theParams{DATA})) ;

    if (ref($theParams{DATA}))
    {
	foreach (@{$theParams{DATA}})
	{
	    chomp $_ ;
	}
    }
    else
    {
	#
	# Assume that it's a string with embedded new lines and
	# split it.
	#

	my @theLines = split /\n/,$theParams{DATA} ;

	if (@theLines)
	{
	    $theParams{DATA} = \@theLines ;
	}
    }

    my $theFileHandle = vmssysopen($theParams{FILENAME}, O_TRUNC|O_CREAT|O_WRONLY, 0, "rfm=var", "rat=cr") ;

    if ($theFileHandle)
    {
	foreach (@{$theParams{DATA}})
	{
	    $theStatus = syswrite($theFileHandle, $_, length($_)) ;
	    last if (! defined($theStatus)) ;
	}
    }

    if (! defined($theStatus)) 
    {
	if ($theDebug & 1) { print "Error [$!][$^E] in write_module; returning undef\n" }
	close($theFileHandle) ;
	return $theStatus ;
    }

    close($theFileHandle) ;

    if ($theDebug & 1) {
	display (\%theParams, "write_module returned with:");
	print "exiting write_module";
    }

    return 1 ;
}

1;
__END__

=head1 NAME

VMS::Librarian::Text - Perl extension for OpenVMS Text Libraries

=head1 DESCRIPTION

This class is derived from VMS::Librarian and provides specific
support for Text libraries.  In addition, this class acts as the
base class for any OpenVMS library containg text (currently
Macro and Help libraries).

=head2 Member Functions

=over 4

=item add_module

    $status = $l->add_module(KEY   => name,
			     DATA  => array reference)
    $status = $l->add_module(KEY   => name,
			     DATA  => string)

Since text libraries (and libraries derived from text libraries)
contain text data, the DATA parameter may be a string containing
one or more lines delimited by "\n".  The string data is
converted to an array with the new lines removed and that data is
inserted in the library.

If the DATA parameter is an array reference, trailing new lines,
if any, are removed prior to adding the module to the library.

=item creopt

    $theCreopt = VMS::Librarian->creopt(TYPE   => library type,
					KEYLEN => integer,
					ALLOC  => integer,
					IDXMAX => integer,
					UHDMAX => integer,
					ENTALL => integer,
					LUHMAX => integer,
					VERTYP => integer,
					IDXOPT => bitmap)

creopt returns a hash reference containing the creation options
used to create a new text library.

=item get_module

    @theData = $l->get_module(KEY => string)
    $theData = $l->get_module(KEY => string)

The data returned from get_module has "\n" delimiters inserted at
the end of each record.

=item new

    $l = new VMS::Librarian(LIBNAME  => string,
			    FUNCTION => integer,
			   [TYPE     => integer,]
			   [CREOPT   => hash reference])

The TYPE defaults to VLIB_TEXT if omitted..

=item replace_module

    $status = $l->replace_module(KEY   => name,
				 DATA  => array reference)
    $status = $l->replace_module(KEY   => name,
				 DATA  => string)

See add_module for the details of handling the DATA parameter.

=back 4

=head1 AUTHOR

The author of this module was is Dick Munroe
(munroe@csworks.com).  Any support questions or fixes should be
send to him at the above address.

On another note, I'm looking for work (contract or permanent).  My
resume is available at:

    http://www.csworks.com/resume

my CV (much more detailed, but too long for general distribution) is
available at:

    http://www.csworks.com/cv

I do a lot more than hack the web and Perl so take a look and if you
think there's a match, drop me a note and let us see if we can't work
something out.

=head1 SEE ALSO

VMS::Librarian (which includes this module) may be downloaded as
a zip file from:

    http://www.csworks.com/download/vms-librarian-1_03.zip

=cut
