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