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