1# Check tz tables for consistency. 2 3# Contributed by Paul Eggert. This file is in the public domain. 4 5BEGIN { 6 FS = "\t" 7 8 if (!iso_table) iso_table = "iso3166.tab" 9 if (!zone_table) zone_table = "zone1970.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 if (cc == cc0) { 29 s = "duplicate"; 30 } else { 31 s = "out of order"; 32 } 33 34 printf "%s:%d: country code '%s' is %s\n", \ 35 iso_table, iso_NR, cc, s \ 36 >>"/dev/stderr" 37 status = 1 38 } 39 cc0 = cc 40 if (name2cc[name]) { 41 printf "%s:%d: '%s' and '%s' have the same name\n", \ 42 iso_table, iso_NR, name2cc[name], cc \ 43 >>"/dev/stderr" 44 status = 1 45 } 46 name2cc[name] = cc 47 cc2name[cc] = name 48 cc2NR[cc] = iso_NR 49 } 50 51 cc0 = "" 52 53 while (getline <zone_table) { 54 zone_NR++ 55 if ($0 ~ /^#/) continue 56 if (NF != 3 && NF != 4) { 57 printf "%s:%d: wrong number of columns\n", \ 58 zone_table, zone_NR >>"/dev/stderr" 59 status = 1 60 } 61 ccs = input_ccs[zone_NR] = $1 62 coordinates = $2 63 tz = $3 64 comments = input_comments[zone_NR] = $4 65 split(ccs, cca, /,/) 66 cc = cca[1] 67 68 # Don't complain about a special case for Crimea in zone.tab. 69 # FIXME: zone.tab should be removed, since it is obsolete. 70 # Or at least put just "XX" in its country-code column. 71 if (cc < cc0 \ 72 && !(zone_table == "zone.tab" \ 73 && tz0 == "Europe/Simferopol")) { 74 printf "%s:%d: country code '%s' is out of order\n", \ 75 zone_table, zone_NR, cc >>"/dev/stderr" 76 status = 1 77 } 78 cc0 = cc 79 tz0 = tz 80 tztab[tz] = 1 81 tz2NR[tz] = zone_NR 82 for (i in cca) { 83 cc = cca[i] 84 if (cc2name[cc]) { 85 cc_used[cc]++ 86 } else if (! (cc == "XX" && zone_table == "zonenow.tab")) { 87 printf "%s:%d: %s: unknown country code\n", \ 88 zone_table, zone_NR, cc >>"/dev/stderr" 89 status = 1 90 } 91 } 92 if (coordinates !~ /^[-+][0-9][0-9][0-5][0-9][-+][01][0-9][0-9][0-5][0-9]$/ \ 93 && 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]$/) { 94 printf "%s:%d: %s: invalid coordinates\n", \ 95 zone_table, zone_NR, coordinates >>"/dev/stderr" 96 status = 1 97 } 98 } 99 100 for (i = 1; i <= zone_NR; i++) { 101 ccs = input_ccs[i] 102 if (!ccs) continue 103 comments = input_comments[i] 104 split(ccs, cca, /,/) 105 used_max = 0 106 for (j in cca) { 107 cc = cca[j] 108 if (used_max < cc_used[cc]) { 109 used_max = cc_used[cc] 110 used_max_cc = cc 111 } 112 } 113 if (used_max <= 1 && comments && zone_table != "zonenow.tab") { 114 printf "%s:%d: unnecessary comment '%s'\n", \ 115 zone_table, i, comments \ 116 >>"/dev/stderr" 117 status = 1 118 } else if (1 < used_max && !comments) { 119 printf "%s:%d: missing comment for %s\n", \ 120 zone_table, i, used_max_cc \ 121 >>"/dev/stderr" 122 status = 1 123 } 124 } 125 FS = " " 126} 127 128$1 ~ /^#/ { next } 129 130{ 131 tz = rules = "" 132 if ($1 == "Zone") { 133 tz = $2 134 ruleUsed[$4] = 1 135 if ($5 ~ /%/) rulePercentUsed[$4] = 1 136 } else if ($1 == "Link" && zone_table == "zone.tab") { 137 # Ignore Link commands if source and destination basenames 138 # are identical, e.g. Europe/Istanbul versus Asia/Istanbul. 139 src = $2 140 dst = $3 141 while ((i = index(src, "/"))) src = substr(src, i+1) 142 while ((i = index(dst, "/"))) dst = substr(dst, i+1) 143 if (src != dst) tz = $3 144 } else if ($1 == "Rule") { 145 ruleDefined[$2] = 1 146 if ($10 != "-") ruleLetters[$2] = 1 147 } else { 148 ruleUsed[$2] = 1 149 if ($3 ~ /%/) rulePercentUsed[$2] = 1 150 } 151 if (tz && tz ~ /\// && tz !~ /^Etc\//) { 152 if (!tztab[tz] && FILENAME != "backward" \ 153 && zone_table != "zonenow.tab") { 154 printf "%s: no data for '%s'\n", zone_table, tz \ 155 >>"/dev/stderr" 156 status = 1 157 } 158 zoneSeen[tz] = 1 159 } 160} 161 162END { 163 for (tz in ruleDefined) { 164 if (!ruleUsed[tz]) { 165 printf "%s: Rule never used\n", tz 166 status = 1 167 } 168 } 169 for (tz in ruleLetters) { 170 if (!rulePercentUsed[tz]) { 171 printf "%s: Rule contains letters never used\n", tz 172 status = 1 173 } 174 } 175 for (tz in tztab) { 176 if (!zoneSeen[tz] && tz !~ /^Etc\//) { 177 printf "%s:%d: no Zone table for '%s'\n", \ 178 zone_table, tz2NR[tz], tz >>"/dev/stderr" 179 status = 1 180 } 181 } 182 if (0 < want_warnings) { 183 for (cc in cc2name) { 184 if (!cc_used[cc]) { 185 printf "%s:%d: warning: " \ 186 "no Zone entries for %s (%s)\n", \ 187 iso_table, cc2NR[cc], cc, cc2name[cc] 188 } 189 } 190 } 191 192 exit status 193} 194