# -*- Mode: Perl -*-
eval "exec perl -S $0 $*"
  if $running_under_some_shell;
#
# Hours:Minutes:Seconds <-> Chrons
#
# by Seth Golub (seth@thehouse.org)
#  & Ian Flanigan (flan@lean.to)
#
# $Revision: 1.9 $
# $Date: 1995/01/29 14:01:47 $
# $Author: flan $
#
# $Log: chrons,v $
# Revision 1.9  1995/01/29  14:01:47  flan
# * Made the number of decimal places a constant to allow for easy
#   adjustment.  Made the smallest place round to nearest instead of
#   just being truncated.
#
# Revision 1.8  1995/01/27  13:44:57  flan
# * Changed number of chrons per day from 100 to 1000 as suggested by
#   Merle.  Also made it a constant in case we decide we don't like it.
#   It's *not* a user option.  And should never be.  Also changed the
#   usage string to reflect this change.
#
# Revision 1.7  1994/05/23  20:23:56  flan
# * Fixed the regexps so that lone hours MUST be followed by AM or PM in
#   order to qualify.  It was a big pain in the ass, let me tell you.
#
# Revision 1.6  1994/05/23  16:42:32  flan
# * Allowed hour formats to be a bit looser: 8pm now works too.
#
# Revision 1.5  1994/04/04  17:55:15  flan
# * Fixed some typos.
#
# Revision 1.4  1994/04/04  17:06:17  flan
# * Added the ability to convert chrons to hh:mm:ss (Seth)
# * Added options to signal what kind of conversion should be done.
#   Also added auto-selection of the conversion when the file is named
#   "h2c" or "c2h".   This allows links to the main program to function
#   correctly.
# * Changed the name to "chrons"
# * Added a --reverse option to reverse the conversion specified.
# * Added a few more comments
# * Re-wrote the usage string.
# * Changed the chron suffix to "c" from "ch".  This may change again.
#
# Revision 1.3  1994/03/31  21:54:48  flan
# * Made the version print right.  (Piddling change.)
#
# Revision 1.2  1994/03/31  21:52:28  flan
# * Encapsulated the changing routines into a subroutine h2c which takes
#   one argument (a string) and returns a list of two values: a new
#   string and whether any replacement was done.
# * Now replaces all occurances of "normal" time read from standard in
#   with the chron time.
# * Added a --version switch.
#
# Revision 1.1  1994/03/31  21:32:12  flan
# Initial revision
#
#

# Number of Chrons in a day
#
$CHRONS_PER_DAY = 1000;

# Chron resolution to the left of the decimal place
#
$CHRON_RES = 2;

if ($0 =~ /c2h$/)
{
    $c2h = 1;
    $h2c = 0;
}
elsif ($0 =~ /h2c$/)
{
    $h2c = 1;
    $c2h = 0;
}

while (@ARGV[0] =~ /^-.+/)
{
    if (@ARGV[0] eq "-r" || @ARGV[0] eq "--reverse")
    {
	$reverse = 1;
	next;
    }
    
    if (@ARGV[0] eq "-c" || @ARGV[0] eq "--h2c")
    {
	$h2c = 1;
	next;
    }
    
    if (@ARGV[0] eq "-h" || @ARGV[0] eq "--c2h")
    {
	$c2h = 1;
	next;
    }

    if (@ARGV[0] eq "-v" || @ARGV[0] eq "--version")
    {
	print '$Id: chrons,v 1.9 1995/01/29 14:01:47 flan Exp $ ';
	print "\n";
    }

    &usage;

} continue {
    
    shift @ARGV;
}

if ($reverse)
{
    $c2h = !$c2h;
    $h2c = !$h2c;
}

if (($c2h && $h2c) || (!$c2h && !$h2c))
{
    &usage;
}

if (!@ARGV[0] || @ARGV[0] eq "-")
{
    while($time = <>)
    {
	do
	{
	    ($time, $found) = &h2c($time) if $h2c;
	    ($time, $found) = &c2h($time) if $c2h;
	} while ($found);
	print $time;
    }
}
else
{
    $time = "@ARGV";
    ($time, $found) = &h2c($time) if $h2c;
    ($time, $found) = &c2h($time) if $c2h;
    &usage unless $found;
    print "$time\n";
}


# Convert HH:MM:SS [AM/PM] into Chrons
#
# Args: $time
#   $time: a string
#
# Returns: ($string, $found)
#   $string: $time with possibly an occurance of HH:MM:SS converted to chrons
#   $found: zero if no conversion was performed
sub h2c
{
    local ($string) = @_;
    local ($found) = (0);
    local ($hours, $minutes, $seconds, $ampm, $space, $chrons);

    $found =
	(($hours, $minutes, $space, $seconds, $space, $ampm) = 
	 $string =~ /(\d\d?):(\d\d)(:(\d\d))?(\s*([ap]\.?m\.?))?/i)
	    || (($hours, $space, $ampm) = 
		$string =~ /(\d\d?)(\s*([ap]\.?m\.?))/i);

    if (!$found)
    {
	return ($string, $found);
    }

    $hours = 0   if ($hours == 12) && ($ampm =~ /^a.*/i); # AM
    $hours += 12 if ($hours <  12) && ($ampm =~ /^p.*/i); # PM

    if(($hours   < 0) || ($hours   > 23) ||
       ($minutes < 0) || ($minutes > 59) ||
       ($seconds < 0) || ($seconds > 59))
    {
	&usage();
    }

    $chrons = $hours   * $CHRONS_PER_DAY / 24 + 
	      $minutes * $CHRONS_PER_DAY / 24 / 60 + 
	      $seconds * $CHRONS_PER_DAY / 24 / 60 / 60;

    $chrons += 10**(-($CHRON_RES+1)) * 5;
    $chrons =~ s/([^\.]*\..{$CHRON_RES}).*/$1/;

    ($string =~ s/(\d\d?):(\d\d)(:(\d\d))?(\s*[ap]\.?m\.?)?/${chrons}c/i)
	|| ($string =~ s/(\d\d?)(\s*([ap]\.?m\.?))/${chrons}c/i)
	    || die "Couldn't find string to replace with chrons again";
    
    ($string, $found);
}

# Convert Chrons into HH:MM:SS
#
# Args: $time
#   $time: a string
#
# Returns: ($string, $found)
#   $string: $time with possibly an occurance ofchrons converted to HH:MM:SS
#   $found: zero if no conversion was performed
sub c2h
{
    local ($string) = @_;
    local ($found) = (0);
    local ($hours, $minutes, $seconds, $chrons, $hhmmss);

    $found = ($chrons) = $string =~ /(\d+\.?\d+c)/;

    if (!$found)
    {
	return ($string, $found);
    }

    $chrons *= 24*60*60/$CHRONS_PER_DAY;
    # Now it's number of seconds into the day (exactly)

    $seconds = $chrons % 60;  $chrons = ($chrons - $seconds) / 60;
    $minutes = $chrons % 60;  $chrons = ($chrons - $minutes) / 60;
    $hours = $chrons % 24;

    $hhmmss = sprintf("%02d:%02d:%02d", $hours, $minutes, $seconds);

    $string =~ s/\d+\.?\d+c/$hhmmss/;
    
    ($string, $found);
}


sub usage
{
    $0 =~ s@.*/@@;

    print <<EOF;

Usage: h2c ... hh[:mm[:ss]][am/pm] ...
       c2h ... 123.456789c ...
       chrons -v | --version
       chrons -c | --h2c [ ... hh[:mm[:ss]][am/pm] ... ]]
       chrons -h | --c2h [ ... 123.456789c ... ]

  If neither am, nor pm is specified, 24 hour time is assumed.
  The parsing is fairly robust, so you don't need to be too anal
  about formatting.

  Input is read from standard input if no command line arguments are given.

EOF
    exit(1);
}

