]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/tzdata/checktab.awk
contrib/tzdata: import tzdata 2023a and tzdata 2023b
[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                 ccs = input_ccs[zone_NR] = $1
62                 coordinates = $2
63                 tz = $3
64                 comments = input_comments[zone_NR] = $4
65                 split(ccs, cca, /,/)
66                 cc = cca[1]
67
68                 # Don't complain about a special case for Crimea in zone.tab.
69                 # FIXME: zone.tab should be removed, since it is obsolete.
70                 # Or at least put just "XX" in its country-code column.
71                 if (cc < cc0 \
72                     && !(zone_table == "zone.tab" \
73                          && tz0 == "Europe/Simferopol")) {
74                         printf "%s:%d: country code '%s' is out of order\n", \
75                                 zone_table, zone_NR, cc >>"/dev/stderr"
76                         status = 1
77                 }
78                 cc0 = cc
79                 tz0 = tz
80                 tztab[tz] = 1
81                 tz2NR[tz] = zone_NR
82                 for (i in cca) {
83                     cc = cca[i]
84                     if (cc2name[cc]) {
85                         cc_used[cc]++
86                     } else {
87                         printf "%s:%d: %s: unknown country code\n", \
88                                 zone_table, zone_NR, cc >>"/dev/stderr"
89                         status = 1
90                     }
91                 }
92                 if (coordinates !~ /^[-+][0-9][0-9][0-5][0-9][-+][01][0-9][0-9][0-5][0-9]$/ \
93                     && 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]$/) {
94                         printf "%s:%d: %s: invalid coordinates\n", \
95                                 zone_table, zone_NR, coordinates >>"/dev/stderr"
96                         status = 1
97                 }
98         }
99
100         for (i = 1; i <= zone_NR; i++) {
101           ccs = input_ccs[i]
102           if (!ccs) continue
103           comments = input_comments[i]
104           split(ccs, cca, /,/)
105           used_max = 0
106           for (j in cca) {
107             cc = cca[j]
108             if (used_max < cc_used[cc]) {
109               used_max = cc_used[cc]
110               used_max_cc = cc
111             }
112           }
113           if (used_max <= 1 && comments) {
114             printf "%s:%d: unnecessary comment '%s'\n", \
115               zone_table, i, comments \
116               >>"/dev/stderr"
117             status = 1
118           } else if (1 < used_max && !comments) {
119             printf "%s:%d: missing comment for %s\n", \
120               zone_table, i, used_max_cc \
121               >>"/dev/stderr"
122             status = 1
123           }
124         }
125         FS = " "
126 }
127
128 $1 ~ /^#/ { next }
129
130 {
131         tz = rules = ""
132         if ($1 == "Zone") {
133                 tz = $2
134                 ruleUsed[$4] = 1
135                 if ($5 ~ /%/) rulePercentUsed[$4] = 1
136         } else if ($1 == "Link" && zone_table == "zone.tab") {
137                 # Ignore Link commands if source and destination basenames
138                 # are identical, e.g. Europe/Istanbul versus Asia/Istanbul.
139                 src = $2
140                 dst = $3
141                 while ((i = index(src, "/"))) src = substr(src, i+1)
142                 while ((i = index(dst, "/"))) dst = substr(dst, i+1)
143                 if (src != dst) tz = $3
144         } else if ($1 == "Rule") {
145                 ruleDefined[$2] = 1
146                 if ($10 != "-") ruleLetters[$2] = 1
147         } else {
148                 ruleUsed[$2] = 1
149                 if ($3 ~ /%/) rulePercentUsed[$2] = 1
150         }
151         if (tz && tz ~ /\// && tz !~ /^Etc\//) {
152                 if (!tztab[tz] && FILENAME != "backward") {
153                         printf "%s: no data for '%s'\n", zone_table, tz \
154                                 >>"/dev/stderr"
155                         status = 1
156                 }
157                 zoneSeen[tz] = 1
158         }
159 }
160
161 END {
162         for (tz in ruleDefined) {
163                 if (!ruleUsed[tz]) {
164                         printf "%s: Rule never used\n", tz
165                         status = 1
166                 }
167         }
168         for (tz in ruleLetters) {
169                 if (!rulePercentUsed[tz]) {
170                         printf "%s: Rule contains letters never used\n", tz
171                         status = 1
172                 }
173         }
174         for (tz in tztab) {
175                 if (!zoneSeen[tz] && tz !~ /^Etc\//) {
176                         printf "%s:%d: no Zone table for '%s'\n", \
177                                 zone_table, tz2NR[tz], tz >>"/dev/stderr"
178                         status = 1
179                 }
180         }
181         if (0 < want_warnings) {
182                 for (cc in cc2name) {
183                         if (!cc_used[cc]) {
184                                 printf "%s:%d: warning: " \
185                                         "no Zone entries for %s (%s)\n", \
186                                         iso_table, cc2NR[cc], cc, cc2name[cc]
187                         }
188                 }
189         }
190
191         exit status
192 }