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