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