#!/usr/bin/perl
use strict;
use warnings;
use feature 'say';
use autodie;

use FindBin '$Bin';
use lib "$Bin/lib";

use Vnlog::Util qw(parse_options read_and_preparse_input ensure_all_legends_equivalent close_nondev_inputs reconstruct_substituted_command);



# This comes from the struct option long_options in tail.c in GNU coreutils
my @specs = ( # options with no args
             "silent|quiet|q",
             "zero-terminated|z",
             "verbose|v",
             "retry",
             "F",
             "f",

             # options with args
             "bytes|c=s",
             "lines|n=s",
             "sleep-interval|s=f",
             "max-unchanged-stats=i",
             "pid=i",

             # '--follow' and '--follow=...' are valid. '--follow ...' is NOT
             # valid. parse_options handles that
             "follow:s",

             "help|h");




my %options_unsupported = ( 'bytes' => <<'EOF',
vnlog is line-oriented, so I refuse to split lines
EOF
                            'zero-terminated' => <<'EOF'
vnlog is built on assuming a particular record separator
EOF
                          );

my ($filenames,$options) = parse_options(\@ARGV, \@specs, 0, <<EOF);
  $0 [options] logfile logfile logfile ... < logfile

The most common options are (from the GNU tail manpage)

  -n, --lines=[+]NUM
         output the last NUM lines, instead of the last 10;
         or use -n +NUM to output starting with line NUM

  -f, --follow[={name|descriptor}]
         output appended data as the file grows;
         an absent option argument means 'descriptor'
EOF

if( defined $options->{follow}         &&
    length($options->{follow}) > 0     &&
    $options->{follow} ne 'name'       &&
    $options->{follow} ne 'descriptor' )
{
    die "--follow can be given ONLY as --follow=name or --follow=descriptor";
}



for my $key(keys %$options)
{
    if($options_unsupported{$key})
    {
        my $keyname = length($key) == 1 ? "-$key" : "--$key";
        die("I don't support $keyname: $options_unsupported{$key}");
    }
}

my $inputs = read_and_preparse_input($filenames,
                                     # read all lines, including comments
                                     ['cat']);
ensure_all_legends_equivalent($inputs);
say '# ' . join(' ', @{$inputs->[0]{keys}});


# When looking at normal files, tail needs the original filenames to be able to
# do its thing. A pipe filter won't do; especially if we're doing a tail -f. But
# if the thing I'm tailing is a pipe to begin with, I need to give it that pipe.
# The NAME of the device won't do. Thus I call reconstruct_substituted_command()
# telling it to substitute the dev filenames, but leave non-dev filenames alone.
#
# Additionally, since I don't use the file filter anymore, I close those pipes

my $ARGV_new = reconstruct_substituted_command($inputs, $options, [], \@specs, 1);
close_nondev_inputs($inputs);
exec 'tail', @$ARGV_new;



__END__

=head1 NAME

vnl-tail - tail a log file, preserving the legend

=head1 SYNOPSIS

 $ read_temperature | tee temp.vnl
 # temperature
 29.5
 30.4
 28.3
 22.1
 ... continually produces data

 ... at the same time, in another terminal
 $ vnl-tail -f temp.vnl
 # temperature
 28.3
 22.1
 ... outputs data as it comes in

=head1 DESCRIPTION

  Usage: vnl-tail [options] logfile logfile logfile ... < logfile

This tool runs C<tail> on given vnlog files in various ways. C<vnl-tail> is a
wrapper around the GNU coreutils C<tail> tool. Since this is a wrapper, most
commandline options and behaviors of the C<tail> tool are present; consult the
L<tail(1)> manpage for detail. The differences from GNU coreutils C<tail> are

=over

=item *

The input and output to this tool are vnlog files, complete with a legend

=item *

C<-c> is not supported because vnlog really doesn't want to break up lines

=item *

C<--zero-terminated> is not supported because vnlog assumes
newline-separated records

=back

Past that, everything C<tail> does is supported, so see that man page for
detailed documentation.

=head1 BUGS

This and the other C<vnl-xxx> tools that wrap coreutils are written specifically
to work with the Linux kernel and the GNU coreutils. None of these have been
tested with BSD tools or with non-Linux kernels, and I'm sure things don't just
work. It's probably not too effortful to get that running, but somebody needs to
at least bug me for that. Or better yet, send me nice patches :)

=head1 SEE ALSO

L<tail(1)>

=head1 REPOSITORY

https://github.com/dkogan/vnlog/

=head1 AUTHOR

Dima Kogan C<< <dima@secretsauce.net> >>

=head1 LICENSE AND COPYRIGHT

Copyright 2018 Dima Kogan C<< <dima@secretsauce.net> >>

This library is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the Free
Software Foundation; either version 2.1 of the License, or (at your option) any
later version.

=cut
