#!/usr/bin/perl -w
#<longest: print the longest line in a file

use Getopt::Long;
use File::Basename;
use Carp;
use strict;
use diagnostics;

use subs qw(manpage myuuid usage version where);
$ENV{'PATH'} = join ":", qw(/bin /usr/bin /usr/local/bin /opt/sfw/bin);

my $myname = basename($0);
$myname =~ s/\.\w*$//;    # strip any extension

my %options;
my @getopt_args = (
    'h|?',          # print usage
    'l=i',          # print lines longer than this
    'm',            # print manpage
    'u',            # print UUID
    'v',            # print version
    'w',            # print source location
    );

Getopt::Long::config("noignorecase", "bundling");
usage unless GetOptions(\%options, @getopt_args);

manpage if $options{'m'};
myuuid  if $options{'u'};
version if $options{'v'};
where   if $options{'w'};
usage   if $options{'h'};

my $minlength = $options{'l'} || 0;    # print if longer than this.

push(@ARGV, '-') unless @ARGV;
for my $file (@ARGV) {
    process($file, $minlength);
}

exit(0);

#---------------------------------------------------------------------
# Handle stdin or a regular file.

sub process {
    my $file    = shift;
    my $min     = shift;
    my $k       = 0;
    my $line    = 0;
    my $longest = 0;
    my $string  = '';
    my $fh;

    return unless $fh = saferead($file);
    return unless (-f $fh || -p $fh);

    while (<$fh>) {
        chomp;
        $k = length($_);

        if ($k >= $min && $min > 0) {
            print "$. $k [$_]\n";
        }

        if ($k > $longest) {
            $longest = $k;
            $string  = $_;
            $line    = $.;
        }
    }

    # Don't print anything if we haven't read anything.
    # Don't print a summary line if we haven't specified a minimum
    # length, i.e. haven't said "print anything longer than ___".

    if ($min == 0 && $line > 0) {
        print "$line $longest [$string]\n";
    }

    close($fh);
    return;
}

# --------------------------------------------------------------------
# saferead($file): opens a file (or stdin) for reading.

sub saferead {
    my $sname = (caller(0))[3];
    my $file  = shift;
    my $fh;

    if ($file eq '-') {
        unless (open($fh, "<&STDIN")) {
            warn "$sname: can't dup stdin: $!\n";
            $fh = undef;
        }
    }
    else {
        unless (open($fh, '<', $file)) {
            warn "$sname: can't read $file: $!\n";
            $fh = undef;
        }
    }

    return $fh;
}

#---------------------------------------------------------------------
# Print a usage message from the comments and exit.

sub usage {
    my ($emsg) = @_;
    use Pod::Usage qw(pod2usage);
    warn "$emsg\n" if defined $emsg;
    pod2usage(-verbose => 99, -sections => "NAME|SYNOPSIS|OPTIONS");
}

sub manpage {
    my @args = ("perldoc", "$0");
    exec { $args[0] } @args;          # safe even with one-arg list
    die("should not get here\n");
}

#---------------------------------------------------------------------
# Print the UUID, current version, or source location.

sub myuuid {
    my $UUID = sprintf("%s",
        q$UUID: 736339b5-e4eb-3611-9ee7-a20d017cd505 $ =~ /UUID: (.*) /);
    print "$UUID\n";
    exit(0);
}

sub version {
    my $VERSION = sprintf("%d.%02d", q$Revision: 1.6 $ =~ /(\d+)\.(\d+)/);
    my $DATE =
      sprintf("%s", q$Date: 2010-11-02 17:50:12-04 $ =~ /Date: (.*) /);
    print "$myname $VERSION $DATE\n";
    exit(0);
}

sub where {
    my $SOURCE =
      sprintf("%s", q$Source: /home/vogelke/bin/RCS/longest,v $ =~ /Source: (.*) /);
    print "$SOURCE\n";
    exit(0);
}

#---------------------------------------------------------------------
__END__

=head1 NAME

longest - find the longest line in a file

=head1 SYNOPSIS

longest [-hmuvw] [file ...]

=head1 OPTIONS

=over 4

=item B<-h>

Print a brief help message and exit.

=item B<-m>

Print the manual page and exit.

=item B<-u>

Print the script UUID and exit.

=item B<-v>

Print the version and exit.

=item B<-w>

Print the source location and exit.

=back

=head1 DESCRIPTION

B<longest> prints the line number, length, and contents of
the longest string in a file, not counting the newline.
If no files are entered on the command line, stdin is read.

=head1 AUTHOR

 Karl Vogel <vogelke@pobox.com>
 Sumaria Systems, Inc.

=cut
