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