14616d0f9Sopenharmony_ci#!/bin/bash
24616d0f9Sopenharmony_ci# Ask the user about the time zone, and output the resulting TZ value to stdout.
34616d0f9Sopenharmony_ci# Interact with the user via stderr and stdin.
44616d0f9Sopenharmony_ci
54616d0f9Sopenharmony_ciPKGVERSION='(tzcode) '
64616d0f9Sopenharmony_ciTZVERSION=see_Makefile
74616d0f9Sopenharmony_ciREPORT_BUGS_TO=tz@iana.org
84616d0f9Sopenharmony_ci
94616d0f9Sopenharmony_ci# Contributed by Paul Eggert.  This file is in the public domain.
104616d0f9Sopenharmony_ci
114616d0f9Sopenharmony_ci# Porting notes:
124616d0f9Sopenharmony_ci#
134616d0f9Sopenharmony_ci# This script requires a POSIX-like shell and prefers the extension of a
144616d0f9Sopenharmony_ci# 'select' statement.  The 'select' statement was introduced in the
154616d0f9Sopenharmony_ci# Korn shell and is available in Bash and other shell implementations.
164616d0f9Sopenharmony_ci# If your host lacks both Bash and the Korn shell, you can get their
174616d0f9Sopenharmony_ci# source from one of these locations:
184616d0f9Sopenharmony_ci#
194616d0f9Sopenharmony_ci#	Bash <https://www.gnu.org/software/bash/>
204616d0f9Sopenharmony_ci#	Korn Shell <http://www.kornshell.com/>
214616d0f9Sopenharmony_ci#	MirBSD Korn Shell <http://www.mirbsd.org/mksh.htm>
224616d0f9Sopenharmony_ci#
234616d0f9Sopenharmony_ci# For portability to Solaris 10 /bin/sh (supported by Oracle through
244616d0f9Sopenharmony_ci# January 2027) this script avoids some POSIX features and common
254616d0f9Sopenharmony_ci# extensions, such as $(...), $((...)), ! CMD, unquoted ^, ${#ID},
264616d0f9Sopenharmony_ci# ${ID##PAT}, ${ID%%PAT}, and $10.  Although some of these constructs
274616d0f9Sopenharmony_ci# work sometimes, it's simpler to avoid them entirely.
284616d0f9Sopenharmony_ci#
294616d0f9Sopenharmony_ci# This script also uses several features of POSIX awk.
304616d0f9Sopenharmony_ci# If your host lacks awk, or has an old awk that does not conform to POSIX,
314616d0f9Sopenharmony_ci# you can use any of the following free programs instead:
324616d0f9Sopenharmony_ci#
334616d0f9Sopenharmony_ci#	Gawk (GNU awk) <https://www.gnu.org/software/gawk/>
344616d0f9Sopenharmony_ci#	mawk <https://invisible-island.net/mawk/>
354616d0f9Sopenharmony_ci#	nawk <https://github.com/onetrueawk/awk>
364616d0f9Sopenharmony_ci#
374616d0f9Sopenharmony_ci# Because 'awk "VAR=VALUE" ...' and 'awk -v "VAR=VALUE" ...' are not portable
384616d0f9Sopenharmony_ci# if VALUE contains \, ", or newline, awk scripts in this file use:
394616d0f9Sopenharmony_ci#   awk 'BEGIN { VAR = substr(ARGV[1], 2); ARGV[1] = "" } ...' ="VALUE"
404616d0f9Sopenharmony_ci# The substr avoids problems when VALUE is of the form X=Y and would be
414616d0f9Sopenharmony_ci# misinterpreted as an assignment.
424616d0f9Sopenharmony_ci
434616d0f9Sopenharmony_ci# This script does not want path expansion.
444616d0f9Sopenharmony_ciset -f
454616d0f9Sopenharmony_ci
464616d0f9Sopenharmony_ci# Specify default values for environment variables if they are unset.
474616d0f9Sopenharmony_ci: ${AWK=awk}
484616d0f9Sopenharmony_ci: ${PWD=`pwd`}
494616d0f9Sopenharmony_ci: ${TZDIR=$PWD}
504616d0f9Sopenharmony_ci
514616d0f9Sopenharmony_ci# Output one argument as-is to standard output, with trailing newline.
524616d0f9Sopenharmony_ci# Safer than 'echo', which can mishandle '\' or leading '-'.
534616d0f9Sopenharmony_cisay() {
544616d0f9Sopenharmony_ci  printf '%s\n' "$1"
554616d0f9Sopenharmony_ci}
564616d0f9Sopenharmony_ci
574616d0f9Sopenharmony_ci# Check for awk POSIX compliance.
584616d0f9Sopenharmony_ci($AWK -v x=y 'BEGIN { exit 123 }') <>/dev/null >&0 2>&0
594616d0f9Sopenharmony_ci[ $? = 123 ] || {
604616d0f9Sopenharmony_ci  say >&2 "$0: Sorry, your '$AWK' program is not POSIX compatible."
614616d0f9Sopenharmony_ci  exit 1
624616d0f9Sopenharmony_ci}
634616d0f9Sopenharmony_ci
644616d0f9Sopenharmony_cicoord=
654616d0f9Sopenharmony_cilocation_limit=10
664616d0f9Sopenharmony_cizonetabtype=zone1970
674616d0f9Sopenharmony_ci
684616d0f9Sopenharmony_ciusage="Usage: tzselect [--version] [--help] [-c COORD] [-n LIMIT]
694616d0f9Sopenharmony_ciSelect a timezone interactively.
704616d0f9Sopenharmony_ci
714616d0f9Sopenharmony_ciOptions:
724616d0f9Sopenharmony_ci
734616d0f9Sopenharmony_ci  -c COORD
744616d0f9Sopenharmony_ci    Instead of asking for continent and then country and then city,
754616d0f9Sopenharmony_ci    ask for selection from time zones whose largest cities
764616d0f9Sopenharmony_ci    are closest to the location with geographical coordinates COORD.
774616d0f9Sopenharmony_ci    COORD should use ISO 6709 notation, for example, '-c +4852+00220'
784616d0f9Sopenharmony_ci    for Paris (in degrees and minutes, North and East), or
794616d0f9Sopenharmony_ci    '-c -35-058' for Buenos Aires (in degrees, South and West).
804616d0f9Sopenharmony_ci
814616d0f9Sopenharmony_ci  -n LIMIT
824616d0f9Sopenharmony_ci    Display at most LIMIT locations when -c is used (default $location_limit).
834616d0f9Sopenharmony_ci
844616d0f9Sopenharmony_ci  --version
854616d0f9Sopenharmony_ci    Output version information.
864616d0f9Sopenharmony_ci
874616d0f9Sopenharmony_ci  --help
884616d0f9Sopenharmony_ci    Output this help.
894616d0f9Sopenharmony_ci
904616d0f9Sopenharmony_ciReport bugs to $REPORT_BUGS_TO."
914616d0f9Sopenharmony_ci
924616d0f9Sopenharmony_ci# Ask the user to select from the function's arguments,
934616d0f9Sopenharmony_ci# and assign the selected argument to the variable 'select_result'.
944616d0f9Sopenharmony_ci# Exit on EOF or I/O error.  Use the shell's nicer 'select' builtin if
954616d0f9Sopenharmony_ci# available, falling back on a portable substitute otherwise.
964616d0f9Sopenharmony_ciif
974616d0f9Sopenharmony_ci  case $BASH_VERSION in
984616d0f9Sopenharmony_ci  ?*) :;;
994616d0f9Sopenharmony_ci  '')
1004616d0f9Sopenharmony_ci    # '; exit' should be redundant, but Dash doesn't properly fail without it.
1014616d0f9Sopenharmony_ci    (eval 'set --; select x; do break; done; exit') <>/dev/null 2>&0
1024616d0f9Sopenharmony_ci  esac
1034616d0f9Sopenharmony_cithen
1044616d0f9Sopenharmony_ci  # Do this inside 'eval', as otherwise the shell might exit when parsing it
1054616d0f9Sopenharmony_ci  # even though it is never executed.
1064616d0f9Sopenharmony_ci  eval '
1074616d0f9Sopenharmony_ci    doselect() {
1084616d0f9Sopenharmony_ci      select select_result
1094616d0f9Sopenharmony_ci      do
1104616d0f9Sopenharmony_ci	case $select_result in
1114616d0f9Sopenharmony_ci	"") echo >&2 "Please enter a number in range.";;
1124616d0f9Sopenharmony_ci	?*) break
1134616d0f9Sopenharmony_ci	esac
1144616d0f9Sopenharmony_ci      done || exit
1154616d0f9Sopenharmony_ci    }
1164616d0f9Sopenharmony_ci  '
1174616d0f9Sopenharmony_cielse
1184616d0f9Sopenharmony_ci  doselect() {
1194616d0f9Sopenharmony_ci    # Field width of the prompt numbers.
1204616d0f9Sopenharmony_ci    print_nargs_length="BEGIN {print length(\"$#\");}"
1214616d0f9Sopenharmony_ci    select_width=`$AWK "$print_nargs_length"`
1224616d0f9Sopenharmony_ci
1234616d0f9Sopenharmony_ci    select_i=
1244616d0f9Sopenharmony_ci
1254616d0f9Sopenharmony_ci    while :
1264616d0f9Sopenharmony_ci    do
1274616d0f9Sopenharmony_ci      case $select_i in
1284616d0f9Sopenharmony_ci      '')
1294616d0f9Sopenharmony_ci	select_i=0
1304616d0f9Sopenharmony_ci	for select_word
1314616d0f9Sopenharmony_ci	do
1324616d0f9Sopenharmony_ci	  select_i=`$AWK "BEGIN { print $select_i + 1 }"`
1334616d0f9Sopenharmony_ci	  printf >&2 "%${select_width}d) %s\\n" $select_i "$select_word"
1344616d0f9Sopenharmony_ci	done;;
1354616d0f9Sopenharmony_ci      *[!0-9]*)
1364616d0f9Sopenharmony_ci	echo >&2 'Please enter a number in range.';;
1374616d0f9Sopenharmony_ci      *)
1384616d0f9Sopenharmony_ci	if test 1 -le $select_i && test $select_i -le $#; then
1394616d0f9Sopenharmony_ci	  shift `$AWK "BEGIN { print $select_i - 1 }"`
1404616d0f9Sopenharmony_ci	  select_result=$1
1414616d0f9Sopenharmony_ci	  break
1424616d0f9Sopenharmony_ci	fi
1434616d0f9Sopenharmony_ci	echo >&2 'Please enter a number in range.'
1444616d0f9Sopenharmony_ci      esac
1454616d0f9Sopenharmony_ci
1464616d0f9Sopenharmony_ci      # Prompt and read input.
1474616d0f9Sopenharmony_ci      printf >&2 %s "${PS3-#? }"
1484616d0f9Sopenharmony_ci      read select_i || exit
1494616d0f9Sopenharmony_ci    done
1504616d0f9Sopenharmony_ci  }
1514616d0f9Sopenharmony_cifi
1524616d0f9Sopenharmony_ci
1534616d0f9Sopenharmony_ciwhile getopts c:n:t:-: opt
1544616d0f9Sopenharmony_cido
1554616d0f9Sopenharmony_ci  case $opt$OPTARG in
1564616d0f9Sopenharmony_ci  c*)
1574616d0f9Sopenharmony_ci    coord=$OPTARG;;
1584616d0f9Sopenharmony_ci  n*)
1594616d0f9Sopenharmony_ci    location_limit=$OPTARG;;
1604616d0f9Sopenharmony_ci  t*) # Undocumented option, used for developer testing.
1614616d0f9Sopenharmony_ci    zonetabtype=$OPTARG;;
1624616d0f9Sopenharmony_ci  -help)
1634616d0f9Sopenharmony_ci    exec echo "$usage";;
1644616d0f9Sopenharmony_ci  -version)
1654616d0f9Sopenharmony_ci    exec echo "tzselect $PKGVERSION$TZVERSION";;
1664616d0f9Sopenharmony_ci  -*)
1674616d0f9Sopenharmony_ci    say >&2 "$0: -$opt$OPTARG: unknown option; try '$0 --help'"; exit 1;;
1684616d0f9Sopenharmony_ci  *)
1694616d0f9Sopenharmony_ci    say >&2 "$0: try '$0 --help'"; exit 1
1704616d0f9Sopenharmony_ci  esac
1714616d0f9Sopenharmony_cidone
1724616d0f9Sopenharmony_ci
1734616d0f9Sopenharmony_cishift `$AWK "BEGIN { print $OPTIND - 1 }"`
1744616d0f9Sopenharmony_cicase $# in
1754616d0f9Sopenharmony_ci0) ;;
1764616d0f9Sopenharmony_ci*) say >&2 "$0: $1: unknown argument"; exit 1
1774616d0f9Sopenharmony_ciesac
1784616d0f9Sopenharmony_ci
1794616d0f9Sopenharmony_ci# translit=true to try transliteration.
1804616d0f9Sopenharmony_ci# This is false if U+12345 CUNEIFORM SIGN URU TIMES KI has length 1
1814616d0f9Sopenharmony_ci# which means awk (and presumably the shell) do not need transliteration.
1824616d0f9Sopenharmony_ciif $AWK 'BEGIN { u12345 = "\360\222\215\205"; exit length(u12345) == 1 }'; then
1834616d0f9Sopenharmony_ci  translit=true
1844616d0f9Sopenharmony_cielse
1854616d0f9Sopenharmony_ci  translit=false
1864616d0f9Sopenharmony_cifi
1874616d0f9Sopenharmony_ci
1884616d0f9Sopenharmony_ci# Read into shell variable $1 the contents of file $2.
1894616d0f9Sopenharmony_ci# Convert to the current locale's encoding if possible,
1904616d0f9Sopenharmony_ci# as the shell aligns columns better that way.
1914616d0f9Sopenharmony_ci# If GNU iconv's //TRANSLIT does not work, fall back on POSIXish iconv;
1924616d0f9Sopenharmony_ci# if that does not work, fall back on 'cat'.
1934616d0f9Sopenharmony_ciread_file() {
1944616d0f9Sopenharmony_ci  { $translit && {
1954616d0f9Sopenharmony_ci    eval "$1=\`(iconv -f UTF-8 -t //TRANSLIT) 2>/dev/null <\"\$2\"\`" ||
1964616d0f9Sopenharmony_ci    eval "$1=\`(iconv -f UTF-8) 2>/dev/null <\"\$2\"\`"
1974616d0f9Sopenharmony_ci  }; } ||
1984616d0f9Sopenharmony_ci  eval "$1=\`cat <\"\$2\"\`" || {
1994616d0f9Sopenharmony_ci    say >&2 "$0: time zone files are not set up correctly"
2004616d0f9Sopenharmony_ci    exit 1
2014616d0f9Sopenharmony_ci  }
2024616d0f9Sopenharmony_ci}
2034616d0f9Sopenharmony_ciread_file TZ_COUNTRY_TABLE "$TZDIR/iso3166.tab"
2044616d0f9Sopenharmony_ciread_file TZ_ZONETABTYPE_TABLE "$TZDIR/$zonetabtype.tab"
2054616d0f9Sopenharmony_ciTZ_ZONENOW_TABLE=
2064616d0f9Sopenharmony_ci
2074616d0f9Sopenharmony_cinewline='
2084616d0f9Sopenharmony_ci'
2094616d0f9Sopenharmony_ciIFS=$newline
2104616d0f9Sopenharmony_ci
2114616d0f9Sopenharmony_ci# Awk script to output a country list.
2124616d0f9Sopenharmony_cioutput_country_list='
2134616d0f9Sopenharmony_ci  BEGIN {
2144616d0f9Sopenharmony_ci    continent_re = substr(ARGV[1], 2)
2154616d0f9Sopenharmony_ci    TZ_COUNTRY_TABLE = substr(ARGV[2], 2)
2164616d0f9Sopenharmony_ci    TZ_ZONE_TABLE = substr(ARGV[3], 2)
2174616d0f9Sopenharmony_ci    ARGV[1] = ARGV[2] = ARGV[3] = ""
2184616d0f9Sopenharmony_ci    FS = "\t"
2194616d0f9Sopenharmony_ci    nlines = split(TZ_ZONE_TABLE, line, /\n/)
2204616d0f9Sopenharmony_ci    for (iline = 1; iline <= nlines; iline++) {
2214616d0f9Sopenharmony_ci      $0 = line[iline]
2224616d0f9Sopenharmony_ci      commentary = $0 ~ /^#@/
2234616d0f9Sopenharmony_ci      if (commentary) {
2244616d0f9Sopenharmony_ci	if ($0 !~ /^#@/)
2254616d0f9Sopenharmony_ci	  continue
2264616d0f9Sopenharmony_ci	col1ccs = substr($1, 3)
2274616d0f9Sopenharmony_ci	conts = $2
2284616d0f9Sopenharmony_ci      } else {
2294616d0f9Sopenharmony_ci	col1ccs = $1
2304616d0f9Sopenharmony_ci	conts = $3
2314616d0f9Sopenharmony_ci      }
2324616d0f9Sopenharmony_ci      ncc = split(col1ccs, cc, /,/)
2334616d0f9Sopenharmony_ci      ncont = split(conts, cont, /,/)
2344616d0f9Sopenharmony_ci      for (i = 1; i <= ncc; i++) {
2354616d0f9Sopenharmony_ci	elsewhere = commentary
2364616d0f9Sopenharmony_ci	for (ci = 1; ci <= ncont; ci++) {
2374616d0f9Sopenharmony_ci	  if (cont[ci] ~ continent_re) {
2384616d0f9Sopenharmony_ci	    if (!cc_seen[cc[i]]++)
2394616d0f9Sopenharmony_ci	      cc_list[++ccs] = cc[i]
2404616d0f9Sopenharmony_ci	    elsewhere = 0
2414616d0f9Sopenharmony_ci	  }
2424616d0f9Sopenharmony_ci	}
2434616d0f9Sopenharmony_ci	if (elsewhere)
2444616d0f9Sopenharmony_ci	  for (i = 1; i <= ncc; i++)
2454616d0f9Sopenharmony_ci	    cc_elsewhere[cc[i]] = 1
2464616d0f9Sopenharmony_ci      }
2474616d0f9Sopenharmony_ci    }
2484616d0f9Sopenharmony_ci    nlines = split(TZ_COUNTRY_TABLE, line, /\n/)
2494616d0f9Sopenharmony_ci    for (i = 1; i <= nlines; i++) {
2504616d0f9Sopenharmony_ci      $0 = line[i]
2514616d0f9Sopenharmony_ci      if ($0 !~ /^#/)
2524616d0f9Sopenharmony_ci	cc_name[$1] = $2
2534616d0f9Sopenharmony_ci    }
2544616d0f9Sopenharmony_ci    for (i = 1; i <= ccs; i++) {
2554616d0f9Sopenharmony_ci      country = cc_list[i]
2564616d0f9Sopenharmony_ci      if (cc_elsewhere[country])
2574616d0f9Sopenharmony_ci	continue
2584616d0f9Sopenharmony_ci      if (cc_name[country])
2594616d0f9Sopenharmony_ci	country = cc_name[country]
2604616d0f9Sopenharmony_ci      print country
2614616d0f9Sopenharmony_ci    }
2624616d0f9Sopenharmony_ci  }
2634616d0f9Sopenharmony_ci'
2644616d0f9Sopenharmony_ci
2654616d0f9Sopenharmony_ci# Awk script to process a time zone table and output the same table,
2664616d0f9Sopenharmony_ci# with each row preceded by its distance from 'here'.
2674616d0f9Sopenharmony_ci# If output_times is set, each row is instead preceded by its local time
2684616d0f9Sopenharmony_ci# and any apostrophes are escaped for the shell.
2694616d0f9Sopenharmony_cioutput_distances_or_times='
2704616d0f9Sopenharmony_ci  BEGIN {
2714616d0f9Sopenharmony_ci    coord = substr(ARGV[1], 2)
2724616d0f9Sopenharmony_ci    TZ_COUNTRY_TABLE = substr(ARGV[2], 2)
2734616d0f9Sopenharmony_ci    TZ_ZONE_TABLE = substr(ARGV[3], 2)
2744616d0f9Sopenharmony_ci    ARGV[1] = ARGV[2] = ARGV[3] = ""
2754616d0f9Sopenharmony_ci    FS = "\t"
2764616d0f9Sopenharmony_ci    if (!output_times) {
2774616d0f9Sopenharmony_ci      nlines = split(TZ_COUNTRY_TABLE, line, /\n/)
2784616d0f9Sopenharmony_ci      for (i = 1; i <= nlines; i++) {
2794616d0f9Sopenharmony_ci	$0 = line[i]
2804616d0f9Sopenharmony_ci	if ($0 ~ /^#/)
2814616d0f9Sopenharmony_ci	  continue
2824616d0f9Sopenharmony_ci	country[$1] = $2
2834616d0f9Sopenharmony_ci      }
2844616d0f9Sopenharmony_ci      country["US"] = "US" # Otherwise the strings get too long.
2854616d0f9Sopenharmony_ci    }
2864616d0f9Sopenharmony_ci  }
2874616d0f9Sopenharmony_ci  function abs(x) {
2884616d0f9Sopenharmony_ci    return x < 0 ? -x : x;
2894616d0f9Sopenharmony_ci  }
2904616d0f9Sopenharmony_ci  function min(x, y) {
2914616d0f9Sopenharmony_ci    return x < y ? x : y;
2924616d0f9Sopenharmony_ci  }
2934616d0f9Sopenharmony_ci  function convert_coord(coord, deg, minute, ilen, sign, sec) {
2944616d0f9Sopenharmony_ci    if (coord ~ /^[-+]?[0-9]?[0-9][0-9][0-9][0-9][0-9][0-9]([^0-9]|$)/) {
2954616d0f9Sopenharmony_ci      degminsec = coord
2964616d0f9Sopenharmony_ci      intdeg = degminsec < 0 ? -int(-degminsec / 10000) : int(degminsec / 10000)
2974616d0f9Sopenharmony_ci      minsec = degminsec - intdeg * 10000
2984616d0f9Sopenharmony_ci      intmin = minsec < 0 ? -int(-minsec / 100) : int(minsec / 100)
2994616d0f9Sopenharmony_ci      sec = minsec - intmin * 100
3004616d0f9Sopenharmony_ci      deg = (intdeg * 3600 + intmin * 60 + sec) / 3600
3014616d0f9Sopenharmony_ci    } else if (coord ~ /^[-+]?[0-9]?[0-9][0-9][0-9][0-9]([^0-9]|$)/) {
3024616d0f9Sopenharmony_ci      degmin = coord
3034616d0f9Sopenharmony_ci      intdeg = degmin < 0 ? -int(-degmin / 100) : int(degmin / 100)
3044616d0f9Sopenharmony_ci      minute = degmin - intdeg * 100
3054616d0f9Sopenharmony_ci      deg = (intdeg * 60 + minute) / 60
3064616d0f9Sopenharmony_ci    } else
3074616d0f9Sopenharmony_ci      deg = coord
3084616d0f9Sopenharmony_ci    return deg * 0.017453292519943296
3094616d0f9Sopenharmony_ci  }
3104616d0f9Sopenharmony_ci  function convert_latitude(coord) {
3114616d0f9Sopenharmony_ci    match(coord, /..*[-+]/)
3124616d0f9Sopenharmony_ci    return convert_coord(substr(coord, 1, RLENGTH - 1))
3134616d0f9Sopenharmony_ci  }
3144616d0f9Sopenharmony_ci  function convert_longitude(coord) {
3154616d0f9Sopenharmony_ci    match(coord, /..*[-+]/)
3164616d0f9Sopenharmony_ci    return convert_coord(substr(coord, RLENGTH))
3174616d0f9Sopenharmony_ci  }
3184616d0f9Sopenharmony_ci  # Great-circle distance between points with given latitude and longitude.
3194616d0f9Sopenharmony_ci  # Inputs and output are in radians.  This uses the great-circle special
3204616d0f9Sopenharmony_ci  # case of the Vicenty formula for distances on ellipsoids.
3214616d0f9Sopenharmony_ci  function gcdist(lat1, long1, lat2, long2, dlong, x, y, num, denom) {
3224616d0f9Sopenharmony_ci    dlong = long2 - long1
3234616d0f9Sopenharmony_ci    x = cos(lat2) * sin(dlong)
3244616d0f9Sopenharmony_ci    y = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(dlong)
3254616d0f9Sopenharmony_ci    num = sqrt(x * x + y * y)
3264616d0f9Sopenharmony_ci    denom = sin(lat1) * sin(lat2) + cos(lat1) * cos(lat2) * cos(dlong)
3274616d0f9Sopenharmony_ci    return atan2(num, denom)
3284616d0f9Sopenharmony_ci  }
3294616d0f9Sopenharmony_ci  # Parallel distance between points with given latitude and longitude.
3304616d0f9Sopenharmony_ci  # This is the product of the longitude difference and the cosine
3314616d0f9Sopenharmony_ci  # of the latitude of the point that is further from the equator.
3324616d0f9Sopenharmony_ci  # I.e., it considers longitudes to be further apart if they are
3334616d0f9Sopenharmony_ci  # nearer the equator.
3344616d0f9Sopenharmony_ci  function pardist(lat1, long1, lat2, long2) {
3354616d0f9Sopenharmony_ci    return abs(long1 - long2) * min(cos(lat1), cos(lat2))
3364616d0f9Sopenharmony_ci  }
3374616d0f9Sopenharmony_ci  # The distance function is the sum of the great-circle distance and
3384616d0f9Sopenharmony_ci  # the parallel distance.  It could be weighted.
3394616d0f9Sopenharmony_ci  function dist(lat1, long1, lat2, long2) {
3404616d0f9Sopenharmony_ci    return gcdist(lat1, long1, lat2, long2) + pardist(lat1, long1, lat2, long2)
3414616d0f9Sopenharmony_ci  }
3424616d0f9Sopenharmony_ci  BEGIN {
3434616d0f9Sopenharmony_ci    coord_lat = convert_latitude(coord)
3444616d0f9Sopenharmony_ci    coord_long = convert_longitude(coord)
3454616d0f9Sopenharmony_ci    nlines = split(TZ_ZONE_TABLE, line, /\n/)
3464616d0f9Sopenharmony_ci    for (h = 1; h <= nlines; h++) {
3474616d0f9Sopenharmony_ci      $0 = line[h]
3484616d0f9Sopenharmony_ci      if ($0 ~ /^#/)
3494616d0f9Sopenharmony_ci	continue
3504616d0f9Sopenharmony_ci      inline[inlines++] = $0
3514616d0f9Sopenharmony_ci      ncc = split($1, cc, /,/)
3524616d0f9Sopenharmony_ci      for (i = 1; i <= ncc; i++)
3534616d0f9Sopenharmony_ci	cc_used[cc[i]]++
3544616d0f9Sopenharmony_ci    }
3554616d0f9Sopenharmony_ci    for (h = 0; h < inlines; h++) {
3564616d0f9Sopenharmony_ci      $0 = inline[h]
3574616d0f9Sopenharmony_ci      outline = $1 "\t" $2 "\t" $3
3584616d0f9Sopenharmony_ci      sep = "\t"
3594616d0f9Sopenharmony_ci      ncc = split($1, cc, /,/)
3604616d0f9Sopenharmony_ci      split("", item_seen)
3614616d0f9Sopenharmony_ci      item_seen[""] = 1
3624616d0f9Sopenharmony_ci      for (i = 1; i <= ncc; i++) {
3634616d0f9Sopenharmony_ci	item = cc_used[cc[i]] <= 1 ? country[cc[i]] : $4
3644616d0f9Sopenharmony_ci	if (item_seen[item]++)
3654616d0f9Sopenharmony_ci	  continue
3664616d0f9Sopenharmony_ci	outline = outline sep item
3674616d0f9Sopenharmony_ci	sep = "; "
3684616d0f9Sopenharmony_ci      }
3694616d0f9Sopenharmony_ci      if (output_times) {
3704616d0f9Sopenharmony_ci	fmt = "TZ='\''%s'\'' date +'\''%d %%Y %%m %%d %%H:%%M %%a %%b\t%s'\''\n"
3714616d0f9Sopenharmony_ci	gsub(/'\''/, "&\\\\&&", outline)
3724616d0f9Sopenharmony_ci	printf fmt, $3, h, outline
3734616d0f9Sopenharmony_ci      } else {
3744616d0f9Sopenharmony_ci	here_lat = convert_latitude($2)
3754616d0f9Sopenharmony_ci	here_long = convert_longitude($2)
3764616d0f9Sopenharmony_ci	printf "%g\t%s\n", dist(coord_lat, coord_long, here_lat, here_long), \
3774616d0f9Sopenharmony_ci	  outline
3784616d0f9Sopenharmony_ci      }
3794616d0f9Sopenharmony_ci    }
3804616d0f9Sopenharmony_ci  }
3814616d0f9Sopenharmony_ci'
3824616d0f9Sopenharmony_ci
3834616d0f9Sopenharmony_ci# Begin the main loop.  We come back here if the user wants to retry.
3844616d0f9Sopenharmony_ciwhile
3854616d0f9Sopenharmony_ci
3864616d0f9Sopenharmony_ci  echo >&2 'Please identify a location' \
3874616d0f9Sopenharmony_ci    'so that time zone rules can be set correctly.'
3884616d0f9Sopenharmony_ci
3894616d0f9Sopenharmony_ci  continent=
3904616d0f9Sopenharmony_ci  country=
3914616d0f9Sopenharmony_ci  country_result=
3924616d0f9Sopenharmony_ci  region=
3934616d0f9Sopenharmony_ci  time=
3944616d0f9Sopenharmony_ci  TZ_ZONE_TABLE=$TZ_ZONETABTYPE_TABLE
3954616d0f9Sopenharmony_ci
3964616d0f9Sopenharmony_ci  case $coord in
3974616d0f9Sopenharmony_ci  ?*)
3984616d0f9Sopenharmony_ci    continent=coord;;
3994616d0f9Sopenharmony_ci  '')
4004616d0f9Sopenharmony_ci
4014616d0f9Sopenharmony_ci    # Ask the user for continent or ocean.
4024616d0f9Sopenharmony_ci
4034616d0f9Sopenharmony_ci    echo >&2 \
4044616d0f9Sopenharmony_ci      'Please select a continent, ocean, "coord", "TZ", "time", or "now".'
4054616d0f9Sopenharmony_ci
4064616d0f9Sopenharmony_ci    quoted_continents=`
4074616d0f9Sopenharmony_ci      $AWK '
4084616d0f9Sopenharmony_ci	function handle_entry(entry) {
4094616d0f9Sopenharmony_ci	  entry = substr(entry, 1, index(entry, "/") - 1)
4104616d0f9Sopenharmony_ci	  if (entry == "America")
4114616d0f9Sopenharmony_ci	    entry = entry "s"
4124616d0f9Sopenharmony_ci	  if (entry ~ /^(Arctic|Atlantic|Indian|Pacific)$/)
4134616d0f9Sopenharmony_ci	    entry = entry " Ocean"
4144616d0f9Sopenharmony_ci	  printf "'\''%s'\''\n", entry
4154616d0f9Sopenharmony_ci	}
4164616d0f9Sopenharmony_ci	BEGIN {
4174616d0f9Sopenharmony_ci	  TZ_ZONETABTYPE_TABLE = substr(ARGV[1], 2)
4184616d0f9Sopenharmony_ci	  ARGV[1] = ""
4194616d0f9Sopenharmony_ci	  FS = "\t"
4204616d0f9Sopenharmony_ci	  nlines = split(TZ_ZONETABTYPE_TABLE, line, /\n/)
4214616d0f9Sopenharmony_ci	  for (i = 1; i <= nlines; i++) {
4224616d0f9Sopenharmony_ci	    $0 = line[i]
4234616d0f9Sopenharmony_ci	    if ($0 ~ /^[^#]/)
4244616d0f9Sopenharmony_ci	      handle_entry($3)
4254616d0f9Sopenharmony_ci	    else if ($0 ~ /^#@/) {
4264616d0f9Sopenharmony_ci	      ncont = split($2, cont, /,/)
4274616d0f9Sopenharmony_ci	      for (ci = 1; ci <= ncont; ci++)
4284616d0f9Sopenharmony_ci		handle_entry(cont[ci])
4294616d0f9Sopenharmony_ci	    }
4304616d0f9Sopenharmony_ci	  }
4314616d0f9Sopenharmony_ci	}
4324616d0f9Sopenharmony_ci      ' ="$TZ_ZONETABTYPE_TABLE" |
4334616d0f9Sopenharmony_ci      sort -u |
4344616d0f9Sopenharmony_ci      tr '\n' ' '
4354616d0f9Sopenharmony_ci      echo ''
4364616d0f9Sopenharmony_ci    `
4374616d0f9Sopenharmony_ci
4384616d0f9Sopenharmony_ci    eval '
4394616d0f9Sopenharmony_ci      doselect '"$quoted_continents"' \
4404616d0f9Sopenharmony_ci	"coord - I want to use geographical coordinates." \
4414616d0f9Sopenharmony_ci	"TZ - I want to specify the timezone using a POSIX.1-2017 TZ string." \
4424616d0f9Sopenharmony_ci	"time - I know local time already." \
4434616d0f9Sopenharmony_ci	"now - Like \"time\", but configure only for timestamps from now on."
4444616d0f9Sopenharmony_ci      continent=$select_result
4454616d0f9Sopenharmony_ci      case $continent in
4464616d0f9Sopenharmony_ci      Americas) continent=America;;
4474616d0f9Sopenharmony_ci      *)
4484616d0f9Sopenharmony_ci	# Get the first word of $continent.  Path expansion is disabled
4494616d0f9Sopenharmony_ci	# so this works even with "*", which should not happen.
4504616d0f9Sopenharmony_ci	IFS=" "
4514616d0f9Sopenharmony_ci	for continent in $continent ""; do break; done
4524616d0f9Sopenharmony_ci	IFS=$newline;;
4534616d0f9Sopenharmony_ci      esac
4544616d0f9Sopenharmony_ci      case $zonetabtype,$continent in
4554616d0f9Sopenharmony_ci      zonenow,*) ;;
4564616d0f9Sopenharmony_ci      *,now)
4574616d0f9Sopenharmony_ci	${TZ_ZONENOW_TABLE:+:} read_file TZ_ZONENOW_TABLE "$TZDIR/zonenow.tab"
4584616d0f9Sopenharmony_ci	TZ_ZONE_TABLE=$TZ_ZONENOW_TABLE
4594616d0f9Sopenharmony_ci      esac
4604616d0f9Sopenharmony_ci    '
4614616d0f9Sopenharmony_ci  esac
4624616d0f9Sopenharmony_ci
4634616d0f9Sopenharmony_ci  case $continent in
4644616d0f9Sopenharmony_ci  TZ)
4654616d0f9Sopenharmony_ci    # Ask the user for a POSIX.1-2017 TZ string.  Check that it conforms.
4664616d0f9Sopenharmony_ci    check_POSIX_TZ_string='
4674616d0f9Sopenharmony_ci      BEGIN {
4684616d0f9Sopenharmony_ci	tz = substr(ARGV[1], 2)
4694616d0f9Sopenharmony_ci	ARGV[1] = ""
4704616d0f9Sopenharmony_ci	tzname = ("(<[[:alnum:]+-][[:alnum:]+-][[:alnum:]+-]+>" \
4714616d0f9Sopenharmony_ci		  "|[[:alpha:]][[:alpha:]][[:alpha:]]+)")
4724616d0f9Sopenharmony_ci	time = ("(2[0-4]|[0-1]?[0-9])" \
4734616d0f9Sopenharmony_ci		"(:[0-5][0-9](:[0-5][0-9])?)?")
4744616d0f9Sopenharmony_ci	offset = "[-+]?" time
4754616d0f9Sopenharmony_ci	mdate = "M([1-9]|1[0-2])\\.[1-5]\\.[0-6]"
4764616d0f9Sopenharmony_ci	jdate = ("((J[1-9]|[0-9]|J?[1-9][0-9]" \
4774616d0f9Sopenharmony_ci		 "|J?[1-2][0-9][0-9])|J?3[0-5][0-9]|J?36[0-5])")
4784616d0f9Sopenharmony_ci	datetime = ",(" mdate "|" jdate ")(/" time ")?"
4794616d0f9Sopenharmony_ci	tzpattern = ("^(:.*|" tzname offset "(" tzname \
4804616d0f9Sopenharmony_ci		     "(" offset ")?(" datetime datetime ")?)?)$")
4814616d0f9Sopenharmony_ci	exit tz ~ tzpattern
4824616d0f9Sopenharmony_ci      }
4834616d0f9Sopenharmony_ci    '
4844616d0f9Sopenharmony_ci
4854616d0f9Sopenharmony_ci    while
4864616d0f9Sopenharmony_ci      echo >&2 'Please enter the desired value' \
4874616d0f9Sopenharmony_ci	'of the TZ environment variable.'
4884616d0f9Sopenharmony_ci      echo >&2 'For example, AEST-10 is abbreviated' \
4894616d0f9Sopenharmony_ci	'AEST and is 10 hours'
4904616d0f9Sopenharmony_ci      echo >&2 'ahead (east) of Greenwich,' \
4914616d0f9Sopenharmony_ci	'with no daylight saving time.'
4924616d0f9Sopenharmony_ci      read tz
4934616d0f9Sopenharmony_ci      $AWK "$check_POSIX_TZ_string" ="$tz"
4944616d0f9Sopenharmony_ci    do
4954616d0f9Sopenharmony_ci      say >&2 "'$tz' is not a conforming POSIX.1-2017 timezone string."
4964616d0f9Sopenharmony_ci    done
4974616d0f9Sopenharmony_ci    TZ_for_date=$tz;;
4984616d0f9Sopenharmony_ci  *)
4994616d0f9Sopenharmony_ci    case $continent in
5004616d0f9Sopenharmony_ci    coord)
5014616d0f9Sopenharmony_ci      case $coord in
5024616d0f9Sopenharmony_ci      '')
5034616d0f9Sopenharmony_ci	echo >&2 'Please enter coordinates' \
5044616d0f9Sopenharmony_ci	  'in ISO 6709 notation.'
5054616d0f9Sopenharmony_ci	echo >&2 'For example, +4042-07403 stands for'
5064616d0f9Sopenharmony_ci	echo >&2 '40 degrees 42 minutes north,' \
5074616d0f9Sopenharmony_ci	  '74 degrees 3 minutes west.'
5084616d0f9Sopenharmony_ci	read coord
5094616d0f9Sopenharmony_ci      esac
5104616d0f9Sopenharmony_ci      distance_table=`
5114616d0f9Sopenharmony_ci	$AWK \
5124616d0f9Sopenharmony_ci	  "$output_distances_or_times" \
5134616d0f9Sopenharmony_ci	  ="$coord" ="$TZ_COUNTRY_TABLE" ="$TZ_ZONE_TABLE" |
5144616d0f9Sopenharmony_ci	sort -n |
5154616d0f9Sopenharmony_ci	$AWK "{print} NR == $location_limit { exit }"
5164616d0f9Sopenharmony_ci      `
5174616d0f9Sopenharmony_ci      regions=`
5184616d0f9Sopenharmony_ci	$AWK '
5194616d0f9Sopenharmony_ci	  BEGIN {
5204616d0f9Sopenharmony_ci	    distance_table = substr(ARGV[1], 2)
5214616d0f9Sopenharmony_ci	    ARGV[1] = ""
5224616d0f9Sopenharmony_ci	    nlines = split(distance_table, line, /\n/)
5234616d0f9Sopenharmony_ci	    for (nr = 1; nr <= nlines; nr++) {
5244616d0f9Sopenharmony_ci	      nf = split(line[nr], f, /\t/)
5254616d0f9Sopenharmony_ci	      print f[nf]
5264616d0f9Sopenharmony_ci	    }
5274616d0f9Sopenharmony_ci	  }
5284616d0f9Sopenharmony_ci	' ="$distance_table"
5294616d0f9Sopenharmony_ci      `
5304616d0f9Sopenharmony_ci      echo >&2 'Please select one of the following timezones,'
5314616d0f9Sopenharmony_ci      echo >&2 'listed roughly in increasing order' \
5324616d0f9Sopenharmony_ci	"of distance from $coord".
5334616d0f9Sopenharmony_ci      doselect $regions
5344616d0f9Sopenharmony_ci      region=$select_result
5354616d0f9Sopenharmony_ci      tz=`
5364616d0f9Sopenharmony_ci	$AWK '
5374616d0f9Sopenharmony_ci	  BEGIN {
5384616d0f9Sopenharmony_ci	    distance_table = substr(ARGV[1], 2)
5394616d0f9Sopenharmony_ci	    region = substr(ARGV[2], 2)
5404616d0f9Sopenharmony_ci	    ARGV[1] = ARGV[2] = ""
5414616d0f9Sopenharmony_ci	    nlines = split(distance_table, line, /\n/)
5424616d0f9Sopenharmony_ci	    for (nr = 1; nr <= nlines; nr++) {
5434616d0f9Sopenharmony_ci	      nf = split(line[nr], f, /\t/)
5444616d0f9Sopenharmony_ci	      if (f[nf] == region)
5454616d0f9Sopenharmony_ci		print f[4]
5464616d0f9Sopenharmony_ci	    }
5474616d0f9Sopenharmony_ci	  }
5484616d0f9Sopenharmony_ci	' ="$distance_table" ="$region"
5494616d0f9Sopenharmony_ci      `;;
5504616d0f9Sopenharmony_ci    *)
5514616d0f9Sopenharmony_ci      case $continent in
5524616d0f9Sopenharmony_ci      now|time)
5534616d0f9Sopenharmony_ci	minute_format='%a %b %d %H:%M'
5544616d0f9Sopenharmony_ci	old_minute=`TZ=UTC0 date +"$minute_format"`
5554616d0f9Sopenharmony_ci	for i in 1 2 3
5564616d0f9Sopenharmony_ci	do
5574616d0f9Sopenharmony_ci	  time_table_command=`
5584616d0f9Sopenharmony_ci	    $AWK \
5594616d0f9Sopenharmony_ci	      -v output_times=1 \
5604616d0f9Sopenharmony_ci	      "$output_distances_or_times" \
5614616d0f9Sopenharmony_ci	      = = ="$TZ_ZONE_TABLE"
5624616d0f9Sopenharmony_ci	  `
5634616d0f9Sopenharmony_ci	  time_table=`eval "$time_table_command"`
5644616d0f9Sopenharmony_ci	  new_minute=`TZ=UTC0 date +"$minute_format"`
5654616d0f9Sopenharmony_ci	  case $old_minute in
5664616d0f9Sopenharmony_ci	  "$new_minute") break
5674616d0f9Sopenharmony_ci	  esac
5684616d0f9Sopenharmony_ci	  old_minute=$new_minute
5694616d0f9Sopenharmony_ci	done
5704616d0f9Sopenharmony_ci	echo >&2 "The system says Universal Time is $new_minute."
5714616d0f9Sopenharmony_ci	echo >&2 "Assuming that's correct, what is the local time?"
5724616d0f9Sopenharmony_ci	sorted_table=`say "$time_table" | sort -k2n -k2,5 -k1n` || {
5734616d0f9Sopenharmony_ci	  say >&2 "$0: cannot sort time table"
5744616d0f9Sopenharmony_ci	  exit 1
5754616d0f9Sopenharmony_ci	}
5764616d0f9Sopenharmony_ci	eval doselect `
5774616d0f9Sopenharmony_ci	  $AWK '
5784616d0f9Sopenharmony_ci	    BEGIN {
5794616d0f9Sopenharmony_ci	      sorted_table = substr(ARGV[1], 2)
5804616d0f9Sopenharmony_ci	      ARGV[1] = ""
5814616d0f9Sopenharmony_ci	      nlines = split(sorted_table, line, /\n/)
5824616d0f9Sopenharmony_ci	      for (i = 1; i <= nlines; i++) {
5834616d0f9Sopenharmony_ci		$0 = line[i]
5844616d0f9Sopenharmony_ci		outline = $6 " " $7 " " $4 " " $5
5854616d0f9Sopenharmony_ci		if (outline == oldline)
5864616d0f9Sopenharmony_ci		  continue
5874616d0f9Sopenharmony_ci		oldline = outline
5884616d0f9Sopenharmony_ci		gsub(/'\''/, "&\\\\&&", outline)
5894616d0f9Sopenharmony_ci		printf "'\''%s'\''\n", outline
5904616d0f9Sopenharmony_ci	      }
5914616d0f9Sopenharmony_ci	    }
5924616d0f9Sopenharmony_ci	  ' ="$sorted_table"
5934616d0f9Sopenharmony_ci	`
5944616d0f9Sopenharmony_ci	time=$select_result
5954616d0f9Sopenharmony_ci	continent_re='^'
5964616d0f9Sopenharmony_ci	zone_table=`
5974616d0f9Sopenharmony_ci	  $AWK '
5984616d0f9Sopenharmony_ci	    BEGIN {
5994616d0f9Sopenharmony_ci	      time = substr(ARGV[1], 2)
6004616d0f9Sopenharmony_ci	      time_table = substr(ARGV[2], 2)
6014616d0f9Sopenharmony_ci	      ARGV[1] = ARGV[2] = ""
6024616d0f9Sopenharmony_ci	      nlines = split(time_table, line, /\n/)
6034616d0f9Sopenharmony_ci	      for (i = 1; i <= nlines; i++) {
6044616d0f9Sopenharmony_ci		$0 = line[i]
6054616d0f9Sopenharmony_ci		if ($6 " " $7 " " $4 " " $5 == time) {
6064616d0f9Sopenharmony_ci		  sub(/[^\t]*\t/, "")
6074616d0f9Sopenharmony_ci		  print
6084616d0f9Sopenharmony_ci		}
6094616d0f9Sopenharmony_ci	      }
6104616d0f9Sopenharmony_ci	    }
6114616d0f9Sopenharmony_ci	  ' ="$time" ="$time_table"
6124616d0f9Sopenharmony_ci	`
6134616d0f9Sopenharmony_ci	countries=`
6144616d0f9Sopenharmony_ci	  $AWK \
6154616d0f9Sopenharmony_ci	    "$output_country_list" \
6164616d0f9Sopenharmony_ci	    ="$continent_re" ="$TZ_COUNTRY_TABLE" ="$zone_table" |
6174616d0f9Sopenharmony_ci	  sort -f
6184616d0f9Sopenharmony_ci	`
6194616d0f9Sopenharmony_ci	;;
6204616d0f9Sopenharmony_ci      *)
6214616d0f9Sopenharmony_ci	continent_re="^$continent/"
6224616d0f9Sopenharmony_ci	zone_table=$TZ_ZONE_TABLE
6234616d0f9Sopenharmony_ci      esac
6244616d0f9Sopenharmony_ci
6254616d0f9Sopenharmony_ci      # Get list of names of countries in the continent or ocean.
6264616d0f9Sopenharmony_ci      countries=`
6274616d0f9Sopenharmony_ci	$AWK \
6284616d0f9Sopenharmony_ci	  "$output_country_list" \
6294616d0f9Sopenharmony_ci	  ="$continent_re" ="$TZ_COUNTRY_TABLE" ="$zone_table" |
6304616d0f9Sopenharmony_ci	sort -f
6314616d0f9Sopenharmony_ci      `
6324616d0f9Sopenharmony_ci      # If all zone table entries have comments, and there are
6334616d0f9Sopenharmony_ci      # at most 22 entries, asked based on those comments.
6344616d0f9Sopenharmony_ci      # This fits the prompt onto old-fashioned 24-line screens.
6354616d0f9Sopenharmony_ci      regions=`
6364616d0f9Sopenharmony_ci	$AWK '
6374616d0f9Sopenharmony_ci	  BEGIN {
6384616d0f9Sopenharmony_ci	    TZ_ZONE_TABLE = substr(ARGV[1], 2)
6394616d0f9Sopenharmony_ci	    ARGV[1] = ""
6404616d0f9Sopenharmony_ci	    FS = "\t"
6414616d0f9Sopenharmony_ci	    nlines = split(TZ_ZONE_TABLE, line, /\n/)
6424616d0f9Sopenharmony_ci	    for (i = 1; i <= nlines; i++) {
6434616d0f9Sopenharmony_ci	      $0 = line[i]
6444616d0f9Sopenharmony_ci	      if ($0 ~ /^[^#]/ && !missing_comment) {
6454616d0f9Sopenharmony_ci		if ($4)
6464616d0f9Sopenharmony_ci		  comment[++inlines] = $4
6474616d0f9Sopenharmony_ci		else
6484616d0f9Sopenharmony_ci		  missing_comment = 1
6494616d0f9Sopenharmony_ci	      }
6504616d0f9Sopenharmony_ci	    }
6514616d0f9Sopenharmony_ci	    if (!missing_comment && inlines <= 22)
6524616d0f9Sopenharmony_ci	      for (i = 1; i <= inlines; i++)
6534616d0f9Sopenharmony_ci		print comment[i]
6544616d0f9Sopenharmony_ci	  }
6554616d0f9Sopenharmony_ci	' ="$zone_table"
6564616d0f9Sopenharmony_ci      `
6574616d0f9Sopenharmony_ci
6584616d0f9Sopenharmony_ci      # If there's more than one country, ask the user which one.
6594616d0f9Sopenharmony_ci      case $countries in
6604616d0f9Sopenharmony_ci      *"$newline"*)
6614616d0f9Sopenharmony_ci	echo >&2 'Please select a country' \
6624616d0f9Sopenharmony_ci	  'whose clocks agree with yours.'
6634616d0f9Sopenharmony_ci	doselect $countries
6644616d0f9Sopenharmony_ci	country_result=$select_result
6654616d0f9Sopenharmony_ci	country=$select_result;;
6664616d0f9Sopenharmony_ci      *)
6674616d0f9Sopenharmony_ci	country=$countries
6684616d0f9Sopenharmony_ci      esac
6694616d0f9Sopenharmony_ci
6704616d0f9Sopenharmony_ci
6714616d0f9Sopenharmony_ci      # Get list of timezones in the country.
6724616d0f9Sopenharmony_ci      regions=`
6734616d0f9Sopenharmony_ci	$AWK '
6744616d0f9Sopenharmony_ci	  BEGIN {
6754616d0f9Sopenharmony_ci	    country = substr(ARGV[1], 2)
6764616d0f9Sopenharmony_ci	    TZ_COUNTRY_TABLE = substr(ARGV[2], 2)
6774616d0f9Sopenharmony_ci	    TZ_ZONE_TABLE = substr(ARGV[3], 2)
6784616d0f9Sopenharmony_ci	    ARGV[1] = ARGV[2] = ARGV[3] = ""
6794616d0f9Sopenharmony_ci	    FS = "\t"
6804616d0f9Sopenharmony_ci	    cc = country
6814616d0f9Sopenharmony_ci	    nlines = split(TZ_COUNTRY_TABLE, line, /\n/)
6824616d0f9Sopenharmony_ci	    for (i = 1; i <= nlines; i++) {
6834616d0f9Sopenharmony_ci	      $0 = line[i]
6844616d0f9Sopenharmony_ci	      if ($0 !~ /^#/  &&  country == $2) {
6854616d0f9Sopenharmony_ci		cc = $1
6864616d0f9Sopenharmony_ci		break
6874616d0f9Sopenharmony_ci	      }
6884616d0f9Sopenharmony_ci	    }
6894616d0f9Sopenharmony_ci	    nlines = split(TZ_ZONE_TABLE, line, /\n/)
6904616d0f9Sopenharmony_ci	    for (i = 1; i <= nlines; i++) {
6914616d0f9Sopenharmony_ci	      $0 = line[i]
6924616d0f9Sopenharmony_ci	      if ($0 ~ /^#/)
6934616d0f9Sopenharmony_ci		continue
6944616d0f9Sopenharmony_ci	      if ($1 ~ cc)
6954616d0f9Sopenharmony_ci		print $4
6964616d0f9Sopenharmony_ci	    }
6974616d0f9Sopenharmony_ci	  }
6984616d0f9Sopenharmony_ci	' ="$country" ="$TZ_COUNTRY_TABLE" ="$zone_table"
6994616d0f9Sopenharmony_ci      `
7004616d0f9Sopenharmony_ci
7014616d0f9Sopenharmony_ci      # If there's more than one region, ask the user which one.
7024616d0f9Sopenharmony_ci      case $regions in
7034616d0f9Sopenharmony_ci      *"$newline"*)
7044616d0f9Sopenharmony_ci	echo >&2 'Please select one of the following timezones.'
7054616d0f9Sopenharmony_ci	doselect $regions
7064616d0f9Sopenharmony_ci	region=$select_result
7074616d0f9Sopenharmony_ci      esac
7084616d0f9Sopenharmony_ci
7094616d0f9Sopenharmony_ci      # Determine tz from country and region.
7104616d0f9Sopenharmony_ci      tz=`
7114616d0f9Sopenharmony_ci	$AWK '
7124616d0f9Sopenharmony_ci	  BEGIN {
7134616d0f9Sopenharmony_ci	    country = substr(ARGV[1], 2)
7144616d0f9Sopenharmony_ci	    region = substr(ARGV[2], 2)
7154616d0f9Sopenharmony_ci	    TZ_COUNTRY_TABLE = substr(ARGV[3], 2)
7164616d0f9Sopenharmony_ci	    TZ_ZONE_TABLE = substr(ARGV[4], 2)
7174616d0f9Sopenharmony_ci	    ARGV[1] = ARGV[2] = ARGV[3] = ARGV[4] = ""
7184616d0f9Sopenharmony_ci	    FS = "\t"
7194616d0f9Sopenharmony_ci	    cc = country
7204616d0f9Sopenharmony_ci	    nlines = split(TZ_COUNTRY_TABLE, line, /\n/)
7214616d0f9Sopenharmony_ci	    for (i = 1; i <= nlines; i++) {
7224616d0f9Sopenharmony_ci	      $0 = line[i]
7234616d0f9Sopenharmony_ci	      if ($0 !~ /^#/  &&  country == $2) {
7244616d0f9Sopenharmony_ci		cc = $1
7254616d0f9Sopenharmony_ci		break
7264616d0f9Sopenharmony_ci	      }
7274616d0f9Sopenharmony_ci	    }
7284616d0f9Sopenharmony_ci	    nlines = split(TZ_ZONE_TABLE, line, /\n/)
7294616d0f9Sopenharmony_ci	    for (i = 1; i <= nlines; i++) {
7304616d0f9Sopenharmony_ci	      $0 = line[i]
7314616d0f9Sopenharmony_ci	      if ($0 ~ /^#/)
7324616d0f9Sopenharmony_ci		continue
7334616d0f9Sopenharmony_ci	      if ($1 ~ cc && ($4 == region || !region))
7344616d0f9Sopenharmony_ci		print $3
7354616d0f9Sopenharmony_ci	    }
7364616d0f9Sopenharmony_ci	  }
7374616d0f9Sopenharmony_ci	' ="$country" ="$region" ="$TZ_COUNTRY_TABLE" ="$zone_table"
7384616d0f9Sopenharmony_ci      `
7394616d0f9Sopenharmony_ci    esac
7404616d0f9Sopenharmony_ci
7414616d0f9Sopenharmony_ci    # Make sure the corresponding zoneinfo file exists.
7424616d0f9Sopenharmony_ci    TZ_for_date=$TZDIR/$tz
7434616d0f9Sopenharmony_ci    <"$TZ_for_date" || {
7444616d0f9Sopenharmony_ci      say >&2 "$0: time zone files are not set up correctly"
7454616d0f9Sopenharmony_ci      exit 1
7464616d0f9Sopenharmony_ci    }
7474616d0f9Sopenharmony_ci  esac
7484616d0f9Sopenharmony_ci
7494616d0f9Sopenharmony_ci
7504616d0f9Sopenharmony_ci  # Use the proposed TZ to output the current date relative to UTC.
7514616d0f9Sopenharmony_ci  # Loop until they agree in seconds.
7524616d0f9Sopenharmony_ci  # Give up after 8 unsuccessful tries.
7534616d0f9Sopenharmony_ci
7544616d0f9Sopenharmony_ci  extra_info=
7554616d0f9Sopenharmony_ci  for i in 1 2 3 4 5 6 7 8
7564616d0f9Sopenharmony_ci  do
7574616d0f9Sopenharmony_ci    TZdate=`LANG=C TZ="$TZ_for_date" date`
7584616d0f9Sopenharmony_ci    UTdate=`LANG=C TZ=UTC0 date`
7594616d0f9Sopenharmony_ci    if $AWK '
7604616d0f9Sopenharmony_ci	  function getsecs(d) {
7614616d0f9Sopenharmony_ci	    return match(d, /.*:[0-5][0-9]/) ? substr(d, RLENGTH - 1, 2) : ""
7624616d0f9Sopenharmony_ci	  }
7634616d0f9Sopenharmony_ci	  BEGIN { exit getsecs(ARGV[1]) != getsecs(ARGV[2]) }
7644616d0f9Sopenharmony_ci       ' ="$TZdate" ="$UTdate"
7654616d0f9Sopenharmony_ci    then
7664616d0f9Sopenharmony_ci      extra_info="
7674616d0f9Sopenharmony_ciSelected time is now:	$TZdate.
7684616d0f9Sopenharmony_ciUniversal Time is now:	$UTdate."
7694616d0f9Sopenharmony_ci      break
7704616d0f9Sopenharmony_ci    fi
7714616d0f9Sopenharmony_ci  done
7724616d0f9Sopenharmony_ci
7734616d0f9Sopenharmony_ci
7744616d0f9Sopenharmony_ci  # Output TZ info and ask the user to confirm.
7754616d0f9Sopenharmony_ci
7764616d0f9Sopenharmony_ci  echo >&2 ""
7774616d0f9Sopenharmony_ci  echo >&2 "Based on the following information:"
7784616d0f9Sopenharmony_ci  echo >&2 ""
7794616d0f9Sopenharmony_ci  case $time%$country_result%$region%$coord in
7804616d0f9Sopenharmony_ci  ?*%?*%?*%)
7814616d0f9Sopenharmony_ci    say >&2 "	$time$newline	$country_result$newline	$region";;
7824616d0f9Sopenharmony_ci  ?*%?*%%|?*%%?*%) say >&2 "	$time$newline	$country_result$region";;
7834616d0f9Sopenharmony_ci  ?*%%%)	say >&2 "	$time";;
7844616d0f9Sopenharmony_ci  %?*%?*%)	say >&2 "	$country_result$newline	$region";;
7854616d0f9Sopenharmony_ci  %?*%%)	say >&2 "	$country_result";;
7864616d0f9Sopenharmony_ci  %%?*%?*)	say >&2 "	coord $coord$newline	$region";;
7874616d0f9Sopenharmony_ci  %%%?*)	say >&2 "	coord $coord";;
7884616d0f9Sopenharmony_ci  *)		say >&2 "	TZ='$tz'"
7894616d0f9Sopenharmony_ci  esac
7904616d0f9Sopenharmony_ci  say >&2 ""
7914616d0f9Sopenharmony_ci  say >&2 "TZ='$tz' will be used.$extra_info"
7924616d0f9Sopenharmony_ci  say >&2 "Is the above information OK?"
7934616d0f9Sopenharmony_ci
7944616d0f9Sopenharmony_ci  doselect Yes No
7954616d0f9Sopenharmony_ci  ok=$select_result
7964616d0f9Sopenharmony_ci  case $ok in
7974616d0f9Sopenharmony_ci  Yes) break
7984616d0f9Sopenharmony_ci  esac
7994616d0f9Sopenharmony_cido coord=
8004616d0f9Sopenharmony_cidone
8014616d0f9Sopenharmony_ci
8024616d0f9Sopenharmony_cicase $SHELL in
8034616d0f9Sopenharmony_ci*csh) file=.login line="setenv TZ '$tz'";;
8044616d0f9Sopenharmony_ci*)    file=.profile line="TZ='$tz'; export TZ"
8054616d0f9Sopenharmony_ciesac
8064616d0f9Sopenharmony_ci
8074616d0f9Sopenharmony_citest -t 1 && say >&2 "
8084616d0f9Sopenharmony_ciYou can make this change permanent for yourself by appending the line
8094616d0f9Sopenharmony_ci	$line
8104616d0f9Sopenharmony_cito the file '$file' in your home directory; then log out and log in again.
8114616d0f9Sopenharmony_ci
8124616d0f9Sopenharmony_ciHere is that TZ value again, this time on standard output so that you
8134616d0f9Sopenharmony_cican use the $0 command in shell scripts:"
8144616d0f9Sopenharmony_ci
8154616d0f9Sopenharmony_cisay "$tz"
816