1#
2# Program: make_timezonelist.pl
3#
4# Copyright 2003 Double Precision, Inc.  See COPYING for
5# distribution information.
6#
7# Author: Sam Varshavchik <mrsam@courier-mta.com>
8#
9# $Id: sv-make_timezonelist.pl,v 1.4 2006/12/30 14:22:02 mrsam Exp $
10#
11#       Original Author: Paul L. Allen <pla@softflare.com>
12#
13#       Version: pla-0.1, 11-Aug-2003
14#
15# Purpose: uses Olsen zoneinfo data to generate TIMEZONELIST
16#
17# OS: most recent release of *nix that include the Olsen TZ system.
18#
19# Warning: if you have updated the TZ source files without recompiling
20# then then some of the timezones generated by this program won't
21# work.  But you wouldn't forget to recompile, would you?
22#
23# Copyright conditions: do whatever you want with it provided that if
24# you make changes and distribute the changed version you:
25#
26#   1) Replace the author with your contact details so I don't get people
27#   asking me what's wrong with your changed version.
28#
29#   2) Add an "Original Author:" line with my contact details.
30#
31#   3) Change the version to be prefixed with your initials rather than
32#   mine.
33
34
35# List of possible paths to the zoneinfo directory with the most common
36# cases first.  Let me know if there are any others that should be included.
37@zoneinfo_dirs = qw
38(
39   /usr/share/zoneinfo
40   /usr/local/etc/zoneinfo
41   /usr/compat/linux/usr/share/zoneinfo
42   /usr/share/lib/zoneinfo
43);
44
45foreach $dir (@zoneinfo_dirs)
46{
47  if (-d($dir))
48  {
49    $zoneinfo_dir = $dir;
50    last;
51  }
52}
53die "Could not find a zoneinfo directory\n" unless ($zoneinfo_dir);
54if ( $^O eq "freebsd" )
55{
56  $iso3166tab = "/usr/share/misc/iso3166";
57}
58elsif ( $^O eq "netbsd" )
59{
60  $iso3166tab = "/usr/share/misc/domains"
61}
62else
63{
64  $iso3166tab = "$zoneinfo_dir/iso3166.tab";
65}
66$zonetab = "$zoneinfo_dir/zone.tab";
67$etc_dir = "$zoneinfo_dir/Etc";
68
69$output = 'TIMEZONELIST';
70
71open(ISO3166, $iso3166tab) ||
72  die "Could not open '$iso3166tab' for reading ($!)\n";
73@lines = <ISO3166>;
74close(ISO3166);
75
76foreach $line (@lines)
77{
78  next if ($line =~ /^\s*#/);
79  next unless ($line =~ /\S/);
80
81  chomp($line);
82if ( $^O eq "freebsd" )
83{
84  ($code, undef, undef, $country) = split(/\t/, $line, 4);
85}
86else
87{
88  ($code, $country) = split(/\t/, $line, 2);
89}
90
91  $countries{$code} = $country;
92}
93
94# Correct the entry for GB.
95$countries{GB} = 'United Kingdom';
96
97if ( open(ZONES, $zonetab) == 0 )
98{
99  if ( $^O eq "netbsd" )
100  {
101    die "Could not open '$zonetab' for reading ($!). Currently, NetBSD does not install zone.tab by default. You must manually fetch sharesrc.tgz from the source of your version and extract zone.tab into /usr/share/zoneinfo\n";
102  }
103  else
104  {
105    die "Could not open '$zonetab' for reading ($!)\n";
106  }
107}
108@lines = <ZONES>;
109close(ZONES);
110
111foreach $line (@lines)
112{
113  next if ($line =~ /^\s*#/);
114  next unless ($line =~ /\S/);
115
116  chomp($line);
117  ($country_code, undef, $tz, $comment) = split(/\t/, $line, 4);
118
119  $country = $countries{$country_code};
120  push(@zones, [lc($country), $tz, $country, $comment]);
121  $longest_tz = length($tz) if (length($tz) > $longest_tz);
122}
123
124$num_tabs = int($longest_tz / 8) + 1;
125
126@sorted_zones = sort
127  {
128    $a->[0] cmp $b->[0] ||
129    $a->[3] cmp $b->[3] ||
130    $a cmp $b
131  } @zones;
132
133open(OUT, ">$output") ||
134  die "Could not open '$output' for writing ($!)\n";
135
136print OUT '*', "\t" x $num_tabs, "*\n";
137
138foreach $zone (@sorted_zones)
139{
140  if ($zone->[3])
141  {
142    print OUT $zone->[1],
143      "\t" x ($num_tabs - int(length($zone->[1]) / 8)),
144      "$zone->[2]: $zone->[3]\n";
145  }
146  else
147  {
148    print OUT $zone->[1],
149	"\t" x  ($num_tabs - int(length($zone->[1]) / 8)),
150	"$zone->[2]\n";
151  }
152}
153
154# might not have zoneinfo/Etc on this machine so don't complain if it's
155# not there
156if (opendir(ETC, $etc_dir))
157{
158  @objects = readdir(ETC);
159  closedir(ETC);
160
161  foreach $object (@objects)
162  {
163    next unless ($object =~ /^GMT(.*)$/);
164    next if ($1 =~ /^[+-]?0$/);
165
166    if ($1)
167    {
168      push(@gmts, [$object, $1]);
169    }
170    else
171    {
172      $gmt_no_offset++;
173    }
174  }
175
176  @sorted_gmts = sort {$b->[1] <=> $a->[1]} (@gmts);
177
178  print OUT 'Etc/GMT', "\t" x $num_tabs, "GMT\n" if ($gmt_no_offset);
179
180  foreach $gmt (@sorted_gmts)
181  {
182    $offset = $gmt->[1];
183    $abs_offset = abs($offset);
184    $designator = "Etc/GMT$offset";
185
186    print OUT $designator,
187      "\t" x ($num_tabs - int(length($designator) / 8)),
188      "$abs_offset hour",
189      ($abs_offset == 1 ? '' : 's'),
190      ($offset < 0 ? ' ahead of' : ' behind'),
191      " GMT\n";;
192  }
193
194  close(OUT);
195}
196