xref: /netbsd-src/lib/libc/time/checktab.awk (revision 96fc3e30a7c3f7bba53384bf41dad5f78306fac4)
1#	$NetBSD: checktab.awk,v 1.5 2012/08/09 12:38:25 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 = "zone.tab"
12	if (!want_warnings) want_warnings = -1
13
14	while (getline <iso_table) {
15		iso_NR++
16		if ($0 ~ /^#/) continue
17		if (NF != 2) {
18			printf "%s:%d: wrong number of columns\n", \
19				iso_table, iso_NR >>"/dev/stderr"
20			status = 1
21		}
22		cc = $1
23		name = $2
24		if (cc !~ /^[A-Z][A-Z]$/) {
25			printf "%s:%d: invalid country code `%s'\n", \
26				iso_table, iso_NR, cc >>"/dev/stderr"
27			status = 1
28		}
29		if (cc <= cc0) {
30			if (cc == cc0) {
31				s = "duplicate";
32			} else {
33				s = "out of order";
34			}
35
36			printf "%s:%d: country code `%s' is %s\n", \
37				iso_table, iso_NR, cc, s \
38				>>"/dev/stderr"
39			status = 1
40		}
41		cc0 = cc
42		if (name2cc[name]) {
43			printf "%s:%d: `%s' and `%s' have the sname name\n", \
44				iso_table, iso_NR, name2cc[name], cc \
45				>>"/dev/stderr"
46			status = 1
47		}
48		name2cc[name] = cc
49		cc2name[cc] = name
50		cc2NR[cc] = iso_NR
51	}
52
53	zone_table = "zone.tab"
54	cc0 = ""
55
56	while (getline <zone_table) {
57		zone_NR++
58		if ($0 ~ /^#/) continue
59		if (NF != 3 && NF != 4) {
60			printf "%s:%d: wrong number of columns\n", \
61				zone_table, zone_NR >>"/dev/stderr"
62			status = 1
63		}
64		cc = $1
65		coordinates = $2
66		tz = $3
67		comments = $4
68		if (cc < cc0) {
69			printf "%s:%d: country code `%s' is out of order\n", \
70				zone_table, zone_NR, cc >>"/dev/stderr"
71			status = 1
72		}
73		cc0 = cc
74		if (tz2cc[tz]) {
75			printf "%s:%d: %s: duplicate TZ column\n", \
76				zone_table, zone_NR, tz >>"/dev/stderr"
77			status = 1
78		}
79		tz2cc[tz] = cc
80		tz2comments[tz] = 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 (tz in tz2cc) {
98		if (cc_used[tz2cc[tz]] == 1) {
99			if (tz2comments[tz]) {
100				printf "%s:%d: unnecessary comment `%s'\n", \
101					zone_table, tz2NR[tz], tz2comments[tz] \
102					>>"/dev/stderr"
103				status = 1
104			}
105		} else {
106			if (!tz2comments[tz]) {
107				printf "%s:%d: missing comment\n", \
108					zone_table, tz2NR[tz] >>"/dev/stderr"
109				status = 1
110			}
111		}
112	}
113
114	FS = " "
115}
116
117{
118	tz = ""
119	if ($1 == "Zone") tz = $2
120	if ($1 == "Link") {
121		# Ignore Link commands if source and destination basenames
122		# are identical, e.g. Europe/Istanbul versus Asia/Istanbul.
123		src = $2
124		dst = $3
125		while ((i = index(src, "/"))) src = substr(src, i+1)
126		while ((i = index(dst, "/"))) dst = substr(dst, i+1)
127		if (src != dst) tz = $3
128	}
129	if (tz && tz ~ /\//) {
130		if (!tz2cc[tz]) {
131			printf "%s: no data for `%s'\n", zone_table, tz \
132				>>"/dev/stderr"
133			status = 1
134		}
135		zoneSeen[tz] = 1
136	}
137}
138
139END {
140	for (tz in tz2cc) {
141		if (!zoneSeen[tz]) {
142			printf "%s:%d: no Zone table for `%s'\n", \
143				zone_table, tz2NR[tz], tz >>"/dev/stderr"
144			status = 1
145		}
146	}
147
148	if (0 < want_warnings) {
149		for (cc in cc2name) {
150			if (!cc_used[cc]) {
151				printf "%s:%d: warning: " \
152					"no Zone entries for %s (%s)\n", \
153					iso_table, cc2NR[cc], cc, cc2name[cc]
154			}
155		}
156	}
157
158	exit status
159}
160