dialog.subr revision 260678
1if [ ! "$_DIALOG_SUBR" ]; then _DIALOG_SUBR=1
2#
3# Copyright (c) 2006-2013 Devin Teske
4# All rights reserved.
5#
6# Redistribution and use in source and binary forms, with or without
7# modification, are permitted provided that the following conditions
8# are met:
9# 1. Redistributions of source code must retain the above copyright
10#    notice, this list of conditions and the following disclaimer.
11# 2. Redistributions in binary form must reproduce the above copyright
12#    notice, this list of conditions and the following disclaimer in the
13#    documentation and/or other materials provided with the distribution.
14#
15# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25# SUCH DAMAGE.
26#
27# $FreeBSD: stable/10/usr.sbin/bsdconfig/share/dialog.subr 260678 2014-01-15 07:49:17Z dteske $
28#
29############################################################ INCLUDES
30
31BSDCFG_SHARE="/usr/share/bsdconfig"
32. $BSDCFG_SHARE/common.subr || exit 1
33f_dprintf "%s: loading includes..." dialog.subr
34f_include $BSDCFG_SHARE/strings.subr
35f_include $BSDCFG_SHARE/variable.subr
36
37BSDCFG_LIBE="/usr/libexec/bsdconfig"
38f_include_lang $BSDCFG_LIBE/include/messages.subr
39
40############################################################ CONFIGURATION
41
42#
43# Default file descriptor to link to stdout for dialog(1) passthru allowing
44# execution of dialog from within a sub-shell (so-long as its standard output
45# is explicitly redirected to this file descriptor).
46#
47: ${DIALOG_TERMINAL_PASSTHRU_FD:=${TERMINAL_STDOUT_PASSTHRU:-3}}
48
49############################################################ GLOBALS
50
51#
52# Default name of dialog(1) utility
53# NOTE: This is changed to "Xdialog" by the optional `-X' argument
54#
55DIALOG="dialog"
56
57#
58# Default dialog(1) title and backtitle text
59#
60DIALOG_TITLE="$pgm"
61DIALOG_BACKTITLE="bsdconfig"
62
63#
64# Settings used while interacting with dialog(1)
65#
66DIALOG_MENU_TAGS="123456789ABCDEFGHIJKLMNOPQRSTUVWYZabcdefghijklmnopqrstuvwxyz"
67
68#
69# Declare that we are fully-compliant with Xdialog(1) by unset'ing all
70# compatibility settings.
71#
72unset XDIALOG_HIGH_DIALOG_COMPAT
73unset XDIALOG_FORCE_AUTOSIZE
74unset XDIALOG_INFOBOX_TIMEOUT
75
76#
77# Exit codes for [X]dialog(1)
78#
79DIALOG_OK=${SUCCESS:-0}
80DIALOG_CANCEL=${FAILURE:-1}
81DIALOG_HELP=2
82DIALOG_ITEM_HELP=2
83DIALOG_EXTRA=3
84DIALOG_ITEM_HELP=4
85export DIALOG_ERROR=254 # sh(1) can't handle the default of `-1'
86DIALOG_ESC=255
87
88#
89# Default behavior is to call f_dialog_init() automatically when loaded.
90#
91: ${DIALOG_SELF_INITIALIZE=1}
92
93#
94# Default terminal size (used if/when running without a controlling terminal)
95#
96: ${DEFAULT_TERMINAL_SIZE:=24 80}
97
98#
99# Minimum width(s) for various dialog(1) implementations (sensible global
100# default(s) for all widgets of a given variant)
101#
102: ${DIALOG_MIN_WIDTH:=24}
103: ${XDIALOG_MIN_WIDTH:=35}
104
105#
106# When manually sizing Xdialog(1) widgets such as calendar and timebox, you'll
107# need to know the size of the embedded GUI objects because the height passed
108# to Xdialog(1) for these widgets has to be tall enough to accomodate them.
109#
110# These values are helpful when manually sizing with dialog(1) too, but in a
111# different way. dialog(1) does not make you accomodate the custom items in the
112# height (but does for width) -- a height of 3 will display three lines and a
113# full calendar, for example (whereas Xdialog will truncate the calendar if
114# given a height of 3). For dialog(1), use these values for making sure that
115# the height does not exceed max_height (obtained by f_dialog_max_size()).
116#
117DIALOG_CALENDAR_HEIGHT=15
118DIALOG_TIMEBOX_HEIGHT=6
119
120############################################################ GENERIC FUNCTIONS
121
122# f_dialog_data_sanitize $var_to_edit ...
123#
124# When using dialog(1) or Xdialog(1) sometimes unintended warnings or errors
125# are generated from underlying libraries. For example, if $LANG is set to an
126# invalid or unknown locale, the warnings from the Xdialog(1) libraries will
127# clutter the output. This function helps by providing a centralied function
128# that removes spurious warnings from the dialog(1) (or Xdialog(1)) response.
129#
130# Simply pass the name of one or more variables that need to be sanitized.
131# After execution, the variables will hold their newly-sanitized data.
132#
133f_dialog_data_sanitize()
134{
135	if [ "$#" -eq 0 ]; then
136		f_dprintf "%s: called with zero arguments" \
137		          f_dialog_response_sanitize
138		return $FAILURE
139	fi
140
141	local __var_to_edit
142	for __var_to_edit in $*; do
143		# Skip warnings and trim leading/trailing whitespace
144		setvar $__var_to_edit "$( f_getvar $__var_to_edit | awk '
145			BEGIN { data = 0 }
146			{
147				if ( ! data )
148				{
149					if ( $0 ~ /^$/ ) next
150					if ( $0 ~ /^Gdk-WARNING \*\*:/ ) next
151					data = 1
152				}
153				print
154			}
155		' )"
156	done
157}
158
159# f_dialog_line_sanitize $var_to_edit ...
160#
161# When using dialog(1) or Xdialog(1) sometimes unintended warnings or errors
162# are generated from underlying libraries. For example, if $LANG is set to an
163# invalid or unknown locale, the warnings from the Xdialog(1) libraries will
164# clutter the output. This function helps by providing a centralied function
165# that removes spurious warnings from the dialog(1) (or Xdialog(1)) response.
166#
167# Simply pass the name of one or more variables that need to be sanitized.
168# After execution, the variables will hold their newly-sanitized data.
169#
170# This function, unlike f_dialog_data_sanitize(), also removes leading/trailing
171# whitespace from each line.
172#
173f_dialog_line_sanitize()
174{
175	if [ "$#" -eq 0 ]; then
176		f_dprintf "%s: called with zero arguments" \
177		          f_dialog_response_sanitize
178		return $FAILURE
179	fi
180
181	local __var_to_edit
182	for __var_to_edit in $*; do
183		# Skip warnings and trim leading/trailing whitespace
184		setvar $__var_to_edit "$( f_getvar $__var_to_edit | awk '
185			BEGIN { data = 0 }
186			{
187				if ( ! data )
188				{
189					if ( $0 ~ /^$/ ) next
190					if ( $0 ~ /^Gdk-WARNING \*\*:/ ) next
191					data = 1
192				}
193				sub(/^[[:space:]]*/, "")
194				sub(/[[:space:]]*$/, "")
195				print
196			}
197		' )"
198	done
199}
200
201############################################################ TITLE FUNCTIONS
202
203# f_dialog_title [$new_title]
204#
205# Set the title of future dialog(1) ($DIALOG_TITLE) or backtitle of Xdialog(1)
206# ($DIALOG_BACKTITLE) invocations. If no arguments are given or the first
207# argument is NULL, the current title is returned.
208#
209# Each time this function is called, a backup of the current values is made
210# allowing a one-time (single-level) restoration of the previous title using
211# the f_dialog_title_restore() function (below).
212#
213f_dialog_title()
214{
215	local new_title="$1"
216
217	if [ "${1+set}" ]; then
218		if [ "$USE_XDIALOG" ]; then
219			_DIALOG_BACKTITLE="$DIALOG_BACKTITLE"
220			DIALOG_BACKTITLE="$new_title"
221		else
222			_DIALOG_TITLE="$DIALOG_TITLE"
223			DIALOG_TITLE="$new_title"
224		fi
225	else
226		if [ "$USE_XDIALOG" ]; then
227			echo "$DIALOG_BACKTITLE"
228		else
229			echo "$DIALOG_TITLE"
230		fi
231	fi
232}
233
234# f_dialog_title_restore
235#
236# Restore the previous title set by the last call to f_dialog_title().
237# Restoration is non-recursive and only works to restore the most-recent title.
238#
239f_dialog_title_restore()
240{
241	if [ "$USE_XDIALOG" ]; then
242		DIALOG_BACKTITLE="$_DIALOG_BACKTITLE"
243	else
244		DIALOG_TITLE="$_DIALOG_TITLE"
245	fi
246}
247
248# f_dialog_backtitle [$new_backtitle]
249#
250# Set the backtitle of future dialog(1) ($DIALOG_BACKTITLE) or title of
251# Xdialog(1) ($DIALOG_TITLE) invocations. If no arguments are given or the
252# first argument is NULL, the current backtitle is returned.
253#
254f_dialog_backtitle()
255{
256	local new_backtitle="$1"
257
258	if [ "${1+set}" ]; then
259		if [ "$USE_XDIALOG" ]; then
260			_DIALOG_TITLE="$DIALOG_TITLE"
261			DIALOG_TITLE="$new_backtitle"
262		else
263			_DIALOG_BACKTITLE="$DIALOG_BACKTITLE"
264			DIALOG_BACKTITLE="$new_backtitle"
265		fi
266	else
267		if [ "$USE_XDIALOG" ]; then
268			echo "$DIALOG_TITLE"
269		else
270			echo "$DIALOG_BACKTITLE"
271		fi
272	fi
273}
274
275# f_dialog_backtitle_restore
276#
277# Restore the previous backtitle set by the last call to f_dialog_backtitle().
278# Restoration is non-recursive and only works to restore the most-recent
279# backtitle.
280#
281f_dialog_backtitle_restore()
282{
283	if [ "$USE_XDIALOG" ]; then
284		DIALOG_TITLE="$_DIALOG_TITLE"
285	else
286		DIALOG_BACKTITLE="$_DIALOG_BACKTITLE"
287	fi
288}
289
290############################################################ SIZE FUNCTIONS
291
292# f_dialog_max_size $var_height $var_width
293#
294# Get the maximum height and width for a dialog widget and store the values in
295# $var_height and $var_width (respectively).
296#
297f_dialog_max_size()
298{
299	local funcname=f_dialog_max_size
300	local __var_height="$1" __var_width="$2" __max_size
301	[ "$__var_height" -o "$__var_width" ] || return $FAILURE
302	if [ "$USE_XDIALOG" ]; then
303		__max_size="$XDIALOG_MAXSIZE" # see CONFIGURATION
304	else
305		if __max_size=$( $DIALOG --print-maxsize \
306			2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD )
307		then
308			f_dprintf "$funcname: %s --print-maxsize = [%s]" \
309			          "$DIALOG" "$__max_size"
310			# usually "MaxSize: 24, 80"
311			__max_size="${__max_size#*: }"
312			f_replaceall "$__max_size" "," "" __max_size
313		else
314			f_eval_catch -dk __max_size $funcname stty \
315				'stty size' || __max_size=
316			# usually "24 80"
317		fi
318		: ${__max_size:=$DEFAULT_TERMINAL_SIZE}
319	fi
320	if [ "$__var_height" ]; then
321		local __height="${__max_size%%[$IFS]*}"
322		#
323		# If we're not using Xdialog(1), we should assume that $DIALOG
324		# will render --backtitle behind the widget. In such a case, we
325		# should prevent a widget from obscuring the backtitle (unless
326		# $NO_BACKTITLE is set and non-NULL, allowing a trap-door).
327		#
328		if [ ! "$USE_XDIALOG" ] && [ ! "$NO_BACKTITLE" ]; then
329			#
330			# If use_shadow (in ~/.dialogrc) is OFF, we need to
331			# subtract 4, otherwise 5. However, don't check this
332			# every time, rely on an initialization variable set
333			# by f_dialog_init().
334			#
335			local __adjust=5
336			[ "$NO_SHADOW" ] && __adjust=4
337
338			# Don't adjust height if already too small (allowing
339			# obscured backtitle for small values of __height).
340			[ ${__height:-0} -gt 11 ] &&
341				__height=$(( $__height - $__adjust ))
342		fi
343		setvar "$__var_height" "$__height"
344	fi
345	[ "$__var_width" ] && setvar "$__var_width" "${__max_size##*[$IFS]}"
346}
347
348# f_dialog_size_constrain $var_height $var_width [$min_height [$min_width]]
349#
350# Modify $var_height to be no-less-than $min_height (if given; zero otherwise)
351# and no-greater-than terminal height (or screen height if $USE_XDIALOG is
352# set).
353#
354# Also modify $var_width to be no-less-than $XDIALOG_MIN_WIDTH (or
355# $XDIALOG_MIN_WIDTH if $_USE_XDIALOG is set) and no-greater-than terminal
356# or screen width. The use of $[X]DIALOG_MIN_WIDTH can be overridden by
357# passing $min_width.
358#
359# Return status is success unless one of the passed arguments is invalid
360# or all of the $var_* arguments are either NULL or missing.
361#
362f_dialog_size_constrain()
363{
364	local __var_height="$1" __var_width="$2"
365	local __min_height="$3" __min_width="$4"
366	local __retval=$SUCCESS
367
368	# Return failure unless at least one var_* argument is passed
369	[ "$__var_height" -o "$__var_width" ] || return $FAILURE
370
371	#
372	# Print debug warnings if any given (non-NULL) argument are invalid
373	# NOTE: Don't change the name of $__{var,min,}{height,width}
374	#
375	local __height __width
376	local __arg __cp __fname=f_dialog_size_constrain 
377	for __arg in height width; do
378		debug= f_getvar __var_$__arg __cp
379		[ "$__cp" ] || continue
380		if ! debug= f_getvar "$__cp" __$__arg; then
381			f_dprintf "%s: var_%s variable \`%s' not set" \
382			          $__fname $__arg "$__cp"
383			__retval=$FAILURE
384		elif ! eval f_isinteger \$__$__arg; then
385			f_dprintf "%s: var_%s variable value not a number" \
386			          $__fname $__arg
387			__retval=$FAILURE
388		fi
389	done
390	for __arg in height width; do
391		debug= f_getvar __min_$__arg __cp
392		[ "$__cp" ] || continue
393		f_isinteger "$__cp" && continue
394		f_dprintf "%s: min_%s value not a number" $__fname $__arg
395		__retval=$FAILURE
396		setvar __min_$__arg ""
397	done
398
399	# Obtain maximum height and width values
400	# NOTE: Function name appended to prevent __var_{height,width} values
401	#       from becoming local (and thus preventing setvar from working).
402	local __max_height_size_constain __max_width_size_constrain
403	f_dialog_max_size \
404		__max_height_size_constrain __max_width_size_constrain
405
406	# Adjust height if desired
407	if [ "$__var_height" ]; then
408		if [ $__height -lt ${__min_height:-0} ]; then
409			setvar "$__var_height" $__min_height
410		elif [ $__height -gt $__max_height_size_constrain ]; then
411			setvar "$__var_height" $__max_height_size_constrain
412		fi
413	fi
414
415	# Adjust width if desired
416	if [ "$__var_width" ]; then
417		if [ "$USE_XDIALOG" ]; then
418			: ${__min_width:=${XDIALOG_MIN_WIDTH:-35}}
419		else
420			: ${__min_width:=${DIALOG_MIN_WIDTH:-24}}
421		fi
422		if [ $__width -lt $__min_width ]; then
423			setvar "$__var_width" $__min_width
424		elif [ $__width -gt $__max_width_size_constrain ]; then
425			setvar "$__var_width" $__max_width_size_constrain
426		fi
427	fi
428
429	if [ "$debug" ]; then
430		# Print final constrained values to debugging
431		[ "$__var_height" ] && f_quietly f_getvar "$__var_height"
432		[ "$__var_width"  ] && f_quietly f_getvar "$__var_width"
433	fi
434
435	return $__retval # success if no debug warnings were printed
436}
437
438# f_dialog_menu_constrain $var_height $var_width $var_rows "$prompt" \
439#                         [$min_height [$min_width [$min_rows]]]
440#
441# Modify $var_height to be no-less-than $min_height (if given; zero otherwise)
442# and no-greater-than terminal height (or screen height if $USE_XDIALOG is
443# set).
444#
445# Also modify $var_width to be no-less-than $XDIALOG_MIN_WIDTH (or
446# $XDIALOG_MIN_WIDTH if $_USE_XDIALOG is set) and no-greater-than terminal
447# or screen width. The use of $[X]DIALOG_MIN_WIDTH can be overridden by
448# passing $min_width.
449#
450# Last, modify $var_rows to be no-less-than $min_rows (if specified; zero
451# otherwise) and no-greater-than (max_height - 8) where max_height is the
452# terminal height (or screen height if $USE_XDIALOG is set). If $prompt is NULL
453# or missing, dialog(1) allows $var_rows to be (max_height - 7), maximizing the
454# number of visible rows.
455#
456# Return status is success unless one of the passed arguments is invalid
457# or all of the $var_* arguments are either NULL or missing.
458#
459f_dialog_menu_constrain()
460{
461	local __var_height="$1" __var_width="$2" __var_rows="$3" __prompt="$4"
462	local __min_height="$5" __min_width="$6" __min_rows="$7"
463
464	# Return failure unless at least one var_* argument is passed
465	[ "$__var_height" -o "$__var_width" -o "$__var_rows" ] ||
466		return $FAILURE
467
468	#
469	# Print debug warnings if any given (non-NULL) argument are invalid
470	# NOTE: Don't change the name of $__{var,min,}{height,width,rows}
471	#
472	local __height __width __rows
473	local __arg __cp __fname=f_dialog_menu_constrain 
474	for __arg in height width rows; do
475		debug= f_getvar __var_$__arg __cp
476		[ "$__cp" ] || continue
477		if ! debug= f_getvar "$__cp" __$__arg; then
478			f_dprintf "%s: var_%s variable \`%s' not set" \
479			          $__fname $__arg "$__cp"
480			__retval=$FAILURE
481		elif ! eval f_isinteger \$__$__arg; then
482			f_dprintf "%s: var_%s variable value not a number" \
483			          $__fname $__arg
484			__retval=$FAILURE
485		fi
486	done
487	for __arg in height width rows; do
488		debug= f_getvar __min_$__arg __cp
489		[ "$__cp" ] || continue
490		f_isinteger "$__cp" && continue
491		f_dprintf "%s: min_%s value not a number" $__fname $__arg
492		__retval=$FAILURE
493		setvar __min_$__arg ""
494	done
495
496	# Obtain maximum height and width values
497	# NOTE: Function name appended to prevent __var_{height,width} values
498	#       from becoming local (and thus preventing setvar from working).
499	local __max_height_menu_constrain __max_width_menu_constrain
500	f_dialog_max_size \
501		__max_height_menu_constrain __max_width_menu_constrain
502
503	# Adjust height if desired
504	if [ "$__var_height" ]; then
505		if [ $__height -lt ${__min_height:-0} ]; then
506			setvar "$__var_height" $__min_height
507		elif [ $__height -gt $__max_height_menu_constrain ]; then
508			setvar "$__var_height" $__max_height_menu_constrain
509		fi
510	fi
511
512	# Adjust width if desired
513	if [ "$__var_width" ]; then
514		if [ "$USE_XDIALOG" ]; then
515			: ${__min_width:=${XDIALOG_MIN_WIDTH:-35}}
516		else
517			: ${__min_width:=${DIALOG_MIN_WIDTH:-24}}
518		fi
519		if [ $__width -lt $__min_width ]; then
520			setvar "$__var_width" $__min_width
521		elif [ $__width -gt $__max_width_menu_constrain ]; then
522			setvar "$__var_width" $__max_width_menu_constrain
523		fi
524	fi
525
526	# Adjust rows if desired
527	if [ "$__var_rows" ]; then
528		if [ "$USE_XDIALOG" ]; then
529			: ${__min_rows:=1}
530		else
531			: ${__min_rows:=0}
532		fi
533
534		local __max_rows=$(( $__max_height_menu_constrain - 7 ))
535		# If prompt_len is zero (no prompt), bump the max-rows by 1
536		# Default assumption is (if no argument) that there's no prompt
537		[ ${__prompt_len:-0} -gt 0 ] ||
538			__max_rows=$(( $__max_rows + 1 ))
539
540		if [ $__rows -lt $__min_rows ]; then
541			setvar "$__var_rows" $__min_rows
542		elif [ $__rows -gt $__max_rows ]; then
543			setvar "$__var_rows" $__max_rows
544		fi
545	fi
546
547	if [ "$debug" ]; then
548		# Print final constrained values to debugging
549		[ "$__var_height" ] && f_quietly f_getvar "$__var_height"
550		[ "$__var_width"  ] && f_quietly f_getvar "$__var_width"
551		[ "$__var_rows"   ] && f_quietly f_getvar "$__var_rows"
552	fi
553
554	return $__retval # success if no debug warnings were printed
555}
556
557# f_dialog_infobox_size [-n] $var_height $var_width \
558#                       $title $backtitle $prompt [$hline]
559#
560# Not all versions of dialog(1) perform auto-sizing of the width and height of
561# `--infobox' boxes sensibly.
562#
563# This function helps solve this issue by taking two sets of sequential
564# arguments. The first set of arguments are the variable names to use when
565# storing the calculated height and width. The second set of arguments are the
566# title, backtitle, prompt, and [optionally] hline. The optimal height and
567# width for the described widget (not exceeding the actual terminal height or
568# width) is stored in $var_height and $var_width (respectively).
569#
570# If the first argument is `-n', the calculated sizes ($var_height and
571# $var_width) are not constrained to minimum/maximum values.
572#
573# Newline character sequences (``\n'') in $prompt are expanded as-is done by
574# dialog(1).
575#
576f_dialog_infobox_size()
577{
578	local __constrain=1
579	[ "$1" = "-n" ] && __constrain= && shift 1 # -n
580	local __var_height="$1" __var_width="$2"
581	local __title="$3" __btitle="$4" __prompt="$5" __hline="$6"
582
583	# Return unless at least one size aspect has been requested
584	[ "$__var_height" -o "$__var_width" ] || return $FAILURE
585
586	# Default height/width of zero for auto-sizing
587	local __height=0 __width=0 __n
588
589	# Adjust height if desired
590	if [ "$__var_height" ]; then
591		#
592		# Set height based on number of rows in prompt
593		#
594		__n=$( echo -n "$__prompt" | f_number_of_lines )
595		__n=$(( $__n + 2 ))
596		[ $__n -gt $__height ] && __height=$__n
597
598		#
599		# For Xdialog(1) bump height if backtitle is enabled (displayed
600		# in the X11 window with a separator line between the backtitle
601		# and msg text).
602		#
603		if [ "$USE_XDIALOG" -a "$__btitle" ]; then
604			__n=$( echo "$__btitle" | f_number_of_lines )
605			__height=$(( $__height + $__n + 2 ))
606		fi
607
608		setvar "$__var_height" $__height
609	fi
610
611	# Adjust width if desired
612	if [ "$__var_width" ]; then
613		#
614		# Bump width for long titles
615		#
616		__n=$(( ${#__title} + 4 ))
617		[ $__n -gt $__width ] && __width=$__n
618
619		#
620		# If using Xdialog(1), bump width for long backtitles (which
621		# appear within the window).
622		#
623		if [ "$USE_XDIALOG" ]; then
624			__n=$(( ${#__btitle} + 4 ))
625			[ $__n -gt $__width ] && __width=$__n
626		fi
627
628		#
629		# Bump width for long prompts
630		#
631		__n=$( echo "$__prompt" | f_longest_line_length )
632		__n=$(( $__n + 4 )) # add width for border
633		[ $__n -gt $__width ] && __width=$__n
634
635		#
636		# Bump width for long hlines. Xdialog(1) supports `--hline' but
637		# it's currently not used (so don't do anything here if using
638		# Xdialog(1)).
639		#
640		if [ ! "$USE_XDIALOG" ]; then
641			__n=$(( ${#__hline} + 10 ))
642			[ $__n -gt $__width ] && __width=$__n
643		fi
644
645		# Bump width by 16.6% if using Xdialog(1)
646		[ "$USE_XDIALOG" ] && __width=$(( $__width + $__width / 6 ))
647
648		setvar "$__var_width" $__width
649	fi
650
651	# Constrain values to sensible minimums/maximums unless `-n' was passed
652	# Return success if no-constrain, else return status from constrain
653	[ ! "$__constrain" ] ||
654		f_dialog_size_constrain "$__var_height" "$__var_width"
655}
656
657# f_dialog_buttonbox_size [-n] $var_height $var_width \
658#                         $title $backtitle $prompt [$hline]
659#
660# Not all versions of dialog(1) perform auto-sizing of the width and height of
661# `--msgbox' and `--yesno' boxes sensibly.
662#
663# This function helps solve this issue by taking two sets of sequential
664# arguments. The first set of arguments are the variable names to use when
665# storing the calculated height and width. The second set of arguments are the
666# title, backtitle, prompt, and [optionally] hline. The optimal height and
667# width for the described widget (not exceeding the actual terminal height or
668# width) is stored in $var_height and $var_width (respectively).
669#
670# If the first argument is `-n', the calculated sizes ($var_height and
671# $var_width) are not constrained to minimum/maximum values.
672#
673# Newline character sequences (``\n'') in $prompt are expanded as-is done by
674# dialog(1).
675#
676f_dialog_buttonbox_size()
677{
678	local __constrain=1
679	[ "$1" = "-n" ] && __constrain= && shift 1 # -n
680	local __var_height="$1" __var_width="$2"
681	local __title="$3" __btitle="$4" __prompt="$5" __hline="$6"
682
683	# Return unless at least one size aspect has been requested
684	[ "$__var_height" -o "$__var_width" ] || return $FAILURE
685
686	# Calculate height/width of infobox (adjusted/constrained below)
687	# NOTE: Function name appended to prevent __var_{height,width} values
688	#       from becoming local (and thus preventing setvar from working).
689	local __height_bbox_size __width_bbox_size
690	f_dialog_infobox_size -n \
691		"${__var_height:+__height_bbox_size}" \
692		"${__var_width:+__width_bbox_size}" \
693		"$__title" "$__btitle" "$__prompt" "$__hline"
694
695	# Adjust height if desired
696	if [ "$__var_height" ]; then
697		# Add height to accomodate the buttons
698		__height_bbox_size=$(( $__height_bbox_size + 2 ))
699
700		# Adjust for clipping with Xdialog(1) on Linux/GTK2
701		[ "$USE_XDIALOG" ] &&
702			__height_bbox_size=$(( $__height_bbox_size + 3 ))
703
704		setvar "$__var_height" $__height_bbox_size
705	fi
706
707	# No adjustemnts to width, just pass-thru the infobox width
708	if [ "$__var_width" ]; then
709		setvar "$__var_width" $__width_bbox_size
710	fi
711
712	# Constrain values to sensible minimums/maximums unless `-n' was passed
713	# Return success if no-constrain, else return status from constrain
714	[ ! "$__constrain" ] ||
715		f_dialog_size_constrain "$__var_height" "$__var_width"
716}
717
718# f_dialog_inputbox_size [-n] $var_height $var_width \
719#                        $title $backtitle $prompt $init [$hline]
720#
721# Not all versions of dialog(1) perform auto-sizing of the width and height of
722# `--inputbox' boxes sensibly.
723#
724# This function helps solve this issue by taking two sets of sequential
725# arguments. The first set of arguments are the variable names to use when
726# storing the calculated height and width. The second set of arguments are the
727# title, backtitle, prompt, and [optionally] hline. The optimal height and
728# width for the described widget (not exceeding the actual terminal height or
729# width) is stored in $var_height and $var_width (respectively).
730#
731# If the first argument is `-n', the calculated sizes ($var_height and
732# $var_width) are not constrained to minimum/maximum values.
733#
734# Newline character sequences (``\n'') in $prompt are expanded as-is done by
735# dialog(1).
736#
737f_dialog_inputbox_size()
738{
739	local __constrain=1
740	[ "$1" = "-n" ] && __constrain= && shift 1 # -n
741	local __var_height="$1" __var_width="$2"
742	local __title="$3" __btitle="$4" __prompt="$5" __init="$6" __hline="$7"
743
744	# Return unless at least one size aspect has been requested
745	[ "$__var_height" -o "$__var_width" ] || return $FAILURE
746
747	# Calculate height/width of buttonbox (adjusted/constrained below)
748	# NOTE: Function name appended to prevent __var_{height,width} values
749	#       from becoming local (and thus preventing setvar from working).
750	local __height_ibox_size __width_ibox_size
751	f_dialog_buttonbox_size -n \
752		"${__var_height:+__height_ibox_size}" \
753		"${__var_width:+__width_ibox_size}" \
754		"$__title" "$__btitle" "$__prompt" "$__hline"
755
756	# Adjust height if desired
757	if [ "$__var_height" ]; then
758		# Add height for input box (not needed for Xdialog(1))
759		[ ! "$USE_XDIALOG" ] &&
760			__height_ibox_size=$(( $__height_ibox_size + 3 ))
761
762		setvar "$__var_height" $__height_ibox_size
763	fi
764
765	# Adjust width if desired
766	if [ "$__var_width" ]; then
767		# Bump width for initial text (something neither dialog(1) nor
768		# Xdialog(1) do, but worth it!; add 16.6% if using Xdialog(1))
769		local __n=$(( ${#__init} + 7 ))
770		[ "$USE_XDIALOG" ] && __n=$(( $__n + $__n / 6 ))
771		[ $__n -gt $__width_ibox_size ] && __width_ibox_size=$__n
772
773		setvar "$__var_width" $__width_ibox_size
774	fi
775
776	# Constrain values to sensible minimums/maximums unless `-n' was passed
777	# Return success if no-constrain, else return status from constrain
778	[ ! "$__constrain" ] ||
779		f_dialog_size_constrain "$__var_height" "$__var_width"
780}
781
782# f_xdialog_2inputsbox_size [-n] $var_height $var_width \
783#                           $title $backtitle $prompt \
784#                           $label1 $init1 $label2 $init2
785#
786# Xdialog(1) does not perform auto-sizing of the width and height of
787# `--2inputsbox' boxes sensibly.
788#
789# This function helps solve this issue by taking two sets of sequential
790# arguments. The first set of arguments are the variable names to use when
791# storing the calculated height and width. The second set of arguments are the
792# title, backtitle, prompt, label for the first field, initial text for said
793# field, label for the second field, and initial text for said field. The
794# optimal height and width for the described widget (not exceeding the actual
795# terminal height or width) is stored in $var_height and $var_width
796# (respectively).
797#
798# If the first argument is `-n', the calculated sizes ($var_height and
799# $var_width) are not constrained to minimum/maximum values.
800#
801# Newline character sequences (``\n'') in $prompt are expanded as-is done by
802# Xdialog(1).
803#
804f_xdialog_2inputsbox_size()
805{
806	local __constrain=1
807	[ "$1" = "-n" ] && __constrain= && shift 1 # -n
808	local __var_height="$1" __var_width="$2"
809	local __title="$3" __btitle="$4" __prompt="$5"
810	local __label1="$6" __init1="$7" __label2="$8" __init2="$9"
811
812	# Return unless at least one size aspect has been requested
813	[ "$__var_height" -o "$__var_width" ] || return $FAILURE
814
815	# Calculate height/width of inputbox (adjusted/constrained below)
816	# NOTE: Function name appended to prevent __var_{height,width} values
817	#       from becoming local (and thus preventing setvar from working).
818	local __height_2ibox_size __width_2ibox_size
819	f_dialog_inputbox_size -n \
820		"${__var_height:+__height_2ibox_size}" \
821		"${__var_width:+__width_2ibox_size}" \
822		"$__title" "$__btitle" "$__prompt" "$__hline" "$__init1"
823	
824	# Adjust height if desired
825	if [ "$__var_height" ]; then
826		# Add height for 1st label, 2nd label, and 2nd input box
827		__height_2ibox_size=$(( $__height_2ibox_size + 2 + 2 + 2  ))
828		setvar "$__var_height" $__height_2ibox_size
829	fi
830
831	# Adjust width if desired
832	if [ "$__var_width" ]; then
833		local __n
834
835		# Bump width for first label text (+16.6% since Xdialog(1))
836		__n=$(( ${#__label1} + 7 ))
837		__n=$(( $__n + $__n / 6 ))
838		[ $__n -gt $__width_2ibox_size ] && __width_2ibox_size=$__n
839
840		# Bump width for second label text (+16.6% since Xdialog(1))
841		__n=$(( ${#__label2} + 7 ))
842		__n=$(( $__n + $__n / 6 ))
843		[ $__n -gt $__width_2ibox_size ] && __width_2ibox_size=$__n
844
845		# Bump width for 2nd initial text (something neither dialog(1)
846		# nor Xdialog(1) do, but worth it!; +16.6% since Xdialog(1))
847		__n=$(( ${#__init2} + 7 ))
848		__n=$(( $__n + $__n / 6 ))
849		[ $__n -gt $__width_2ibox_size ] && __width_2ibox_size=$__n
850
851		setvar "$__var_width" $__width_2ibox_size
852	fi
853
854	# Constrain values to sensible minimums/maximums unless `-n' was passed
855	# Return success if no-constrain, else return status from constrain
856	[ ! "$__constrain" ] ||
857		f_dialog_size_constrain "$__var_height" "$__var_width"
858}
859
860# f_dialog_menu_size [-n] $var_height $var_width $var_rows \
861#                    $title $backtitle $prompt $hline \
862#                    $tag1 $item1 $tag2 $item2 ...
863#
864# Not all versions of dialog(1) perform auto-sizing of the width and height of
865# `--menu' boxes sensibly.
866#
867# This function helps solve this issue by taking three sets of sequential
868# arguments. The first set of arguments are the variable names to use when
869# storing the calculated height, width, and rows. The second set of arguments
870# are the title, backtitle, prompt, and hline. The [optional] third set of
871# arguments are the menu list itself (comprised of tag/item couplets). The
872# optimal height, width, and rows for the described widget (not exceeding the
873# actual terminal height or width) is stored in $var_height, $var_width, and
874# $var_rows (respectively).
875#
876# If the first argument is `-n', the calculated sizes ($var_height, $var_width,
877# and $var_rows) are not constrained to minimum/maximum values.
878#
879f_dialog_menu_size()
880{
881	local __constrain=1
882	[ "$1" = "-n" ] && __constrain= && shift 1 # -n
883	local __var_height="$1" __var_width="$2" __var_rows="$3"
884	local __title="$4" __btitle="$5" __prompt="$6" __hline="$7"
885	shift 7 # var_height/var_width/var_rows/title/btitle/prompt/hline
886
887	# Return unless at least one size aspect has been requested
888	[ "$__var_height" -o "$__var_width" -o "$__var_rows" ] ||
889		return $FAILURE
890
891	# Calculate height/width of infobox (adjusted/constrained below)
892	# NOTE: Function name appended to prevent __var_{height,width} values
893	#       from becoming local (and thus preventing setvar from working).
894	local __height_menu_size __width_menu_size
895	f_dialog_infobox_size -n \
896		"${__var_height:+__height_menu_size}" \
897		"${__var_width:+__width_menu_size}" \
898		"$__title" "$__btitle" "$__prompt" "$__hline"
899
900	#
901	# Always process the menu-item arguments to get the longest tag-length,
902	# longest item-length (both used to bump the width), and the number of
903	# rows (used to bump the height).
904	#
905	local __longest_tag=0 __longest_item=0 __rows=0
906	while [ $# -ge 2 ]; do
907		local __tag="$1" __item="$2"
908		shift 2 # tag/item
909		[ ${#__tag} -gt $__longest_tag ] && __longest_tag=${#__tag}
910		[ ${#__item} -gt $__longest_item ] && __longest_item=${#__item}
911		__rows=$(( $__rows + 1 ))
912	done
913
914	# Adjust rows early (for up-comning height calculation)
915	if [ "$__var_height" -o "$__var_rows" ]; then
916		# Add a row for visual aid if using Xdialog(1)
917		[ "$USE_XDIALOG" ] && __rows=$(( $__rows + 1 ))
918	fi
919
920	# Adjust height if desired
921	if [ "$__var_height" ]; then
922		# Add rows to height
923		if [ "$USE_XDIALOG" ]; then
924			__height_menu_size=$((
925				$__height_menu_size + $__rows + 7 ))
926		else
927			__height_menu_size=$((
928				$__height_menu_size + $__rows + 4 ))
929		fi
930		setvar "$__var_height" $__height_menu_size
931	fi
932
933	# Adjust width if desired
934	if [ "$__var_width" ]; then
935		# The sum total between the longest tag-length and the
936		# longest item-length should be used to bump menu width
937		local __n=$(( $__longest_tag + $__longest_item + 10 ))
938		[ "$USE_XDIALOG" ] && __n=$(( $__n + $__n / 6 )) # plus 16.6%
939		[ $__n -gt $__width_menu_size ] && __width_menu_size=$__n
940
941		setvar "$__var_width" $__width_menu_size
942	fi
943
944	# Store adjusted rows if desired
945	[ "$__var_rows" ] && setvar "$__var_rows" $__rows
946
947	# Constrain height, width, and rows to sensible minimum/maximum values
948	# Return success if no-constrain, else return status from constrain
949	[ ! "$__constrain" ] || f_dialog_menu_constrain \
950		"$__var_height" "$__var_width" "$__var_rows" "$__prompt"
951}
952
953# f_dialog_menu_with_help_size [-n] $var_height $var_width $var_rows \
954#                              $title $backtitle $prompt $hline \
955#                              $tag1 $item1 $help1 $tag2 $item2 $help2 ...
956#
957# Not all versions of dialog(1) perform auto-sizing of the width and height of
958# `--menu' boxes sensibly.
959#
960# This function helps solve this issue by taking three sets of sequential
961# arguments. The first set of arguments are the variable names to use when
962# storing the calculated height, width, and rows. The second set of arguments
963# are the title, backtitle, prompt, and hline. The [optional] third set of
964# arguments are the menu list itself (comprised of tag/item/help triplets). The
965# optimal height, width, and rows for the described widget (not exceeding the
966# actual terminal height or width) is stored in $var_height, $var_width, and
967# $var_rows (respectively).
968#
969# If the first argument is `-n', the calculated sizes ($var_height, $var_width,
970# and $var_rows) are not constrained to minimum/maximum values.
971#
972f_dialog_menu_with_help_size()
973{
974	local __constrain=1
975	[ "$1" = "-n" ] && __constrain= && shift 1 # -n
976	local __var_height="$1" __var_width="$2" __var_rows="$3"
977	local __title="$4" __btitle="$5" __prompt="$6" __hline="$7"
978	shift 7 # var_height/var_width/var_rows/title/btitle/prompt/hline
979
980	# Return unless at least one size aspect has been requested
981	[ "$__var_height" -o "$__var_width" -o "$__var_rows" ] ||
982		return $FAILURE
983
984	# Calculate height/width of infobox (adjusted/constrained below)
985	# NOTE: Function name appended to prevent __var_{height,width} values
986	#       from becoming local (and thus preventing setvar from working).
987	local __height_menu_with_help_size __width_menu_with_help_size
988	f_dialog_infobox_size -n \
989		"${__var_height:+__height_menu_with_help_size}" \
990		"${__var_width:+__width_menu_with_help_size}" \
991		"$__title" "$__btitle" "$__prompt" "$__hline"
992
993	#
994	# Always process the menu-item arguments to get the longest tag-length,
995	# longest item-length, longest help-length (help-length only considered
996	# if using Xdialog(1), as it places the help string in the widget) --
997	# all used to bump the width -- and the number of rows (used to bump
998	# the height).
999	#
1000	local __longest_tag=0 __longest_item=0 __longest_help=0 __rows=0
1001	while [ $# -ge 3 ]; do
1002		local __tag="$1" __item="$2" __help="$3"
1003		shift 3 # tag/item/help
1004		[ ${#__tag} -gt $__longest_tag ] && __longest_tag=${#__tag}
1005		[ ${#__item} -gt $__longest_item ] && __longest_item=${#__item}
1006		[ ${#__help} -gt $__longest_help ] && __longest_help=${#__help}
1007		__rows=$(( $__rows + 1 ))
1008	done
1009
1010	# Adjust rows early (for up-coming height calculation)
1011	if [ "$__var_height" -o "$__var_rows" ]; then
1012		# Add a row for visual aid if using Xdialog(1)
1013		[ "$USE_XDIALOG" ] && __rows=$(( $__rows + 1 ))
1014	fi
1015
1016	# Adjust height if desired
1017	if [ "$__var_height" ]; then
1018		# Add rows to height
1019		if [ "$USE_XDIALOG" ]; then
1020			__height_menu_with_help_size=$((
1021				$__height_menu_with_help_size + $__rows + 8 ))
1022		else
1023			__height_menu_with_help_size=$((
1024				$__height_menu_with_help_size + $__rows + 4 ))
1025		fi
1026		setvar "$__var_height" $__height_menu_with_help_size
1027	fi
1028
1029	# Adjust width if desired
1030	if [ "$__var_width" ]; then
1031		# The sum total between the longest tag-length and the
1032		# longest item-length should be used to bump menu width
1033		local __n=$(( $__longest_tag + $__longest_item + 10 ))
1034		[ "$USE_XDIALOG" ] && __n=$(( $__n + $__n / 6 )) # plus 16.6%
1035		[ $__n -gt $__width_menu_with_help_size ] &&
1036			__width_menu_with_help_size=$__n
1037
1038		# Update width for help text if using Xdialog(1)
1039		if [ "$USE_XDIALOG" ]; then
1040			__n=$(( $__longest_help + 10 ))
1041			__n=$(( $__n + $__n / 6 )) # plus 16.6%
1042			[ $__n -gt $__width_menu_with_help_size ] &&
1043				__width_menu_with_help_size=$__n
1044		fi
1045
1046		setvar "$__var_width" $__width_menu_with_help_size
1047	fi
1048
1049	# Store adjusted rows if desired
1050	[ "$__var_rows" ] && setvar "$__var_rows" $__rows
1051
1052	# Constrain height, width, and rows to sensible minimum/maximum values
1053	# Return success if no-constrain, else return status from constrain
1054	[ ! "$__constrain" ] || f_dialog_menu_constrain \
1055		"$__var_height" "$__var_width" "$__var_rows" "$__prompt"
1056}
1057
1058# f_dialog_radiolist_size [-n] $var_height $var_width $var_rows \
1059#                         $title $backtitle $prompt $hline \
1060#                         $tag1 $item1 $status1 $tag2 $item2 $status2 ...
1061#
1062# Not all versions of dialog(1) perform auto-sizing of the width and height of
1063# `--radiolist' boxes sensibly.
1064#
1065# This function helps solve this issue by taking three sets of sequential
1066# arguments. The first set of arguments are the variable names to use when
1067# storing the calculated height, width, and rows. The second set of arguments
1068# are the title, backtitle, prompt, and hline. The [optional] third set of
1069# arguments are the radio list itself (comprised of tag/item/status triplets).
1070# The optimal height, width, and rows for the described widget (not exceeding
1071# the actual terminal height or width) is stored in $var_height, $var_width,
1072# and $var_rows (respectively).
1073#
1074# If the first argument is `-n', the calculated sizes ($var_height, $var_width,
1075# and $var_rows) are not constrained to minimum/maximum values.
1076#
1077f_dialog_radiolist_size()
1078{
1079	local __constrain=1
1080	[ "$1" = "-n" ] && __constrain= && shift 1 # -n
1081	local __var_height="$1" __var_width="$2" __var_rows="$3"
1082	local __title="$4" __btitle="$5" __prompt="$6" __hline="$7"
1083	shift 7 # var_height/var_width/var_rows/title/btitle/prompt/hline
1084
1085	# Return unless at least one size aspect has been requested
1086	[ "$__var_height" -o "$__var_width" -o "$__var_rows" ] ||
1087		return $FAILURE
1088
1089	# Calculate height/width of infobox (adjusted/constrained below)
1090	# NOTE: Function name appended to prevent __var_{height,width} values
1091	#       from becoming local (and thus preventing setvar from working).
1092	local __height_rlist_size __width_rlist_size
1093	f_dialog_infobox_size -n \
1094		"${__var_height:+__height_rlist_size}" \
1095		"${__var_width:+__width_rlist_size}" \
1096		"$__title" "$__btitle" "$__prompt" "$__hline"
1097
1098	#
1099	# Always process the menu-item arguments to get the longest tag-length,
1100	# longest item-length (both used to bump the width), and the number of
1101	# rows (used to bump the height).
1102	#
1103	local __longest_tag=0 __longest_item=0 __rows=0
1104	while [ $# -ge 3 ]; do
1105		local __tag="$1" __item="$2"
1106		shift 3 # tag/item/status
1107		[ ${#__tag} -gt $__longest_tag ] && __longest_tag=${#__tag}
1108		[ ${#__item} -gt $__longest_item ] && __longest_item=${#__item}
1109		__rows=$(( $__rows + 1 ))
1110	done
1111
1112	# Adjust rows early (for up-coming height calculation)
1113	if [ "$__var_height" -o "$__var_rows" ]; then
1114		# Add a row for visual aid if using Xdialog(1)
1115		[ "$USE_XDIALOG" ] && __rows=$(( $__rows + 1 ))
1116	fi
1117
1118	# Adjust height if desired
1119	if [ "$__var_height" ]; then
1120		# Add rows to height
1121		if [ "$USE_XDIALOG" ]; then
1122			__height_rlist_size=$((
1123				$__height_rlist_size + $__rows + 7 ))
1124		else
1125			__height_rlist_size=$((
1126				$__height_rlist_size + $__rows + 4 ))
1127		fi
1128		setvar "$__var_height" $__height_rlist_size
1129	fi
1130
1131	# Adjust width if desired
1132	if [ "$__var_width" ]; then
1133		# Sum total between longest tag-length, longest item-length,
1134		# and radio-button width should be used to bump menu width
1135		local __n=$(( $__longest_tag + $__longest_item + 13 ))
1136		[ "$USE_XDIALOG" ] && __n=$(( $__n + $__n / 6 )) # plus 16.6%
1137		[ $__n -gt $__width_rlist_size ] && __width_rlist_size=$__n
1138
1139		setvar "$__var_width" $__width_rlist_size
1140	fi
1141
1142	# Store adjusted rows if desired
1143	[ "$__var_rows" ] && setvar "$__var_rows" $__rows
1144
1145	# Constrain height, width, and rows to sensible minimum/maximum values
1146	# Return success if no-constrain, else return status from constrain
1147	[ ! "$__constrain" ] || f_dialog_menu_constrain \
1148		"$__var_height" "$__var_width" "$__var_rows" "$__prompt"
1149}
1150
1151# f_dialog_checklist_size [-n] $var_height $var_width $var_rows \
1152#                         $title $backtitle $prompt $hline \
1153#                         $tag1 $item1 $status1 $tag2 $item2 $status2 ...
1154#
1155# Not all versions of dialog(1) perform auto-sizing of the width and height of
1156# `--checklist' boxes sensibly.
1157#
1158# This function helps solve this issue by taking three sets of sequential
1159# arguments. The first set of arguments are the variable names to use when
1160# storing the calculated height, width, and rows. The second set of arguments
1161# are the title, backtitle, prompt, and hline. The [optional] third set of
1162# arguments are the check list itself (comprised of tag/item/status triplets).
1163# The optimal height, width, and rows for the described widget (not exceeding
1164# the actual terminal height or width) is stored in $var_height, $var_width,
1165# and $var_rows (respectively). 
1166#
1167# If the first argument is `-n', the calculated sizes ($var_height, $var_width,
1168# and $var_rows) are not constrained to minimum/maximum values.
1169#
1170f_dialog_checklist_size()
1171{
1172	f_dialog_radiolist_size "$@"
1173}
1174
1175# f_dialog_radiolist_with_help_size [-n] $var_height $var_width $var_rows \
1176#                                   $title $backtitle $prompt $hline \
1177#                                   $tag1 $item1 $status1 $help1 \
1178#                                   $tag2 $item2 $status2 $help2 ...
1179#
1180# Not all versions of dialog(1) perform auto-sizing of the width and height of
1181# `--radiolist' boxes sensibly.
1182#
1183# This function helps solve this issue by taking three sets of sequential
1184# arguments. The first set of arguments are the variable names to use when
1185# storing the calculated height, width, and rows. The second set of arguments
1186# are the title, backtitle, prompt, and hline. The [optional] third set of
1187# arguments are the radio list itself (comprised of tag/item/status/help
1188# quadruplets). The optimal height, width, and rows for the described widget
1189# (not exceeding the actual terminal height or width) is stored in $var_height,
1190# $var_width, and $var_rows (respectively).
1191#
1192# If the first argument is `-n', the calculated sizes ($var_height, $var_width,
1193# and $var_rows) are not constrained to minimum/maximum values.
1194#
1195f_dialog_radiolist_with_help_size()
1196{
1197	local __constrain=1
1198	[ "$1" = "-n" ] && __constrain= && shift 1 # -n
1199	local __var_height="$1" __var_width="$2" __var_rows="$3"
1200	local __title="$4" __btitle="$5" __prompt="$6" __hline="$7"
1201	shift 7 # var_height/var_width/var_rows/title/btitle/prompt/hline
1202
1203	# Return unless at least one size aspect has been requested
1204	[ "$__var_height" -o "$__var_width" -o "$__var_rows" ] ||
1205		return $FAILURE
1206
1207	# Calculate height/width of infobox (adjusted/constrained below)
1208	# NOTE: Function name appended to prevent __var_{height,width} values
1209	#       from becoming local (and thus preventing setvar from working).
1210	local __height_rlist_with_help_size __width_rlist_with_help_size
1211	f_dialog_infobox_size -n \
1212		"${__var_height:+__height_rlist_with_help_size}" \
1213		"${__var_width:+__width_rlist_with_help_size}" \
1214		"$__title" "$__btitle" "$__prompt" "$__hline"
1215
1216	#
1217	# Always process the menu-item arguments to get the longest tag-length,
1218	# longest item-length, longest help-length (help-length only considered
1219	# if using Xdialog(1), as it places the help string in the widget) --
1220	# all used to bump the width -- and the number of rows (used to bump
1221	# the height).
1222	#
1223	local __longest_tag=0 __longest_item=0 __longest_help=0 __rows=0
1224	while [ $# -ge 4 ]; do
1225		local __tag="$1" __item="$2" __status="$3" __help="$4"
1226		shift 4 # tag/item/status/help
1227		[ ${#__tag} -gt $__longest_tag ] && __longest_tag=${#__tag}
1228		[ ${#__item} -gt $__longest_item ] && __longest_item=${#__item}
1229		[ ${#__help} -gt $__longest_help ] && __longest_help=${#__help}
1230		__rows=$(( $__rows + 1 ))
1231	done
1232
1233	# Adjust rows early (for up-coming height calculation)
1234	if [ "$__var_height" -o "$__var_rows" ]; then
1235		# Add a row for visual aid if using Xdialog(1)
1236		[ "$USE_XDIALOG" ] && __rows=$(( $__rows + 1 ))
1237	fi
1238
1239	# Adjust height if desired
1240	if [ "$__var_height" ]; then
1241		# Add rows to height
1242		if [ "$USE_XDIALOG" ]; then
1243			__height_rlist_with_help_size=$((
1244				$__height_rlist_with_help_size + $__rows + 7 ))
1245		else
1246			__height_rlist_with_help_size=$((
1247				$__height_rlist_with_help_size + $__rows + 4 ))
1248		fi
1249		setvar "$__var_height" $__height
1250	fi
1251
1252	# Adjust width if desired
1253	if [ "$__var_width" ]; then
1254		# Sum total between longest tag-length, longest item-length,
1255		# and radio-button width should be used to bump menu width
1256		local __n=$(( $__longest_tag + $__longest_item + 13 ))
1257		[ "$USE_XDIALOG" ] && __n=$(( $__n + $__n / 6 )) # plus 16.6%
1258		[ $__n -gt $__width_rlist_with_help_size ] &&
1259			__width_rlist_with_help_size=$__n
1260
1261		# Update width for help text if using Xdialog(1)
1262		if [ "$USE_XDIALOG" ]; then
1263			__n=$(( $__longest_help + 10 ))
1264			__n=$(( $__n + $__n / 6 )) # plus 16.6%
1265			[ $__n -gt $__width_rlist_with_help_size ] &&
1266				__width_rlist_with_help_size=$__n
1267		fi
1268
1269		setvar "$__var_width" $__width_rlist_with_help_size
1270	fi
1271
1272	# Store adjusted rows if desired
1273	[ "$__var_rows" ] && setvar "$__var_rows" $__rows
1274
1275	# Constrain height, width, and rows to sensible minimum/maximum values
1276	# Return success if no-constrain, else return status from constrain
1277	[ ! "$__constrain" ] || f_dialog_menu_constrain \
1278		"$__var_height" "$__var_width" "$__var_rows" "$__prompt"
1279}
1280
1281# f_dialog_checklist_with_help_size [-n] $var_height $var_width $var_rows \
1282#                                   $title $backtitle $prompt $hline \
1283#                                   $tag1 $item1 $status1 $help1 \
1284#                                   $tag2 $item2 $status2 $help2 ...
1285#
1286# Not all versions of dialog(1) perform auto-sizing of the width and height of
1287# `--checklist' boxes sensibly.
1288#
1289# This function helps solve this issue by taking three sets of sequential
1290# arguments. The first set of arguments are the variable names to use when
1291# storing the calculated height, width, and rows. The second set of arguments
1292# are the title, backtitle, prompt, and hline. The [optional] third set of
1293# arguments are the check list itself (comprised of tag/item/status/help
1294# quadruplets). The optimal height, width, and rows for the described widget
1295# (not exceeding the actual terminal height or width) is stored in $var_height,
1296# $var_width, and $var_rows (respectively).
1297#
1298# If the first argument is `-n', the calculated sizes ($var_height, $var_width,
1299# and $var_rows) are not constrained to minimum/maximum values.
1300#
1301f_dialog_checklist_with_help_size()
1302{
1303	f_dialog_radiolist_with_help_size "$@"
1304}
1305
1306# f_dialog_calendar_size [-n] $var_height $var_width \
1307#                        $title $backtitle $prompt [$hline]
1308#
1309# Not all versions of dialog(1) perform auto-sizing of the width and height of
1310# `--calendar' boxes sensibly.
1311#
1312# This function helps solve this issue by taking two sets of sequential
1313# arguments. The first set of arguments are the variable names to use when
1314# storing the calculated height and width. The second set of arguments are the
1315# title, backtitle, prompt, and [optionally] hline. The optimal height and
1316# width for the described widget (not exceeding the actual terminal height or
1317# width) is stored in $var_height and $var_width (respectively).
1318#
1319# If the first argument is `-n', the calculated sizes ($var_height and
1320# $var_width) are not constrained to minimum/maximum values.
1321#
1322# Newline character sequences (``\n'') in $prompt are expanded as-is done by
1323# dialog(1).
1324#
1325f_dialog_calendar_size()
1326{
1327	local __constrain=1
1328	[ "$1" = "-n" ] && __constrain= && shift 1 # -n
1329	local __var_height="$1" __var_width="$2"
1330	local __title="$3" __btitle="$4" __prompt="$5" __hline="$6"
1331
1332	# Return unless at least one size aspect has been requested
1333	[ "$__var_height" -o "$__var_width" ] || return $FAILURE
1334
1335	#
1336	# Obtain/Adjust minimum and maximum thresholds
1337	# NOTE: Function name appended to prevent __var_{height,width} values
1338	#       from becoming local (and thus preventing setvar from working).
1339	#
1340	local __max_height_cal_size __max_width_cal_size
1341	f_dialog_max_size __max_height_cal_size __max_width_cal_size
1342	__max_width_cal_size=$(( $__max_width_cal_size - 2 ))
1343		# the calendar box will refuse to display if too wide
1344	local __min_width
1345	if [ "$USE_XDIALOG" ]; then
1346		__min_width=55
1347	else
1348		__min_width=40
1349		__max_height_cal_size=$((
1350			$__max_height_cal_size - $DIALOG_CALENDAR_HEIGHT ))
1351		# When using dialog(1), we can't predict whether the user has
1352		# disabled shadow's in their `$HOME/.dialogrc' file, so we'll
1353		# subtract one for the potential shadow around the widget
1354		__max_height_cal_size=$(( $__max_height_cal_size - 1 ))
1355	fi
1356
1357	# Calculate height if desired
1358	if [ "$__var_height" ]; then
1359		local __height
1360		__height=$( echo "$__prompt" | f_number_of_lines )
1361
1362		if [ "$USE_XDIALOG" ]; then
1363			# Add height to accomodate for embedded calendar widget
1364			__height=$(( $__height + $DIALOG_CALENDAR_HEIGHT - 1 ))
1365
1366			# Also, bump height if backtitle is enabled
1367			if [ "$__btitle" ]; then
1368				local __n
1369				__n=$( echo "$__btitle" | f_number_of_lines )
1370				__height=$(( $__height + $__n + 2 ))
1371			fi
1372		else
1373			[ "$__prompt" ] && __height=$(( $__height + 1 ))
1374		fi
1375
1376		# Enforce maximum height, unless `-n' was passed
1377		[ "$__constrain" -a $__height -gt $__max_height_cal_size ] &&
1378			__height=$__max_height_cal_size
1379
1380		setvar "$__var_height" $__height
1381	fi
1382
1383	# Calculate width if desired
1384	if [ "$__var_width" ]; then
1385		# NOTE: Function name appended to prevent __var_{height,width}
1386		#       values from becoming local (and thus preventing setvar
1387		#       from working).
1388		local __width_cal_size
1389		f_dialog_infobox_size -n "" __width_cal_size \
1390			"$__title" "$__btitle" "$__prompt" "$__hline"
1391
1392		# Enforce minimum/maximum width, unless `-n' was passed
1393		if [ "$__constrain" ]; then
1394			if [ $__width_cal_size -lt $__min_width ]; then
1395				__width_cal_size=$__min_width
1396			elif [ $__width_cal_size -gt $__max_width_cal_size ]
1397			then
1398				__width_cal_size=$__max_width_size
1399			fi
1400		fi
1401
1402		setvar "$__var_width" $__width_cal_size
1403	fi
1404
1405	return $SUCCESS
1406}
1407
1408# f_dialog_timebox_size [-n] $var_height $var_width \
1409#                       $title $backtitle $prompt [$hline]
1410#
1411# Not all versions of dialog(1) perform auto-sizing of the width and height of
1412# `--timebox' boxes sensibly.
1413#
1414# This function helps solve this issue by taking two sets of sequential
1415# arguments. The first set of arguments are the variable names to use when
1416# storing the calculated height and width. The second set of arguments are the
1417# title, backtitle, prompt, and [optionally] hline. The optional height and
1418# width for the described widget (not exceeding the actual terminal height or
1419# width) is stored in $var_height and $var_width (respectively).
1420#
1421# If the first argument is `-n', the calculated sizes ($var_height and
1422# $var_width) are not constrained to minimum/maximum values.
1423#
1424# Newline character sequences (``\n'') in $prompt are expanded as-is done by
1425# dialog(1).
1426#
1427f_dialog_timebox_size()
1428{
1429	local __constrain=1
1430	[ "$1" = "-n" ] && __constrain= && shift 1 # -n
1431	local __var_height="$1" __var_width="$2"
1432	local __title="$3" __btitle="$4" __prompt="$5" __hline="$6"
1433
1434	# Return unless at least one size aspect has been requested
1435	[ "$__var_height" -o "$__var_width" ] || return $FAILURE
1436
1437	#
1438	# Obtain/Adjust minimum and maximum thresholds
1439	# NOTE: Function name appended to prevent __var_{height,width} values
1440	#       from becoming local (and thus preventing setvar from working).
1441	#
1442	local __max_height_tbox_size __max_width_tbox_size
1443	f_dialog_max_size __max_height_tbox_size __max_width_tbox_size
1444	__max_width_tbox_size=$(( $__max_width_tbox_size - 2 ))
1445		# the timebox widget refuses to display if too wide
1446	local __min_width
1447	if [ "$USE_XDIALOG" ]; then
1448		__min_width=40
1449	else
1450		__min_width=20
1451		__max_height_tbox_size=$(( \
1452			$__max_height_tbox_size - $DIALOG_TIMEBOX_HEIGHT ))
1453		# When using dialog(1), we can't predict whether the user has
1454		# disabled shadow's in their `$HOME/.dialogrc' file, so we'll
1455		# subtract one for the potential shadow around the widget
1456		__max_height_tbox_size=$(( $__max_height_tbox_size - 1 ))
1457	fi
1458
1459	# Calculate height if desired
1460	if [ "$__var_height" -a "$USE_XDIALOG" ]; then
1461		# When using Xdialog(1), the height seems to have
1462		# no effect. All values provide the same results.
1463		setvar "$__var_height" 0 # autosize
1464	elif [ "$__var_height" ]; then
1465		local __height
1466		__height=$( echo "$__prompt" | f_number_of_lines )
1467		__height=$(( $__height ${__prompt:++1} + 1 ))
1468
1469		# Enforce maximum height, unless `-n' was passed
1470		[ "$__constrain" -a $__height -gt $__max_height_tbox_size ] &&
1471			__height=$__max_height_tbox_size
1472
1473		setvar "$__var_height" $__height
1474	fi
1475
1476	# Calculate width if desired
1477	if [ "$__var_width" ]; then
1478		# NOTE: Function name appended to prevent __var_{height,width}
1479		#       values from becoming local (and thus preventing setvar
1480		#       from working).
1481		local __width_tbox_size
1482		f_dialog_infobox_size -n "" __width_tbox_size \
1483			"$__title" "$__btitle" "$__prompt" "$__hline"
1484
1485		# Enforce the minimum width for displaying the timebox
1486		if [ "$__constrain" ]; then
1487			if [ $__width_tbox_size -lt $__min_width ]; then
1488				__width_tbox_size=$__min_width
1489			elif [ $__width_tbox_size -ge $__max_width_tbox_size ]
1490			then
1491				__width_tbox_size=$__max_width_tbox_size
1492			fi
1493		fi
1494
1495		setvar "$__var_width" $__width_tbox_size
1496	fi
1497
1498	return $SUCCESS
1499}
1500
1501############################################################ CLEAR FUNCTIONS
1502
1503# f_dialog_clear
1504#
1505# Clears any/all previous dialog(1) displays.
1506#
1507f_dialog_clear()
1508{
1509	$DIALOG --clear
1510}
1511
1512############################################################ INFO FUNCTIONS
1513
1514# f_dialog_info $info_text ...
1515#
1516# Throw up a dialog(1) infobox. The infobox remains until another dialog is
1517# displayed or `dialog --clear' (or f_dialog_clear) is called.
1518#
1519f_dialog_info()
1520{
1521	local info_text="$*" height width
1522	f_dialog_infobox_size height width \
1523		"$DIALOG_TITLE" "$DIALOG_BACKTITLE" "$info_text"
1524	$DIALOG \
1525		--title "$DIALOG_TITLE"         \
1526		--backtitle "$DIALOG_BACKTITLE" \
1527		${USE_XDIALOG:+--ignore-eof}    \
1528		${USE_XDIALOG:+--no-buttons}    \
1529		--infobox "$info_text" $height $width
1530}
1531
1532# f_xdialog_info $info_text ...
1533#
1534# Throw up an Xdialog(1) infobox and do not dismiss it until stdin produces
1535# EOF. This implies that you must execute this either as an rvalue to a pipe,
1536# lvalue to indirection or in a sub-shell that provides data on stdin.
1537#
1538f_xdialog_info()
1539{
1540	local info_text="$*" height width
1541	f_dialog_infobox_size height width \
1542		"$DIALOG_TITLE" "$DIALOG_BACKTITLE" "$info_text"
1543	$DIALOG \
1544		--title "$DIALOG_TITLE"               \
1545		--backtitle "$DIALOG_BACKTITLE"       \
1546		--no-close --no-buttons               \
1547		--infobox "$info_text" $height $width \
1548		-1 # timeout of -1 means abort when EOF on stdin
1549}
1550
1551############################################################ MSGBOX FUNCTIONS
1552
1553# f_dialog_msgbox $msg_text [$hline]
1554#
1555# Throw up a dialog(1) msgbox. The msgbox remains until the user presses ENTER
1556# or ESC, acknowledging the modal dialog.
1557#
1558# If the user presses ENTER, the exit status is zero (success), otherwise if
1559# the user presses ESC the exit status is 255.
1560#
1561f_dialog_msgbox()
1562{
1563	local msg_text="$1" hline="$2" height width
1564	f_dialog_buttonbox_size height width \
1565		"$DIALOG_TITLE" "$DIALOG_BACKTITLE" "$msg_text" "$hline"
1566	$DIALOG \
1567		--title "$DIALOG_TITLE"         \
1568		--backtitle "$DIALOG_BACKTITLE" \
1569		--hline "$hline"                \
1570		--ok-label "$msg_ok"            \
1571		--msgbox "$msg_text" $height $width
1572}
1573
1574############################################################ TEXTBOX FUNCTIONS
1575
1576# f_dialog_textbox $file
1577#
1578# Display the contents of $file (or an error if $file does not exist, etc.) in
1579# a dialog(1) textbox (which has a scrollable region for the text). The textbox
1580# remains until the user presses ENTER or ESC, acknowledging the modal dialog.
1581#
1582# If the user presses ENTER, the exit status is zero (success), otherwise if
1583# the user presses ESC the exit status is 255.
1584#
1585f_dialog_textbox()
1586{
1587	local file="$1"
1588	local contents height width retval
1589
1590	contents=$( cat "$file" 2>&1 )
1591	retval=$?
1592
1593	f_dialog_buttonbox_size height width \
1594		"$DIALOG_TITLE" "$DIALOG_BACKTITLE" "$contents"
1595
1596	if [ $retval -eq $SUCCESS ]; then
1597		$DIALOG \
1598			--title "$DIALOG_TITLE"         \
1599			--backtitle "$DIALOG_BACKTITLE" \
1600			--exit-label "$msg_ok"          \
1601			--no-cancel                     \
1602			--textbox "$file" $height $width
1603	else
1604		$DIALOG \
1605			--title "$DIALOG_TITLE"         \
1606			--backtitle "$DIALOG_BACKTITLE" \
1607			--ok-label "$msg_ok"            \
1608			--msgbox "$contents" $height $width
1609	fi
1610}
1611
1612############################################################ YESNO FUNCTIONS
1613
1614# f_dialog_yesno $msg_text [$hline]
1615#
1616# Display a dialog(1) Yes/No prompt to allow the user to make some decision.
1617# The yesno prompt remains until the user presses ENTER or ESC, acknowledging
1618# the modal dialog.
1619#
1620# If the user chooses YES the exit status is zero, or chooses NO the exit
1621# status is one, or presses ESC the exit status is 255.
1622#
1623f_dialog_yesno()
1624{
1625	local msg_text="$1" height width
1626	local hline="${2-$hline_arrows_tab_enter}"
1627
1628	f_interactive || return 0 # If non-interactive, return YES all the time
1629
1630	f_dialog_buttonbox_size height width \
1631		"$DIALOG_TITLE" "$DIALOG_BACKTITLE" "$msg_text" "$hline"
1632
1633	if [ "$USE_XDIALOG" ]; then
1634		$DIALOG \
1635			--title "$DIALOG_TITLE"         \
1636			--backtitle "$DIALOG_BACKTITLE" \
1637			--hline "$hline"                \
1638			--ok-label "$msg_yes"           \
1639			--cancel-label "$msg_no"        \
1640			--yesno "$msg_text" $height $width
1641	else
1642		$DIALOG \
1643			--title "$DIALOG_TITLE"         \
1644			--backtitle "$DIALOG_BACKTITLE" \
1645			--hline "$hline"                \
1646			--yes-label "$msg_yes"          \
1647			--no-label "$msg_no"            \
1648			--yesno "$msg_text" $height $width
1649	fi
1650}
1651
1652# f_dialog_noyes $msg_text [$hline]
1653#
1654# Display a dialog(1) No/Yes prompt to allow the user to make some decision.
1655# The noyes prompt remains until the user presses ENTER or ESC, acknowledging
1656# the modal dialog.
1657#
1658# If the user chooses YES the exit status is zero, or chooses NO the exit
1659# status is one, or presses ESC the exit status is 255.
1660#
1661# NOTE: This is just like the f_dialog_yesno function except "No" is default.
1662#
1663f_dialog_noyes()
1664{
1665	local msg_text="$1" height width
1666	local hline="${2-$hline_arrows_tab_enter}"
1667
1668	f_interactive || return 1 # If non-interactive, return NO all the time
1669
1670	f_dialog_buttonbox_size height width \
1671		"$DIALOG_TITLE" "$DIALOG_BACKTITLE" "$msg_text" "$hline"
1672
1673	if [ "$USE_XDIALOG" ]; then
1674		$DIALOG \
1675			--title "$DIALOG_TITLE"         \
1676			--backtitle "$DIALOG_BACKTITLE" \
1677			--hline "$hline"                \
1678			--default-no                    \
1679			--ok-label "$msg_yes"           \
1680			--cancel-label "$msg_no"        \
1681			--yesno "$msg_text" $height $width
1682	else
1683		$DIALOG \
1684			--title "$DIALOG_TITLE"         \
1685			--backtitle "$DIALOG_BACKTITLE" \
1686			--hline "$hline"                \
1687			--defaultno                     \
1688			--yes-label "$msg_yes"          \
1689			--no-label "$msg_no"            \
1690			--yesno "$msg_text" $height $width
1691	fi
1692}
1693
1694############################################################ INPUT FUNCTIONS
1695
1696# f_dialog_inputstr_store [-s] $text
1697#
1698# Store some text from a dialog(1) inputbox to be retrieved later by
1699# f_dialog_inputstr_fetch(). If the first argument is `-s', the text is
1700# sanitized before being stored.
1701#
1702f_dialog_inputstr_store()
1703{
1704	local sanitize=
1705	[ "$1" = "-s" ] && sanitize=1 && shift 1 # -s
1706	local text="$1"
1707
1708	# Sanitize the line before storing it if desired
1709	[ "$sanitize" ] && f_dialog_line_sanitize text
1710
1711	setvar DIALOG_INPUTBOX_$$ "$text"
1712}
1713
1714# f_dialog_inputstr_fetch [$var_to_set]
1715#
1716# Obtain the inputstr entered by the user from the most recently displayed
1717# dialog(1) inputbox (previously stored with f_dialog_inputstr_store() above).
1718# If $var_to_set is NULL or missing, output is printed to stdout (which is less
1719# recommended due to performance degradation; in a loop for example).
1720#
1721f_dialog_inputstr_fetch()
1722{
1723	local __var_to_set="$1" __cp
1724
1725	debug= f_getvar DIALOG_INPUTBOX_$$ "${__var_to_set:-__cp}" # get data
1726	setvar DIALOG_INPUTBOX_$$ "" # scrub memory in case data was sensitive
1727
1728	# Return the line on standard-out if desired
1729	[ "$__var_to_set" ] || echo "$__cp"
1730
1731	return $SUCCESS
1732}
1733
1734# f_dialog_input $var_to_set $prompt [$init [$hline]]
1735#
1736# Prompt the user with a dialog(1) inputbox to enter some value. The inputbox
1737# remains until the the user presses ENTER or ESC, or otherwise ends the
1738# editing session (by selecting `Cancel' for example).
1739#
1740# If the user presses ENTER, the exit status is zero (success), otherwise if
1741# the user presses ESC the exit status is 255, or if the user chose Cancel, the
1742# exit status is instead 1.
1743#
1744# NOTE: The hline should correspond to the type of data you want from the user.
1745# NOTE: Should not be used to edit multiline values.
1746#
1747f_dialog_input()
1748{
1749	local __var_to_set="$1" __prompt="$2" __init="$3" __hline="$4"
1750
1751	# NOTE: Function name appended to prevent __var_{height,width} values
1752	#       from becoming local (and thus preventing setvar from working).
1753	local __height_input __width_input
1754	f_dialog_inputbox_size __height_input __width_input \
1755		"$DIALOG_TITLE" "$DIALOG_BACKTITLE" \
1756		"$__prompt" "$__init" "$__hline"
1757
1758	local __opterm="--"
1759	[ "$USE_XDIALOG" ] && __opterm=
1760
1761	local __dialog_input
1762	__dialog_input=$(
1763		$DIALOG \
1764			--title "$DIALOG_TITLE"         \
1765			--backtitle "$DIALOG_BACKTITLE" \
1766			--hline "$__hline"              \
1767			--ok-label "$msg_ok"            \
1768			--cancel-label "$msg_cancel"    \
1769			--inputbox "$__prompt"          \
1770			$__height_input $__width_input  \
1771			$__opterm "$__init"             \
1772			2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
1773	)
1774	local __retval=$?
1775
1776	# Remove warnings and leading/trailing whitespace from user input
1777	f_dialog_line_sanitize __dialog_input
1778
1779	setvar "$__var_to_set" "$__dialog_input"
1780	return $__retval
1781}
1782
1783############################################################ MENU FUNCTIONS
1784
1785# f_dialog_menutag_store [-s] $text
1786#
1787# Store some text from a dialog(1) menu to be retrieved later by
1788# f_dialog_menutag_fetch(). If the first argument is `-s', the text is
1789# sanitized before being stored.
1790#
1791f_dialog_menutag_store()
1792{
1793	local sanitize=
1794	[ "$1" = "-s" ] && sanitize=1 && shift 1 # -s
1795	local text="$1"
1796
1797	# Sanitize the menutag before storing it if desired
1798	[ "$sanitize" ] && f_dialog_data_sanitize text
1799
1800	setvar DIALOG_MENU_$$ "$text"
1801}
1802
1803# f_dialog_menutag_fetch [$var_to_set]
1804#
1805# Obtain the menutag chosen by the user from the most recently displayed
1806# dialog(1) menu (previously stored with f_dialog_menutag_store() above). If
1807# $var_to_set is NULL or missing, output is printed to stdout (which is less
1808# recommended due to performance degradation; in a loop for example).
1809#
1810f_dialog_menutag_fetch()
1811{
1812	local __var_to_set="$1" __cp
1813
1814	debug= f_getvar DIALOG_MENU_$$ "${__var_to_set:-__cp}" # get the data
1815	setvar DIALOG_MENU_$$ "" # scrub memory in case data was sensitive
1816
1817	# Return the data on standard-out if desired
1818	[ "$__var_to_set" ] || echo "$__cp"
1819
1820	return $SUCCESS
1821}
1822
1823# f_dialog_menuitem_store [-s] $text
1824#
1825# Store the item from a dialog(1) menu (see f_dialog_menutag2item()) to be
1826# retrieved later by f_dialog_menuitem_fetch(). If the first argument is `-s',
1827# the text is sanitized before being stored.
1828#
1829f_dialog_menuitem_store()
1830{
1831	local sanitize=
1832	[ "$1" = "-s" ] && sanitize=1 && shift 1 # -s
1833	local text="$1"
1834
1835	# Sanitize the menuitem before storing it if desired
1836	[ "$sanitize" ] && f_dialog_data_sanitize text
1837
1838	setvar DIALOG_MENUITEM_$$ "$text"
1839}
1840
1841# f_dialog_menuitem_fetch [$var_to_set]
1842#
1843# Obtain the menuitem chosen by the user from the most recently displayed
1844# dialog(1) menu (previously stored with f_dialog_menuitem_store() above). If
1845# $var_to_set is NULL or missing, output is printed to stdout (which is less
1846# recommended due to performance degradation; in a loop for example).
1847#
1848f_dialog_menuitem_fetch()
1849{
1850	local __var_to_set="$1" __cp
1851
1852	debug= f_getvar DIALOG_MENUITEM_$$ "${__var_to_set:-__cp}" # get data
1853	setvar DIALOG_MENUITEM_$$ "" # scrub memory in case data was sensitive
1854
1855	# Return the data on standard-out if desired
1856	[ "$__var_to_set" ] || echo "$__cp"
1857
1858	return $SUCCESS
1859}
1860
1861# f_dialog_default_store [-s] $text
1862#
1863# Store some text to be used later as the --default-item argument to dialog(1)
1864# (or Xdialog(1)) for --menu, --checklist, and --radiolist widgets. Retrieve
1865# the text later with f_dialog_menutag_fetch(). If the first argument is `-s',
1866# the text is sanitized before being stored.
1867#
1868f_dialog_default_store()
1869{
1870	local sanitize=
1871	[ "$1" = "-s" ] && sanitize=1 && shift 1 # -s
1872	local text="$1"
1873
1874	# Sanitize the defaulitem before storing it if desired
1875	[ "$sanitize" ] && f_dialog_data_sanitize text
1876
1877	setvar DEFAULTITEM_$$ "$text"
1878}
1879
1880# f_dialog_default_fetch [$var_to_set]
1881#
1882# Obtain text to be used with the --default-item argument of dialog(1) (or
1883# Xdialog(1)) (previously stored with f_dialog_default_store() above). If
1884# $var_to_set is NULL or missing, output is printed to stdout (which is less
1885# recommended due to performance degradation; in a loop for example).
1886#
1887f_dialog_default_fetch()
1888{
1889	local __var_to_set="$1" __cp
1890
1891	debug= f_getvar DEFAULTITEM_$$ "${__var_to_set:-__cp}" # get the data
1892	setvar DEFAULTITEM_$$ "" # scrub memory in case data was sensitive
1893
1894	# Return the data on standard-out if desired
1895	[ "$__var_to_set" ] || echo "$__cp"
1896
1897	return $SUCCESS
1898}
1899
1900# f_dialog_menutag2item $tag_chosen $tag1 $item1 $tag2 $item2 ...
1901#
1902# To use the `--menu' option of dialog(1) you must pass an ordered list of
1903# tag/item pairs on the command-line. When the user selects a menu option the
1904# tag for that item is printed to stderr.
1905#
1906# This function allows you to dereference the tag chosen by the user back into
1907# the item associated with said tag.
1908#
1909# Pass the tag chosen by the user as the first argument, followed by the
1910# ordered list of tag/item pairs (HINT: use the same tag/item list as was
1911# passed to dialog(1) for consistency).
1912#
1913# If the tag cannot be found, NULL is returned.
1914#
1915f_dialog_menutag2item()
1916{
1917	local tag="$1" tagn item
1918	shift 1 # tag
1919
1920	while [ $# -gt 0 ]; do
1921		tagn="$1"
1922		item="$2"
1923		shift 2 # tagn/item
1924
1925		if [ "$tag" = "$tagn" ]; then
1926			echo "$item"
1927			return $SUCCESS
1928		fi
1929	done
1930	return $FAILURE
1931}
1932
1933# f_dialog_menutag2item_with_help $tag_chosen $tag1 $item1 $help1 \
1934#                                             $tag2 $item2 $help2 ...
1935#
1936# To use the `--menu' option of dialog(1) with the `--item-help' option, you
1937# must pass an ordered list of tag/item/help triplets on the command-line. When
1938# the user selects a menu option the tag for that item is printed to stderr.
1939#
1940# This function allows you to dereference the tag chosen by the user back into
1941# the item associated with said tag (help is discarded/ignored).
1942#
1943# Pass the tag chosen by the user as the first argument, followed by the
1944# ordered list of tag/item/help triplets (HINT: use the same tag/item/help list
1945# as was passed to dialog(1) for consistency).
1946#
1947# If the tag cannot be found, NULL is returned.
1948#
1949f_dialog_menutag2item_with_help()
1950{
1951	local tag="$1" tagn item
1952	shift 1 # tag
1953
1954	while [ $# -gt 0 ]; do
1955		tagn="$1"
1956		item="$2"
1957		shift 3 # tagn/item/help
1958
1959		if [ "$tag" = "$tagn" ]; then
1960			echo "$item"
1961			return $SUCCESS
1962		fi
1963	done
1964	return $FAILURE
1965}
1966
1967# f_dialog_menutag2index $tag_chosen $tag1 $item1 $tag2 $item2 ...
1968#
1969# To use the `--menu' option of dialog(1) you must pass an ordered list of
1970# tag/item pairs on the command-line. When the user selects a menu option the
1971# tag for that item is printed to stderr.
1972#
1973# This function allows you to dereference the tag chosen by the user back into
1974# the index associated with said tag. The index is the one-based tag/item pair
1975# array position within the ordered list of tag/item pairs passed to dialog(1).
1976#
1977# Pass the tag chosen by the user as the first argument, followed by the
1978# ordered list of tag/item pairs (HINT: use the same tag/item list as was
1979# passed to dialog(1) for consistency).
1980#
1981# If the tag cannot be found, NULL is returned.
1982#
1983f_dialog_menutag2index()
1984{
1985	local tag="$1" tagn n=1
1986	shift 1 # tag
1987
1988	while [ $# -gt 0 ]; do
1989		tagn="$1"
1990		shift 2 # tagn/item
1991
1992		if [ "$tag" = "$tagn" ]; then
1993			echo $n
1994			return $SUCCESS
1995		fi
1996		n=$(( $n + 1 ))
1997	done
1998	return $FAILURE
1999}
2000
2001# f_dialog_menutag2index_with_help $tag_chosen $tag1 $item1 $help1 \
2002#                                              $tag2 $item2 $help2 ...
2003#
2004# To use the `--menu' option of dialog(1) with the `--item-help' option, you
2005# must pass an ordered list of tag/item/help triplets on the command-line. When
2006# the user selects a menu option the tag for that item is printed to stderr.
2007#
2008# This function allows you to dereference the tag chosen by the user back into
2009# the index associated with said tag. The index is the one-based tag/item/help
2010# triplet array position within the ordered list of tag/item/help triplets
2011# passed to dialog(1).
2012#
2013# Pass the tag chosen by the user as the first argument, followed by the
2014# ordered list of tag/item/help triplets (HINT: use the same tag/item/help list
2015# as was passed to dialog(1) for consistency).
2016#
2017# If the tag cannot be found, NULL is returned.
2018#
2019f_dialog_menutag2index_with_help()
2020{
2021	local tag="$1" tagn n=1
2022	shift 1 # tag
2023
2024	while [ $# -gt 0 ]; do
2025		tagn="$1"
2026		shift 3 # tagn/item/help
2027
2028		if [ "$tag" = "$tagn" ]; then
2029			echo $n
2030			return $SUCCESS
2031		fi
2032		n=$(( $n + 1 ))
2033	done
2034	return $FAILURE
2035}
2036
2037############################################################ INIT FUNCTIONS
2038
2039# f_dialog_init
2040#
2041# Initialize (or re-initialize) the dialog module after setting/changing any
2042# of the following environment variables:
2043#
2044# 	USE_XDIALOG   Either NULL or Non-NULL. If given a value will indicate
2045# 	              that Xdialog(1) should be used instead of dialog(1).
2046#
2047# 	SECURE        Either NULL or Non-NULL. If given a value will indicate
2048# 	              that (while running as root) sudo(8) authentication is
2049# 	              required to proceed.
2050#
2051# Also reads ~/.dialogrc for the following information:
2052#
2053# 	NO_SHADOW     Either NULL or Non-NULL. If use_shadow is OFF (case-
2054# 	              insensitive) in ~/.dialogrc this is set to "1" (otherwise
2055# 	              unset).
2056#
2057f_dialog_init()
2058{
2059	local funcname=f_dialog_init
2060
2061	DIALOG_SELF_INITIALIZE=
2062	USE_DIALOG=1
2063
2064	#
2065	# Clone terminal stdout so we can redirect to it from within sub-shells
2066	#
2067	eval exec $DIALOG_TERMINAL_PASSTHRU_FD\>\&1
2068
2069	#
2070	# Add `-S' and `-X' to the list of standard arguments supported by all
2071	#
2072	case "$GETOPTS_STDARGS" in
2073	*SX*) : good ;; # already present
2074	   *) GETOPTS_STDARGS="${GETOPTS_STDARGS}SX"
2075	esac
2076
2077	#
2078	# Process stored command-line arguments
2079	#
2080	f_dprintf "f_dialog_init: ARGV=[%s] GETOPTS_STDARGS=[%s]" \
2081	          "$ARGV" "$GETOPTS_STDARGS"
2082	SECURE=$( set -- $ARGV
2083		while getopts \
2084			"$GETOPTS_STDARGS$GETOPTS_EXTRA$GETOPTS_ALLFLAGS" \
2085		flag > /dev/null; do
2086			case "$flag" in
2087			S) echo 1 ;;
2088			esac
2089		done
2090	)
2091	USE_XDIALOG=$( set -- $ARGV
2092		while getopts \
2093			"$GETOPTS_STDARGS$GETOPTS_EXTRA$GETOPTS_ALLFLAGS" \
2094		flag > /dev/null; do
2095			case "$flag" in
2096			S|X) echo 1 ;;
2097			esac
2098		done
2099	)
2100	f_dprintf "f_dialog_init: SECURE=[%s] USE_XDIALOG=[%s]" \
2101	          "$SECURE" "$USE_XDIALOG"
2102
2103	#
2104	# Process `-X' command-line option
2105	#
2106	[ "$USE_XDIALOG" ] && DIALOG=Xdialog USE_DIALOG=
2107
2108	#
2109	# Sanity check, or die gracefully
2110	#
2111	if ! f_have $DIALOG; then
2112		unset USE_XDIALOG
2113		local failed_dialog="$DIALOG"
2114		DIALOG=dialog
2115		f_die 1 "$msg_no_such_file_or_directory" "$pgm" "$failed_dialog"
2116	fi
2117
2118	#
2119	# Read ~/.dialogrc (unless using Xdialog(1)) for properties
2120	#
2121	if [ -f ~/.dialogrc -a ! "$USE_XDIALOG" ]; then
2122		eval "$(
2123			awk -v param=use_shadow -v expect=OFF \
2124			    -v set="NO_SHADOW=1" '
2125			!/^[[:space:]]*(#|$)/ && \
2126			tolower($1) ~ "^"param"(=|$)" && \
2127			/[^#]*=/ {
2128				sub(/^[^=]*=[[:space:]]*/, "")
2129				if ( toupper($1) == expect ) print set";"
2130			}' ~/.dialogrc
2131		)"
2132	fi
2133
2134	#
2135	# If we're already running as root but we got there by way of sudo(8)
2136	# and we have X11, we should merge the xauth(1) credentials from our
2137	# original user.
2138	#
2139	if [ "$USE_XDIALOG" ] &&
2140	   [ "$( id -u )" = "0" ] &&
2141	   [ "$SUDO_USER" -a "$DISPLAY" ]
2142	then
2143		if ! f_have xauth; then
2144			# Die gracefully, as we [likely] can't use Xdialog(1)
2145			unset USE_XDIALOG
2146			DIALOG=dialog
2147			f_die 1 "$msg_no_such_file_or_directory" "$pgm" "xauth"
2148		fi
2149		HOSTNAME=$( hostname )
2150		local displaynum="${DISPLAY#*:}"
2151		eval xauth -if \~$SUDO_USER/.Xauthority extract - \
2152			\"\$HOSTNAME/unix:\$displaynum\" \
2153			\"\$HOSTNAME:\$displaynum\" | sudo sh -c 'xauth -ivf \
2154			~root/.Xauthority merge - > /dev/null 2>&1'
2155	fi
2156
2157	#
2158	# Probe Xdialog(1) for maximum height/width constraints, or die
2159	# gracefully
2160	#
2161	if [ "$USE_XDIALOG" ]; then
2162		local maxsize
2163		if ! f_eval_catch -dk maxsize $funcname "$DIALOG" \
2164			'LANG= LC_ALL= %s --print-maxsize' "$DIALOG"
2165		then
2166			# Xdialog(1) failed, fall back to dialog(1)
2167			unset USE_XDIALOG
2168
2169			# Display the error message produced by Xdialog(1)
2170			local height width
2171			f_dialog_buttonbox_size height width \
2172				"$DIALOG_TITLE" "$DIALOG_BACKTITLE" "$maxsize"
2173			dialog \
2174				--title "$DIALOG_TITLE"         \
2175				--backtitle "$DIALOG_BACKTITLE" \
2176				--ok-label "$msg_ok"            \
2177				--msgbox "$maxsize" $height $width
2178			exit $FAILURE
2179		fi
2180
2181		XDIALOG_MAXSIZE=$(
2182			set -- ${maxsize##*:}
2183
2184			height=${1%,}
2185			width=$2
2186
2187			echo $height $width
2188		)
2189	fi
2190
2191	#
2192	# If using Xdialog(1), swap DIALOG_TITLE with DIALOG_BACKTITLE.
2193	# The reason for this is because many dialog(1) applications use
2194	# --backtitle for the program name (which is better suited as
2195	# --title with Xdialog(1)).
2196	#
2197	if [ "$USE_XDIALOG" ]; then
2198		local _DIALOG_TITLE="$DIALOG_TITLE"
2199		DIALOG_TITLE="$DIALOG_BACKTITLE"
2200		DIALOG_BACKTITLE="$_DIALOG_TITLE"
2201	fi
2202
2203	f_dprintf "f_dialog_init: dialog(1) API initialized."
2204}
2205
2206############################################################ MAIN
2207
2208#
2209# Self-initialize unless requested otherwise
2210#
2211f_dprintf "%s: DIALOG_SELF_INITIALIZE=[%s]" \
2212          dialog.subr "$DIALOG_SELF_INITIALIZE"
2213case "$DIALOG_SELF_INITIALIZE" in
2214""|0|[Nn][Oo]|[Oo][Ff][Ff]|[Ff][Aa][Ll][Ss][Ee]) : do nothing ;;
2215*) f_dialog_init
2216esac
2217
2218f_dprintf "%s: Successfully loaded." dialog.subr
2219
2220fi # ! $_DIALOG_SUBR
2221