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