checktab.awk 4.4 KB

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