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