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