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