update from main archive 970118
[kopensolaris-gnu/glibc.git] / time / tzselect.ksh
1 #! @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-2.0.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.2.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=@TZDIR@}
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"