xref: /netbsd-src/lib/libc/time/checktab.awk (revision d0fed6c87ddc40a8bffa6f99e7433ddfc864dd83)
1# Check tz tables for consistency.
2
3# Contributed by Paul Eggert <eggert@twinsun.com>.
4
5BEGIN {
6	FS = "\t"
7
8	if (!iso_table) iso_table = "iso3166.tab"
9	if (!zone_table) zone_table = "zone.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			printf "%s:%d: country code `%s' is %s\n", \
29				iso_table, iso_NR, cc, \
30				cc==cc0 ? "duplicate"  : "out of order" \
31				>>"/dev/stderr"
32			status = 1
33		}
34		cc0 = cc
35		if (name2cc[name]) {
36			printf "%s:%d: `%s' and `%s' have the sname name\n", \
37				iso_table, iso_NR, name2cc[name], cc \
38				>>"/dev/stderr"
39			status = 1
40		}
41		name2cc[name] = cc
42		cc2name[cc] = name
43		cc2NR[cc] = iso_NR
44	}
45
46	zone_table = "zone.tab"
47	cc0 = ""
48
49	while (getline <zone_table) {
50		zone_NR++
51		if ($0 ~ /^#/) continue
52		if (NF != 3 && NF != 4) {
53			printf "%s:%d: wrong number of columns\n",
54				zone_table, zone_NR >>"/dev/stderr"
55			status = 1
56		}
57		cc = $1
58		coordinates = $2
59		tz = $3
60		comments = $4
61		if (cc < cc0) {
62			printf "%s:%d: country code `%s' is out of order\n", \
63				zone_table, zone_NR, cc >>"/dev/stderr"
64			status = 1
65		}
66		cc0 = cc
67		if (tz2cc[tz]) {
68			printf "%s:%d: %s: duplicate TZ column\n", \
69				zone_table, zone_NR, tz >>"/dev/stderr"
70			status = 1
71		}
72		tz2cc[tz] = cc
73		tz2comments[tz] = comments
74		tz2NR[tz] = zone_NR
75		if (cc2name[cc]) {
76			cc_used[cc]++
77		} else {
78			printf "%s:%d: %s: unknown country code\n", \
79				zone_table, zone_NR, cc >>"/dev/stderr"
80			status = 1
81		}
82		if (coordinates !~ /^[-+][0-9][0-9][0-5][0-9][-+][01][0-9][0-9][0-5][0-9]$/ \
83		    && 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]$/) {
84			printf "%s:%d: %s: invalid coordinates\n", \
85				zone_table, zone_NR, coordinates >>"/dev/stderr"
86			status = 1
87		}
88	}
89
90	for (tz in tz2cc) {
91		if (cc_used[tz2cc[tz]] == 1) {
92			if (tz2comments[tz]) {
93				printf "%s:%d: unnecessary comment `%s'\n", \
94					zone_table, tz2NR[tz], tz2comments[tz] \
95					>>"/dev/stderr"
96				status = 1
97			}
98		} else {
99			if (!tz2comments[tz]) {
100				printf "%s:%d: missing comment\n", \
101					zone_table, tz2NR[tz] >>"/dev/stderr"
102				status = 1
103			}
104		}
105	}
106
107	FS = " "
108}
109
110{
111	tz = ""
112	if ($1 == "Zone") tz = $2
113	if ($1 == "Link") {
114		# Ignore Link commands if source and destination basenames
115		# are identical, e.g. Europe/Istanbul versus Asia/Istanbul.
116		src = $2
117		dst = $3
118		while ((i = index(src, "/"))) src = substr(src, i+1)
119		while ((i = index(dst, "/"))) dst = substr(dst, i+1)
120		if (src != dst) tz = $3
121	}
122	if (tz && tz ~ /\//) {
123		if (!tz2cc[tz]) {
124			printf "%s: no data for `%s'\n", zone_table, tz \
125				>>"/dev/stderr"
126			status = 1
127		}
128		zoneSeen[tz] = 1
129	}
130}
131
132END {
133	for (tz in tz2cc) {
134		if (!zoneSeen[tz]) {
135			printf "%s:%d: no Zone table for `%s'\n", \
136				zone_table, tz2NR[tz], tz >>"/dev/stderr"
137			status = 1
138		}
139	}
140
141	if (0 < want_warnings) {
142		for (cc in cc2name) {
143			if (!cc_used[cc]) {
144				printf "%s:%d: warning:" \
145					"no Zone entries for %s (%s)\n",
146					iso_table, cc2NR[cc], cc, cc2name[cc]
147			}
148		}
149	}
150
151	exit status
152}
153