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_include $file 144# 145# Include a shell subroutine file. 146# 147# If the subroutine file exists but returns error status during loading, exit 148# is called and execution is prematurely terminated with the same error status. 149# 150f_include() 151{ 152 local file="$1" 153 . "$file" || exit $? 154} 155 156# f_include_lang $file 157# 158# Include a language file. Automatically takes $LANG and $LC_ALL into 159# consideration when including $file (suffix ".$LC_ALL" or ".$LANG" will 160# automatically by added prior to loading the language file). 161# 162# No error is produced if (a) a language has been requested (by setting either 163# $LANG or $LC_ALL in the environment) and (b) the language file does not 164# exist -- in which case we will fall back to loading $file without-suffix. 165# 166# If the language file exists but returns error status during loading, exit 167# is called and execution is prematurely terminated with the same error status. 168# 169f_include_lang() 170{ 171 local file="$1" 172 local lang="${LANG:-$LC_ALL}" 173 174 f_dprintf "lang=[$lang]" 175 if [ -f "$file.$lang" ]; then 176 . "$file.$lang" || exit $? 177 else 178 . "$file" || exit $? 179 fi 180} 181 182# f_include_help NAME [$file] 183# 184# When given both arguments, cache the contents of a language help-file to 185# later be retrieved by executing again with only the first argument. 186# 187# Automatically takes $LANG and $LC_ALL into consideration when reading $file 188# (suffix ".$LC_ALL" or ".$LANG" will automatically be added prior to loading 189# the language help-file). 190# 191# If a language has been requested by setting either $LANG or $LC_ALL in the 192# environment and the language-specific help-file does not exist we will fall 193# back to $file without-suffix. 194# 195# If the language help-file does not exist, an error is cached in place of the 196# help-file contents. 197# 198f_include_help() 199{ 200 local name="$1" file="$2" 201 202 if [ "$file" ]; then 203 local lang="${LANG:-$LC_ALL}" 204 205 f_dprintf "name=[$name] lang=[$lang]" 206 if [ -f "$file.$lang" ]; then 207 setvar HELP_${name}_$$ "$( cat "$file.$lang" 2>&1 )" 208 else 209 setvar HELP_${name}_$$ "$( cat "$file" 2>&1 )" 210 fi 211 else 212 eval echo \"\$HELP_${name}_$$\" 213 fi 214} 215 216# f_usage $file [ $key1 $value1 ... ] 217# 218# Display USAGE file with optional pre-processor macro definitions. The first 219# argument is the template file containing the usage text to be displayed. If 220# $LANG or $LC_ALL (in order of preference, respectively) is set, ".encoding" 221# will automatically be appended as a suffix to the provided $file pathname. 222# 223# When processing $file, output begins at the first line containing that is 224# (a) not a comment, (b) not empty, and (c) is not pure-whitespace. All lines 225# appearing after this first-line are output, including (a) comments (b) empty 226# lines, and (c) lines that are purely whitespace-only. 227# 228# If additional arguments appear after $file, substitutions are made while 229# printing the contents of the USAGE file. The pre-processor macro syntax is in 230# the style of autoconf(1), for example: 231# 232# f_usage $file "FOO" "BAR" 233# 234# Will cause instances of "@FOO@" appearing in $file to be replaced with the 235# text "BAR" before bering printed to the screen. 236# 237# This function is a two-parter. Below is the awk(1) portion of the function, 238# afterward is the sh(1) function which utilizes the below awk script. 239# 240f_usage_awk=' 241BEGIN { found = 0 } 242{ 243 if ( !found && $0 ~ /^[[:space:]]*($|#)/ ) next 244 found = 1 245 print 246} 247' 248f_usage() 249{ 250 local file="$1" 251 local lang="${LANG:-$LC_ALL}" 252 253 f_dprintf "lang=[$lang]" 254 255 shift 1 # file 256 257 local usage 258 if [ -f "$file.$lang" ]; then 259 usage=$( awk "$f_usage_awk" "$file.$lang" ) || exit $FAILURE 260 else 261 usage=$( awk "$f_usage_awk" "$file" ) || exit $FAILURE 262 fi 263 264 while [ $# -gt 0 ]; do 265 local key="$1" 266 export value="$2" 267 usage=$( echo "$usage" | awk \ 268 "{ gsub(/@$key@/, ENVIRON[\"value\"]); print }" ) 269 shift 2 270 done 271 272 f_err "%s\n" "$usage" 273 274 exit $FAILURE 275} 276 277# f_index_menu_selection $file $pgm 278# 279# Process $file looking for $menu_selection values that correspond to $pgm. 280# This function is for internationalization (i18n) mapping of the on-disk 281# scriptname ($pgm) into the localized language (given language-specific 282# $file). If $LANG or $LC_ALL (in orderder of preference, respectively) is set, 283# ".encoding" will automatically be appended as a suffix to the provided $file 284# pathname. 285# 286# If, within $file, multiple $menu_selection values map to $pgm, only the first 287# one will be returned. If no mapping can be made, the NULL string is returned. 288# 289# If $file does not exist, error status is returned along with the NULL string. 290# 291# This function is a two-parter. Below is the awk(1) portion of the function, 292# afterward is the sh(1) function which utilizes the below awk script. 293# 294f_index_menusel_awk=' 295# Variables that should be defined on the invocation line: 296# -v pgm="program_name" 297# 298( $0 ~ "^menu_selection=.*\\|" pgm "\"" ) { 299 sub(/\|.*/, "") 300 sub(/^menu_selection="/, "") 301 print 302 exit 303} 304' 305f_index_menu_selection() 306{ 307 local file="$1" pgm="$2" 308 local lang="${LANG:-$LC_ALL}" 309 310 f_dprintf "lang=[$lang]" 311 312 if [ -f "$file.$lang" ]; then 313 awk -v pgm="$pgm" "$f_index_menusel_awk" "$file.$lang" || 314 exit $FAILURE 315 elif [ -f "$file" ]; then 316 awk -v pgm="$pgm" "$f_index_menusel_awk" "$file" || 317 exit $FAILURE 318 else 319 return $FAILURE 320 fi 321} 322 323############################################################ MAIN 324 325# 326# Trap signals so we can recover gracefully 327# 328trap 'f_interrupt' SIGINT 329trap 'f_die' SIGTERM SIGPIPE SIGXCPU SIGXFSZ \ 330 SIGFPE SIGTRAP SIGABRT SIGSEGV 331trap '' SIGALRM SIGPROF SIGUSR1 SIGUSR2 SIGHUP SIGVTALRM 332 333fi # ! $_COMMON_SUBR 334