#!/usr/bin/perl

=begin metadata

Name: paste
Description: merge corresponding or subsequent lines of files
Author: Randy Yarger, randy.yarger@nextel.com
License: perl

=end metadata

=cut


use strict;

use File::Basename qw(basename);
use Getopt::Std qw(getopts);

use constant EX_SUCCESS => 0;
use constant EX_FAILURE => 1;

my $Program = basename($0);
my ($VERSION) = '1.4';
my (@fh, @sep, %opt);

getopts('d:s', \%opt) or usage();
@ARGV or usage();

if (defined $opt{'d'}) {
	@sep = split //, eval { "$opt{d}" };
} else {
	@sep = ("\t");
}

foreach my $f (@ARGV) {
	if ($f eq '-') {
		push @fh, *STDIN;
	} else {
		if (-d $f) {
			warn "$Program: '$f': is a directory\n";
			exit EX_FAILURE;
		}
		my $fil;
		unless (open $fil, '<', $f) {
			warn "$Program: '$f': $!\n";
			exit EX_FAILURE;
		}
		push @fh, $fil;
	}
}

if ($opt{'s'}) {
	for my $i (0..$#fh) {
		my $fh = $fh[$i];
		my $current_sep = 0;
		my $tline;
		while(<$fh>) {
			chomp;
			$tline .= $_ . $sep[$current_sep];
			$current_sep = ($current_sep + 1) % scalar(@sep);
		}
		chop $tline;
		print "$tline\n";
		close $fh;
	}
	exit EX_SUCCESS;
}

while (files_open()) {
	my $current_sep = 0;
	my $tline;
	for my $i (0..$#fh) {
		if (not eof $fh[$i]) {
			my $fh = $fh[$i];
			my $line = <$fh>;
			chomp($line);
			$tline .= $line;
		}
		if ($i != $#fh) {
			$tline .= $sep[$current_sep];
			$current_sep = ($current_sep + 1) % scalar(@sep);
		}
	}
	print "$tline\n";
}
exit EX_SUCCESS;

sub files_open {
	for my $f (@fh) {
		return 1 unless eof $f;
	}
	return 0;
}

sub usage {
	print "usage: $Program [-s] [-d list] file ...\n";
	exit EX_FAILURE;
}

sub VERSION_MESSAGE {
    print "$Program version $VERSION\n";
    exit EX_SUCCESS;
}

__END__

=pod

=head1 NAME

paste - merge corresponding or subsequent lines of files

=head1 SYNOPSIS

paste [-s] [-d list] file ...

=head1 DESCRIPTION

Paste combines the corresponding lines of multiple files. Each line of each
file is printed separated by a tab character (or by the characters listed in the -d
option).

The argument '-' will result in standard input being read.
If '-' is repeated, standard input will be read one line at a time for each instance of '-'.

=head2 OPTIONS

I<paste> accepts the following options:

=over 4

=item -d list

Define the column delimiters. Each character in this list will be used
one at a time, as a delimiter for the columns. If there are fewer characters
than columns, the characters will be repeated. Standard Perl special characters
("\n", "\t", etc.) are recognized.

=item -s

Displays the output one file per row, rather than interleaving the
lines of the files.

=back

=head1 ENVIRONMENT

The working of I<paste> is not influenced by any environment variables.

=head1 BUGS

I<paste> has no known bugs, unless you count the use of eval EXPR.

=head1 AUTHOR

The Perl implementation of I<paste>
was written by Randy Yarger, I<randy.yarger@nextel.com>.

=head1 COPYRIGHT and LICENSE

This program is copyright by Randy Yarger 1999.

This program is free and open software. You may use, modify, distribute
and sell this program (and any modified variants) in any way you wish,
provided you do not restrict others to do the same.

=cut

Randy Jay Yarger        | Nextel Communications
randy.yarger@nextel.com | http://hs1.hst.msu.edu/~randy/