8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / zic / tzselect.ksh
blob24ba630295fac05d51e171181afb948eaf5739b0
1 #! /usr/bin/ksh
3 # Copyright 2005 Sun Microsystems, Inc. All rights reserved.
4 # Use is subject to license terms.
6 # ident "%Z%%M% %I% %E% SMI"
8 # '@(#)tzselect.ksh 1.8'
10 # Ask the user about the time zone, and output the resulting TZ value to stdout.
11 # Interact with the user via stderr and stdin.
13 # Contributed by Paul Eggert
15 # Porting notes:
17 # This script requires several features of the Korn shell.
18 # If your host lacks the Korn shell,
19 # you can use either of the following free programs instead:
21 # <a href=ftp://ftp.gnu.org/pub/gnu/>
22 # Bourne-Again shell (bash)
23 # </a>
25 # <a href=ftp://ftp.cs.mun.ca/pub/pdksh/pdksh.tar.gz>
26 # Public domain ksh
27 # </a>
29 # This script also uses several features of modern awk programs.
30 # If your host lacks awk, or has an old awk that does not conform to POSIX.2,
31 # you can use either of the following free programs instead:
33 # <a href=ftp://ftp.gnu.org/pub/gnu/>
34 # GNU awk (gawk)
35 # </a>
37 # <a href=ftp://ftp.whidbey.net/pub/brennan/>
38 # mawk
39 # </a>
41 AWK=/usr/bin/nawk
42 GREP=/usr/bin/grep
43 EXPR=/usr/bin/expr
44 LOCALE=/usr/bin/locale
45 SORT=/usr/bin/sort
46 PRINTF=/usr/bin/printf
47 DATE=/usr/bin/date
48 GETTEXT=/usr/bin/gettext
50 TZDIR=/usr/share/lib/zoneinfo
52 # Messages
53 ERR_NO_SETUP="%s: time zone files are not set up correctly"
54 INFO_LOCATION="Please identify a location so that time zone rules \
55 can be set correctly."
56 INFO_SELECT_CONT="Please select a continent or ocean."
57 INFO_POSIX="none - I want to specify the time zone using the POSIX \
58 TZ format."
59 WARN_ENTER_NUM="Please enter a number in range."
60 INFO_ENTER_POSIX="Please enter the desired value of the TZ environment \
61 variable."
62 INFO_POSIX_EX="For example, GST-10 is a zone named GST that is 10 hours \
63 ahead (east) of UTC."
64 ERR_INV_POSIX="\`%s\' is not a conforming POSIX time zone string."
65 INFO_SELECT_CNTRY="Please select a country or region."
66 INFO_SELECT_TZ="Please select one of the following time zone regions."
67 INFO_EXTRA1="Local time is now: %s"
68 INFO_EXTRA2="Universal Time is now: %s"
69 INFO_INFO="The following information has been given:"
70 INFO_TZ="Therefore TZ='%s' will be used."
71 INFO_OK="Is the above information OK?"
72 INFO_YES="Yes"
73 INFO_NO="No"
74 WARN_ENTER_YORN="Please enter 1 for Yes, or 2 for No."
75 INFO_FINE="Here is the TZ value again, this time on standard output:"
77 # I18n support
78 TEXTDOMAINDIR=/usr/lib/locale; export TEXTDOMAINDIR
79 TEXTDOMAIN=SUNW_OST_OSCMD; export TEXTDOMAIN
80 DOMAIN2=SUNW_OST_ZONEINFO
82 # Make sure the tables are readable.
83 TZ_COUNTRY_TABLE=$TZDIR/tab/country.tab
84 TZ_ZONE_TABLE=$TZDIR/tab/zone_sun.tab
85 for f in $TZ_COUNTRY_TABLE $TZ_ZONE_TABLE
87 <$f || {
88 $PRINTF >&2 "`$GETTEXT "$ERR_NO_SETUP"`\n" $0
89 exit 1
91 done
93 newline='
95 IFS=$newline
97 # For C locale, don't need to call gettext(1)
98 loc_messages=`$LOCALE | $GREP LC_MESSAGES | $AWK -F"=" '{print $2}`
99 if [ "$loc_messages" = "\"C\"" -o "$loc_messages" = "C" ]; then
100 is_C=1
101 else
102 is_C=0
105 iafrica=`$GETTEXT $DOMAIN2 Africa`
106 iamerica=`$GETTEXT $DOMAIN2 Americas`
107 iantarctica=`$GETTEXT $DOMAIN2 Antarctica`
108 iarcticocean=`$GETTEXT $DOMAIN2 "Arctic Ocean"`
109 iasia=`$GETTEXT $DOMAIN2 Asia`
110 iatlanticocean=`$GETTEXT $DOMAIN2 "Atlantic Ocean"`
111 iaustralia=`$GETTEXT $DOMAIN2 Australia`
112 ieurope=`$GETTEXT $DOMAIN2 Europe`
113 ipacificocean=`$GETTEXT $DOMAIN2 "Pacific Ocean"`
114 iindianocean=`$GETTEXT $DOMAIN2 "Indian Ocean"`
115 none=`$GETTEXT "$INFO_POSIX"`
117 # Begin the main loop. We come back here if the user wants to retry.
118 while
119 $PRINTF >&2 "`$GETTEXT "$INFO_LOCATION"`\n"
121 continent=
122 country=
123 region=
125 # Ask the user for continent or ocean.
126 $PRINTF >&2 "`$GETTEXT "$INFO_SELECT_CONT"`\n"
128 select continent in \
129 $iafrica \
130 $iamerica \
131 $iantarctica \
132 $iarcticocean \
133 $iasia \
134 $iatlanticocean \
135 $iaustralia \
136 $ieurope \
137 $iindianocean \
138 $ipacificocean \
139 $none
142 case $continent in
144 $PRINTF >&2 "`$GETTEXT "$WARN_ENTER_NUM"`\n";;
147 case $continent in
148 $iafrica) continent=Africa;;
149 $iamerica) continent=America;;
150 $iantarctica) continent=Antarctica;;
151 $iarcticocean) continent=Arctic;;
152 $iasia) continent=Asia;;
153 $iatlanticocean) continent=Atlantic;;
154 $iaustralia) continent=Australia;;
155 $ieurope) continent=Europe;;
156 $iindianocean) continent=Indian;;
157 $ipacificocean) continent=Pacific;;
158 $none) continent=none;;
159 esac
160 break
161 esac
162 done
163 case $continent in
165 exit 1;;
166 none)
167 # Ask the user for a POSIX TZ string. Check that it conforms.
168 while
169 $PRINTF >&2 "`$GETTEXT "$INFO_ENTER_POSIX"`\n"
170 $PRINTF >&2 "`$GETTEXT "$INFO_POSIX_EX"`\n"
172 read TZ
173 env LC_ALL=C $AWK -v TZ="$TZ" 'BEGIN {
174 tzname = "[^-+,0-9][^-+,0-9][^-+,0-9]+"
175 time = "[0-2]?[0-9](:[0-5][0-9](:[0-5][0-9])?)?"
176 offset = "[-+]?" time
177 date = "(J?[0-9]+|M[0-9]+\.[0-9]+\.[0-9]+)"
178 datetime = "," date "(/" time ")?"
179 tzpattern = "^(:.*|" tzname offset "(" tzname \
180 "(" offset ")?(" datetime datetime ")?)?)$"
181 if (TZ ~ tzpattern) exit 1
182 exit 0
185 $PRINTF >&2 "`$GETTEXT "$ERR_INV_POSIX"`\n" $TZ
187 done
188 TZ_for_date=$TZ;;
190 # Get list of names of countries in the continent or ocean.
191 countries=$($AWK -F'\t' \
192 -v continent="$continent" \
193 -v TZ_COUNTRY_TABLE="$TZ_COUNTRY_TABLE" \
195 /^#/ { next }
196 $3 ~ ("^" continent "/") {
197 if (!cc_seen[$1]++) cc_list[++ccs] = $1
199 END {
200 while (getline <TZ_COUNTRY_TABLE) {
201 if ($0 !~ /^#/) cc_name[$1] = $2
203 for (i = 1; i <= ccs; i++) {
204 country = cc_list[i]
205 if (cc_name[country]) {
206 country = cc_name[country]
208 print country
211 ' <$TZ_ZONE_TABLE | $SORT -f)
213 # i18n country names
215 set -A icountry
216 for country in $countries
218 if [ $is_C -eq 1 ]; then
219 icountry[c]=$country
220 else
221 icountry[c]=`${GETTEXT} ${DOMAIN2} $country`
223 ocountry[c]="$country"
224 c=$(( $c + 1 ))
225 done
226 maxnum=$c
228 # If there's more than one country, ask the user which one.
229 case $countries in
230 *"$newline"*)
231 $PRINTF >&2 "`$GETTEXT "$INFO_SELECT_CNTRY"`\n"
232 select xcountry in ${icountry[*]}
234 case $xcountry in
236 $PRINTF >&2 "`$GETTEXT "$WARN_ENTER_NUM"`\n"
238 ?*) c=0
239 while true; do
240 if [ "$xcountry" = "${icountry[$c]}" ];
241 then
242 country="${ocountry[$c]}"
243 break
245 if [ $c -lt $maxnum ]; then
246 c=$(( $c + 1 ))
247 else
248 break
250 done
251 break
252 esac
253 done
255 case $xcountry in
256 '') exit 1
257 esac;;
259 country=$countries
260 xcountry=$countries
261 esac
264 # Get list of names of time zone rule regions in the country.
265 regions=$($AWK -F'\t' \
266 -v country="$country" \
267 -v TZ_COUNTRY_TABLE="$TZ_COUNTRY_TABLE" \
269 BEGIN {
270 cc = country
271 while (getline <TZ_COUNTRY_TABLE) {
272 if ($0 !~ /^#/ && country == $2) {
273 cc = $1
274 break
278 $1 == cc { print $5 }
279 ' <$TZ_ZONE_TABLE)
281 # I18n region names
283 set -A iregion
284 for region in $regions
286 if [ $is_C -eq 1 ]; then
287 iregion[c]=$region
288 else
289 iregion[c]=`${GETTEXT} ${DOMAIN2} $region`
291 oregion[c]="$region"
292 c=$(( $c + 1 ))
293 done
294 maxnum=$c
296 # If there's more than one region, ask the user which one.
297 case $regions in
298 *"$newline"*)
299 $PRINTF >&2 "`$GETTEXT "$INFO_SELECT_TZ"`\n"
301 select xregion in ${iregion[*]}
303 case $xregion in
304 '')
305 $PRINTF >&2 "`$GETTEXT "$WARN_ENTER_NUM"`\n"
307 ?*) c=0
308 while true; do
309 if [ "$xregion" = "${iregion[$c]}" ];
310 then
311 region="${oregion[$c]}"
312 break
314 if [ $c -lt $maxnum ]; then
315 c=$(( $c + 1 ))
316 else
317 break
319 done
320 break
321 esac
322 done
324 case $region in
325 '') exit 1
326 esac;;
328 region=$regions
329 xregion=$regions
330 esac
332 # Determine TZ from country and region.
333 TZ=$($AWK -F'\t' \
334 -v country="$country" \
335 -v region="$region" \
336 -v TZ_COUNTRY_TABLE="$TZ_COUNTRY_TABLE" \
338 BEGIN {
339 cc = country
340 while (getline <TZ_COUNTRY_TABLE) {
341 if ($0 !~ /^#/ && country == $2) {
342 cc = $1
343 break
348 $1 == cc && $5 == region {
349 # Check if tzname mapped to
350 # backward compatible tzname
351 if ($4 == "-") {
352 print $3
353 } else {
354 print $4
357 ' <$TZ_ZONE_TABLE)
359 # Make sure the corresponding zoneinfo file exists.
360 TZ_for_date=$TZDIR/$TZ
361 <$TZ_for_date || {
362 $PRINTF >&2 "`$GETTEXT "$ERR_NO_SETUP"`\n" $0
363 exit 1
365 # Absolute path TZ's not supported
366 TZ_for_date=$TZ
367 esac
370 # Use the proposed TZ to output the current date relative to UTC.
371 # Loop until they agree in seconds.
372 # Give up after 8 unsuccessful tries.
374 extra_info1=
375 extra_info2=
376 for i in 1 2 3 4 5 6 7 8
378 TZdate=$(LANG=C TZ="$TZ_for_date" $DATE)
379 UTdate=$(LANG=C TZ=UTC0 $DATE)
380 TZsec=$($EXPR "$TZdate" : '.*:\([0-5][0-9]\)')
381 UTsec=$($EXPR "$UTdate" : '.*:\([0-5][0-9]\)')
382 case $TZsec in
383 $UTsec)
384 extra_info1=$($PRINTF "`$GETTEXT "$INFO_EXTRA1"`" \
385 "$TZdate")
386 extra_info2=$($PRINTF "`$GETTEXT "$INFO_EXTRA2"`" \
387 "$UTdate")
388 break
389 esac
390 done
393 # Output TZ info and ask the user to confirm.
395 $PRINTF >&2 "\n"
396 $PRINTF >&2 "`$GETTEXT "$INFO_INFO"`\n"
397 $PRINTF >&2 "\n"
399 case $country+$region in
400 ?*+?*) $PRINTF >&2 " $xcountry$newline $xregion\n";;
401 ?*+) $PRINTF >&2 " $xcountry\n";;
402 +) $PRINTF >&2 " TZ='$TZ'\n"
403 esac
404 $PRINTF >&2 "\n"
405 $PRINTF >&2 "`$GETTEXT "$INFO_TZ"`\n" "$TZ"
406 $PRINTF >&2 "$extra_info1\n"
407 $PRINTF >&2 "$extra_info2\n"
408 $PRINTF >&2 "`$GETTEXT "$INFO_OK"`\n"
411 # select ok in Yes No
412 Yes="`$GETTEXT "$INFO_YES"`"
413 No="`$GETTEXT "$INFO_NO"`"
414 select ok in $Yes $No
416 case $ok in
417 '')
418 $PRINTF >&2 "`$GETTEXT "$WARN_ENTER_YORN"`\n"
420 ?*) break
421 esac
422 done
423 case $ok in
424 '') exit 1;;
425 $Yes) break
426 esac
427 do :
428 done
430 $PRINTF >&2 "`$GETTEXT "$INFO_FINE"`\n"
432 $PRINTF "%s\n" "$TZ"