1if [ ! "$_COMMON_SUBR" ]; then _COMMON_SUBR=1 2# 3# Copyright (c) 2012 Ron McDowell 4# Copyright (c) 2012 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############################################################ GLOBALS 31 32# 33# Program name 34# 35pgm="${0##*/}" 36 37# 38# Program arguments 39# 40ARGC="$#" 41ARGV="$@" 42 43# 44# Global exit status variables 45# 46SUCCESS=0 47FAILURE=1 48 49############################################################ FUNCTIONS 50 51# 52# This is an empty function by default, to use it, copy 53# /usr/share/examples/bsdconfig/bsdconfigrc to $HOME/.bsdconfigrc 54# 55f_dprintf() 56{ 57 : this page intentionally left blank 58} 59 60# f_err $fmt [ $opts ... ] 61# 62# Print a message to stderr (fd=2). 63# 64f_err() 65{ 66 printf "$@" >&2 67} 68 69# f_quietly $command [ $arguments ... ] 70# 71# Run a command quietly (quell any output to stdout or stderr) 72# 73f_quietly() 74{ 75 "$@" > /dev/null 2>&1 76} 77 78# f_have $anything ... 79# 80# A wrapper to the `type' built-in. Returns true if argument is a valid shell 81# built-in, keyword, or externally-tracked binary, otherwise false. 82# 83f_have() 84{ 85 f_quietly type "$@" 86} 87 88# f_die [ $status [ $fmt [ $opts ... ]]] 89# 90# Abruptly terminate due to an error optionally displaying a message in a 91# dialog box using printf(1) syntax. 92# 93f_die() 94{ 95 local status=$FAILURE 96 97 # If there is at least one argument, take it as the status 98 if [ $# -gt 0 ]; then 99 status=$1 100 shift 1 # status 101 fi 102 103 # If there are still arguments left, pass them to f_show_msg 104 [ $# -gt 0 ] && f_show_msg "$@" 105 106 # Optionally call f_clean_up() function if it exists 107 f_have f_clean_up && f_clean_up 108 109 exit $status 110} 111 112# f_interrupt 113# 114# Interrupt handler. 115# 116f_interrupt() 117{ 118 exec 2>&1 # fix sh(1) bug where stderr gets lost within async-trap 119 f_die 120} 121 122# f_show_msg $fmt [ $opts ... ] 123# 124# Display a message in a dialog box using printf(1) syntax. 125# 126f_show_msg() 127{ 128 local msg 129 msg=$( printf "$@" ) 130 131 # 132 # Use f_dialog_msgbox from dialog.subr if possible, otherwise fall 133 # back to dialog(1) (without options, making it obvious when using 134 # un-aided system dialog). 135 # 136 if f_have f_dialog_msgbox; then 137 f_dialog_msgbox "$msg" 138 else 139 dialog --msgbox "$msg" 0 0 140 fi 141} 142 143# f_show_help $file 144# 145# Display a language help-file. Automatically takes $LANG and $LC_ALL into 146# consideration when displaying $file (suffix ".$LC_ALL" or ".$LANG" will 147# automatically be added prior to loading the language help-file). 148# 149# If a language has been requested by setting either $LANG or $LC_ALL in the 150# environment and the language-specific help-file does not exist we will fall 151# back to $file without-suffix. 152# 153# If the language help-file does not exist, an error is displayed instead. 154# 155f_show_help() 156{ 157 local file="$1" 158 local lang="${LANG:-$LC_ALL}" 159 160 [ -f "$file.$lang" ] && file="$file.$lang" 161 162 # 163 # Use f_dialog_textbox from dialog.subr if possible, otherwise fall 164 # back to dialog(1) (without options, making it obvious when using 165 # un-aided system dialog). 166 # 167 if f_have f_dialog_textbox; then 168 f_dialog_textbox "$file" 169 else 170 dialog --msgbox "$( cat "$file" 2>&1 )" 0 0 171 fi 172} 173 174# f_include $file 175# 176# Include a shell subroutine file. 177# 178# If the subroutine file exists but returns error status during loading, exit 179# is called and execution is prematurely terminated with the same error status. 180# 181f_include() 182{ 183 local file="$1" 184 . "$file" || exit $? 185} 186 187# f_include_lang $file 188# 189# Include a language file. Automatically takes $LANG and $LC_ALL into 190# consideration when including $file (suffix ".$LC_ALL" or ".$LANG" will 191# automatically by added prior to loading the language file). 192# 193# No error is produced if (a) a language has been requested (by setting either 194# $LANG or $LC_ALL in the environment) and (b) the language file does not 195# exist -- in which case we will fall back to loading $file without-suffix. 196# 197# If the language file exists but returns error status during loading, exit 198# is called and execution is prematurely terminated with the same error status. 199# 200f_include_lang() 201{ 202 local file="$1" 203 local lang="${LANG:-$LC_ALL}" 204 205 f_dprintf "lang=[$lang]" 206 if [ -f "$file.$lang" ]; then 207 . "$file.$lang" || exit $? 208 else 209 . "$file" || exit $? 210 fi 211} 212 213# f_usage $file [ $key1 $value1 ... ] 214# 215# Display USAGE file with optional pre-processor macro definitions. The first 216# argument is the template file containing the usage text to be displayed. If 217# $LANG or $LC_ALL (in order of preference, respectively) is set, ".encoding" 218# will automatically be appended as a suffix to the provided $file pathname. 219# 220# When processing $file, output begins at the first line containing that is 221# (a) not a comment, (b) not empty, and (c) is not pure-whitespace. All lines 222# appearing after this first-line are output, including (a) comments (b) empty 223# lines, and (c) lines that are purely whitespace-only. 224# 225# If additional arguments appear after $file, substitutions are made while 226# printing the contents of the USAGE file. The pre-processor macro syntax is in 227# the style of autoconf(1), for example: 228# 229# f_usage $file "FOO" "BAR" 230# 231# Will cause instances of "@FOO@" appearing in $file to be replaced with the 232# text "BAR" before bering printed to the screen. 233# 234# This function is a two-parter. Below is the awk(1) portion of the function, 235# afterward is the sh(1) function which utilizes the below awk script. 236# 237f_usage_awk=' 238BEGIN { found = 0 } 239{ 240 if ( !found && $0 ~ /^[[:space:]]*($|#)/ ) next 241 found = 1 242 print 243} 244' 245f_usage() 246{ 247 local file="$1" 248 local lang="${LANG:-$LC_ALL}" 249 250 f_dprintf "lang=[$lang]" 251 252 shift 1 # file 253 254 local usage 255 if [ -f "$file.$lang" ]; then 256 usage=$( awk "$f_usage_awk" "$file.$lang" ) || exit $FAILURE 257 else 258 usage=$( awk "$f_usage_awk" "$file" ) || exit $FAILURE 259 fi 260 261 while [ $# -gt 0 ]; do 262 local key="$1" 263 export value="$2" 264 usage=$( echo "$usage" | awk \ 265 "{ gsub(/@$key@/, ENVIRON[\"value\"]); print }" ) 266 shift 2 267 done 268 269 f_err "%s\n" "$usage" 270 271 exit $FAILURE 272} 273 274# f_index_menu_selection $file $pgm 275# 276# Process $file looking for $menu_selection values that correspond to $pgm. 277# This function is for internationalization (i18n) mapping of the on-disk 278# scriptname ($pgm) into the localized language (given language-specific 279# $file). If $LANG or $LC_ALL (in orderder of preference, respectively) is set, 280# ".encoding" will automatically be appended as a suffix to the provided $file 281# pathname. 282# 283# If, within $file, multiple $menu_selection values map to $pgm, only the first 284# one will be returned. If no mapping can be made, the NULL string is returned. 285# 286# If $file does not exist, error status is returned along with the NULL string. 287# 288# This function is a two-parter. Below is the awk(1) portion of the function, 289# afterward is the sh(1) function which utilizes the below awk script. 290# 291f_index_menusel_awk=' 292# Variables that should be defined on the invocation line: 293# -v pgm="program_name" 294# 295( $0 ~ "^menu_selection=.*\\|" pgm "\"" ) { 296 sub(/\|.*/, "") 297 sub(/^menu_selection="/, "") 298 print 299 exit 300} 301' 302f_index_menu_selection() 303{ 304 local file="$1" pgm="$2" 305 local lang="${LANG:-$LC_ALL}" 306 307 f_dprintf "lang=[$lang]" 308 309 if [ -f "$file.$lang" ]; then 310 awk -v pgm="$pgm" "$f_index_menusel_awk" "$file.$lang" || 311 exit $FAILURE 312 elif [ -f "$file" ]; then 313 awk -v pgm="$pgm" "$f_index_menusel_awk" "$file" || 314 exit $FAILURE 315 else 316 return $FAILURE 317 fi 318} 319 320############################################################ MAIN 321 322# 323# Trap signals so we can recover gracefully 324# 325trap 'f_interrupt' SIGINT 326trap 'f_die' SIGTERM SIGPIPE SIGXCPU SIGXFSZ \ 327 SIGFPE SIGTRAP SIGABRT SIGSEGV 328trap '' SIGALRM SIGPROF SIGUSR1 SIGUSR2 SIGHUP SIGVTALRM 329 330fi # ! $_COMMON_SUBR 331