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