
	
		#!/usr/bin/perl -w

use strict;
use Getopt::Std;
use English;
# ---------------------------------------------------------------------

#   if 1 arg is supplied; converts JD to MM DD YYYY
#   if 3 args are supplied converts MM DD YYYY to Julian Day
#   if no args are supplied converts current date to Julian Day

# ---------------------------------------------------------------------
use constant VRSN => '[2.2 p]';
# 2.05p  04/29/2002 acs Converted from Shell/Awk caljd.sh Vrsn 2.05
# 2.05p1 05/13/2002 acs no more than 6 -x args allowed
# 2.1 p  06/26/2002 acs added the -c argument to allow 12/31/2001 to be
#                       processed; added -i and -o options so that months
#                       could be input or output in 'Jan','Feb', ... format
#                       or weekdays could be output in 'Sun','Mon', ...
#                       format; the -I and -O options do the same but now full
#                       names are used. e.g. 'January','February' ...
#                       and 'Sunday','Monday', ... . For example,
#                       '04-July-1776' could be parsed as valid input
#                       with the '-c -e -I -S "-"' options; NLS support
#                       is provided with the -i,-o,-I, and -O options;
#                       examples added to usage(). 
# 2.2 p  09/05/2003 acs added -f option to allow file input
# ---------------------------------------------------------------------
# The Julian Day to Gregorian conversion routines are based upon algorithms
# developed by Henry F. Fliegel and Thomas C. Van Flandern and from sources 
# published in Sky & Telescope magazine
#
#


use constant FALSE          => 0;
use constant TRUE           => 1;

use constant DMY_NONE       => 0;
use constant DMY_DAY        => 1;
use constant DMY_MONTH      => 2;
use constant DMY_YEAR       => 3;

use constant MDY_MDY        => 0;
use constant MDY_DMY        => 1;
use constant MDY_YMD        => 2;

use constant MAX_MONTH      => 12;
use constant MAX_DAY        => 31;
use constant DAYS_PER_WK    => 7;

use constant HOLIDAY_FILE   => '/etc/acct/holidays';

# Month and weekday names constants
use constant WORDS_NONE     => 0;
use constant WORDS_ABREV    => 1;
use constant WORDS_FULL     => 2;


use constant DAY_ABREV      => 0;
use constant DAY_FULL       => 1;
use constant MONTH_ABREV    => 2;
use constant MONTH_FULL     => 3;


# --------------------------------------------------------------------------

my $in_words = WORDS_NONE;
my $out_words = WORDS_NONE;
my @lc_time_array;

sub problem
{
  my $msg = $_[0];
  my $err = $_[1];

  printf STDERR ("%s: %s (%d).\n",$PROGRAM_NAME,$msg,$err);
  printf STDERR ("\n");
  return($err);
} # problem 



# -----------------------------------------------------------------

sub examples
{
  my $prog = $PROGRAM_NAME;

  printf STDERR ("\n\nEXAMPLES:\n\n");
  printf STDERR ("  Determine the current Julian Day:\n");
  printf STDERR ("  JD=\$(%s)\n\n",$prog);
  printf STDERR ("  Determine the Julian Day 25 days from now in UTC:\n");
  printf STDERR ("  JD=\$(%s -U -n 25)\n\n",$prog);
  printf STDERR ("  Determine the Julian Day 5 days prior to now:\n");
  printf STDERR ("  JD=\$(%s -p 5)\n\n",$prog);
  printf STDERR ("  Determine the Julian Day 5 days from now unless that ");
  printf STDERR ("falls on a weekend:\n");
  printf STDERR ("  JD=\$(%s -n 5 -x 6 -x 0)\n\n",$prog);
  printf STDERR ("  Determine the Julian Day 5 days from now unless that ");
  printf STDERR ("falls on a weekend\n");
  printf STDERR ("  or a holiday:\n");
  printf STDERR ("  JD=\$(%s -n 5 -x 6 -x 0 -h)\n\n",$prog);
  printf STDERR ("  Determine the month 2 days from now unless that ");
  printf STDERR ("falls on a weekend\n");
  printf STDERR ("  or a holiday; output in numeric format:\n");
  printf STDERR ("  JD=\$(%s -n 2 -x 6 -x 0 -h -M)\n\n",$prog);
  printf STDERR ("  Determine the month 3 days from now unless that ");
  printf STDERR ("falls on a weekend\n");
  printf STDERR ("  or a holiday; output in numeric format:\n");
  printf STDERR ("  JD=\$(%s -n 3 -x 6 -x 0 -h -M -O)\n\n",$prog);
  printf STDERR ("  Determine the Julian Day of 26-Jun-2002 MM DD YYYY ");
  printf STDERR ("format:\n");
  printf STDERR ("  JD=\$(%s 6 26 2002)\n\n",$prog);
  printf STDERR ("  Determine the Julian Day of 26-Jun-2002 YYYY MM DD ");
  printf STDERR ("format:\n");
  printf STDERR ("  JD=\$(%s -y 2002 6 26)\n\n",$prog);
  printf STDERR ("  Determine the Julian Day of 26-Jun-2002 entered as ");
  printf STDERR ("'26-JUN-2002':\n");
  printf STDERR ("  JD=\$(%s -i -S \"-\" -e -c  \"26-JUN-2002\")\n\n",$prog);
  printf STDERR ("  Determine the Julian Day 7 days from 26-Jun-2002 ");
  printf STDERR ("entered as 'JUNE/26/2002':\n");
  printf STDERR ("  JD=\$(%s -I -S \"/\" -n 7  -c  \"JUNE/26/2002\")\n\n",
                 $prog);
  printf STDERR ("  Determine the calendar date of JD 2452452; output in ");
  printf STDERR ("MM DD YYYY\n");
  printf STDERR ("  format:\n");
  printf STDERR ("  CD=\$(%s 2452452)\n\n",$prog);
  printf STDERR ("  Determine the calendar date of JD 2452452; output in ");
  printf STDERR ("DD MM YYYY\n");
  printf STDERR ("  format:\n");
  printf STDERR ("  CD=\$(%s -e 2452452)\n\n",$prog);
  printf STDERR ("  Determine the calendar date 12 days after JD 2452452;\n");
  printf STDERR ("  output in YYYY MM DD format:\n");
  printf STDERR ("  CD=\$(%s -y -n 12 2452452)\n\n",$prog);
  printf STDERR ("  Determine the calendar date 2 days before JD 2452452\n");
  printf STDERR ("  unless that falls on a Sunday; output in YYYY MM DD ");
  printf STDERR ("format:\n");
  printf STDERR ("  CD=\$(%s -y -p 2 -x 0 2452452)\n\n",$prog);
  printf STDERR ("\f");
  printf STDERR ("\n");
  printf STDERR ("  Determine the calendar date 20 days after JD 2452452\n");
  printf STDERR ("  unless that falls on a holiday; output in ");
  printf STDERR ("DD-FullMonthName-YYYY\n");
  printf STDERR ("  format:\n");
  printf STDERR ("  CD=\$(%s -e -n 20 -h -O -S \"-\" 2452452)\n\n",$prog);
  printf STDERR ("  Determine the weekday 5 days after JD 2452452\n");
  printf STDERR ("  unless that falls on a holiday; output in numeric ");
  printf STDERR ("format:\n");
  printf STDERR ("  CD=\$(%s -n 5 -h -w 2452452)\n\n",$prog);
  printf STDERR ("  Determine the weekday 4 days prior to JD 2452452;\n");
  printf STDERR ("  output in abbreviated weekday name format:\n");
  printf STDERR ("  CD=\$(%s -p 4 -w -o 2452452)\n\n",$prog);
  printf STDERR ("  Get the calendar date in DD MM YYYY format 9 days from ");
  printf STDERR ("now unless that\n");
  printf STDERR ("  falls on a Saturday:\n");
  printf STDERR ("  CD=\$(%s -e \$(%s -n 9 -x 6))\n\n",$prog,$prog);
  printf STDERR ("  Get the calendar date in YYYYMMDD format 3 days prior ");
  printf STDERR ("to now unless that\n");
  printf STDERR ("  falls on a Sunday:\n");
  printf STDERR ("  CD=\$(%s -y -s \$(%s -p 3 -x 0))\n\n",$prog,$prog);
  printf STDERR ("  Get the calendar date in YYYYAbbrevMonthNameDD format ");
  printf STDERR ("3 days\n");
  printf STDERR ("  prior to now unless that falls on a Sunday:\n");
  printf STDERR ("  CD=\$(%s -y -s -o \$(%s -p 3 -x 0))\n\n",$prog,$prog);
  printf STDERR ("\f");
  return(254);
} # examples

sub usage
{
  printf STDERR 
    ("\nUsage: %s [-w|-D|-M|-Y] [-u] [-U] [-n days | -p days] \\\n",
     $PROGRAM_NAME);
  printf STDERR
    ("          [-h] [-x wday] [-v|-V] [-f]\n");
  printf STDERR ("        or\n");
  printf STDERR
    ("       %s [-w|-D|-M|-Y] [-n days | -p days] \\\n",
     $PROGRAM_NAME);
  printf STDERR
    ("          [-h] [-x wday] [-v|-V] [-c] [-f] MM DD YYYY\n");
  printf STDERR ("        or\n");
  printf STDERR
    ("       %s [-w|-D|-M|-Y] [-n days | -p days] \\\n",
     $PROGRAM_NAME);
  printf STDERR
   ("          [-h] [-x wday] [-v|-V] [-c] [-f] -e DD MM YYYY\n");
  printf STDERR ("        or\n");
  printf STDERR
    ("       %s [-w|-D|-M|-Y] [-n days | -p days] \\\n",
     $PROGRAM_NAME);
  printf STDERR
    ("          [-h] [-x wday] [-v|-V] [-c] [-f] -y YYYY MM DD\n");
  printf STDERR ("        or\n");
  printf STDERR
    ("       %s [-w|-D|-M|-Y] [-n days | -p days] [-e | -y]  \\\n",
     $PROGRAM_NAME);
  printf STDERR
    ("               [-h] [-x wday] [-v|-V] [-s] [-S sep] [-f] JulianDay\n");
  printf STDERR ("\n");
  printf STDERR ("If MM DD YYYY is supplied, convert to Julian Day or\n");
  printf STDERR ("weekday if -w is supplied.\n");
  printf STDERR ("If JulianDay is supplied, convert to MM DD YYYY or\n"); 
  printf STDERR ("weekday if -w is supplied.\n");
  printf STDERR ("If no args are supplied, convert current date to Julian\n");
  printf STDERR ("Day or weekday is -w is supplied alone.\n");
  printf STDERR ("\n");
  printf STDERR ("-w return Weekday 0-Sun 6-Sat\n");
  printf STDERR ("-D return Day of Month (01-31)\n");
  printf STDERR ("-M return Month Number (01-12)\n");
  printf STDERR ("-Y return Year (YYYY)\n"); 
  printf STDERR ("-u print this usage message on stderr and exit.\n");
  printf STDERR ("-U use UTC rather than local time to compute ");
  printf STDERR ("current date.\n");
  printf STDERR ("-n days - add days to result before outputting.\n");
  printf STDERR ("-p days - subtract days from result before outputting.\n");
  printf STDERR ("-s - remove spaces from output; MM DD YYYY --> MMDDYYYY.\n");
  printf STDERR ("-S sep - separate MM DD YYYY with sep (default space).\n"); 
  printf STDERR ("-x wday (wday = 0 - Sun; 6 - Sat.) skip past wday. ");
  printf STDERR ("Multiple\n");
  printf STDERR ("   -x arguments may to used. The skip is positive if ");
  printf STDERR ("using\n");
  printf STDERR ("   -n days (or no -n or -p argument) and negative if ");
  printf STDERR ("using\n");
  printf STDERR ("   -p days.\n");
  printf STDERR ("-h - skip past holidays as defined in %s for the\n",
                 HOLIDAY_FILE);
  printf STDERR ("     current year or in %s_yyyy for other years.\n",
                 HOLIDAY_FILE);
  printf STDERR ("-c - the supplied date is a calendar date. This is ");
  printf STDERR ("normally used\n");
  printf STDERR ("     in conjunction with the -S sep argument to identify ");
  printf STDERR ("the field\n");
  printf STDERR ("     separator. For example, -S \"-\" -c -y would accept\n");
  printf STDERR ("     \"2001-12-31\" as a calendar date and output a ");
  printf STDERR ("Julian Day\n");
  printf STDERR ("     just as if the normal three arguments, 2001 12 31, ");
  printf STDERR ("had been\n");
  printf STDERR ("     supplied. (Note the use of the -y argument to order ");
  printf STDERR ("the year,\n");
  printf STDERR ("     month, and day values.)\n");
  printf STDERR ("-i - on input, abbreviated case-insensitive month names\n");
  printf STDERR ("     (e.g. 'Jan','Feb','Mar') are recognized.\n");
  printf STDERR ("-o - On output, abbreviated month names and weekday ");
  printf STDERR ("names,\n");
  printf STDERR ("     (e.g. 'Sun','Mon','Tue') are used rather than ");
  printf STDERR ("numeric values.\n");
  printf STDERR ("-I - on input, full case-insensitive month names\n");
  printf STDERR ("     (e.g. 'January','February','March') are ");
  printf STDERR ("recognized.\n");
  printf STDERR ("-O - On output, full month names and weekday names\n");
  printf STDERR ("     (e.g. 'Sunday','Monday','Tuesday') ");
  printf STDERR ("are used rather than\n");
  printf STDERR ("     numeric values.\n");
  printf STDERR ("\n");
  printf STDERR ("     Native Language Support (NLS) is provided with the ");
  printf STDERR ("-i,-I,-o and\n");
  printf STDERR ("     -O options.\n");
  printf STDERR ("\f");
  printf STDERR ("\n");
  printf STDERR ("By default, year, month, and day arguments are input and\n");
  printf STDERR ("output in 'MM DD YYYY' order. This behavior can be ");
  printf STDERR ("changed\n");
  printf STDERR ("to DD MM YYYY with the '-e' argument or to 'YYYY MM DD' ");
  printf STDERR ("with\n");
  printf STDERR ("the '-y' argument.\n");
  printf STDERR ("\n");
  printf STDERR ("-f - Normally the date operands are passed on the ");
  printf STDERR ("command line\n");
  printf STDERR ("     but -f instructs %s to examine each line of ",
                 $PROGRAM_NAME);
  printf STDERR ("stdin for\n");
  printf STDERR ("     date operands and process them as if they were ");
  printf STDERR ("command line\n");
  printf STDERR ("     operands. For each line of input, a line of output ");
  printf STDERR ("is written\n");
  printf STDERR ("     on stdout. The options (-y, -e, -S, ...) are ");
  printf STDERR ("processed only\n");
  printf STDERR ("     once when %s is launched.\n\n",$PROGRAM_NAME);
  printf STDERR ("NOTE: Julian Days count sequentially from 4713 BCE; they ");
  printf STDERR ("are used by\n");
  printf STDERR ("      astronomers to simplify orbital calculations. ");
  printf STDERR ("Julian Days are actually\n");
  printf STDERR ("      floating point values that can represent days, ");
  printf STDERR ("hours, minutes, and\n");
  printf STDERR ("      seconds to any desired precision. They begin at ");
  printf STDERR ("noon UTC so that midnight\n");
  printf STDERR ("      is JD.500000. The values returned by this script ");
  printf STDERR ("are Truncated (integer)\n");
  printf STDERR ("      Julian Days and begin at midnight local time.\n"); 
  printf STDERR ("\n");
  printf STDERR ("Version: %s\n",VRSN);
  printf STDERR ("\f");
  examples();
  return(255);
} # usage 

# --------------------------------------------------------------------

sub Cal_Jdate
{
  use integer;

  my $mo = $_[0];
  my $da = $_[1];
  my $yr = $_[2];

  my $jd = $da - 32075 + (1461 * ($yr + 4800 + (($mo - 14)/12)) / 4) +
           ((367 * ($mo - 2 - (($mo - 14)/12) * 12))/12) -
           ((3 * (($yr + 4900 + (($mo - 14)/12))/100))/4);
  return($jd);
} # Cal_Jdate

sub Jdate_Cal
{
  use integer;

  my $jd = $_[0];
  my ($l,$n,$ll,$i,$j,$da,$mo,$yr);

  $l = $jd + 68569;
  $n = (4 * $l) / 146097;
  $ll = ((146097 * $n) + 3) / 4;
  $l -= $ll;
  $i = (4000 * ($l + 1)) / 1461001;
  $ll = (1461 * $i) / 4;
  $l  = $l - $ll + 31;
  $j = (80 * $l) / 2447;
  $da = $l - ((2447 * $j) / 80);
  $l = $j / 11;
  $mo = $j + 2 - (12 * $l);
  $yr = 100 * ($n - 49) + $i + $l;
  return($mo,$da,$yr);
} # Jdate_Cal

sub Wkday
{
  use integer;

  my $x = $_[0];
  return(($x + 1) % DAYS_PER_WK);
} # Wkday

sub Today
{
  use integer;

  my ($mo,$da,$yr) = (localtime)[4,3,5];
  $yr += 1900; # years returned by localtime() are years since 1900
  $mo++;       # months returned by localtime() range from 0 to 11
  return($mo,$da,$yr)
} # Today

sub GM_Today
{
  use integer;

  my ($mo,$da,$yr) = (gmtime)[4,3,5];
  $yr += 1900; # years returned by gmtime() are years since 1900
  $mo++;       # months returned by gmtime() range from 0 to 11
  return($mo,$da,$yr)
} # GM_Today


sub Is_Holiday
{
  use integer;

  my $jdate_in = $_[0];
  my $utc = $_[1];

  my $is_hol = FALSE; 
  my $curr_yr = 0;
  my $fname = '';

  my ($dummy_mo,$dummy_da,$yr) = Jdate_Cal($jdate_in);
  # Get julian day of 1st day of $yr
  my $day1 = Cal_Jdate(1,1,$yr);
  my $target_day = $jdate_in - $day1 + 1;
  ($dummy_mo,$dummy_da,$curr_yr) = ($utc) ? GM_Today() : Today();
  if ($yr == $curr_yr)
    {
      $fname = HOLIDAY_FILE . sprintf("_%04d",$yr); 
      if (!(-e $fname && -r $fname && -f $fname))
        {
          $fname = HOLIDAY_FILE;
        }
    }
  else
    {
      $fname = HOLIDAY_FILE . sprintf("_%04d",$yr); 
    }
  if (-e $fname && -r $fname && -f $fname)
    {
      if (open(F1,"< $fname"))
        {
          my @holidays;
          my $s_tmp = '';
          while ($s_tmp = <F1>)
            {
              chomp($s_tmp);
              if (!($s_tmp =~ /^\*/))
                {
                  my @tmp_array = split(/\s+/,$s_tmp);
                  # strip off blank entries
                  my $cont = TRUE;
                  while ($#tmp_array >= 0 && $cont)
                    {
                      if (length($tmp_array[0]) < 1) 
                        {
                          splice(@tmp_array,0,1);
                        }
                      else
                        {
                          $cont = FALSE;
                        }
                    } # while
                  if ($#tmp_array >= 0)
                    {
                      if ($tmp_array[0] =~ /\d+$/)
                        {   
                          push(@holidays,$tmp_array[0]);
                        }
                    }
                }
            } # while
          close F1;
          if ($#holidays > 0)
            {
              if ($yr == $holidays[0])
                {
                  my $i = 1;
                  while ($i <= $#holidays && !($is_hol))
                    {
                      $is_hol = ($target_day == $holidays[$i]);
                      ++$i;
                    } # while                 
                }
              else
                {
                  $s_tmp = sprintf(
                        "File %s year %d does not match expected year %d",
                                   $fname,$holidays[0],$yr);
                  problem($s_tmp,-2);
                }             
            }
        }
      else
        {
          problem(sprintf("Can't read holidays file '%s'",$fname),-1);
        }
    } 
  return($is_hol); 
} # Is_Holiday

sub Skip_Days
{
  use integer;

  my $jdate = $_[0];
  my $day_offset = $_[1];
  my $wdaysref = $_[2];
  my $holiday_flag = $_[3];
  my $utc = $_[4];    

  my $wdays_knt = $#$wdaysref + 1;
  if ($wdays_knt > 0 || $holiday_flag)
    {
      my $increment = ($day_offset >= 0) ? 1 : -1;
      my $fnd = TRUE;
      until (!($fnd)) 
        {
          $fnd = FALSE;
          if ($wdays_knt > 0)
            {
              my $weekday = Wkday($jdate);
              my $i = 0;
              while ($i < $wdays_knt && !($fnd))
                {
                  $fnd = ($weekday == $$wdaysref[$i]);
                  ++$i;
                } # while
            }
          if (!($fnd) && $holiday_flag)
            {
              $fnd = Is_Holiday($jdate,$utc);
            }
          if ($fnd)
            {
              $jdate += $increment; 
            }
        } # until
    }
  return($jdate);
} # Skip_Days


sub load_locale_lc_time
{
  use integer;

  # default values; load these and then try to replace with 'locale LC_TIME'
  # equivalents, but don't crash or complain if locale not found
  my @tmp_lc_time_array =
    (
      ["Sun","Mon","Tue","Wed","Thu","Fri","Sat",""],
      ["Sunday","Monday","Tuesday","Wednesday","Thursday",
       "Friday","Saturday",""],
      ["Jan","Feb","Mar","Apr","May","Jun","Jul",
       "Aug","Sep","Oct","Nov","Dec",""],
      ["January","February","March","April","May","June","July",
       "August","September","October","November","December",""],
    );

  # Now attempt to load the locale LC_TIME for NLS
  eval
    {
       # so Windows is ok
       my $null_dev = ($OSNAME =~ /MSW.*/i) ? 'NUL' : '/dev/null';
       my $pipe_cmd = sprintf("locale LC_TIME 2>%s |",$null_dev);
       my $knt = 0;
       open F2,$pipe_cmd or die "Locale LC_TIME Load Failed";
       my @tmp_arry1 = <F2>;
       close F2;
       chomp @tmp_arry1;
       while ($knt <= $#tmp_arry1 && $knt <= MONTH_FULL)
         {
           my @tmp_arry2 = split /;/,$tmp_arry1[$knt];
           foreach my $tmp_element (@tmp_arry2)
             {
               $tmp_element =~ s/^"//;
               $tmp_element =~ s/"$//;
             }
           push(@tmp_arry2,""); # for null entry; flag
           splice(@tmp_lc_time_array,$knt,1,\@tmp_arry2);
           ++$knt;
         }
     };
   return(@tmp_lc_time_array);
} # load_locale_lc_time

sub find_lc_time
{
  use integer;

  my $mode = $_[0];
  my $to_number = $_[1];
  my $key = $_[2];
  my $cc = 0;
  my $s_out = "";
  if ($#lc_time_array >= 0)
    {
      if (($mode >= DAY_ABREV) && ($mode <= MONTH_FULL))
        {
          my $fnd = FALSE;
          my $i = 0;
          if ($to_number)
            {
              my $lc_key = lc($key); 
              while ((length($lc_time_array[$mode][$i]) > 0) && (!($fnd)))
                {
                  if ($lc_key eq lc($lc_time_array[$mode][$i]))
                    {
                      $fnd = TRUE;
                    }
                  else
                    {
                      ++$i;
                    }
                }
              if ($fnd)
                {
                  $s_out = sprintf("%02d",$i + 1);
                }
              else
                {
                  $cc = 1;
                }
            }
          else
            {
              while (length($lc_time_array[$mode][$i]) > 0)
                {
                  ++$i;
                }
              if (($key >= 1) && ($key <= $i))
                {
                  $s_out = $lc_time_array[$mode][$key - 1];
                }
              else
                {
                  $cc = 1;
                }
            }
        }
      else
        {
          $cc = 255;
        }
    }
  else
    {
      $cc = 235;
    }
  return($cc,$s_out);
} # find_lc_time

my $dmy_mode = DMY_NONE;
my $dmy_knt = 0;
my $wkday = FALSE;
my $utc_arg = FALSE;
my $mdy_mode = MDY_MDY;
my $mdy_arg_knt = 0;
my $cal_mode = FALSE;
my $in_words_knt = 0;
my $out_words_knt = 0;
my $sep = ' ';
my $space_knt = 0;
my $day_offset = 0;
my $day_arg_knt = 0;
my $hol = FALSE;
my $usefile = FALSE;
my @wdays;
                                 
sub process_1_date
{
  my @operands = @_;
  my $knt = $#operands + 1;
  my $s_out = "";
  my $cc = 0;

# test for -c processing
  if ($cal_mode && length($sep) > 0)
    {
      if ($knt == 1 && $sep =~ /^\S+$/)
        {
          my @tmp_array0 = split($sep,$operands[0]);
          if ($#tmp_array0 == 2)
            {
              if ($in_words)
                {
                  my $tmp_cc = 0;
                  my $tmp_val = '';
                  my $sel_mode = ($in_words == WORDS_ABREV) ? MONTH_ABREV :
                    MONTH_FULL;
                  my $tmp_ndx = ($mdy_mode == MDY_DMY || $mdy_mode == MDY_YMD)
                    ? 1 : 0; 
                  ($tmp_cc,$tmp_val) = find_lc_time($sel_mode,TRUE,
                                                    $tmp_array0[$tmp_ndx]);
                  if ($tmp_cc == 0)
                    {
                      $tmp_array0[$tmp_ndx] = $tmp_val;
                    }
                  else
                    {
                      problem("Could not convert month name",$cc);
                      return(237,"");
                    }
                }
              @operands = @tmp_array0;
              $knt = 3;
            }
          else
            {
              $cc = 238;
              problem(sprintf("-c argument expected 3 parts; got %d",
                              $#tmp_array0 + 1),$cc);
              return($cc,"");
            } 
        } 
    } 
  SWITCH_0:
    {
      if ($knt == 0)
        {
          my ($mo,$day,$yr) = ($utc_arg) ? GM_Today() : Today();  
          my $jdate = Cal_Jdate($mo,$day,$yr) + $day_offset; 
          $jdate = Skip_Days($jdate,$day_offset,\@wdays,$hol,$utc_arg);
          if ($wkday || $dmy_mode != DMY_NONE)
            {
              if ($wkday) 
                {
                  $s_out = sprintf("%d",Wkday($jdate));
                  if ($out_words)
                    {
                      my $tmp_cc = 0;
                      my $tmp_val = '';
                      my $sel_mode = ($out_words == WORDS_ABREV) ? DAY_ABREV :
                        DAY_FULL;
                      ($tmp_cc,$tmp_val) = find_lc_time($sel_mode,FALSE,
                                                        Wkday($jdate) + 1);
                      if ($tmp_cc == 0)
                        {
                          $s_out = $tmp_val;
                        }     
                    }
                }
              else
                {
                  ($mo,$day,$yr) = Jdate_Cal($jdate);
                  SWITCH_01:
                    {
                      if ($dmy_mode == DMY_MONTH)
                        {
                          $s_out = sprintf("%02d",$mo % (MAX_MONTH + 1));
                          if ($out_words)
                            {
                              my $tmp_cc = 0;
                              my $tmp_val = '';
                              my $sel_mode = ($out_words == WORDS_ABREV) ?
                                MONTH_ABREV : MONTH_FULL;
                              ($tmp_cc,$tmp_val) = find_lc_time($sel_mode,
                                                                FALSE,$mo);
                              if ($tmp_cc == 0)
                                {
                                  $s_out = $tmp_val;
                                }     
                            }
                          last SWITCH_01;
                        };  
                      if ($dmy_mode == DMY_YEAR)
                        {
                          $s_out = sprintf("%04d",$yr);
                          last SWITCH_01;
                        };
                      $s_out = sprintf("%02d",$day % (MAX_DAY + 1));
                    }; # SWITCH_01
                }
            }
          else
            {
              $s_out = sprintf("%d",$jdate);
            }
          last SWITCH_0;
        } # 0 args

      if ($knt == 1)
        {
          my $jdate = 0;
          if ($operands[0] =~ /^\d+$/)
            {
              $jdate = $operands[0] + $day_offset;
              $jdate = Skip_Days($jdate,$day_offset,\@wdays,$hol,FALSE);
            }
          else
            {
              $cc = 244;
              problem(sprintf("Invalid numeriic argument '%s'",$operands[0]),
                      $cc);
            }
          if ($cc == 0)
            {
              if ($wkday || $dmy_mode != DMY_NONE)
                {
                  if ($wkday) 
                    {
                      $s_out = sprintf("%d",Wkday($jdate));
                      if ($out_words)
                        {
                          my $tmp_cc = 0;
                          my $tmp_val = '';
                          my $sel_mode = ($out_words == WORDS_ABREV) ?
                            DAY_ABREV : DAY_FULL;
                          ($tmp_cc,$tmp_val) = find_lc_time($sel_mode,FALSE,
                                                            Wkday($jdate) + 1);
                          if ($tmp_cc == 0)
                            {
                              $s_out = $tmp_val;
                            }     
                        }
                    }
                  else
                    {
                      my ($mo,$day,$yr) = Jdate_Cal($jdate);
                      SWITCH_11:
                        {
                          if ($dmy_mode == DMY_MONTH)
                            {
                              $s_out = sprintf("%02d",$mo % (MAX_MONTH + 1));
                              if ($out_words)
                                {
                                  my $tmp_cc = 0;
                                  my $tmp_val = '';
                                  my $sel_mode = ($out_words == WORDS_ABREV) ?
                                    MONTH_ABREV : MONTH_FULL;
                                  ($tmp_cc,$tmp_val) = find_lc_time($sel_mode,
                                                                    FALSE,
                                                                    $mo);
                                  if ($tmp_cc == 0)
                                    {
                                      $s_out = $tmp_val;
                                    }     
                                }
                              last SWITCH_11;
                            };  
                          if ($dmy_mode == DMY_YEAR)
                            {
                              $s_out = sprintf("%04d",$yr);
                              last SWITCH_11;
                            };
                          $s_out = sprintf("%02d",$day % (MAX_DAY + 1));
                        }; # SWITCH_11
                    }
                }
              else
                {
                  my ($mo,$day,$yr) = Jdate_Cal($jdate);
                  my $s_mo = sprintf("%02d",$mo % (MAX_MONTH + 1));
                  if ($out_words)
                    {
                      my $tmp_cc = 0;
                      my $tmp_val = '';
                      my $sel_mode = ($out_words == WORDS_ABREV) ?
                        MONTH_ABREV : MONTH_FULL;
                      ($tmp_cc,$tmp_val) = find_lc_time($sel_mode,FALSE,$mo);
                      if ($tmp_cc == 0)
                        {
                          $s_mo = $tmp_val;
                        }
                    }
                  SWITCH_12:
                     {
                       if ($mdy_mode == MDY_YMD)
                         {
                           $s_out = sprintf("%04d%s%s%s%02d",$yr,$sep,
                                            $s_mo,$sep,
                                            $day % (MAX_DAY + 1));
                           last SWITCH_12;
                         }
                       if ($mdy_mode == MDY_DMY)
                         {
                           $s_out = sprintf("%02d%s%s%s%04d",
                                            $day % (MAX_DAY + 1),$sep,
                                            $s_mo,$sep,$yr);
                           last SWITCH_12;
                         }
                       $s_out = sprintf("%s%s%02d%s%04d",
                                        $s_mo,$sep,$day % (MAX_DAY + 1),
                                        $sep,$yr);
                     }; # SWITCH_12
                }
            }
          last SWITCH_0;
        } # 1 arg

      if ($knt == 3)
        {
          my $i = 0;
          my $mo_ndx = ($mdy_mode == MDY_DMY || $mdy_mode == MDY_YMD)
            ? 1 : 0;

          while (($i < $knt) && ($cc == 0))
            {
              if (($operands[$i] =~ /^-*\d+$/) ||
                  (($i == $mo_ndx) && ($in_words)))
                {
                  ++$i;
                }
              else
                {
                  $cc = 243; 
                  problem(sprintf("Arg %d '%s' invalid numeric value",
                                  $i + 1,$operands[$i]),
                          $cc);
                }
            } # while
          if ($cc == 0)
            {
              my $tmp_cc = -1;
              my $tmp_val = '';
              my ($day,$yr);
              if ($in_words && !($cal_mode))
                {
                  my $sel_mode = ($in_words == WORDS_ABREV) ? MONTH_ABREV :
                    MONTH_FULL;
                  ($tmp_cc,$tmp_val) = find_lc_time($sel_mode,TRUE,
                                                    $operands[$mo_ndx]);
                }
              my $mo = ($tmp_cc == 0) ? $tmp_val : $operands[$mo_ndx]; 
              SWITCH_31:
                {
                  if ($mdy_mode == MDY_YMD)
                    {
                      $yr = $operands[0];
                      $day = $operands[2];
                      last SWITCH_31;
                    }
                  if ($mdy_mode == MDY_DMY)
                    {
                      $day = $operands[0];
                      $yr = $operands[2];
                      last SWITCH_31;
                    }
                  $day = $operands[1];
                  $yr = $operands[2];
                }; # SWITCH_31
              if ($mo < 1 || $mo > MAX_MONTH)
                {
                  $cc = 242;
                  problem(sprintf("Month %d is out of range 1-%d",
                                  $mo,MAX_MONTH),$cc);
                }
              if (($day < 1 || $day > MAX_DAY) && $cc == 0)
                {
                  $cc = 241;
                  problem(sprintf("Day %d is out of range 1-%d",
                                  $day,MAX_DAY),$cc);
                }
              if ($cc == 0)
                {
                  my $jdate = Cal_Jdate($mo,$day,$yr) + $day_offset;
                  $jdate = Skip_Days($jdate,$day_offset,\@wdays,$hol,FALSE);
                  if ($wkday || $dmy_mode != DMY_NONE)
                    {
                      if ($wkday) 
                        {
                          $s_out = sprintf("%d",Wkday($jdate));
                          if ($out_words)
                            {
                              $tmp_cc = 0;
                              $tmp_val = '';
                              my $sel_mode = ($out_words == WORDS_ABREV) ?
                                DAY_ABREV : DAY_FULL;
                              ($tmp_cc,$tmp_val) =
                                 find_lc_time($sel_mode,FALSE,
                                              Wkday($jdate) + 1);
                              if ($tmp_cc == 0)
                                {
                                  $s_out = $tmp_val;
                                }     
                            }
                        }
                      else
                        {
                          ($mo,$day,$yr) = Jdate_Cal($jdate);
                          SWITCH_32:
                            {
                              if ($dmy_mode == DMY_MONTH)
                                {
                                  $s_out = sprintf("%02d",
                                                   $mo % (MAX_MONTH + 1));
                                  if ($out_words)
                                    {
                                      my $tmp_cc = 0;
                                      my $tmp_val = '';
                                      my $sel_mode =
                                        ($out_words == WORDS_ABREV) ?
                                        MONTH_ABREV : MONTH_FULL;
                                      ($tmp_cc,$tmp_val) =
                                         find_lc_time($sel_mode,FALSE,$mo);
                                      if ($tmp_cc == 0)
                                        {
                                          $s_out = $tmp_val;
                                        }     
                                    }
                                  last SWITCH_32;
                                };  
                              if ($dmy_mode == DMY_YEAR)
                                {
                                  $s_out = sprintf("%04d",$yr);
                                  last SWITCH_32;
                                };
                              $s_out = sprintf("%02d",$day % (MAX_DAY + 1));
                            };
                        }
                    }
                  else
                    {
                      $s_out = sprintf("%d",$jdate);
                    }
                }
            }                        
          last SWITCH_0;
        } # 3 args
#
# Invalid number of arguments; fell through case
      $cc = 240;
      problem(sprintf("Invalid number of arguments %d",$knt),$cc);
    }; # SWITCH_0
  return($cc,$s_out);
} # process_1_date


# ------------------------------------------------------------------
# ---------------- Main Program ------------------------------------
# ------------------------------------------------------------------

use integer;

my $i = 0;
my $cc = 0;

# First strip off the possible multiple -x or -X args and load @wdays
#

while ($i <= $#ARGV && $cc == 0)
  {
    if (lc($ARGV[$i]) eq '-x')
      {
        if ($i < $#ARGV)
          {
            if ($ARGV[$i + 1] =~ /^[0-6]$/)
              {
                push(@wdays,$ARGV[$i + 1]);
                splice(@ARGV,$i,2);
              }
            else
              {
                $cc = 253;
                problem(sprintf("Illegal -x value '%s' must be in range 0-6",
                                $ARGV[$i + 1]),$cc);
              }
          }
        else
          {
            $cc = 246;
            problem("Missing argument after -x",$cc);
          }
      }
    else
      {
        ++$i;
      }
  } # while

if (($cc == 0) && ($#wdays >= (DAYS_PER_WK - 1)))
  {
    $cc = 239;
    problem(sprintf("No more than %d -x args allowed.",DAYS_PER_WK - 1),$cc);
  }

if ($cc != 0)
  {
    usage();
    exit($cc);
  }

# Now process the rest of the args using getopts()
# ---------------------------------------------------

our ($opt_D,$opt_M,$opt_Y,$opt_w,$opt_W,$opt_u,$opt_U,$opt_s,$opt_e,$opt_y,
     $opt_n,$opt_N,$opt_p,$opt_P,$opt_h,$opt_H,$opt_S,$opt_c,$opt_i,$opt_I,
     $opt_o,$opt_O,$opt_f,$opt_F);


if (!getopts('DMYwWuUciIoOseyn:N:p:P:hHS:fF'))
  {
    $cc = 252;
    usage();
    exit($cc);
  }

if (defined($opt_D))
  {
    $dmy_mode = DMY_DAY;
    ++$dmy_knt;
  }
if (defined($opt_M))
  {
    $dmy_mode = DMY_MONTH;
    ++$dmy_knt;
  }
if (defined($opt_Y))
  {
    $dmy_mode = DMY_YEAR;
    ++$dmy_knt;
  }
if (defined($opt_w) || defined($opt_W))
  {
    $wkday = TRUE;
  }
if (defined($opt_u))
  {
    $cc = 251;
  }
if (defined($opt_U))
  {
    $utc_arg = TRUE;
  }
if (defined($opt_c))
  {
    $cal_mode = TRUE;
  }
if (defined($opt_i))
  {
    $in_words = WORDS_ABREV;
    ++$in_words_knt;
  }
if (defined($opt_I))
  {
    $in_words = WORDS_FULL;
    ++$in_words_knt;
  }
if (defined($opt_o))
  {
    $out_words = WORDS_ABREV;
    ++$out_words_knt;
  }
if (defined($opt_O))
  {
    $out_words = WORDS_FULL;
    ++$out_words_knt;
  }
if (defined($opt_s))
  {
    $sep = '';
    ++$space_knt;
  }
if (defined($opt_e))
  {
    $mdy_mode = MDY_DMY;
    ++$mdy_arg_knt;
  }
if (defined($opt_y))
  {
    $mdy_mode = MDY_YMD;
    ++$mdy_arg_knt;
  }
if (defined($opt_n))
  {
    $day_offset = $opt_n;
    ++$day_arg_knt;
  }
if (defined($opt_N))
  {
    $day_offset = $opt_N;
    ++$day_arg_knt;
  }
if (defined($opt_p))
  {
    $day_offset = $opt_p * -1;
    ++$day_arg_knt;
  }
if (defined($opt_P))
  {
    $day_offset = $opt_P * -1;
    ++$day_arg_knt;
  }
if (defined($opt_h) || defined($opt_H))
  {
    $hol = TRUE;
  }
if (defined($opt_S))
  {
    $sep = $opt_S;
    ++$space_knt;
  }
if (defined($opt_f) || defined($opt_F))
  {
    $usefile = TRUE;
  }

# Now check for errors
#

if ($day_arg_knt > 1 && $cc == 0)
  {
    $cc = 255;
    problem("Only one -n or -p argument allowed",$cc);
  }
if (($dmy_knt + $wkday) > 1 && $cc == 0)
  {
    $cc = 245;
    problem("Only one -w, -D, -M, or -Y argument allowed",$cc);
  }
if ($mdy_arg_knt > 1 && $cc == 0)
  {
    $cc = 254;
    problem("Only one -y or -e argument allowed",$cc);
  }
if ($space_knt > 1 && $cc == 0)
  {
    $cc = 247;
    problem("Only one -s or -S argument allowed",$cc);
  }
if ($in_words_knt > 1 && $cc == 0)
  {
    $cc = 236;
    problem("Only one -i or -I argument allowed",$cc);
  }
if ($out_words_knt > 1 && $cc == 0)
  {
    $cc = 235;
    problem("Only one -o or -O argument allowed",$cc);
  }
if ($cc != 0)
  {
    usage();
    exit($cc);
  }

# if $in_words 0r $out_words then setup lc_time_array
#

if (($in_words) || ($out_words))
  {
    @lc_time_array = load_locale_lc_time();
  }

# -------------- Finally ready to start work --------------------
# ---------------------------------------------------------------

my $s_out = '';
if (!($usefile))
  {
    ($cc,$s_out) = process_1_date(@ARGV);
    if ($cc == 0)
      {
        printf("%s\n",$s_out);
      }
  }
else
  {
    use FileHandle;

    my $s_in = '';
    STDOUT->autoflush(TRUE); # do not buffer output
    while (defined($s_in = <STDIN>) && $cc == 0)
      {
        chomp($s_in);
        my @a_in = split(/\s+/,$s_in);
        ($cc,$s_out) = process_1_date(@a_in);
        if ($cc == 0)
          {
            printf("%s\n",$s_out);
          }
      }
  }
exit($cc);

 