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