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