#! /usr/bin/ksh # # Copyright 2005 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" # # '@(#)tzselect.ksh 1.8' # Ask the user about the time zone, and output the resulting TZ value to stdout. # Interact with the user via stderr and stdin. # Contributed by Paul Eggert # Porting notes: # # This script requires several features of the Korn shell. # If your host lacks the Korn shell, # you can use either of the following free programs instead: # # # Bourne-Again shell (bash) # # # # Public domain ksh # # # This script also uses several features of modern awk programs. # If your host lacks awk, or has an old awk that does not conform to POSIX.2, # you can use either of the following free programs instead: # # # GNU awk (gawk) # # # # mawk # AWK=/usr/bin/nawk GREP=/usr/bin/grep EXPR=/usr/bin/expr LOCALE=/usr/bin/locale SORT=/usr/bin/sort PRINTF=/usr/bin/printf DATE=/usr/bin/date GETTEXT=/usr/bin/gettext TZDIR=/usr/share/lib/zoneinfo # Messages ERR_NO_SETUP="%s: time zone files are not set up correctly" INFO_LOCATION="Please identify a location so that time zone rules \ can be set correctly." INFO_SELECT_CONT="Please select a continent or ocean." INFO_POSIX="none - I want to specify the time zone using the POSIX \ TZ format." WARN_ENTER_NUM="Please enter a number in range." INFO_ENTER_POSIX="Please enter the desired value of the TZ environment \ variable." INFO_POSIX_EX="For example, GST-10 is a zone named GST that is 10 hours \ ahead (east) of UTC." ERR_INV_POSIX="\`%s\' is not a conforming POSIX time zone string." INFO_SELECT_CNTRY="Please select a country or region." INFO_SELECT_TZ="Please select one of the following time zone regions." INFO_EXTRA1="Local time is now: %s" INFO_EXTRA2="Universal Time is now: %s" INFO_INFO="The following information has been given:" INFO_TZ="Therefore TZ='%s' will be used." INFO_OK="Is the above information OK?" INFO_YES="Yes" INFO_NO="No" WARN_ENTER_YORN="Please enter 1 for Yes, or 2 for No." INFO_FINE="Here is the TZ value again, this time on standard output:" # I18n support TEXTDOMAINDIR=/usr/lib/locale; export TEXTDOMAINDIR TEXTDOMAIN=SUNW_OST_OSCMD; export TEXTDOMAIN DOMAIN2=SUNW_OST_ZONEINFO # Make sure the tables are readable. TZ_COUNTRY_TABLE=$TZDIR/tab/country.tab TZ_ZONE_TABLE=$TZDIR/tab/zone_sun.tab for f in $TZ_COUNTRY_TABLE $TZ_ZONE_TABLE do <$f || { $PRINTF >&2 "`$GETTEXT "$ERR_NO_SETUP"`\n" $0 exit 1 } done newline=' ' IFS=$newline # For C locale, don't need to call gettext(1) loc_messages=`$LOCALE | $GREP LC_MESSAGES | $AWK -F"=" '{print $2}` if [ "$loc_messages" = "\"C\"" -o "$loc_messages" = "C" ]; then is_C=1 else is_C=0 fi iafrica=`$GETTEXT $DOMAIN2 Africa` iamerica=`$GETTEXT $DOMAIN2 Americas` iantarctica=`$GETTEXT $DOMAIN2 Antarctica` iarcticocean=`$GETTEXT $DOMAIN2 "Arctic Ocean"` iasia=`$GETTEXT $DOMAIN2 Asia` iatlanticocean=`$GETTEXT $DOMAIN2 "Atlantic Ocean"` iaustralia=`$GETTEXT $DOMAIN2 Australia` ieurope=`$GETTEXT $DOMAIN2 Europe` ipacificocean=`$GETTEXT $DOMAIN2 "Pacific Ocean"` iindianocean=`$GETTEXT $DOMAIN2 "Indian Ocean"` none=`$GETTEXT "$INFO_POSIX"` # Begin the main loop. We come back here if the user wants to retry. while $PRINTF >&2 "`$GETTEXT "$INFO_LOCATION"`\n" continent= country= region= # Ask the user for continent or ocean. $PRINTF >&2 "`$GETTEXT "$INFO_SELECT_CONT"`\n" select continent in \ $iafrica \ $iamerica \ $iantarctica \ $iarcticocean \ $iasia \ $iatlanticocean \ $iaustralia \ $ieurope \ $iindianocean \ $ipacificocean \ $none do case $continent in '') $PRINTF >&2 "`$GETTEXT "$WARN_ENTER_NUM"`\n";; ?*) case $continent in $iafrica) continent=Africa;; $iamerica) continent=America;; $iantarctica) continent=Antarctica;; $iarcticocean) continent=Arctic;; $iasia) continent=Asia;; $iatlanticocean) continent=Atlantic;; $iaustralia) continent=Australia;; $ieurope) continent=Europe;; $iindianocean) continent=Indian;; $ipacificocean) continent=Pacific;; $none) continent=none;; esac break esac done case $continent in '') exit 1;; none) # Ask the user for a POSIX TZ string. Check that it conforms. while $PRINTF >&2 "`$GETTEXT "$INFO_ENTER_POSIX"`\n" $PRINTF >&2 "`$GETTEXT "$INFO_POSIX_EX"`\n" read TZ env LC_ALL=C $AWK -v TZ="$TZ" 'BEGIN { tzname = "[^-+,0-9][^-+,0-9][^-+,0-9]+" time = "[0-2]?[0-9](:[0-5][0-9](:[0-5][0-9])?)?" offset = "[-+]?" time date = "(J?[0-9]+|M[0-9]+\.[0-9]+\.[0-9]+)" datetime = "," date "(/" time ")?" tzpattern = "^(:.*|" tzname offset "(" tzname \ "(" offset ")?(" datetime datetime ")?)?)$" if (TZ ~ tzpattern) exit 1 exit 0 }' do $PRINTF >&2 "`$GETTEXT "$ERR_INV_POSIX"`\n" $TZ done TZ_for_date=$TZ;; *) # Get list of names of countries in the continent or ocean. countries=$($AWK -F'\t' \ -v continent="$continent" \ -v TZ_COUNTRY_TABLE="$TZ_COUNTRY_TABLE" \ ' /^#/ { next } $3 ~ ("^" continent "/") { if (!cc_seen[$1]++) cc_list[++ccs] = $1 } END { while (getline &2 "`$GETTEXT "$INFO_SELECT_CNTRY"`\n" select xcountry in ${icountry[*]} do case $xcountry in '') $PRINTF >&2 "`$GETTEXT "$WARN_ENTER_NUM"`\n" ;; ?*) c=0 while true; do if [ "$xcountry" = "${icountry[$c]}" ]; then country="${ocountry[$c]}" break fi if [ $c -lt $maxnum ]; then c=$(( $c + 1 )) else break fi done break esac done case $xcountry in '') exit 1 esac;; *) country=$countries xcountry=$countries esac # Get list of names of time zone rule regions in the country. regions=$($AWK -F'\t' \ -v country="$country" \ -v TZ_COUNTRY_TABLE="$TZ_COUNTRY_TABLE" \ ' BEGIN { cc = country while (getline &2 "`$GETTEXT "$INFO_SELECT_TZ"`\n" select xregion in ${iregion[*]} do case $xregion in '') $PRINTF >&2 "`$GETTEXT "$WARN_ENTER_NUM"`\n" ;; ?*) c=0 while true; do if [ "$xregion" = "${iregion[$c]}" ]; then region="${oregion[$c]}" break fi if [ $c -lt $maxnum ]; then c=$(( $c + 1 )) else break fi done break esac done case $region in '') exit 1 esac;; *) region=$regions xregion=$regions esac # Determine TZ from country and region. TZ=$($AWK -F'\t' \ -v country="$country" \ -v region="$region" \ -v TZ_COUNTRY_TABLE="$TZ_COUNTRY_TABLE" \ ' BEGIN { cc = country while (getline &2 "`$GETTEXT "$ERR_NO_SETUP"`\n" $0 exit 1 } # Absolute path TZ's not supported TZ_for_date=$TZ esac # Use the proposed TZ to output the current date relative to UTC. # Loop until they agree in seconds. # Give up after 8 unsuccessful tries. extra_info1= extra_info2= for i in 1 2 3 4 5 6 7 8 do TZdate=$(LANG=C TZ="$TZ_for_date" $DATE) UTdate=$(LANG=C TZ=UTC0 $DATE) TZsec=$($EXPR "$TZdate" : '.*:\([0-5][0-9]\)') UTsec=$($EXPR "$UTdate" : '.*:\([0-5][0-9]\)') case $TZsec in $UTsec) extra_info1=$($PRINTF "`$GETTEXT "$INFO_EXTRA1"`" \ "$TZdate") extra_info2=$($PRINTF "`$GETTEXT "$INFO_EXTRA2"`" \ "$UTdate") break esac done # Output TZ info and ask the user to confirm. $PRINTF >&2 "\n" $PRINTF >&2 "`$GETTEXT "$INFO_INFO"`\n" $PRINTF >&2 "\n" case $country+$region in ?*+?*) $PRINTF >&2 " $xcountry$newline $xregion\n";; ?*+) $PRINTF >&2 " $xcountry\n";; +) $PRINTF >&2 " TZ='$TZ'\n" esac $PRINTF >&2 "\n" $PRINTF >&2 "`$GETTEXT "$INFO_TZ"`\n" "$TZ" $PRINTF >&2 "$extra_info1\n" $PRINTF >&2 "$extra_info2\n" $PRINTF >&2 "`$GETTEXT "$INFO_OK"`\n" ok= # select ok in Yes No Yes="`$GETTEXT "$INFO_YES"`" No="`$GETTEXT "$INFO_NO"`" select ok in $Yes $No do case $ok in '') $PRINTF >&2 "`$GETTEXT "$WARN_ENTER_YORN"`\n" ;; ?*) break esac done case $ok in '') exit 1;; $Yes) break esac do : done $PRINTF >&2 "`$GETTEXT "$INFO_FINE"`\n" $PRINTF "%s\n" "$TZ"