xref: /minix/lib/libc/time/checktab.awk (revision 0a6a1f1d)
1#	$NetBSD: checktab.awk,v 1.8 2014/08/15 11:04:07 christos Exp $
2
3# Check tz tables for consistency.
4
5# Contributed by Paul Eggert.
6
7BEGIN {
8	FS = "\t"
9
10	if (!iso_table) iso_table = "iso3166.tab"
11	if (!zone_table) zone_table = "zone1970.tab"
12	if (!want_warnings) want_warnings = -1
13
14	# A special (and we hope temporary) case.
15	tztab["America/Montreal"] = 1
16
17	# Some more special cases; these are zones that should probably
18	# be turned into links.
19	if (zone_table == "zone1970.tab") {
20	  tztab["Africa/Addis_Ababa"] = 1
21	  tztab["Africa/Asmara"] = 1
22	  tztab["Africa/Bangui"] = 1
23	  tztab["Africa/Blantyre"] = 1
24	  tztab["Africa/Brazzaville"] = 1
25	  tztab["Africa/Bujumbura"] = 1
26	  tztab["Africa/Dar_es_Salaam"] = 1
27	  tztab["Africa/Djibouti"] = 1
28	  tztab["Africa/Douala"] = 1
29	  tztab["Africa/Gaborone"] = 1
30	  tztab["Africa/Harare"] = 1
31	  tztab["Africa/Kampala"] = 1
32	  tztab["Africa/Kigali"] = 1
33	  tztab["Africa/Kinshasa"] = 1
34	  tztab["Africa/Libreville"] = 1
35	  tztab["Africa/Luanda"] = 1
36	  tztab["Africa/Lubumbashi"] = 1
37	  tztab["Africa/Lusaka"] = 1
38	  tztab["Africa/Malabo"] = 1
39	  tztab["Africa/Maseru"] = 1
40	  tztab["Africa/Mbabane"] = 1
41	  tztab["Africa/Mogadishu"] = 1
42	  tztab["Africa/Niamey"] = 1
43	  tztab["Africa/Porto-Novo"] = 1
44	  tztab["America/Antigua"] = 1
45	  tztab["America/Cayman"] = 1
46	  tztab["Asia/Aden"] = 1
47	  tztab["Asia/Bahrain"] = 1
48	  tztab["Asia/Ho_Chi_Minh"] = 1
49	  tztab["Asia/Kuwait"] = 1
50	  tztab["Asia/Muscat"] = 1
51	  tztab["Asia/Phnom_Penh"] = 1
52	  tztab["Asia/Vientiane"] = 1
53	  tztab["Indian/Antananarivo"] = 1
54	  tztab["Indian/Comoro"] = 1
55	  tztab["Indian/Mayotte"] = 1
56	  tztab["Pacific/Midway"] = 1
57	  tztab["Pacific/Saipan"] = 1
58	}
59
60	while (getline <iso_table) {
61		iso_NR++
62		if ($0 ~ /^#/) continue
63		if (NF != 2) {
64			printf "%s:%d: wrong number of columns\n", \
65				iso_table, iso_NR >>"/dev/stderr"
66			status = 1
67		}
68		cc = $1
69		name = $2
70		if (cc !~ /^[A-Z][A-Z]$/) {
71			printf "%s:%d: invalid country code '%s'\n", \
72				iso_table, iso_NR, cc >>"/dev/stderr"
73			status = 1
74		}
75		if (cc <= cc0) {
76			if (cc == cc0) {
77				s = "duplicate";
78			} else {
79				s = "out of order";
80			}
81
82			printf "%s:%d: country code '%s' is %s\n", \
83				iso_table, iso_NR, cc, s \
84				>>"/dev/stderr"
85			status = 1
86		}
87		cc0 = cc
88		if (name2cc[name]) {
89			printf "%s:%d: '%s' and '%s' have the sname name\n", \
90				iso_table, iso_NR, name2cc[name], cc \
91				>>"/dev/stderr"
92			status = 1
93		}
94		name2cc[name] = cc
95		cc2name[cc] = name
96		cc2NR[cc] = iso_NR
97	}
98
99	cc0 = ""
100
101	while (getline <zone_table) {
102		zone_NR++
103		if ($0 ~ /^#/) continue
104		if (NF != 3 && NF != 4) {
105			printf "%s:%d: wrong number of columns\n", \
106				zone_table, zone_NR >>"/dev/stderr"
107			status = 1
108		}
109		split($1, cca, /,/)
110		cc = cca[1]
111		coordinates = $2
112		tz = $3
113		comments = $4
114		if (cc < cc0) {
115			printf "%s:%d: country code '%s' is out of order\n", \
116				zone_table, zone_NR, cc >>"/dev/stderr"
117			status = 1
118		}
119		cc0 = cc
120		tztab[tz] = 1
121		tz2comments[tz] = comments
122		tz2NR[tz] = zone_NR
123		for (i in cca) {
124		    cc = cca[i]
125		    cctz = cc tz
126		    cctztab[cctz] = 1
127		    if (cc2name[cc]) {
128			cc_used[cc]++
129		    } else {
130			printf "%s:%d: %s: unknown country code\n", \
131				zone_table, zone_NR, cc >>"/dev/stderr"
132			status = 1
133		    }
134		}
135		if (coordinates !~ /^[-+][0-9][0-9][0-5][0-9][-+][01][0-9][0-9][0-5][0-9]$/ \
136		    && 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]$/) {
137			printf "%s:%d: %s: invalid coordinates\n", \
138				zone_table, zone_NR, coordinates >>"/dev/stderr"
139			status = 1
140		}
141	}
142
143	for (cctz in cctztab) {
144		cc = substr (cctz, 1, 2)
145		tz = substr (cctz, 3)
146		if (1 < cc_used[cc]) {
147			comments_needed[tz] = cc
148		}
149	}
150	for (cctz in cctztab) {
151	  cc = substr (cctz, 1, 2)
152	  tz = substr (cctz, 3)
153	  if (!comments_needed[tz] && tz2comments[tz]) {
154	    printf "%s:%d: unnecessary comment '%s'\n", \
155		zone_table, tz2NR[tz], tz2comments[tz] \
156		>>"/dev/stderr"
157	    tz2comments[tz] = 0
158	    status = 1
159	  } else if (comments_needed[tz] && !tz2comments[tz]) {
160	    printf "%s:%d: missing comment for %s\n", \
161	      zone_table, tz2NR[tz], comments_needed[tz] \
162	      >>"/dev/stderr"
163	    status = 1
164	  }
165	}
166	FS = " "
167}
168
169$1 ~ /^#/ { next }
170
171{
172	tz = rules = ""
173	if ($1 == "Zone") {
174		tz = $2
175		ruleUsed[$4] = 1
176	} else if ($1 == "Link" && zone_table == "zone.tab") {
177		# Ignore Link commands if source and destination basenames
178		# are identical, e.g. Europe/Istanbul versus Asia/Istanbul.
179		src = $2
180		dst = $3
181		while ((i = index(src, "/"))) src = substr(src, i+1)
182		while ((i = index(dst, "/"))) dst = substr(dst, i+1)
183		if (src != dst) tz = $3
184	} else if ($1 == "Rule") {
185		ruleDefined[$2] = 1
186	} else {
187		ruleUsed[$2] = 1
188	}
189	if (tz && tz ~ /\//) {
190		if (!tztab[tz]) {
191			printf "%s: no data for '%s'\n", zone_table, tz \
192				>>"/dev/stderr"
193			status = 1
194		}
195		zoneSeen[tz] = 1
196	}
197}
198
199END {
200	for (tz in ruleDefined) {
201		if (!ruleUsed[tz]) {
202			printf "%s: Rule never used\n", tz
203			status = 1
204		}
205	}
206	for (tz in tztab) {
207		if (!zoneSeen[tz]) {
208			printf "%s:%d: no Zone table for '%s'\n", \
209				zone_table, tz2NR[tz], tz >>"/dev/stderr"
210			status = 1
211		}
212	}
213	if (0 < want_warnings) {
214		for (cc in cc2name) {
215			if (!cc_used[cc]) {
216				printf "%s:%d: warning: " \
217					"no Zone entries for %s (%s)\n", \
218					iso_table, cc2NR[cc], cc, cc2name[cc]
219			}
220		}
221	}
222
223	exit status
224}
225