#!/usr/bin/perl -w
#
# $Revision: 1.6 $ $Date: 2012-07-26 17:11:47-04 $
# $Source: /home/vogelke/bin/RCS/add,v $
# $Host: sys7.com $
# $UUID: 600ad346-f623-3869-bc3d-9af545ad6744 $
#
#<add: sums a column of numbers.

use strict;
use Getopt::Long;
use Pod::Usage;
use File::Basename;
use Math::BigInt;

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

my %options;
my @getopt_args = (
    'h|?',    # print usage
    'm',      # print manpage
    'v',      # print version
    'V',      # be verbose about non-numeric input
    );

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

manpage() if $options{'m'};
version() if $options{'v'};
usage()   if $options{'h'};

#
# Use arbitrary precision math in case we get some huge numbers.
#

my $total = Math::BigInt->new('0');

while (<>) {
    chomp;
    my $num = Math::BigInt->new("$_");

    if ($num->is_nan()) {
        warn "line $. [$_] not a number\n" if $options{'V'};
    } else {
        $total->badd($num);
    }
}

my $result = $total->bstr();
print "$result\n";
exit(0);

#---------------------------------------------------------------------
# Print a usage message from the comment header and exit.

sub usage {
    my ($emsg) = @_;

    require Pod::Usage;
    import Pod::Usage qw(pod2usage);
    warn "$emsg\n" if defined $emsg;
    pod2usage(-verbose => 1);
}

sub manpage {
    require Pod::Usage;
    import Pod::Usage qw(pod2usage);
    pod2usage(-exitstatus => 0, -verbose => 2);
}

#---------------------------------------------------------------------
# Print the current version and exit.

sub version {
    $_ = '$Id: add,v 1.6 2012-07-26 17:11:47-04 vogelke Exp $';
    s/,v / /;
    @_ = split;
    print "$myname  v$_[2]  $_[3] $_[4]\n";
    exit(0);
}

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

=head1 NAME

add - add a list of numbers

=head1 SYNOPSIS

add [-hmvV]

=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<-v>

Prints the version and exits.

=item B<-V>

Be verbose about non-numeric input.  Normally, lines
that aren't numbers are simply ignored.

=back

=head1 DESCRIPTION

B<add> will add numbers read from a file or stdin, and print the total
to stdout.  The data can include blank lines or numbers with blanks in
front of them without affecting the total.

=head1 EXAMPLE

 me% cat sample
 923748677987238974829387282
 1

 me% add sample  
 923748677987238974829387283

=head1 AUTHOR

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

=cut
