checktab.awk revision 1.7 1 # $NetBSD: checktab.awk,v 1.7 2014/05/13 16:33:56 christos Exp $
2
3 # Check tz tables for consistency.
4
5 # Contributed by Paul Eggert.
6
7 BEGIN {
8 FS = "\t"
9
10 if (!iso_table) iso_table = "iso3166.tab"
11 if (!zone_table) zone_table = "zone.tab"
12 if (!want_warnings) want_warnings = -1
13
14 # A special (and we hope temporary) case.
15 tztab["America/Montreal"] = 1
16
17 while (getline <iso_table) {
18 iso_NR++
19 if ($0 ~ /^#/) continue
20 if (NF != 2) {
21 printf "%s:%d: wrong number of columns\n", \
22 iso_table, iso_NR >>"/dev/stderr"
23 status = 1
24 }
25 cc = $1
26 name = $2
27 if (cc !~ /^[A-Z][A-Z]$/) {
28 printf "%s:%d: invalid country code `%s'\n", \
29 iso_table, iso_NR, cc >>"/dev/stderr"
30 status = 1
31 }
32 if (cc <= cc0) {
33 if (cc == cc0) {
34 s = "duplicate";
35 } else {
36 s = "out of order";
37 }
38
39 printf "%s:%d: country code `%s' is %s\n", \
40 iso_table, iso_NR, cc, s \
41 >>"/dev/stderr"
42 status = 1
43 }
44 cc0 = cc
45 if (name2cc[name]) {
46 printf "%s:%d: `%s' and `%s' have the sname name\n", \
47 iso_table, iso_NR, name2cc[name], cc \
48 >>"/dev/stderr"
49 status = 1
50 }
51 name2cc[name] = cc
52 cc2name[cc] = name
53 cc2NR[cc] = iso_NR
54 }
55
56 zone_table = "zone.tab"
57 cc0 = ""
58
59 while (getline <zone_table) {
60 zone_NR++
61 if ($0 ~ /^#/) continue
62 if (NF != 3 && NF != 4) {
63 printf "%s:%d: wrong number of columns\n", \
64 zone_table, zone_NR >>"/dev/stderr"
65 status = 1
66 }
67 cc = $1
68 coordinates = $2
69 tz = $3
70 comments = $4
71 if (cc < cc0) {
72 printf "%s:%d: country code `%s' is out of order\n", \
73 zone_table, zone_NR, cc >>"/dev/stderr"
74 status = 1
75 }
76 cc0 = cc
77 cctz = cc tz
78 cctztab[cctz] = 1
79 tztab[tz] = 1
80 tz2comments[cctz] = comments
81 tz2NR[tz] = zone_NR
82 if (cc2name[cc]) {
83 cc_used[cc]++
84 } else {
85 printf "%s:%d: %s: unknown country code\n", \
86 zone_table, zone_NR, cc >>"/dev/stderr"
87 status = 1
88 }
89 if (coordinates !~ /^[-+][0-9][0-9][0-5][0-9][-+][01][0-9][0-9][0-5][0-9]$/ \
90 && 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]$/) {
91 printf "%s:%d: %s: invalid coordinates\n", \
92 zone_table, zone_NR, coordinates >>"/dev/stderr"
93 status = 1
94 }
95 }
96
97 for (cctz in cctztab) {
98 cc = substr (cctz, 1, 2)
99 tz = substr (cctz, 3)
100 if (cc_used[cc] == 1) {
101 if (tz2comments[cctz]) {
102 printf "%s:%d: unnecessary comment `%s'\n", \
103 zone_table, tz2NR[tz], \
104 tz2comments[cctz] \
105 >>"/dev/stderr"
106 status = 1
107 }
108 } else {
109 if (!tz2comments[cctz]) {
110 printf "%s:%d: missing comment\n", \
111 zone_table, tz2NR[tz] >>"/dev/stderr"
112 status = 1
113 }
114 }
115 }
116
117 FS = " "
118 }
119
120 $1 ~ /^#/ { next }
121
122 {
123 tz = rules = ""
124 if ($1 == "Zone") {
125 tz = $2
126 ruleUsed[$4] = 1
127 } else if ($1 == "Link") {
128 # Ignore Link commands if source and destination basenames
129 # are identical, e.g. Europe/Istanbul versus Asia/Istanbul.
130 src = $2
131 dst = $3
132 while ((i = index(src, "/"))) src = substr(src, i+1)
133 while ((i = index(dst, "/"))) dst = substr(dst, i+1)
134 if (src != dst) tz = $3
135 } else if ($1 == "Rule") {
136 ruleDefined[$2] = 1
137 } else {
138 ruleUsed[$2] = 1
139 }
140 if (tz && tz ~ /\//) {
141 if (!tztab[tz]) {
142 printf "%s: no data for `%s'\n", zone_table, tz \
143 >>"/dev/stderr"
144 status = 1
145 }
146 zoneSeen[tz] = 1
147 }
148 }
149
150 END {
151 for (tz in ruleDefined) {
152 if (!ruleUsed[tz]) {
153 printf "%s: Rule never used\n", tz
154 status = 1
155 }
156 }
157 for (tz in tz2cc) {
158 if (!zoneSeen[tz]) {
159 printf "%s:%d: no Zone table for `%s'\n", \
160 zone_table, tz2NR[tz], tz >>"/dev/stderr"
161 status = 1
162 }
163 }
164
165 if (0 < want_warnings) {
166 for (cc in cc2name) {
167 if (!cc_used[cc]) {
168 printf "%s:%d: warning: " \
169 "no Zone entries for %s (%s)\n", \
170 iso_table, cc2NR[cc], cc, cc2name[cc]
171 }
172 }
173 }
174
175 exit status
176 }
177