lh | 9ed821d | 2023-04-07 01:36:19 -0700 | [diff] [blame] | 1 | # Check tz tables for consistency. |
| 2 | |
| 3 | # Contributed by Paul Eggert. |
| 4 | |
| 5 | BEGIN { |
| 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 | # A special (and we hope temporary) case. |
| 13 | tztab["America/Montreal"] = 1 |
| 14 | |
| 15 | while (getline <iso_table) { |
| 16 | iso_NR++ |
| 17 | if ($0 ~ /^#/) continue |
| 18 | if (NF != 2) { |
| 19 | printf "%s:%d: wrong number of columns\n", \ |
| 20 | iso_table, iso_NR >>"/dev/stderr" |
| 21 | status = 1 |
| 22 | } |
| 23 | cc = $1 |
| 24 | name = $2 |
| 25 | if (cc !~ /^[A-Z][A-Z]$/) { |
| 26 | printf "%s:%d: invalid country code `%s'\n", \ |
| 27 | iso_table, iso_NR, cc >>"/dev/stderr" |
| 28 | status = 1 |
| 29 | } |
| 30 | if (cc <= cc0) { |
| 31 | if (cc == cc0) { |
| 32 | s = "duplicate"; |
| 33 | } else { |
| 34 | s = "out of order"; |
| 35 | } |
| 36 | |
| 37 | printf "%s:%d: country code `%s' is %s\n", \ |
| 38 | iso_table, iso_NR, cc, s \ |
| 39 | >>"/dev/stderr" |
| 40 | status = 1 |
| 41 | } |
| 42 | cc0 = cc |
| 43 | if (name2cc[name]) { |
| 44 | printf "%s:%d: `%s' and `%s' have the sname name\n", \ |
| 45 | iso_table, iso_NR, name2cc[name], cc \ |
| 46 | >>"/dev/stderr" |
| 47 | status = 1 |
| 48 | } |
| 49 | name2cc[name] = cc |
| 50 | cc2name[cc] = name |
| 51 | cc2NR[cc] = iso_NR |
| 52 | } |
| 53 | |
| 54 | zone_table = "zone.tab" |
| 55 | cc0 = "" |
| 56 | |
| 57 | while (getline <zone_table) { |
| 58 | zone_NR++ |
| 59 | if ($0 ~ /^#/) continue |
| 60 | if (NF != 3 && NF != 4) { |
| 61 | printf "%s:%d: wrong number of columns\n", \ |
| 62 | zone_table, zone_NR >>"/dev/stderr" |
| 63 | status = 1 |
| 64 | } |
| 65 | cc = $1 |
| 66 | coordinates = $2 |
| 67 | tz = $3 |
| 68 | comments = $4 |
| 69 | if (cc < cc0) { |
| 70 | printf "%s:%d: country code `%s' is out of order\n", \ |
| 71 | zone_table, zone_NR, cc >>"/dev/stderr" |
| 72 | status = 1 |
| 73 | } |
| 74 | cc0 = cc |
| 75 | cctz = cc tz |
| 76 | cctztab[cctz] = 1 |
| 77 | tztab[tz] = 1 |
| 78 | tz2comments[cctz] = comments |
| 79 | tz2NR[tz] = zone_NR |
| 80 | if (cc2name[cc]) { |
| 81 | cc_used[cc]++ |
| 82 | } else { |
| 83 | printf "%s:%d: %s: unknown country code\n", \ |
| 84 | zone_table, zone_NR, cc >>"/dev/stderr" |
| 85 | status = 1 |
| 86 | } |
| 87 | if (coordinates !~ /^[-+][0-9][0-9][0-5][0-9][-+][01][0-9][0-9][0-5][0-9]$/ \ |
| 88 | && 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]$/) { |
| 89 | printf "%s:%d: %s: invalid coordinates\n", \ |
| 90 | zone_table, zone_NR, coordinates >>"/dev/stderr" |
| 91 | status = 1 |
| 92 | } |
| 93 | } |
| 94 | |
| 95 | for (cctz in cctztab) { |
| 96 | cc = substr (cctz, 1, 2) |
| 97 | tz = substr (cctz, 3) |
| 98 | if (cc_used[cc] == 1) { |
| 99 | if (tz2comments[cctz]) { |
| 100 | printf "%s:%d: unnecessary comment `%s'\n", \ |
| 101 | zone_table, tz2NR[tz], \ |
| 102 | tz2comments[cctz] \ |
| 103 | >>"/dev/stderr" |
| 104 | status = 1 |
| 105 | } |
| 106 | } else { |
| 107 | if (!tz2comments[cctz]) { |
| 108 | printf "%s:%d: missing comment\n", \ |
| 109 | zone_table, tz2NR[tz] >>"/dev/stderr" |
| 110 | status = 1 |
| 111 | } |
| 112 | } |
| 113 | } |
| 114 | |
| 115 | FS = " " |
| 116 | } |
| 117 | |
| 118 | $1 ~ /^#/ { next } |
| 119 | |
| 120 | { |
| 121 | tz = rules = "" |
| 122 | if ($1 == "Zone") { |
| 123 | tz = $2 |
| 124 | ruleUsed[$4] = 1 |
| 125 | } else if ($1 == "Link") { |
| 126 | # Ignore Link commands if source and destination basenames |
| 127 | # are identical, e.g. Europe/Istanbul versus Asia/Istanbul. |
| 128 | src = $2 |
| 129 | dst = $3 |
| 130 | while ((i = index(src, "/"))) src = substr(src, i+1) |
| 131 | while ((i = index(dst, "/"))) dst = substr(dst, i+1) |
| 132 | if (src != dst) tz = $3 |
| 133 | } else if ($1 == "Rule") { |
| 134 | ruleDefined[$2] = 1 |
| 135 | } else { |
| 136 | ruleUsed[$2] = 1 |
| 137 | } |
| 138 | if (tz && tz ~ /\//) { |
| 139 | if (!tztab[tz]) { |
| 140 | printf "%s: no data for `%s'\n", zone_table, tz \ |
| 141 | >>"/dev/stderr" |
| 142 | status = 1 |
| 143 | } |
| 144 | zoneSeen[tz] = 1 |
| 145 | } |
| 146 | } |
| 147 | |
| 148 | END { |
| 149 | for (tz in ruleDefined) { |
| 150 | if (!ruleUsed[tz]) { |
| 151 | printf "%s: Rule never used\n", tz |
| 152 | status = 1 |
| 153 | } |
| 154 | } |
| 155 | for (tz in tz2cc) { |
| 156 | if (!zoneSeen[tz]) { |
| 157 | printf "%s:%d: no Zone table for `%s'\n", \ |
| 158 | zone_table, tz2NR[tz], tz >>"/dev/stderr" |
| 159 | status = 1 |
| 160 | } |
| 161 | } |
| 162 | |
| 163 | if (0 < want_warnings) { |
| 164 | for (cc in cc2name) { |
| 165 | if (!cc_used[cc]) { |
| 166 | printf "%s:%d: warning: " \ |
| 167 | "no Zone entries for %s (%s)\n", \ |
| 168 | iso_table, cc2NR[cc], cc, cc2name[cc] |
| 169 | } |
| 170 | } |
| 171 | } |
| 172 | |
| 173 | exit status |
| 174 | } |