[tz] [PATCH 1/4] tzselect: Replace Korn/Bash-only select construct.
Patrick 'P. J.' McDermott
pj at pehjota.net
Sat Oct 5 16:34:17 UTC 2013
* 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 at 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 at 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/
More information about the tz
mailing list