summaryrefslogtreecommitdiffstats
path: root/src/tools/win32tzlist.pl
blob: c43ab7e28833a5a774e2b10f01c07b4384e3a6ed (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#################################################################
#
# win32tzlist.pl -- compare Windows timezone information
#
# Copyright (c) 2008-2022, PostgreSQL Global Development Group
#
# src/tools/win32tzlist.pl
#################################################################

#
# This script compares the timezone information in the Windows registry
# with that in src/bin/initdb/findtimezone.c.  A list of changes will be
# written to stdout - no attempt is made to automatically edit the file.
#
# Run the script from the top-level PG source directory.
#

use strict;
use warnings;

use Win32::Registry;

my $tzfile = 'src/bin/initdb/findtimezone.c';

#
# Fetch all timezones in the registry
#
my $basekey;
$HKEY_LOCAL_MACHINE->Open(
	"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones", $basekey)
  or die $!;

my @subkeys;
$basekey->GetKeys(\@subkeys);

my @system_zones;

foreach my $keyname (@subkeys)
{
	my $subkey;
	my %vals;

	$basekey->Open($keyname, $subkey) or die $!;
	$subkey->GetValues(\%vals) or die $!;
	$subkey->Close();

	die "Incomplete timezone data for $keyname!\n"
	  unless ($vals{Std} && $vals{Dlt} && $vals{Display});
	push @system_zones,
	  {
		'std'     => $vals{Std}->[2],
		'dlt'     => $vals{Dlt}->[2],
		'display' => clean_displayname($vals{Display}->[2]),
	  };
}

$basekey->Close();

#
# Fetch all timezones currently in the file
#
my @file_zones;
my $pgtz;
open(my $tzfh, '<', $tzfile) or die "Could not open $tzfile!\n";
{
	local $/ = undef;
	$pgtz = <$tzfh>;
}
close($tzfh);

# Attempt to locate and extract the complete win32_tzmap struct
$pgtz =~ /win32_tzmap\[\] =\s+{\s+\/\*[^\/]+\*\/\s+(.+?)};/gs
  or die "Could not locate struct win32_tzmap in $tzfile!";
$pgtz = $1;

# Extract each individual record from the struct
while ($pgtz =~
	m/{\s+\/\*(.+?)\*\/\s+"([^"]+)",\s+"([^"]+)",\s+"([^"]+)",?\s+},/gs)
{
	push @file_zones,
	  {
		'display' => clean_displayname($1),
		'std'     => $2,
		'dlt'     => $3,
		'match'   => $4,
	  };
}

#
# Look for anything that has changed
#
my @add;

for my $sys (@system_zones)
{
	my $match = 0;
	for my $file (@file_zones)
	{
		if ($sys->{std} eq $file->{std})
		{
			$match = 1;
			if ($sys->{dlt} ne $file->{dlt})
			{
				print
				  "Timezone $sys->{std}, changed name of daylight zone!\n";
			}
			if ($sys->{display} ne $file->{display})
			{
				print
				  "Timezone $sys->{std} changed displayname ('$sys->{display}' from '$file->{display}')!\n";
			}
			last;
		}
	}
	unless ($match)
	{
		push @add, $sys;
	}
}

if (@add)
{
	print "\n\nOther than that, add the following timezones:\n";
	for my $z (@add)
	{
		print
		  "\t{\n\t\t/* $z->{display} */\n\t\t\"$z->{std}\", \"$z->{dlt}\",\n\t\t\"FIXME\"\n\t},\n";
	}
}

sub clean_displayname
{
	my $dn = shift;

	$dn =~ s/\*//gs;
	$dn =~ s/\s+/ /gs;
	$dn =~ s/^\s+//gs;
	$dn =~ s/\s+$//gs;
	return $dn;
}