[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