]>
Commit | Line | Data |
---|---|---|
d0045e79 UD |
1 | #! /bin/ksh |
2 | # Ask the user about the time zone, and output the resulting TZ value to stdout. | |
3 | # Interact with the user via stderr and stdin. | |
4 | ||
5 | # Contributed by Paul Eggert <eggert@twinsun.com>. | |
6 | ||
7 | # Porting notes: | |
8 | # | |
9 | # This script requires several features of the Korn shell. | |
10 | # If your host lacks the Korn shell, | |
11 | # you can use either of the following free programs instead: | |
12 | # | |
13 | # Bourne-Again shell (bash) | |
14 | # <URL:ftp://prep.ai.mit.edu:/pub/gnu/bash-1.14.7.tar.gz> | |
15 | # (or any later version) | |
16 | # | |
17 | # Public domain ksh | |
18 | # <URL:ftp://ftp.cs.mun.ca:/pub/pdksh/pdksh.tar.gz> | |
19 | # | |
20 | # This script also uses several features of modern awk programs. | |
21 | # If your host lacks awk, or has an old awk that does not conform to Posix.2, | |
22 | # you can use either of the following free programs instead: | |
23 | # | |
24 | # GNU awk (gawk) | |
25 | # <URL:ftp://prep.ai.mit.edu:/pub/gnu/gawk-3.0.0.tar.gz> | |
26 | # (or any later version) | |
27 | # | |
28 | # mawk | |
29 | # <URL:ftp://oxy.edu/public/mawk1.2.2.tar.gz> | |
30 | # (or any later version) | |
31 | ||
32 | ||
33 | # Specify default values for environment variables if they are unset. | |
34 | : ${AWK=awk} | |
35 | : ${TZDIR=$(pwd)} | |
36 | ||
37 | # Check for awk Posix compliance. | |
38 | ($AWK -v x=y 'BEGIN { exit 123 }') </dev/null >/dev/null 2>&1 | |
39 | [ $? = 123 ] || { | |
40 | echo >&2 "$0: Sorry, your \`$AWK' program is not Posix compatible." | |
41 | exit 1 | |
42 | } | |
43 | ||
44 | # Make sure the tables are readable. | |
45 | TZ_COUNTRY_TABLE=$TZDIR/iso3166.tab | |
46 | TZ_ZONE_TABLE=$TZDIR/zone.tab | |
47 | for f in $TZ_COUNTRY_TABLE $TZ_ZONE_TABLE | |
48 | do | |
49 | <$f || { | |
50 | echo >&2 "$0: time zone files are not set up correctly" | |
51 | exit 1 | |
52 | } | |
53 | done | |
54 | ||
55 | newline=' | |
56 | ' | |
57 | IFS=$newline | |
58 | ||
59 | ||
60 | # Work around a bash bug, where $PS3 is sent to stdout. | |
61 | case $(echo 1 | (select x in x; do break; done) 2>/dev/null) in | |
62 | ?*) PS3= | |
63 | esac | |
64 | ||
65 | ||
66 | # Begin the main loop. We come back here if the user wants to retry. | |
67 | while | |
68 | ||
69 | echo >&2 'Please identify a location' \ | |
70 | 'so that time zone rules can be set correctly.' | |
71 | ||
72 | continent= | |
73 | country= | |
74 | region= | |
75 | ||
76 | ||
77 | # Ask the user for continent or ocean. | |
78 | ||
79 | echo >&2 'Please select a continent or ocean.' | |
80 | ||
81 | select continent in \ | |
82 | Africa \ | |
83 | Americas \ | |
84 | Antarctica \ | |
85 | 'Arctic Ocean' \ | |
86 | Asia \ | |
87 | 'Atlantic Ocean' \ | |
88 | Australia \ | |
89 | Europe \ | |
90 | 'Indian Ocean' \ | |
91 | 'Pacific Ocean' \ | |
92 | 'none - I want to specify the time zone using the Posix TZ format.' | |
93 | do | |
94 | case $continent in | |
95 | '') | |
96 | echo >&2 'Please enter a number in range.';; | |
97 | ?*) | |
98 | case $continent in | |
99 | Americas) continent=America;; | |
100 | *' '*) continent=$(expr "$continent" : '\([^ ]*\)') | |
101 | esac | |
102 | break | |
103 | esac | |
104 | done | |
105 | case $continent in | |
106 | '') | |
107 | exit 1;; | |
108 | none) | |
109 | # Ask the user for a Posix TZ string. Check that it conforms. | |
110 | while | |
111 | echo >&2 'Please enter the desired value' \ | |
112 | 'of the TZ environment variable.' | |
113 | echo >&2 'For example, GST-10 is a zone named GST' \ | |
114 | 'that is 10 hours ahead (east) of UTC.' | |
115 | read TZ | |
116 | $AWK -v TZ="$TZ" 'BEGIN { | |
117 | tzname = "[^-+,0-9][^-+,0-9][^-+,0-9]+" | |
118 | time = "[0-2]?[0-9](:[0-5][0-9](:[0-5][0-9])?)?" | |
119 | offset = "[-+]?" time | |
120 | date = "(J?[0-9]+|M[0-9]+\.[0-9]+\.[0-9]+)" | |
121 | datetime = "," date "(/" time ")?" | |
122 | tzpattern = "^(:.*|" tzname offset "(" tzname \ | |
123 | "(" offset ")?(" datetime datetime ")?)?)$" | |
124 | if (TZ ~ tzpattern) exit 1 | |
125 | exit 0 | |
126 | }' | |
127 | do | |
128 | echo >&2 "\`$TZ' is not a conforming" \ | |
129 | 'Posix time zone string.' | |
130 | done | |
131 | TZ_for_date=$TZ;; | |
132 | *) | |
133 | # Get list of names of countries in the continent or ocean. | |
134 | countries=$($AWK -F'\t' \ | |
135 | -v continent="$continent" \ | |
136 | -v TZ_COUNTRY_TABLE="$TZ_COUNTRY_TABLE" \ | |
137 | ' | |
138 | /^#/ { next } | |
139 | $3 ~ ("^" continent "/") { | |
140 | if (!cc_seen[$1]++) cc_list[++ccs] = $1 | |
141 | } | |
142 | END { | |
143 | while (getline <TZ_COUNTRY_TABLE) { | |
144 | if ($0 !~ /^#/) cc_name[$1] = $2 | |
145 | } | |
146 | for (i = 1; i <= ccs; i++) { | |
147 | country = cc_list[i] | |
148 | if (cc_name[country]) { | |
149 | country = cc_name[country] | |
150 | } | |
151 | print country | |
152 | } | |
153 | } | |
154 | ' <$TZ_ZONE_TABLE | sort -f) | |
155 | ||
156 | ||
157 | # If there's more than one country, ask the user which one. | |
158 | case $countries in | |
159 | *"$newline"*) | |
160 | echo >&2 'Please select a country.' | |
161 | select country in $countries | |
162 | do | |
163 | case $country in | |
164 | '') echo >&2 'Please enter a number in range.';; | |
165 | ?*) break | |
166 | esac | |
167 | done | |
168 | ||
169 | case $country in | |
170 | '') exit 1 | |
171 | esac;; | |
172 | *) | |
173 | country=$countries | |
174 | esac | |
175 | ||
176 | ||
177 | # Get list of names of time zone rule regions in the country. | |
178 | regions=$($AWK -F'\t' \ | |
179 | -v country="$country" \ | |
180 | -v TZ_COUNTRY_TABLE="$TZ_COUNTRY_TABLE" \ | |
181 | ' | |
182 | BEGIN { | |
183 | cc = country | |
184 | while (getline <TZ_COUNTRY_TABLE) { | |
185 | if ($0 !~ /^#/ && country == $2) { | |
186 | cc = $1 | |
187 | break | |
188 | } | |
189 | } | |
190 | } | |
191 | $1 == cc { print $4 } | |
192 | ' <$TZ_ZONE_TABLE) | |
193 | ||
194 | ||
195 | # If there's more than one region, ask the user which one. | |
196 | case $regions in | |
197 | *"$newline"*) | |
198 | echo >&2 'Please select one of the following' \ | |
199 | 'time zone regions.' | |
200 | select region in $regions | |
201 | do | |
202 | case $region in | |
203 | '') echo >&2 'Please enter a number in range.';; | |
204 | ?*) break | |
205 | esac | |
206 | done | |
207 | case $region in | |
208 | '') exit 1 | |
209 | esac;; | |
210 | *) | |
211 | region=$regions | |
212 | esac | |
213 | ||
214 | # Determine TZ from country and region. | |
215 | TZ=$($AWK -F'\t' \ | |
216 | -v country="$country" \ | |
217 | -v region="$region" \ | |
218 | -v TZ_COUNTRY_TABLE="$TZ_COUNTRY_TABLE" \ | |
219 | ' | |
220 | BEGIN { | |
221 | cc = country | |
222 | while (getline <TZ_COUNTRY_TABLE) { | |
223 | if ($0 !~ /^#/ && country == $2) { | |
224 | cc = $1 | |
225 | break | |
226 | } | |
227 | } | |
228 | } | |
229 | $1 == cc && $4 == region { print $3 } | |
230 | ' <$TZ_ZONE_TABLE) | |
231 | ||
232 | # Make sure the corresponding zoneinfo file exists. | |
233 | TZ_for_date=$TZDIR/$TZ | |
234 | <$TZ_for_date || { | |
235 | echo >&2 "$0: time zone files are not set up correctly" | |
236 | exit 1 | |
237 | } | |
238 | esac | |
239 | ||
240 | ||
241 | # Use the proposed TZ to output the current date relative to UTC. | |
242 | # Loop until they agree in seconds. | |
243 | # Give up after 8 unsuccessful tries. | |
244 | ||
245 | extra_info= | |
246 | for i in 1 2 3 4 5 6 7 8 | |
247 | do | |
248 | TZdate=$(LANG=C TZ="$TZ_for_date" date) | |
249 | UTdate=$(LANG=C TZ=UTC0 date) | |
250 | TZsec=$(expr "$TZdate" : '.*:\([0-5][0-9]\)') | |
251 | UTsec=$(expr "$UTdate" : '.*:\([0-5][0-9]\)') | |
252 | case $TZsec in | |
253 | $UTsec) | |
254 | extra_info=" | |
255 | Local time is now: $TZdate. | |
256 | Universal Time is now: $UTdate." | |
257 | break | |
258 | esac | |
259 | done | |
260 | ||
261 | ||
262 | # Output TZ info and ask the user to confirm. | |
263 | ||
264 | echo >&2 "" | |
265 | echo >&2 "The following information has been given:" | |
266 | echo >&2 "" | |
267 | case $country+$region in | |
268 | ?*+?*) echo >&2 " $country$newline $region";; | |
269 | ?*+) echo >&2 " $country";; | |
270 | +) echo >&2 " TZ='$TZ'" | |
271 | esac | |
272 | echo >&2 "" | |
273 | echo >&2 "Therefore TZ='$TZ' will be used.$extra_info" | |
274 | echo >&2 "Is the above information OK?" | |
275 | ||
276 | ok= | |
277 | select ok in Yes No | |
278 | do | |
279 | case $ok in | |
280 | '') echo >&2 'Please enter 1 for Yes, or 2 for No.';; | |
281 | ?*) break | |
282 | esac | |
283 | done | |
284 | case $ok in | |
285 | '') exit 1;; | |
286 | Yes) break | |
287 | esac | |
288 | do : | |
289 | done | |
290 | ||
291 | # Output the answer. | |
292 | echo "$TZ" |