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