1#!/bin/sh 2#- 3# Copyright (c) 2012 Ron McDowell 4# Copyright (c) 2012-2013 Devin Teske 5# All rights reserved. 6# 7# Redistribution and use in source and binary forms, with or without 8# modification, are permitted provided that the following conditions 9# are met: 10# 1. Redistributions of source code must retain the above copyright 11# notice, this list of conditions and the following disclaimer. 12# 2. Redistributions in binary form must reproduce the above copyright 13# notice, this list of conditions and the following disclaimer in the 14# documentation and/or other materials provided with the distribution. 15# 16# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26# SUCH DAMAGE. 27# 28# $FreeBSD$ 29# 30############################################################ INCLUDES 31 32# When common.subr is included, it automatically scans "$@" for `-d' and/or 33# `-D file' arguments to conditionally enable debugging. Similarly, when 34# dialog.subr is included, it automatically scans "$@" for `-X' and/or `-S'. 35# To prevent this scanning from becoming confused by extra options, define 36# any/all extra arguments to use in the optstring to getopts when scanning 37# for dedicated options such as those described. 38# 39# NOTE: This needs to be declared before including `common.subr'. 40# NOTE: You really only need to list flags that require an argument as unknown 41# flags are silently accepted unless they take an argument (in which case 42# the following argument will terminate option processing unless it looks 43# like a flag). 44# 45GETOPTS_EXTRA="f:" 46 47BSDCFG_SHARE="/usr/share/bsdconfig" 48. $BSDCFG_SHARE/common.subr || exit 1 49f_dprintf "%s: loading includes..." "$0" 50f_include $BSDCFG_SHARE/dialog.subr 51f_include $BSDCFG_SHARE/mustberoot.subr 52f_include $BSDCFG_SHARE/strings.subr 53 54BSDCFG_LIBE="/usr/libexec/bsdconfig" 55f_include_lang $BSDCFG_LIBE/include/messages.subr 56 57BSDCONFIG_HELPFILE=$BSDCFG_LIBE/include/bsdconfig.hlp 58USAGE_HELPFILE=$BSDCFG_LIBE/include/usage.hlp 59 60############################################################ FUNCTIONS 61 62# usage 63# 64# display usage and exit 65# 66usage() 67{ 68 local index="INDEX" 69 local cmd_list # Calculated below 70 71 cd $BSDCFG_LIBE 72 # No need to preserve CWD (headed toward exit) 73 74 # Test for language-specific indices 75 f_quietly ls */"$index.${LANG:-$LC_ALL}" && 76 index="$index.${LANG:-$LC_ALL}" 77 78 cmd_list=$( 79 awk '/^menu_selection="/ { 80 sub(/\|.*/, "") 81 sub(/^menu_selection="/, "") 82 print 83 }' */$index | sort 84 ) 85 86 # 87 # Determine the longest command-length (in characters) 88 # 89 local longest_cmd 90 longest_cmd=$( echo "$cmd_list" | f_longest_line_length ) 91 f_dprintf "longest_cmd=[%s]" "$longest_cmd" 92 93 # 94 # Determine the maximum width of terminal/console 95 # 96 local max_size="$( stty size 2> /dev/null )" 97 : ${max_size:="24 80"} 98 local max_width="${max_size#*[$IFS]}" 99 f_dprintf "max_width=[%s]" "$max_width" 100 101 # 102 # Using the longest command-length as the width of a single column, 103 # determine if we can use more than one column to display commands. 104 # 105 local x=$longest_cmd ncols=1 106 x=$(( $x + 8 )) # Accomodate leading tab character 107 x=$(( $x + 3 + $longest_cmd )) # Preload end of next column 108 while [ $x -lt $max_width ]; do 109 ncols=$(( $ncols + 1 )) 110 x=$(( $x + 3 + $longest_cmd )) 111 done 112 f_dprintf "ncols=[%u] x=[%u]" $ncols $x 113 114 # 115 # Re-format the command-list into multiple columns 116 # 117 cmd_list=$( eval "$( echo "$cmd_list" | 118 awk -v ncols=$ncols -v size=$longest_cmd ' 119 BEGIN { 120 n = 0 121 row_item[1] = "" 122 } 123 function print_row() 124 { 125 fmt = "printf \"\\t%-" size "s" 126 for (i = 1; i < cur_col; i++) 127 fmt = fmt " %-" size "s" 128 fmt = fmt "\\n\"" 129 printf "%s", fmt 130 for (i = 1; i <= cur_col; i++) 131 printf " \"%s\"", row_item[i] 132 print "" 133 } 134 { 135 n++ 136 cur_col = (( n - 1 ) % ncols ) + 1 137 printf "f_dprintf \"row_item[%u]=[%%s]\" \"%s\"\n", 138 cur_col, $0 139 row_item[cur_col] = $0 140 if ( cur_col == ncols ) print_row() 141 } 142 END { 143 if ( cur_col < ncols ) print_row() 144 }' )" 145 ) 146 147 f_usage $BSDCFG_LIBE/USAGE \ 148 "PROGRAM_NAME" "$pgm" \ 149 "COMMAND_LIST" "$cmd_list" 150 151 # Never reached 152} 153 154# dialog_menu_main 155# 156# Display the dialog(1)-based application main menu. 157# 158dialog_menu_main() 159{ 160 local title="$DIALOG_TITLE" 161 local btitle="$DIALOG_BACKTITLE" 162 local prompt="$msg_menu_text" 163 local menu_list=" 164 'X' '$msg_exit' '$msg_exit_bsdconfig' 165 '1' '$msg_usage' '$msg_quick_start_how_to_use_this_menu_system' 166 " # END-QUOTE 167 local defaultitem= # Calculated below 168 local hline= 169 170 local menuitem menu_title menu_help menu_selection index=2 171 for menuitem in $( cd $BSDCFG_LIBE && ls -d [0-9][0-9][0-9].* ); do 172 [ $index -lt ${#DIALOG_MENU_TAGS} ] || break 173 tag=$( f_substr "$DIALOG_MENU_TAGS" $index 1 ) 174 175 menu_program= 176 menu_title= 177 menu_help= 178 f_include_lang $BSDCFG_LIBE/$menuitem/INDEX 179 [ "$menu_program" ] || continue 180 181 case "$menu_program" in 182 /*) : already fully qualified ;; 183 *) menu_program="$menuitem/$menu_program" 184 esac 185 186 f_shell_escape "$menu_title" menu_title 187 f_shell_escape "$menu_help" menu_help 188 setvar "menu_program$tag" "$menu_program" 189 menu_list="$menu_list '$tag' '$menu_title' '$menu_help'" 190 191 index=$(( $index + 1 )) 192 done 193 194 local height width rows 195 eval f_dialog_menu_with_help_size height width rows \ 196 \"\$title\" \ 197 \"\$btitle\" \ 198 \"\$prompt\" \ 199 \"\$hline\" \ 200 $menu_list 201 202 # Obtain default-item from previously stored selection 203 f_dialog_default_fetch defaultitem 204 205 local menu_choice 206 menu_choice=$( eval $DIALOG \ 207 --clear \ 208 --title \"\$title\" \ 209 --backtitle \"\$btitle\" \ 210 --hline \"\$hline\" \ 211 --item-help \ 212 --ok-label \"\$msg_ok\" \ 213 --cancel-label \"\$msg_exit_bsdconfig\" \ 214 --help-button \ 215 --help-label \"\$msg_help\" \ 216 ${USE_XDIALOG:+--help \"\"} \ 217 --default-item \"\$defaultitem\" \ 218 --menu \"\$prompt\" \ 219 $height $width $rows \ 220 $menu_list \ 221 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD 222 ) 223 local retval=$? 224 f_dialog_data_sanitize menu_choice 225 f_dialog_menutag_store "$menu_choice" 226 227 # Only update default-item on success 228 [ $retval -eq 0 ] && f_dialog_default_store "$menu_choice" 229 230 return $retval 231} 232 233############################################################ MAIN 234 235# 236# If $0 is not "bsdconfig", interpret it either as a keyword to a menuitem or 237# as a valid resword (see script.subr for additional details about reswords). 238# 239if [ "$pgm" != "bsdconfig" ]; then 240 if indexfile=$( f_index_file "$pgm" ) && 241 cmd=$( f_index_menusel_command "$indexfile" "$pgm" ) 242 then 243 f_dprintf "pgm=[%s] indexfile=[%s] cmd=[%s]" \ 244 "$pgm" "$indexfile" "$cmd" 245 exec "$cmd" "$@" || exit 1 246 else 247 f_include $BSDCFG_SHARE/script.subr 248 for resword in $RESWORDS; do 249 [ "$pgm" = "$resword" ] || continue 250 # Found a match 251 f_dprintf "pgm=[%s] A valid resWord!" "$pgm" 252 f_dispatch $resword 253 exit $? 254 done 255 fi 256fi 257 258# 259# Process command-line arguments 260# 261scripts_loaded=0 262while getopts f:h$GETOPTS_STDARGS flag; do 263 case "$flag" in 264 f) [ $scripts_loaded -eq 0 ] && f_include $BSDCFG_SHARE/script.subr 265 f_script_load "$OPTARG" 266 scripts_loaded=$(( $scripts_loaded + 1 )) ;; 267 h|\?) usage ;; 268 esac 269done 270shift $(( $OPTIND -1 )) 271 272# If we've loaded any scripts, do not continue any further 273[ $scripts_loaded -gt 0 ] && exit 274 275# 276# Initialize 277# 278f_dialog_title "$msg_main_menu" 279 280[ "$SECURE" ] && f_mustberoot_init 281 282# Incorporate rc-file if it exists 283[ -f "$HOME/.bsdconfigrc" ] && f_include "$HOME/.bsdconfigrc" 284 285# 286# If a non-option argument was passed, process it as a menuitem selection... 287# 288if [ "$1" ]; then 289 # 290 # ...unless it's a long-option for usage. 291 # 292 case "$1" in -help|--help|-\?) 293 usage 294 # Not reached 295 esac 296 297 # 298 # Find the INDEX (possibly i18n) claiming this keyword and get the 299 # command to execute from the menu_selection line. 300 # 301 if ! { indexfile=$( f_index_file "$1" ) && 302 cmd=$( f_index_menusel_command "$indexfile" "$1" ) 303 }; then 304 # no matches, display usage (which shows valid keywords) 305 f_err "%s: %s: $msg_not_found\n" "$pgm" "$1" 306 usage 307 # Not reached 308 fi 309 310 shift 311 exec $cmd ${USE_XDIALOG:+-X} "$@" || exit 1 312 # Not reached 313fi 314 315# 316# Launch application main menu 317# 318while :; do 319 dialog_menu_main 320 retval=$? 321 f_dialog_menutag_fetch mtag 322 f_dprintf "retval=%u mtag=[%s]" $retval "$mtag" 323 324 if [ $retval -eq 2 ]; then 325 # The Help button was pressed 326 f_show_help "$BSDCONFIG_HELPFILE" 327 continue 328 elif [ $retval -ne 0 ]; then 329 f_die 330 fi 331 332 case "$mtag" in 333 X) break ;; 334 1) # Usage 335 f_show_help "$USAGE_HELPFILE" 336 continue 337 esac 338 339 # Anything else is a dynamically loaded menuitem 340 341 f_getvar menu_program$mtag menu_program 342 case "$menu_program" in 343 /*) cmd="$menu_program" ;; 344 *) cmd="$BSDCFG_LIBE/$menu_program" 345 esac 346 f_dprintf "cmd=[%s]" "$cmd" 347 $cmd ${USE_XDIALOG:+-X} 348done 349 350exit $SUCCESS 351 352################################################################################ 353# END 354################################################################################ 355