* tzselect.ksh (_select): New function. --- tzselect.ksh | 130 +++++++++++++++++++++++++++++------------------------------ 1 file changed, 64 insertions(+), 66 deletions(-) diff --git a/tzselect.ksh b/tzselect.ksh index 1934dd0..89cdfe3 100644 --- a/tzselect.ksh +++ b/tzselect.ksh @@ -8,19 +8,10 @@ REPORT_BUGS_TO=tz@iana.org # Interact with the user via stderr and stdin. # Contributed by Paul Eggert. +# Korn/Bash-like _select function contributed by P. J. McDermott. # Porting notes: # -# This script requires a Posix-like shell with the extension of a -# 'select' statement. The 'select' statement was introduced in the -# Korn shell and is available in Bash and other shell implementations. -# If your host lacks both Bash and the Korn shell, you can get their -# source from one of these locations: -# -# Bash <http://www.gnu.org/software/bash/bash.html> -# Korn Shell <http://www.kornshell.com/> -# Public Domain Korn Shell <http://www.cs.mun.ca/~michael/pdksh/> -# # 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, # you can use either of the following free programs instead: @@ -28,6 +19,48 @@ REPORT_BUGS_TO=tz@iana.org # Gawk (GNU awk) <http://www.gnu.org/software/gawk/> # mawk <http://invisible-island.net/mawk/> +_select() +{( + # Field width of the prompt numbers. + width=$(printf 'scale = 0; l(%d) / l(10) + 1\n' $# | bc -l) + + reply= + while :; do + case "$reply" in + '') + i=0 + for word in "$@"; do + i=$(($i + 1)) + printf >&2 "%${width}d) %s\n" $i "$word" + done + ;; + *[!0-9]*) + printf >&2 'Please enter a number in range.\n' + ;; + *) + if [ $reply -gt 0 ] && [ $reply -le $# ]; then + i=0 + for word in "$@"; do + i=$(($i + 1)) + if [ $i -eq $reply ]; then + printf '%s\n' "$word" + return 0 + fi + done + fi + printf >&2 'Please enter a number in range.\n' + ;; + esac + + # Prompt and read input. + printf >&2 '%s' "${PS3-#? }" + if ! read -r reply; then + # EOF or error. + printf >&2 '\n' + return 1 + fi + done +)} # Specify default values for environment variables if they are unset. : ${AWK=awk} @@ -106,12 +139,6 @@ newline=' ' IFS=$newline - -# Work around a bug in bash 1.14.7 and earlier, where $PS3 is sent to stdout. -case $(echo 1 | (select x in x; do break; done) 2>/dev/null) in -?*) PS3= -esac - # Awk script to read a time zone table and output the same table, # with each column preceded by its distance from 'here'. output_distances=' @@ -208,21 +235,16 @@ while ) eval ' - select continent in '"$quoted_continents"' \ + if ! continent=$(_select '"$quoted_continents"' \ "coord - I want to use geographical coordinates." \ - "TZ - I want to specify the time zone using the Posix TZ format." - do - case $continent in - "") - echo >&2 "Please enter a number in range.";; - ?*) - case $continent in - Americas) continent=America;; - *" "*) continent=$(expr "$continent" : '\''\([^ ]*\)'\'') - esac - break - esac - done + "TZ - I want to specify the time zone using the Posix TZ format.") + then + exit 1 + fi + case $continent in + Americas) continent=America;; + *" "*) continent=$(expr "$continent" : '\''\([^ ]*\)'\'') + esac ' esac @@ -280,13 +302,9 @@ while 'time zone regions,' echo >&2 'listed roughly in increasing order' \ "of distance from $coord". - select region in $regions - do - case $region in - '') echo >&2 'Please enter a number in range.';; - ?*) break;; - esac - done + if ! region=$(_select $regions); then + exit 1 + fi TZ=$(echo "$distance_table" | $AWK -v region="$region" ' BEGIN { FS="\t" } $NF == region { print $4 } @@ -322,17 +340,10 @@ while *"$newline"*) echo >&2 'Please select a country' \ 'whose clocks agree with yours.' - select country in $countries - do - case $country in - '') echo >&2 'Please enter a number in range.';; - ?*) break - esac - done - - case $country in - '') exit 1 - esac;; + if ! country=$(_select $countries); then + exit 1 + fi + ;; *) country=$countries esac @@ -361,16 +372,10 @@ while *"$newline"*) echo >&2 'Please select one of the following' \ 'time zone regions.' - select region in $regions - do - case $region in - '') echo >&2 'Please enter a number in range.';; - ?*) break - esac - done - case $region in - '') exit 1 - esac;; + if ! region=$(_select $regions); then + exit 1 + fi + ;; *) region=$regions esac @@ -440,14 +445,7 @@ Universal Time is now: $UTdate." echo >&2 "Therefore TZ='$TZ' will be used.$extra_info" echo >&2 "Is the above information OK?" - ok= - select ok in Yes No - do - case $ok in - '') echo >&2 'Please enter 1 for Yes, or 2 for No.';; - ?*) break - esac - done + ok=$(_select Yes No) case $ok in '') exit 1;; Yes) break -- Patrick "P. J." McDermott http://www.pehjota.net/ Lead Developer, ProteanOS http://www.proteanos.com/