]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/tzdata/checktab.awk
Import tzdata 2019b.
[FreeBSD/FreeBSD.git] / contrib / tzdata / checktab.awk
1 # Check tz tables for consistency.
2
3 # Contributed by Paul Eggert.  This file is in the public domain.
4
5 BEGIN {
6         FS = "\t"
7
8         if (!iso_table) iso_table = "iso3166.tab"
9         if (!zone_table) zone_table = "zone1970.tab"
10         if (!want_warnings) want_warnings = -1
11
12         while (getline <iso_table) {
13                 iso_NR++
14                 if ($0 ~ /^#/) continue
15                 if (NF != 2) {
16                         printf "%s:%d: wrong number of columns\n", \
17                                 iso_table, iso_NR >>"/dev/stderr"
18                         status = 1
19                 }
20                 cc = $1
21                 name = $2
22                 if (cc !~ /^[A-Z][A-Z]$/) {
23                         printf "%s:%d: invalid country code '%s'\n", \
24                                 iso_table, iso_NR, cc >>"/dev/stderr"
25                         status = 1
26                 }
27                 if (cc <= cc0) {
28                         if (cc == cc0) {
29                                 s = "duplicate";
30                         } else {
31                                 s = "out of order";
32                         }
33
34                         printf "%s:%d: country code '%s' is %s\n", \
35                                 iso_table, iso_NR, cc, s \
36                                 >>"/dev/stderr"
37                         status = 1
38                 }
39                 cc0 = cc
40                 if (name2cc[name]) {
41                         printf "%s:%d: '%s' and '%s' have the same name\n", \
42                                 iso_table, iso_NR, name2cc[name], cc \
43                                 >>"/dev/stderr"
44                         status = 1
45                 }
46                 name2cc[name] = cc
47                 cc2name[cc] = name
48                 cc2NR[cc] = iso_NR
49         }
50
51         cc0 = ""
52
53         while (getline <zone_table) {
54                 zone_NR++
55                 if ($0 ~ /^#/) continue
56                 if (NF != 3 && NF != 4) {
57                         printf "%s:%d: wrong number of columns\n", \
58                                 zone_table, zone_NR >>"/dev/stderr"
59                         status = 1
60                 }
61                 split($1, cca, /,/)
62                 cc = cca[1]
63                 coordinates = $2
64                 tz = $3
65                 comments = $4
66
67                 # Don't complain about a special case for Crimea in zone.tab.
68                 # FIXME: zone.tab should be removed, since it is obsolete.
69                 # Or at least put just "XX" in its country-code column.
70                 if (cc < cc0 \
71                     && !(zone_table == "zone.tab" \
72                          && tz0 == "Europe/Simferopol")) {
73                         printf "%s:%d: country code '%s' is out of order\n", \
74                                 zone_table, zone_NR, cc >>"/dev/stderr"
75                         status = 1
76                 }
77                 cc0 = cc
78                 tz0 = tz
79                 tztab[tz] = 1
80                 tz2comments[tz] = comments
81                 tz2NR[tz] = zone_NR
82                 for (i in cca) {
83                     cc = cca[i]
84                     cctz = cc tz
85                     cctztab[cctz] = 1
86                     if (cc2name[cc]) {
87                         cc_used[cc]++
88                     } else {
89                         printf "%s:%d: %s: unknown country code\n", \
90                                 zone_table, zone_NR, cc >>"/dev/stderr"
91                         status = 1
92                     }
93                 }
94                 if (coordinates !~ /^[-+][0-9][0-9][0-5][0-9][-+][01][0-9][0-9][0-5][0-9]$/ \
95                     && coordinates !~ /^[-+][0-9][0-9][0-5][0-9][0-5][0-9][-+][01][0-9][0-9][0-5][0-9][0-5][0-9]$/) {
96                         printf "%s:%d: %s: invalid coordinates\n", \
97                                 zone_table, zone_NR, coordinates >>"/dev/stderr"
98                         status = 1
99                 }
100         }
101
102         for (cctz in cctztab) {
103                 cc = substr (cctz, 1, 2)
104                 tz = substr (cctz, 3)
105                 if (1 < cc_used[cc]) {
106                         comments_needed[tz] = cc
107                 }
108         }
109         for (cctz in cctztab) {
110           cc = substr (cctz, 1, 2)
111           tz = substr (cctz, 3)
112           if (!comments_needed[tz] && tz2comments[tz]) {
113             printf "%s:%d: unnecessary comment '%s'\n", \
114                 zone_table, tz2NR[tz], tz2comments[tz] \
115                 >>"/dev/stderr"
116             tz2comments[tz] = 0
117             status = 1
118           } else if (comments_needed[tz] && !tz2comments[tz]) {
119             printf "%s:%d: missing comment for %s\n", \
120               zone_table, tz2NR[tz], comments_needed[tz] \
121               >>"/dev/stderr"
122             tz2comments[tz] = 1
123             status = 1
124           }
125         }
126         FS = " "
127 }
128
129 $1 ~ /^#/ { next }
130
131 {
132         tz = rules = ""
133         if ($1 == "Zone") {
134                 tz = $2
135                 ruleUsed[$4] = 1
136                 if ($5 ~ /%/) rulePercentUsed[$4] = 1
137         } else if ($1 == "Link" && zone_table == "zone.tab") {
138                 # Ignore Link commands if source and destination basenames
139                 # are identical, e.g. Europe/Istanbul versus Asia/Istanbul.
140                 src = $2
141                 dst = $3
142                 while ((i = index(src, "/"))) src = substr(src, i+1)
143                 while ((i = index(dst, "/"))) dst = substr(dst, i+1)
144                 if (src != dst) tz = $3
145         } else if ($1 == "Rule") {
146                 ruleDefined[$2] = 1
147                 if ($10 != "-") ruleLetters[$2] = 1
148         } else {
149                 ruleUsed[$2] = 1
150                 if ($3 ~ /%/) rulePercentUsed[$2] = 1
151         }
152         if (tz && tz ~ /\//) {
153                 if (!tztab[tz]) {
154                         printf "%s: no data for '%s'\n", zone_table, tz \
155                                 >>"/dev/stderr"
156                         status = 1
157                 }
158                 zoneSeen[tz] = 1
159         }
160 }
161
162 END {
163         for (tz in ruleDefined) {
164                 if (!ruleUsed[tz]) {
165                         printf "%s: Rule never used\n", tz
166                         status = 1
167                 }
168         }
169         for (tz in ruleLetters) {
170                 if (!rulePercentUsed[tz]) {
171                         printf "%s: Rule contains letters never used\n", tz
172                         status = 1
173                 }
174         }
175         for (tz in tztab) {
176                 if (!zoneSeen[tz]) {
177                         printf "%s:%d: no Zone table for '%s'\n", \
178                                 zone_table, tz2NR[tz], tz >>"/dev/stderr"
179                         status = 1
180                 }
181         }
182         if (0 < want_warnings) {
183                 for (cc in cc2name) {
184                         if (!cc_used[cc]) {
185                                 printf "%s:%d: warning: " \
186                                         "no Zone entries for %s (%s)\n", \
187                                         iso_table, cc2NR[cc], cc, cc2name[cc]
188                         }
189                 }
190         }
191
192         exit status
193 }