#!/usr/bin/perl

# zoneinfo: creates zoneinfo.7 manual page from zone.tab and iso3166.tab

# (C) 2015 Cezary M. Kruk
# (C) 2005-2012 Kevin Boone

use strict;

my @months = qw( January February March April May June July August September October November December );
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime();
$year = $year + 1900;
my $datestring = "$months[$mon] $mday, $year";

my $used_method = $ARGV[0];

if ($used_method eq "" || $used_method eq "-h")
  {
    print "zoneinfo (C) 2015 Cezary M. Kruk\n\n";
    print "  Usage: zoneinfo [-c] [-C] [-m] [-h]\n\n";
    print "  -c : displays the list of the cities.\n";
    print "  -C : displays the list of the countries.\n";
    print "  -m : generates the manual page.\n";
    print "  -h : displays this help.\n";
    exit 0;
  }

open IN,"</usr/share/zoneinfo/zone.tab" or die "zoneinfo: can not read /usr/share/zoneinfo/zone.tab";

if ($used_method eq "-c")
  {
    print "ISO\t lat\t lon\t TZ\n";
    print "-------------------------------------------------------\n";
  }
elsif ($used_method eq "-m")
  {
    open OUT,">zoneinfo.7" or die "Can't write zoneinfo.7";
    print OUT ".TH \"ZONEINFO\" 7 \"$datestring\" \"\" \"\"\n";
    print OUT ".SH \"NAME\"\n";
    print OUT "ZONEINFO \\-\\- uses the data from \\fI/usr/share/zoneinfo/zone.tab\\fP file to generate the table storing countries ISO codes, latitudes and longitudes of the cities, and the time zone names; it uses also the data from \\fI/usr/share/zoneinfo/iso3166.tab\\fP to generate the table storing countries ISO codes and their names.\n";
    print OUT ".ta 5 13 22\n";
    print OUT ".SH \"SYNOPSIS\"\n";
    print OUT "\\fBzoneinfo\\fP [\\fI-c\\fP] [\\fI-C\\fP] [\\fI-m\\fP] [\\fI-h\\fP]\n";
    print OUT ".SH \"OPTIONS\"\n";
    print OUT ".TP\n";
    print OUT ".B \\-c\n";
    print OUT "Displays the list of the cities.\n";
    print OUT ".TP\n";
    print OUT ".B \\-C\n";
    print OUT "Displays the list of the countries.\n";
    print OUT ".TP\n";
    print OUT ".B \\-m\n";
    print OUT "Generates this manual page.\n";
    print OUT ".TP\n";
    print OUT ".B \\-h\n";
    print OUT "Displays short help.\n";
    print OUT ".SH \"DESCRIPTION\"\n";
    print OUT "The following table uses POSIX style in which the longitudes west of Greenwich are positive and east of Greenwich \\-\\- negative.  This format is used by many programs.  The other programs use the reverse convention so in their case you should reverse the sign for the longitude.\n";
    print OUT ".LP\n";
    print OUT "The latitudes and longitudes are in degrees so the values after dot are decimal.\n";
    print OUT ".LP\n";
    print OUT "The names of the time zones are in accordance with the \\fItz database\\fP.\n";
    print OUT ".SH \"CITIES TABLE\"\n";
    print OUT "\\fBISO\t lat\t lon\tTZ\\fP\n";
    print OUT ".br\n";
    print OUT "\\fB-------------------------------------------------------\\fP\n";
    print OUT ".br\n";
  }

while (my $line=<IN>)
  {
  chomp ($line);
  if ($line =~ /^#/) { next; }
  $line =~ /([A-Z][A-Z])\s+([0-9+-]+)\s+([-a-zA-Z\/_]+)/;
  my $iso = $1;
  my $latlon= $2;
  my $tzone= $3;
  $latlon =~ /([+-])([0-9]+)([+-])([0-9]+)/;
  my $lat_sign = $1;
  my $lat = $2;
  my $lon_sign = $3;
  my $lon = $4;
  $lat =~ /([0-9][0-9])([0-9][0-9])/;
  my $lat_deg = $1;
  my $lat_min = $2;
  $lon =~ /([0-9][0-9][0-9])([0-9][0-9])/;
  my $lon_deg = $1;
  my $lon_min = $2;
  $lat_deg =~ s/^0//;
  $lat_min = $lat_min / 60;
  $lat_min =~ s/^0//;
  $lat_min =~ s/\.(..).*/.$1/;
  $lon_deg =~ s/^0//;
  $lon_deg =~ s/^0//;
  $lon_min = $lon_min / 60;
  $lon_min =~ s/\.(..).*/.$1/;
  $lon_min =~ s/^0//;
  if ($lat_sign eq "+") { $lat_sign = " " };
  if ($used_method eq "-c")
    {
      if ($lon_sign eq "-") { $lon_sign = " " } else { $lon_sign = "-" };
    }
  elsif ($used_method eq "-m")
    {
      if ($lat_sign eq "-") { $lat_sign = "\\-" };
      if ($lon_sign eq "-") { $lon_sign = " " } else { $lon_sign = "\\-" };
    }
  if ($used_method eq "-c")
    {
      print "$iso\t";
      print "$lat_sign$lat_deg$lat_min\t"; 
      print "$lon_sign$lon_deg$lon_min\t";
      print " $tzone\n";
    }
  elsif ($used_method eq "-m")
    {
      print OUT "\\fB$iso\\fP\t";
      print OUT "$lat_sign$lat_deg$lat_min\t"; 
      print OUT "$lon_sign$lon_deg$lon_min\t";
      print OUT "$tzone\n";
      print OUT ".br\n";
    }
  }

open IN,"</usr/share/zoneinfo/iso3166.tab" or die "zoneinfo: can not read /usr/share/zoneinfo/iso3166.tab";

if ($used_method eq "-m")
  {
    print OUT ".SH \"COUNTRIES TABLE\"\n";
    print OUT "\\fBISO\t country\\fP\n";
    print OUT ".br\n";
    print OUT "\\fB-------------------------------------------------------\\fP\n";

    print OUT ".br\n";
  }
elsif ($used_method eq "-C")
  {
    print "ISO\t country\n";
    print "-------------------------------------------------------\n";
  }

while (my $line=<IN>)
  {
    chomp ($line);
    if ($line =~ /^#/) { next; }
    $line =~ /([A-Z][A-Z])\s+(.*)/;
    my $iso = $1;
    my $country= $2;
    if ($used_method eq "-C")
      {
        print "$iso\t";
        print " $country\n"; 
      }
    elsif ($used_method eq "-m")
      {
        print OUT "\\fB$iso\\fP\t";
        print OUT " $country\n"; 
        print OUT ".br\n";
      }
  }

if ($used_method eq "-m")
  {
    print OUT ".SH \"MILITARY ZONES\"\n";
    print OUT "\\fBname\t\tcode\toffset\\fP\n";
    print OUT ".br\n";
    print OUT "\\fB-------------------------------------------------------\\fP\n";
    print OUT ".br\n";
    print OUT "Alpha\tA\tGMT-01\n";
    print OUT ".br\n";
    print OUT "Bravo\tB\tGMT-02\n";
    print OUT ".br\n";
    print OUT "Charlie\tC\tGMT-03\n";
    print OUT ".br\n";
    print OUT "Delta\tD\tGMT-04\n";
    print OUT ".br\n";
    print OUT "Echo\t\tE\tGMT-05\n";
    print OUT ".br\n";
    print OUT "Foxtrot\tF\tGMT-06\n";
    print OUT ".br\n";
    print OUT "Golf\t\tG\tGMT-07\n";
    print OUT ".br\n";
    print OUT "Hotel\tH\tGMT-08\n";
    print OUT ".br\n";
    print OUT "India\tI\tGMT-09\n";
    print OUT ".br\n";
    print OUT "Kilo\t\tK\tGMT-10\n";
    print OUT ".br\n";
    print OUT "Lima\t\tL\tGMT-11\n";
    print OUT ".br\n";
    print OUT "Mike\t\tM\tGMT-12\n";
    print OUT ".br\n";
    print OUT "November\tN\tGMT+01\n";
    print OUT ".br\n";
    print OUT "Oscar\tO\tGMT+02\n";
    print OUT ".br\n";
    print OUT "Papa\t\tP\tGMT+03\n";
    print OUT ".br\n";
    print OUT "Quebec\tQ\tGMT+04\n";
    print OUT ".br\n";
    print OUT "Romeo\tR\tGMT+05\n";
    print OUT ".br\n";
    print OUT "Sierra\tS\tGMT+06\n";
    print OUT ".br\n";
    print OUT "Tango\tT\tGMT+07\n";
    print OUT ".br\n";
    print OUT "Uniform\tU\tGMT+08\n";
    print OUT ".br\n";
    print OUT "Victor\tV\tGMT+09\n";
    print OUT ".br\n";
    print OUT "Whiskey\tW\tGMT+10\n";
    print OUT ".br\n";
    print OUT "X-ray\tX\tGMT+11\n";
    print OUT ".br\n";
    print OUT "Yankee\tY\tGMT+12\n";
    print OUT ".br\n";
    print OUT "Zulu\t\tZ\tGMT\n";
    print OUT ".SH \"EXAMPLE\"\n";
    print OUT "Most countries use just one time zone so the time all over such a country is the same in all locations.\n";
    print OUT ".LP\n";
    print OUT "Some countries expand over several time zones.  For example Australia expands over six zones and the time difference between the extremes is equal three hours.  Moreover some of these zones use daylight savings while the other ones do not use them staying with the standard time throughout the year.  As a result it may be tricky to establish the right time zone for a given location which is not included in \\fItz database\\fP.  The following command displays all available zones for a given country:\n";
    print OUT ".IP\n";
    print OUT ".B ISO=\"AU\" ; for tz in \$(zoneinfo \\-c | grep \"\"\"^\$ISO\"\"\" | awk '{print \$4}') ; do offset=\$(TZ=\"\$tz\" date +\"%Z%t%:z%t\") ; echo \"\"\"\$offset \$tz\"\"\" ; done\n";
    print OUT ".IP\n";
    print OUT "LHDT  +11:00  Australia/Lord_Howe\n";
    print OUT ".br\n";
    print OUT "MIST  +11:00  Antarctica/Macquarie\n";
    print OUT ".br\n";
    print OUT "AEDT  +11:00  Australia/Hobart\n";
    print OUT ".br\n";
    print OUT "AEDT  +11:00  Australia/Currie\n";
    print OUT ".br\n";
    print OUT "AEDT  +11:00  Australia/Melbourne\n";
    print OUT ".br\n";
    print OUT "AEDT  +11:00  Australia/Sydney\n";
    print OUT ".br\n";
    print OUT "ACDT  +10:30  Australia/Broken_Hill\n";
    print OUT ".br\n";
    print OUT "AEST  +10:00  Australia/Brisbane\n";
    print OUT ".br\n";
    print OUT "AEST  +10:00  Australia/Lindeman\n";
    print OUT ".br\n";
    print OUT "ACDT  +10:30  Australia/Adelaide\n";
    print OUT ".br\n";
    print OUT "ACST  +09:30  Australia/Darwin\n";
    print OUT ".br\n";
    print OUT "AWST  +08:00  Australia/Perth\n";
    print OUT ".br\n";
    print OUT "ACWST +08:45  Australia/Eucla\n";
    print OUT ".LP\n";
    print OUT "Note that above time offsets are related to the current time zone settings so they change whenever the time zone switches from the standard time to daylight savings time forth and back.\n";
    print OUT ".LP\n";
    print OUT "Note also that \\fItz database\\fP uses ISO 6709 standard rather than POSIX in which the time offsets have a reverse sign.\n";
    print OUT ".LP\n";
    print OUT "In order to display the data for some other country it is enough to set the right \\fIISO\\fP variable at the beginning of the discussed command using the codes from the above countries table.\n";
    print OUT ".LP\n";
    print OUT "You may find also helpful the information from the following site:\n";
    print OUT ".IP\n";
    print OUT "\\fIhttp://www.timeanddate.com/time/map/\\fP\n";
    print OUT ".SH \"LICENSE\"\n";
    print OUT "zoneinfo is provided on the terms of the \\fIGNU General Public License v. 3\\fP.  Read the \\fICOPYING\\fP file for the complete text of the license.\n";
    print OUT ".SH \"PROGRAM AUTHOR\"\n";
    print OUT "zoneinfo:\n";
    print OUT ".IP\n";
    print OUT "(C) 2015 Cezary M. Kruk <\\fIc.kruk\@bigfoot.com\\fP>\n";
    print OUT ".LP\n";
    print OUT "parse_zoneinfo.pl:\n";
    print OUT ".IP\n";
    print OUT "(C) 2005-2012 Kevin Boone\n";
    print OUT ".SH \"MANPAGE AUTHOR\"\n";
    print OUT "(C) 2015 Cezary M. Kruk <\\fIc.kruk\@bigfoot.com\\fP>\n";
    print OUT ".LP\n";
    print OUT "\\fIzoneinfo\\fP(7) manual page is generated by \\fIzoneinfo\\fP script which is modified version of \\fIparse_zoneinfo.pl\\fP script written by Kevin Boone in 2012 and attached to his \\fIsolunar\\fP program.\n";
    print OUT ".LP\n";
    print OUT "See: \\fIhttp://kevinboone.net/README_solunar.html\\fP.\n";
    print OUT ".SH \"SEE ALSO\"\n";
    print OUT "\\fIzdump\\fP(8), \\fIdate\\fP(1).\n";
    print "zoneinfo: zoneinfo.7 manual page created.\n";
  }

