xref: /freebsd/usr.sbin/bsdconfig/share/dialog.subr (revision 56961fd7949de755f95a60fe8ac936f81e953f5b)
1if [ ! "$_DIALOG_SUBR" ]; then _DIALOG_SUBR=1
2#
3# Copyright (c) 2006-2012 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
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# Default behavior is to call f_dialog_init() automatically when loaded.
77#
78: ${DIALOG_SELF_INITIALIZE=1}
79
80############################################################ GENERIC FUNCTIONS
81
82# f_dialog_title [$new_title]
83#
84# Set the title of future dialog(1) ($DIALOG_TITLE) or backtitle of Xdialog(1)
85# ($DIALOG_BACKTITLE) invocations. If no arguments are given or the first
86# argument is NULL, the current title is returned.
87#
88# Each time this function is called, a backup of the current values is made
89# allowing a one-time (single-level) restoration of the previous title using the
90# f_dialog_title_restore() function (below).
91#
92f_dialog_title()
93{
94	local new_title="$1"
95
96	if [ "${1+set}" ]; then
97		if [ "$USE_XDIALOG" ]; then
98			_DIALOG_BACKTITLE="$DIALOG_BACKTITLE"
99			DIALOG_BACKTITLE="$new_title"
100		else
101			_DIALOG_TITLE="$DIALOG_TITLE"
102			DIALOG_TITLE="$new_title"
103		fi
104	else
105		if [ "$USE_XDIALOG" ]; then
106			echo "$DIALOG_BACKTITLE"
107		else
108			echo "$DIALOG_TITLE"
109		fi
110	fi
111}
112
113# f_dialog_title_restore
114#
115# Restore the previous title set by the last call to f_dialog_title().
116# Restoration is non-recursive and only works to restore the most-recent title.
117#
118f_dialog_title_restore()
119{
120	if [ "$USE_XDIALOG" ]; then
121		DIALOG_BACKTITLE="$_DIALOG_BACKTITLE"
122	else
123		DIALOG_TITLE="$_DIALOG_TITLE"
124	fi
125}
126
127# f_dialog_backtitle [$new_backtitle]
128#
129# Set the backtitle of future dialog(1) ($DIALOG_BACKTITLE) or title of
130# Xdialog(1) ($DIALOG_TITLE) invocations. If no arguments are given or the
131# first argument is NULL, the current backtitle is returned.
132#
133f_dialog_backtitle()
134{
135	local new_backtitle="$1"
136
137	if [ "${1+set}" ]; then
138		if [ "$USE_XDIALOG" ]; then
139			_DIALOG_TITLE="$DIALOG_TITLE"
140			DIALOG_TITLE="$new_backtitle"
141		else
142			_DIALOG_BACKTITLE="$DIALOG_BACKTITLE"
143			DIALOG_BACKTITLE="$new_backtitle"
144		fi
145	else
146		if [ "$USE_XDIALOG" ]; then
147			echo "$DIALOG_TITLE"
148		else
149			echo "$DIALOG_BACKTITLE"
150		fi
151	fi
152}
153
154# f_dialog_backtitle_restore
155#
156# Restore the previous backtitle set by the last call to f_dialog_backtitle().
157# Restoration is non-recursive and only works to restore the most-recent
158# backtitle.
159#
160f_dialog_backtitle_restore()
161{
162	if [ "$USE_XDIALOG" ]; then
163		DIALOG_TITLE="$_DIALOG_TITLE"
164	else
165		DIALOG_BACKTITLE="$_DIALOG_BACKTITLE"
166	fi
167}
168
169############################################################ SIZE FUNCTIONS
170
171# f_dialog_infobox_size $title $backtitle $prompt [$hline]
172#
173# Not all versions of dialog(1) perform auto-sizing of the width and height of
174# `--infobox' boxes sensibly.
175#
176# This function helps solve this issue by taking as arguments (in order of
177# appearance) the title, backtitle, prompt, and [optionally] hline returning
178# the optimal width and height for the box (not exceeding the actual terminal
179# width or height).
180#
181# Newline character sequences (``\n'') in $prompt are expanded as-is done by
182# dialog(1).
183#
184# Output is in the format of "height width".
185#
186f_dialog_infobox_size()
187{
188	local title="$1" btitle="$2" prompt="$3" hline="$4" n=0
189	local min_width max_size
190
191	if [ "$USE_XDIALOG" ]; then
192		min_width=35
193		max_size="$XDIALOG_MAXSIZE" # see CONFIGURATION
194	else
195		min_width=24
196		max_size=$( stty size ) # usually "24 80"
197	fi
198
199	local max_height="${max_size%%[$IFS]*}"
200	local max_width="${max_size##*[$IFS]}"
201	local height width=$min_width
202
203	#
204	# Bump width for long titles (but don't exceed terminal width).
205	#
206	n=$(( ${#title} + 4 ))
207	if [ $n -gt $width -a $n -gt $min_width ]; then
208		# Add 16.6% width for Xdialog(1)
209		[ "$USE_XDIALOG" ] && n=$(( $n + $n / 6 ))
210
211		if [ $n -lt $max_width ]; then
212			width=$n
213		else
214			width=$max_width
215		fi
216	fi
217
218	#
219	# For Xdialog(1), bump width for long backtitles (which appear within
220	# the window; don't exceed maximum width).
221	#
222	if [ "$USE_XDIALOG" ]; then
223		n=$(( ${#btitle} + 4 ))
224		n=$(( $n + $n / 6 ))
225		if [ $n -gt $width -a $n -gt $min_width ]; then
226			if [ $n -lt $max_width ]; then
227				width=$n
228			else
229				width=$max_width
230			fi
231		fi
232	fi
233
234	#
235	# Bump width for long prompts (if not already at maximum width).
236	#
237	if [ $width -lt $max_width ]; then
238		n=$( echo "$prompt" | f_longest_line_length )
239		n=$(( $n + 4 ))
240
241		# Add 16.6% width for Xdialog(1)
242		[ "$USE_XDIALOG" ] && n=$(( $n + $n / 6 ))
243
244		if [ $n -gt $width -a $n -gt $min_width ]; then
245			if [ $n -lt $max_width ]; then
246				width=$n
247			else
248				width=$max_width
249			fi
250		fi
251	fi
252
253	#
254	# Bump width for long hlines (if not already at maximum width).
255	# NOTE: Though Xdialog(1) supports `--hline', it's not currently used.
256	#
257	if [ ! "$USE_XDIALOG" ]; then
258		if [ $width -lt $max_width ]; then
259			n=$(( ${#hline} + 10 ))
260			if [ $n -gt $width -a $n -gt $min_width ]; then
261				if [ $n -lt $max_width ]; then
262					width=$n
263				else
264					width=$max_width
265				fi
266			fi
267		fi
268	fi
269
270	#
271	# Set height based on number of rows in prompt
272	#
273	height=$( echo -n "$prompt" | f_number_of_lines )
274	height=$(( $height + 2 ))
275
276	#
277	# For Xdialog(1) bump height if backtitle is enabled (displayed in the
278	# X11 window with a separator line between the backtitle and msg text)
279	#
280	if [ "$USE_XDIALOG" -a "$btitle" ]; then
281		n=$( echo "$btitle" | f_number_of_lines )
282		height=$(( $height + $n + 2 ))
283	fi
284
285	# Make sure height is less than maximum screen size
286	[ $height -le $max_height ] || height=$max_height
287
288	# Return both
289	echo "$height $width"
290}
291
292# f_dialog_buttonbox_size $title $backtitle $prompt [$hline]
293#
294# Not all versions of dialog(1) perform auto-sizing of the width and height of
295# `--msgbox' and `--yesno' boxes sensibly.
296#
297# This function helps solve this issue by taking as arguments (in order of
298# appearance) the title, backtitle, prompt, and [optionally] hline returning
299# the optimal width and height for the box (not exceeding the actual terminal
300# width or height).
301#
302# Newline character sequences (``\n'') in $prompt are expanded as-is done by
303# dialog(1).
304#
305# Output is in the format of "height width".
306#
307f_dialog_buttonbox_size()
308{
309	local title="$1" btitle="$2" prompt="$3" hline="$4"
310	local size="$( f_dialog_infobox_size \
311	               		"$title" "$btitle" "$prompt" "$hline" )"
312	local height="${size%%[$IFS]*}"
313	local width="${size##*[$IFS]}"
314
315	# Add height to accomodate the buttons
316	height=$(( $height + 2 ))
317
318	# Adjust for clipping with Xdialog(1) on Linux/GTK2
319	[ "$USE_XDIALOG" ] && height=$(( $height + 3 ))
320
321	#
322	# Enforce maximum height regardless
323	#
324	local max_size
325	if [ "$USE_XDIALOG" ]; then
326		max_size="$XDIALOG_MAXSIZE" # see CONFIGURATION
327	else
328		max_size=$( stty size ) # usually "24 80"
329	fi
330	local max_height="${max_size%%[$IFS]*}"
331	[ $height -le $max_height ] || height=$max_height
332
333	# Return both
334	echo "$height $width"
335}
336
337# f_dialog_inputbox_size $title $backtitle $prompt $init [$hline]
338#
339# Not all versions of dialog(1) perform auto-sizing of the width and height of
340# `--inputbox' boxes sensibly.
341#
342# This function helps solve this issue by taking as arguments (in order of
343# appearance) the title, backtitle, prompt, initial text, and [optionally]
344# hline returning the optimal width and height for the box (not exceeding the
345# actual terminal width and height).
346#
347# Newline character sequences (``\n'') in $prompt are expanded as-is done by
348# dialog(1).
349#
350# Output is in the format of "height width".
351#
352f_dialog_inputbox_size()
353{
354	local title="$1" btitle="$2" prompt="$3" init="$4" hline="$5" n
355	local size="$( f_dialog_buttonbox_size \
356	               		"$title" "$btitle" "$prompt" "$hline" )"
357	local height="${size%%[$IFS]*}"
358	local width="${size##*[$IFS]}"
359
360	local min_width max_size
361	if [ "$USE_XDIALOG" ]; then
362		min_width=35
363		max_size="$XDIALOG_MAXSIZE" # see CONFIGURATION
364	else
365		min_width=24
366		max_size=$( stty size ) # usually "24 80"
367	fi
368	local max_height="${max_size%%[$IFS]*}"
369	local max_width="${max_size##*[$IFS]}"
370
371	#
372	# Add height to accomodate the input box
373	#
374	[ ! "$USE_XDIALOG" ] && height=$(( $height + 3 ))
375	[ $height -le $max_height ] || height=$max_height
376
377	#
378	# Bump width for initial text (if not already at maximum width).
379	# NOTE: Something neither dialog(1)/Xdialog(1) do, but worth it!
380	#
381	if [ $width -lt $max_width ]; then
382		n=$(( ${#init} + 7 ))
383
384		# Add 16.6% width for Xdialog(1)
385		[ "$USE_XDIALOG" ] && n=$(( $n + $n / 6 ))
386
387		if [ $n -gt $width -a $n -gt $min_width ]; then
388			if [ $n -lt $max_width ]; then
389				width=$n
390			else
391				width=$max_width
392			fi
393		fi
394	fi
395
396	# Return both
397	echo "$height $width"
398}
399
400# f_xdialog_2inputsbox_size $title $backtitle $prompt \
401#                           $label1 $init1 $label2 $init2
402#
403# Xdialog(1) does not perform auto-sizing of the width and height of
404# `--2inputsbox' boxes sensibly.
405#
406# This function helps solve this issue by taking as arguments (in order of
407# appearance) the title, backtitle, prompt, label for the first field, initial
408# text for said field, label for the second field, and initial text for said
409# field returning the optimal width and height for the box (not exceeding the
410# actual terminal width and height).
411#
412# Newline character sequences (``\n'') in $prompt are expanded as-is done by
413# Xdialog(1).
414#
415# Output is in the format of "height width".
416#
417f_xdialog_2inputsbox_size()
418{
419	local title="$1" btitle="$2" prompt="$3"
420	local label1="$4" init1="$5" label2="$6" init2="$7" n
421	local size="$( f_dialog_inputbox_size \
422	               		"$title" "$btitle" "$prompt" "$init1" )"
423	local height="${size%%[$IFS]*}"
424	local width="${size##*[$IFS]}"
425
426	local min_width=35
427	local max_size="$XDIALOG_MAXSIZE" # see CONFIGURATION
428	local max_height="${max_size%%[$IFS]*}"
429	local max_width="${max_size##*[$IFS]}"
430
431	# Add height for first label
432	height=$(( $height + 2 ))
433
434	#
435	# Bump width for first label text (if not already at maximum width).
436	#
437	if [ $width -lt $max_width ]; then
438		n=$(( ${#label1} + 7 ))
439
440		# Add 16.6% width for Xdialog(1)
441		n=$(( $n + $n / 6 ))
442
443		if [ $n -gt $width -a $n -gt $min_width ]; then
444			if [ $n -lt $max_width ]; then
445				width=$n
446			else
447				width=$max_width
448			fi
449		fi
450	fi
451
452	# Add height for second label
453	height=$(( $height + 2 ))
454
455	#
456	# Bump width for second label text (if not already at maximum width).
457	#
458	if [ $width -lt $max_width ]; then
459		n=$(( ${#label2} + 7 ))
460
461		# Add 16.6% width for Xdialog(1)
462		n=$(( $n + $n / 6 ))
463
464		if [ $n -gt $width -a $n -gt $min_width ]; then
465			if [ $n -lt $max_width ]; then
466				width=$n
467			else
468				width=$max_width
469			fi
470		fi
471	fi
472
473	# Add height for a second inputbox
474	height=$(( $height + 2 ))
475
476	#
477	# Bump width for second initial text (if not already at maximum width).
478	# NOTE: Something neither dialog(1)/Xdialog(1) do, but worth it!
479	#
480	if [ $width -lt $max_width ]; then
481		n=$(( ${#init2} + 7 ))
482
483		# Add 16.6% width for Xdialog(1)
484		n=$(( $n + $n / 6 ))
485
486		if [ $n -gt $width -a $n -gt $min_width ]; then
487			if [ $n -lt $max_width ]; then
488				width=$n
489			else
490				width=$max_width
491			fi
492		fi
493	fi
494
495	# Return both
496	echo "$height $width"
497}
498
499# f_dialog_menu_size $title $backtitle $prompt $hline \
500#                    $tag1 $item1 $tag2 $item2 ...
501#
502# Not all versions of dialog(1) perform auto-sizing of the width and height of
503# `--menu' boxes sensibly.
504#
505# This function helps solve this issue by taking as arguments (in order of
506# appearance) the title, backtitle, prompt, hline and list of tag/item pairs,
507# returning the optimal width and height for the menu (not exceeding the actual
508# terminal width or height).
509#
510# Output is in the format of "height width rows".
511#
512f_dialog_menu_size()
513{
514	local title="$1" btitle="$2" prompt="$3" hline="$4" n=0
515	local min_width min_rows max_size
516
517	if [ "$USE_XDIALOG" ]; then
518		min_width=35
519		min_rows=1
520		max_size="$XDIALOG_MAXSIZE" # see CONFIGURATION
521	else
522		min_width=24
523		min_rows=0
524		max_size=$( stty size ) # usually "24 80"
525	fi
526
527	local max_width="${max_size##*[$IFS]}"
528	local max_height="${max_size%%[$IFS]*}"
529	local box_size="$( f_dialog_infobox_size \
530	                   	"$title" "$btitle" "$prompt" "$hline" )"
531	local box_height="${box_size%%[$IFS]*}"
532	local box_width="${box_size##*[$IFS]}"
533	local max_rows=$(( $max_height - 8 ))
534	local height width=$box_width rows=$min_rows
535
536	shift 4 # title/btitle/prompt/hline
537
538	# If there's no prompt, bump the max-rows by 1
539	[ "$prompt" ] || max_rows=$(( $max_rows + 1 ))
540
541	#
542	# The sum total between the longest tag-length and longest item-length
543	# should be used for the menu width (not to exceed terminal width).
544	#
545	# Also, calculate the number of rows (not to exceed terminal height).
546	#
547	local longest_tag=0 longest_item=0
548	while [ $# -ge 2 ]; do
549		local tag="$1" item="$2"
550		shift 2 # tag/item
551
552		[ ${#tag} -gt $longest_tag ] && longest_tag=${#tag}
553		[ ${#item} -gt $longest_item ] && longest_item=${#item}
554		[ $rows -lt $max_rows ] && rows=$(( $rows + 1 ))
555	done
556
557	# Update width
558	n=$(( $longest_tag + $longest_item + 10 ))
559	[ "$USE_XDIALOG" ] && n=$(( $n + $n / 6 )) # Add 16.6% for Xdialog(1)
560	if [ $n -gt $width -a $n -gt $min_width ]; then
561		if [ $n -lt $max_width ]; then
562			width=$n
563		else
564			width=$max_width
565		fi
566	fi
567
568	# Fix rows and set height
569	[ $rows -gt 0 ] || rows=1
570	if [ "$USE_XDIALOG" ]; then
571		height=$(( $rows + $box_height + 7 ))
572	else
573		height=$(( $rows + $box_height + 4 ))
574	fi
575	[ $height -le $max_height ] || height=$max_height
576
577	# Return all three
578	echo "$height $width $rows"
579}
580
581# f_dialog_menu_with_help_size $title $backtitle $prompt $hline \
582#                              $tag1 $item1 $help1 $tag2 $item2 $help2 ...
583#
584# Not all versions of dialog(1) perform auto-sizing of the width and height of
585# `--menu' boxes sensibly.
586#
587# This function helps solve this issue by taking as arguments (in order of
588# appearance) the title, backtitle, prompt, hline and list of tag/item/help
589# triplets, returning the optimal width and height for the menu (not exceeding
590# the actual terminal width or height).
591#
592# Output is in the format of "height width rows".
593#
594f_dialog_menu_with_help_size()
595{
596	local title="$1" btitle="$2" prompt="$3" hline="$4" n=0
597	local min_width min_rows max_size
598
599	if [ "$USE_XDIALOG" ]; then
600		min_width=35
601		min_rows=1
602		max_size="$XDIALOG_MAXSIZE" # see CONFIGURATION
603	else
604		min_width=24
605		min_rows=0
606		max_size=$( stty size ) # usually "24 80"
607	fi
608
609	local max_width="${max_size##*[$IFS]}"
610	local max_height="${max_size%%[$IFS]*}"
611	local box_size="$( f_dialog_infobox_size \
612	                   	"$title" "$btitle" "$prompt" "$hline" )"
613	local box_height="${box_size%%[$IFS]*}"
614	local box_width="${box_size##*[$IFS]}"
615	local max_rows=$(( $max_height - 8 ))
616	local height width=$box_width rows=$min_rows
617
618	shift 4 # title/btitle/prompt/hline
619
620	# If there's no prompt, bump the max-rows by 1
621	[ "$prompt" ] || max_rows=$(( $max_rows + 1 ))
622
623	#
624	# The sum total between the longest tag-length and longest item-length
625	# should be used for the menu width (not to exceed terminal width).
626	#
627	# Also, calculate the number of rows (not to exceed terminal height).
628	#
629	# Also, calculate the longest help while we're here. This will be used
630	# to influence the width of the menu if (and only-if) using Xdialog(1).
631	#
632	local longest_tag=0 longest_item=0 longest_help=0
633	while [ $# -ge 3 ]; do
634		local tag="$1" item="$2" help="$3"
635		shift 3 # tag/item/help
636
637		[ ${#tag} -gt $longest_tag ] && longest_tag=${#tag}
638		[ ${#item} -gt $longest_item ] && longest_item=${#item}
639		[ ${#help} -gt $longest_help ] && longest_help=${#help}
640		[ $rows -lt $max_rows ] && rows=$(( $rows + 1 ))
641	done
642
643	# Update width
644	n=$(( $longest_tag + $longest_item + 10 ))
645	[ "$USE_XDIALOG" ] && n=$(( $n + $n / 6 )) # Add 16.6% for Xdialog(1)
646	if [ $n -gt $width -a $n -gt $min_width ]; then
647		if [ $n -lt $max_width ]; then
648			width=$n
649		else
650			width=$max_width
651		fi
652	fi
653
654	# Update width for help text if using Xdialog(1)
655	if [ "$USE_XDIALOG" ]; then
656		n=$(( $longest_help + 10 ))
657		n=$(( $n + $n / 6 )) # +16.6%
658		if [ $n -gt $width -a $n -gt $min_width ]; then
659			if [ $n -lt $max_width ]; then
660				width=$n
661			else
662				width=$max_width
663			fi
664		fi
665	fi
666
667	# Fix rows and set height
668	[ $rows -gt 0 ] || rows=1
669	if [ "$USE_XDIALOG" ]; then
670		height=$(( $rows + $box_height + 8 ))
671	else
672		height=$(( $rows + $box_height + 4 ))
673	fi
674	[ $height -le $max_height ] || height=$max_height
675
676	# Return all three
677	echo "$height $width $rows"
678}
679
680# f_dialog_radiolist_size $title $backtitle $prompt $hline \
681#                         $tag1 $item1 $status1 $tag2 $item2 $status2 ...
682#
683# Not all versions of dialog(1) perform auto-sizing of the width and height of
684# `--radiolist' boxes sensibly.
685#
686# This function helps solve this issue by taking as arguments (in order of
687# appearance) the title, backtitle, prompt, hline and list of tag/item/status
688# triplets, returning the optimal width and height for the radiolist (not
689# exceeding the actual terminal width or height).
690#
691# Output is in the format of "height width rows".
692#
693f_dialog_radiolist_size()
694{
695	local title="$1" btitle="$2" prompt="$3" hline="$4" n=0
696	local min_width min_rows max_size
697
698	if [ "$USE_XDIALOG" ]; then
699		min_width=35
700		min_rows=1
701		max_size="$XDIALOG_MAXSIZE" # see CONFIGURATION
702	else
703		min_width=24
704		min_rows=0
705		max_size=$( stty size ) # usually "24 80"
706	fi
707
708	local max_width="${max_size##*[$IFS]}"
709	local max_height="${max_size%%[$IFS]*}"
710	local box_size="$( f_dialog_infobox_size \
711	                   	"$title" "$btitle" "$prompt" "$hline" )"
712	local box_height="${box_size%%[$IFS]*}"
713	local box_width="${box_size##*[$IFS]}"
714	local max_rows=$(( $max_height - 8 ))
715	local height width=$box_width rows=$min_rows
716
717	shift 4 # title/btitle/prompt/hline
718
719	#
720	# The sum total between the longest tag-length, longest item-length,
721	# and radio-button width should be used for the menu width (not to
722	# exceed terminal width).
723	#
724	# Also, calculate the number of rows (not to exceed terminal height).
725	#
726	local longest_tag=0 longest_item=0
727	while [ $# -ge 2 ]; do
728		local tag="$1" item="$2" help="$3"
729		shift 3 # tag/item/status
730
731		[ ${#tag} -gt $longest_tag ] && longest_tag=${#tag}
732		[ ${#item} -gt $longest_item ] && longest_item=${#item}
733		[ $rows -lt $max_rows ] && rows=$(( $rows + 1 ))
734	done
735
736	# Update width
737	n=$(( $longest_tag + $longest_item + 13 ))
738	[ "$USE_XDIALOG" ] && n=$(( $n + $n / 6 )) # Add 16.6% for Xdialog(1)
739	if [ $n -gt $width -a $n -gt $min_width ]; then
740		if [ $n -lt $max_width ]; then
741			width=$n
742		else
743			width=$max_width
744		fi
745	fi
746
747	# Fix rows and set height
748	[ $rows -gt 0 ] || rows=1
749	if [ "$USE_XDIALOG" ]; then
750		height=$(( $rows + $box_height + 7 ))
751	else
752		height=$(( $rows + $box_height + 4 ))
753	fi
754	[ $height -le $max_height ] || height=$max_height
755
756	# Return all three
757	echo "$height $width $rows"
758}
759
760# f_dialog_calendar_size $title $backtitle $prompt [$hline]
761#
762# Not all versions of dialog(1) perform auto-sizing of the width and height of
763# `--calendar' boxes sensibly.
764#
765# This function helps solve this issue by taking as arguments (in order of
766# appearance) the title, backtitle, prompt, and [optionally] hline returning
767# the optimal width and height for the box (not exceeding the actual terminal
768# width and height).
769#
770# Newline character sequences (``\n'') in $prompt are expanded as-is done by
771# dialog(1).
772#
773# Output is in the format of "height width".
774#
775f_dialog_calendar_size()
776{
777	local title="$1" btitle="$2" prompt="$3" hline="$4" n
778	local size="$( f_dialog_infobox_size \
779	               		"$title" "$btitle" "$prompt" "$hline" )"
780	local height="${size%%[$IFS]*}"
781	local width="${size##*[$IFS]}"
782
783	local min_width min_height max_size
784	if [ "$USE_XDIALOG" ]; then
785		min_height=15
786		min_width=55
787		max_size="$XDIALOG_MAXSIZE" # see CONFIGURATION
788	else
789		min_height=0
790		min_width=40
791		max_size=$( stty size ) # usually "24 80"
792	fi
793	local max_height="${max_size%%[$IFS]*}"
794	local max_width="${max_size##*[$IFS]}"
795
796	#
797	# Enforce the minimum width for displaying the calendar
798	#
799	[ $width -ge $min_width ] || width=$min_width
800
801	#
802	# When using dialog(1), the calendar box is unique from other dialog(1)
803	# boxes in-that the height passed should not accomodate the 15-lines
804	# required to display the calendar. This does not apply to Xdialog(1).
805	#
806	# When using Xdialog(1), the height must accomodate the 15-lines
807	# required to display the calendar.
808	#
809	# NOTE: Also under dialog(1), because we can't predict whether the user
810	# has disabled shadow's in their `$HOME/.dialogrc' file, we'll subtract
811	# 16 rather than 15. This does not apply to Xdialog(1).
812	#
813	max_height=$(( $max_height - 16 ))
814	height=$( echo "$prompt" | f_number_of_lines )
815	if [ "$USE_XDIALOG" ]; then
816		# Add height to accomodate for the embedded calendar widget
817		height=$(( $height + $min_height - 1 ))
818
819		# Also, bump height if backtitle is enabled
820		if [ "$btitle" ]; then
821			local n="$( echo "$btitle" | f_number_of_lines )"
822			height=$(( $height + $n + 2 ))
823		fi
824	else
825		[ "$prompt" ] && height=$(( $height + 1 ))
826	fi
827	[ $height -le $max_height ] || height=$max_height
828
829	#
830	# The calendar box refuses to display if too large.
831	#
832	max_width=$(( $max_width - 2 ))
833	[ $width -le $max_width ] || width=$max_width
834
835	# Return both
836	echo "$height $width"
837}
838
839# f_dialog_timebox_size $title $backtitle $prompt [$hline]
840#
841# Not all versions of dialog(1) perform auto-sizing of the width and height of
842# `--timebox' boxes sensibly.
843#
844# This function helps solve this issue by taking as arguments (in order of
845# appearance) the title, backtitle, prompt, and [optionally] hline returning
846# the optimal width and height for the box (not exceeding the actual terminal
847# width and height).
848#
849# Newline character sequences (``\n'') in $prompt are expanded as-is done by
850# dialog(1).
851#
852# Output is in the format of "height width".
853#
854f_dialog_timebox_size()
855{
856	local title="$1" btitle="$2" prompt="$3" hline="$4" n
857	local size="$( f_dialog_infobox_size \
858	               		"$title" "$btitle" "$prompt" "$hline" )"
859	local height="${size%%[$IFS]*}"
860	local width="${size##*[$IFS]}"
861
862	local min_width min_height max_size
863	if [ "$USE_XDIALOG" ]; then
864		min_width=40
865		max_size="$XDIALOG_MAXSIZE" # see CONFIGURATION
866	else
867		min_height=0
868		min_width=20
869		max_size=$( stty size ) # usually "24 80"
870	fi
871	local max_height="${max_size%%[$IFS]*}"
872	local max_width="${max_size##*[$IFS]}"
873
874	#
875	# Enforce the minimum width for displaying the timebox
876	#
877	[ $width -ge $min_width ] || width=$min_width
878
879	#
880	# When using dialog(1), the timebox box is unique from other dialog(1)
881	# boxes in-that the height passed should not accomodate the 6-lines
882	# required to display the timebox. This does not apply to Xdialog(1).
883	#
884	# When using Xdialog(1), the height seems to have no effect. All values
885	# provide the same results.
886	#
887	# NOTE: Also under dialog(1), because we can't predict whether the user
888	# has disabled shadow's in their `$HOME/.dialogrc' file, we'll subtract
889	# 7 rather than 6. This does not apply to Xdialog(1).
890	#
891	if [ "$USE_XDIALOG" ]; then
892		height=0 # Autosize; all values produce same results
893	else
894		max_height=$(( $max_height - 7 ))
895		height=$( echo "$prompt" | f_number_of_lines )
896		height=$(( $height + 1 ))
897		[ $height -le $max_height ] || height=$max_height
898		[ "$prompt" ] && height=$(( $height + 1 ))
899	fi
900
901	#
902	# The timebox box refuses to display if too large.
903	#
904	max_width=$(( $max_width - 2 ))
905	[ $width -le $max_width ] || width=$max_width
906
907	# Return both
908	echo "$height $width"
909}
910
911############################################################ CLEAR FUNCTIONS
912
913# f_dialog_clear
914#
915# Clears any/all previous dialog(1) displays.
916#
917f_dialog_clear()
918{
919	$DIALOG --clear
920}
921
922############################################################ INFO FUNCTIONS
923
924# f_dialog_info $info_text ...
925#
926# Throw up a dialog(1) infobox. The infobox remains until another dialog is
927# displayed or `dialog --clear' (or dialog_clear) is called.
928#
929f_dialog_info()
930{
931	local info_text="$*"
932	local size="$( f_dialog_infobox_size \
933	               		"$DIALOG_TITLE"     \
934	               		"$DIALOG_BACKTITLE" \
935	               		"$info_text"        )"
936
937	eval $DIALOG \
938		--title \"\$DIALOG_TITLE\"         \
939		--backtitle \"\$DIALOG_BACKTITLE\" \
940		${USE_XDIALOG:+--ignore-eof}       \
941		${USE_XDIALOG:+--no-buttons}       \
942		--infobox \"\$info_text\" $size
943}
944
945# f_xdialog_info $info_text ...
946#
947# Throw up an Xdialog(1) infobox and do not dismiss it until stdin produces
948# EOF. This implies that you must execute this either as an rvalue to a pipe,
949# lvalue to indirection or in a sub-shell that provides data on stdin.
950#
951f_xdialog_info()
952{
953	local info_text="$*"
954	local size="$( f_dialog_infobox_size \
955	               		"$DIALOG_TITLE"     \
956	               		"$DIALOG_BACKTITLE" \
957	               		"$info_text"        )"
958
959	eval $DIALOG \
960		--title \"\$DIALOG_TITLE\"         \
961		--backtitle \"\$DIALOG_BACKTITLE\" \
962		--no-close --no-buttons            \
963		--infobox \"\$info_text\" $size    \
964		-1 # timeout of -1 means abort when EOF on stdin
965}
966
967############################################################ MSGBOX FUNCTIONS
968
969# f_dialog_msgbox $msg_text ...
970#
971# Throw up a dialog(1) msgbox. The msgbox remains until the user presses ENTER
972# or ESC, acknowledging the modal dialog.
973#
974# If the user presses ENTER, the exit status is zero (success), otherwise if
975# the user presses ESC the exit status is 255.
976#
977f_dialog_msgbox()
978{
979	local msg_text="$*"
980	local size="$( f_dialog_buttonbox_size \
981	               		"$DIALOG_TITLE"     \
982	               		"$DIALOG_BACKTITLE" \
983	               		"$msg_text"         )"
984
985	eval $DIALOG \
986		--title \"\$DIALOG_TITLE\"         \
987		--backtitle \"\$DIALOG_BACKTITLE\" \
988		--ok-label \"\$msg_ok\"            \
989		--msgbox \"\$msg_text\" $size
990}
991
992############################################################ TEXTBOX FUNCTIONS
993
994# f_dialog_textbox $file
995#
996# Display the contents of $file (or an error if $file does not exist, etc.) in
997# a dialog(1) textbox (which has a scrollable region for the text). The textbox
998# remains until the user presses ENTER or ESC, acknowledging the modal dialog.
999#
1000# If the user presses ENTER, the exit status is zero (success), otherwise if
1001# the user presses ESC the exit status is 255.
1002#
1003f_dialog_textbox()
1004{
1005	local file="$1"
1006	local contents retval size
1007
1008	contents=$( cat "$file" 2>&1 )
1009	retval=$?
1010
1011	size=$( f_dialog_buttonbox_size \
1012	        	"$DIALOG_TITLE"     \
1013	        	"$DIALOG_BACKTITLE" \
1014	        	"$contents"         )
1015
1016	if [ $retval -eq $SUCCESS ]; then
1017		eval $DIALOG \
1018			--title \"\$DIALOG_TITLE\"         \
1019			--backtitle \"\$DIALOG_BACKTITLE\" \
1020			--exit-label \"\$msg_ok\"          \
1021			--no-cancel                        \
1022			--textbox \"\$file\" $size
1023	else
1024		eval $DIALOG \
1025			--title \"\$DIALOG_TITLE\"         \
1026			--backtitle \"\$DIALOG_BACKTITLE\" \
1027			--ok-label \"\$msg_ok\"            \
1028			--msgbox \"\$contents\" $size
1029	fi
1030}
1031
1032############################################################ YESNO FUNCTIONS
1033
1034# f_dialog_yesno $msg_text ...
1035#
1036# Display a dialog(1) Yes/No prompt to allow the user to make some decision.
1037# The yesno prompt remains until the user presses ENTER or ESC, acknowledging
1038# the modal dialog.
1039#
1040# If the user chooses YES the exit status is zero, or chooses NO the exit
1041# status is one, or presses ESC the exit status is 255.
1042#
1043f_dialog_yesno()
1044{
1045	local msg_text="$*"
1046	local hline="$hline_arrows_tab_enter"
1047	local size="$( f_dialog_buttonbox_size \
1048	               		"$DIALOG_TITLE"     \
1049	               		"$DIALOG_BACKTITLE" \
1050	               		"$msg_text"         \
1051	               		"$hline"            )"
1052
1053	if [ "$USE_XDIALOG" ]; then
1054		eval $DIALOG \
1055			--title \"\$DIALOG_TITLE\"         \
1056			--backtitle \"\$DIALOG_BACKTITLE\" \
1057			--hline \"\$hline\"                \
1058			--ok-label \"\$msg_yes\"           \
1059			--cancel-label \"\$msg_no\"        \
1060			--yesno \"\$msg_text\" $size
1061	else
1062		eval $DIALOG \
1063			--title \"\$DIALOG_TITLE\"         \
1064			--backtitle \"\$DIALOG_BACKTITLE\" \
1065			--hline \"\$hline\"                \
1066			--yes-label \"\$msg_yes\"          \
1067			--no-label \"\$msg_no\"            \
1068			--yesno \"\$msg_text\" $size
1069	fi
1070}
1071
1072# f_dialog_noyes $msg_text ...
1073#
1074# Display a dialog(1) No/Yes prompt to allow the user to make some decision.
1075# The noyes prompt remains until the user presses ENTER or ESC, acknowledging
1076# the modal dialog.
1077#
1078# If the user chooses YES the exit status is zero, or chooses NO the exit
1079# status is one, or presses ESC the exit status is 255.
1080#
1081# NOTE: This is just like the f_dialog_yesno function except "No" is default.
1082#
1083f_dialog_noyes()
1084{
1085	local msg_text="$*"
1086	local hline="$hline_arrows_tab_enter"
1087	local size="$( f_dialog_buttonbox_size \
1088	               		"$DIALOG_TITLE"     \
1089	               		"$DIALOG_BACKTITLE" \
1090	               		"$msg_text"         \
1091	               		"$hline"            )"
1092
1093	if [ "$USE_XDIALOG" ]; then
1094		eval $DIALOG \
1095			--title \"\$DIALOG_TITLE\"         \
1096			--backtitle \"\$DIALOG_BACKTITLE\" \
1097			--hline \"\$hline\"                \
1098			--default-no                       \
1099			--ok-label \"\$msg_yes\"           \
1100			--cancel-label \"\$msg_no\"        \
1101			--yesno \"\$msg_text\" $size
1102	else
1103		eval $DIALOG \
1104			--title \"\$DIALOG_TITLE\"         \
1105			--backtitle \"\$DIALOG_BACKTITLE\" \
1106			--hline \"\$hline\"                \
1107			--defaultno                        \
1108			--yes-label \"\$msg_yes\"          \
1109			--no-label \"\$msg_no\"            \
1110			--yesno \"\$msg_text\" $size
1111	fi
1112}
1113
1114############################################################ INPUT FUNCTIONS
1115
1116# f_dialog_inputstr
1117#
1118# Obtain the inputstr entered by the user from the most recently displayed
1119# dialog(1) inputbox and clean up any temporary files/variables.
1120#
1121f_dialog_inputstr()
1122{
1123	# Skip warnings and trim leading/trailing whitespace from user input
1124	eval echo \"\$DIALOG_INPUTBOX_$$\" | awk '
1125		BEGIN { found = 0 }
1126		{
1127			if ( ! found )
1128			{
1129				if ( $0 ~ /^$/ ) next
1130				if ( $0 ~ /^Gdk-WARNING \*\*:/ ) next
1131				found = 1
1132			}
1133			sub(/^[[:space:]]*/, "")
1134			sub(/[[:space:]]*$/, "")
1135			print
1136		}
1137	'
1138	setvar DIALOG_INPUTBOX_$$ "" # scrub memory in case data was sensitive
1139	return $SUCCESS
1140}
1141
1142# f_dialog_input $prompt [$init [$hline]]
1143#
1144# Prompt the user with a dialog(1) inputbox to enter some value. The inputbox
1145# remains until the the user presses ENTER or ESC, or otherwise ends the
1146# editing session, by selecting `Cancel' for example.
1147#
1148# If the user presses ENTER, the exit status is zero (success), otherwise if
1149# the user presses ESC the exit status is 255, or if the user chose Cancel, the
1150# exit status is instead 1.
1151#
1152# NOTE: The hline should correspond to the type of data you want from the user.
1153# NOTE: Should not be used to edit multiline values.
1154#
1155f_dialog_input()
1156{
1157	local prompt="$1" init="$2" hline="$3"
1158	local size="$( f_dialog_inputbox_size \
1159	               		"$DIALOG_TITLE"     \
1160	                        "$DIALOG_BACKTITLE" \
1161	               		"$prompt"           \
1162	               		"$init"             \
1163	               		"$hline"            )"
1164
1165	local opterm="--"
1166	[ "$USE_XDIALOG" ] && opterm=
1167
1168	local dialog_input
1169	dialog_input=$(
1170		eval $DIALOG \
1171			--title \"\$DIALOG_TITLE\"         \
1172			--backtitle \"\$DIALOG_BACKTITLE\" \
1173			--hline \"\$hline\"                \
1174			--ok-label \"\$msg_ok\"            \
1175			--cancel-label \"\$msg_cancel\"    \
1176			--inputbox \"\$prompt\" $size      \
1177			$opterm \"\$init\"                 \
1178			2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
1179	)
1180	local retval=$?
1181
1182	setvar DIALOG_INPUTBOX_$$ "$dialog_input"
1183	f_dialog_inputstr
1184
1185	return $retval
1186}
1187
1188############################################################ MENU FUNCTIONS
1189
1190# f_dialog_menutag
1191#
1192# Obtain the menutag chosen by the user from the most recently displayed
1193# dialog(1) menu and clean up any temporary files/variables.
1194#
1195f_dialog_menutag()
1196{
1197	# Skip warnings
1198	eval echo \"\$DIALOG_MENU_$$\" | awk '
1199		BEGIN { found = 0 }
1200		{
1201			if ( found ) # ... just spew
1202			{
1203				print
1204				next
1205			}
1206			if ( $0 ~ /^$/ ) next
1207			if ( $0 ~ /^Gdk-WARNING \*\*:/ ) next
1208			found = 1
1209			print
1210		}
1211	'
1212	setvar DIALOG_MENU_$$ "" # scrub memory in case data was sensitive
1213	return $SUCCESS
1214}
1215
1216# f_dialog_menutag2item $tag_chosen $tag1 $item1 $tag2 $item2 ...
1217#
1218# To use the `--menu' option of dialog(1) you must pass an ordered list of
1219# tag/item pairs on the command-line. When the user selects a menu option the
1220# tag for that item is printed to stderr.
1221#
1222# This function allows you to dereference the tag chosen by the user back into
1223# the item associated with said tag.
1224#
1225# Pass the tag chosen by the user as the first argument, followed by the
1226# ordered list of tag/item pairs (HINT: use the same tag/item list as was
1227# passed to dialog(1) for consistency).
1228#
1229# If the tag cannot be found, NULL is returned.
1230#
1231f_dialog_menutag2item()
1232{
1233	local tag="$1" tagn item
1234	shift 1 # tag
1235
1236	while [ $# -gt 0 ]; do
1237		tagn="$1"
1238		item="$2"
1239		shift 2 # tagn/item
1240
1241		if [ "$tag" = "$tagn" ]; then
1242			echo "$item"
1243			return $SUCCESS
1244		fi
1245	done
1246	return $FAILURE
1247}
1248
1249# f_dialog_menutag2item_with_help $tag_chosen $tag1 $item1 $help1 \
1250#                                             $tag2 $item2 $help2 ...
1251#
1252# To use the `--menu' option of dialog(1) with the `--item-help' option, you
1253# must pass an ordered list of tag/item/help triplets on the command-line. When
1254# the user selects a menu option the tag for that item is printed to stderr.
1255#
1256# This function allows you to dereference the tag chosen by the user back into
1257# the item associated with said tag (help is discarded/ignored).
1258#
1259# Pass the tag chosen by the user as the first argument, followed by the
1260# ordered list of tag/item/help triplets (HINT: use the same tag/item/help list
1261# as was passed to dialog(1) for consistency).
1262#
1263# If the tag cannot be found, NULL is returned.
1264#
1265f_dialog_menutag2item_with_help()
1266{
1267	local tag="$1" tagn item
1268	shift 1 # tag
1269
1270	while [ $# -gt 0 ]; do
1271		tagn="$1"
1272		item="$2"
1273		shift 3 # tagn/item/help
1274
1275		if [ "$tag" = "$tagn" ]; then
1276			echo "$item"
1277			return $SUCCESS
1278		fi
1279	done
1280	return $FAILURE
1281}
1282
1283# f_dialog_menutag2index $tag_chosen $tag1 $item1 $tag2 $item2 ...
1284#
1285# To use the `--menu' option of dialog(1) you must pass an ordered list of
1286# tag/item pairs on the command-line. When the user selects a menu option the
1287# tag for that item is printed to stderr.
1288#
1289# This function allows you to dereference the tag chosen by the user back into
1290# the index associated with said tag. The index is the one-based tag/item pair
1291# array position within the ordered list of tag/item pairs passed to dialog(1).
1292#
1293# Pass the tag chosen by the user as the first argument, followed by the
1294# ordered list of tag/item pairs (HINT: use the same tag/item list as was
1295# passed to dialog(1) for consistency).
1296#
1297# If the tag cannot be found, NULL is returned.
1298#
1299f_dialog_menutag2index()
1300{
1301	local tag="$1" tagn n=1
1302	shift 1 # tag
1303
1304	while [ $# -gt 0 ]; do
1305		tagn="$1"
1306		shift 2 # tagn/item
1307
1308		if [ "$tag" = "$tagn" ]; then
1309			echo $n
1310			return $SUCCESS
1311		fi
1312		n=$(( $n + 1 ))
1313	done
1314	return $FAILURE
1315}
1316
1317# f_dialog_menutag2index_with_help $tag_chosen $tag1 $item1 $help1 \
1318#                                              $tag2 $item2 $help2 ...
1319#
1320# To use the `--menu' option of dialog(1) with the `--item-help' option, you
1321# must pass an ordered list of tag/item/help triplets on the command-line. When
1322# the user selects a menu option the tag for that item is printed to stderr.
1323#
1324# This function allows you to dereference the tag chosen by the user back into
1325# the index associated with said tag. The index is the one-based tag/item/help
1326# triplet array position within the ordered list of tag/item/help triplets
1327# passed to dialog(1).
1328#
1329# Pass the tag chosen by the user as the first argument, followed by the
1330# ordered list of tag/item/help triplets (HINT: use the same tag/item/help list
1331# as was passed to dialog(1) for consistency).
1332#
1333# If the tag cannot be found, NULL is returned.
1334#
1335f_dialog_menutag2index_with_help()
1336{
1337	local tag="$1" tagn n=1
1338	shift 1 # tag
1339
1340	while [ $# -gt 0 ]; do
1341		tagn="$1"
1342		shift 3 # tagn/item/help
1343
1344		if [ "$tag" = "$tagn" ]; then
1345			echo $n
1346			return $SUCCESS
1347		fi
1348		n=$(( $n + 1 ))
1349	done
1350	return $FAILURE
1351}
1352
1353############################################################ INIT FUNCTIONS
1354
1355# f_dialog_init
1356#
1357# Initialize (or re-initialize) the dialog module after setting/changing any
1358# of the following environment variables:
1359#
1360# 	USE_XDIALOG   Either NULL or Non-NULL. If given a value will indicate
1361# 	              that Xdialog(1) should be used instead of dialog(1).
1362#
1363# 	SECURE        Either NULL or Non-NULL. If given a value will indicate
1364# 	              that (while running as root) sudo(8) authentication is
1365# 	              required to proceed.
1366#
1367f_dialog_init()
1368{
1369	DIALOG_SELF_INITIALIZE=
1370
1371	#
1372	# Clone terminal stdout so we can redirect to it from within sub-shells
1373	#
1374	eval exec $DIALOG_TERMINAL_PASSTHRU_FD\>\&1
1375
1376	#
1377	# Process stored command-line arguments
1378	#
1379	SECURE=$( set -- "$ARGV"
1380		while getopts S flag > /dev/null; do
1381			case "$flag" in
1382			S) echo 1;;
1383			\?) continue;;
1384			esac
1385		done
1386	)
1387	USE_XDIALOG=$( set -- "$ARGV"
1388		while getopts SX flag > /dev/null; do
1389			case "$flag" in
1390			S|X) echo 1;;
1391			\?) continue;;
1392			esac
1393		done
1394	)
1395
1396	#
1397	# Process `-X' command-line option
1398	#
1399	[ "$USE_XDIALOG" ] && DIALOG=Xdialog
1400
1401	#
1402	# Sanity check, or die gracefully
1403	#
1404	if ! f_have $DIALOG; then
1405		unset USE_XDIALOG
1406		failed_dialog="$DIALOG"
1407		DIALOG=dialog
1408		f_die 1 "$msg_no_such_file_or_directory" "$pgm" "$failed_dialog"
1409	fi
1410
1411	#
1412	# If we're already running as root but we got there by way of sudo(8)
1413	# and we have X11, we should merge the xauth(1) credentials from our
1414	# original user.
1415	#
1416	if [ "$USE_XDIALOG" ] &&
1417	   [ "$( id -u )" = "0" ] &&
1418	   [ "$SUDO_USER" -a "$DISPLAY" ]
1419	then
1420		if ! f_have xauth; then
1421			# Die gracefully, as we [likely] can't use Xdialog(1)
1422			unset USE_XDIALOG
1423			DIALOG=dialog
1424			f_die 1 "$msg_no_such_file_or_directory" "$pgm" "xauth"
1425		fi
1426		HOSTNAME=$(hostname)
1427		displaynum="${DISPLAY#*:}"
1428		eval xauth -if \~$SUDO_USER/.Xauthority extract - \
1429			\"\$HOSTNAME/unix:\$displaynum\" \
1430			\"\$HOSTNAME:\$displaynum\" | sudo sh -c 'xauth -ivf \
1431			~root/.Xauthority merge - > /dev/null 2>&1'
1432	fi
1433
1434	#
1435	# Probe Xdialog(1) for maximum height/width constraints, or die
1436	# gracefully
1437	#
1438	if [ "$USE_XDIALOG" ]; then
1439		if ! maxsize=$( LANG= LC_ALL= $DIALOG --print-maxsize 2>&1 )
1440		then
1441			# Xdialog(1) failed, fall back to dialog(1)
1442			unset USE_XDIALOG
1443			size=$( f_dialog_buttonbox_size "$DIALOG_TITLE" \
1444			                                "$DIALOG_BACKTITLE" \
1445			                                "$maxsize" "" )
1446			eval dialog \
1447				--title \"\$DIALOG_TITLE\"         \
1448				--backtitle \"\$DIALOG_BACKTITLE\" \
1449				--ok-label \"\$msg_ok\"            \
1450				--msgbox \"\$maxsize\" $size
1451			exit $FAILURE
1452		fi
1453
1454		XDIALOG_MAXSIZE=$(
1455			set -- ${maxsize##*:}
1456
1457			height=${1%,}
1458			width=$2
1459
1460			echo $height $width
1461		)
1462		unset maxsize
1463	fi
1464
1465	#
1466	# If using Xdialog(1), swap DIALOG_TITLE with DIALOG_BACKTITLE.
1467	# The reason for this is because many dialog(1) applications use
1468	# --backtitle for the program name (which is better suited as
1469	# --title with Xdialog(1)).
1470	#
1471	if [ "$USE_XDIALOG" ]; then
1472		_DIALOG_TITLE="$DIALOG_TITLE"
1473		DIALOG_TITLE="$DIALOG_BACKTITLE"
1474		DIALOG_BACKTITLE="$_DIALOG_TITLE"
1475		unset _DIALOG_TITLE
1476	fi
1477
1478	f_dprintf "f_dialog_init: dialog(1) API initialized."
1479}
1480
1481############################################################ MAIN
1482
1483f_dprintf "%s: DIALOG_SELF_INITIALIZE=[%s]" \
1484          dialog.subr "$DIALOG_SELF_INITIALIZE"
1485case "$DIALOG_SELF_INITIALIZE" in
1486""|0|[Nn][Oo]|[Oo][Ff][Ff]|[Ff][Aa][Ll][Ss][Ee]) : do nothing ;;
1487*) f_dialog_init
1488esac
1489
1490f_dprintf "%s: Successfully loaded." dialog.subr
1491
1492fi # ! $_DIALOG_SUBR
1493