#!/bin/bash APP_SVNID='$HeadURL$ $LastChangedRevision$' PROGNAME=${0##*/} VARS="PREFIX BIN_PREFIX DOC_PREFIX ETC_PREFIX INCLUDE_PREFIX LIB_PREFIX LOCK_PREFIX LOG_PREFIX MAN_PREFIX MAN1_PREFIX MAN2_PREFIX MAN3_PREFIX MAN4_PREFIX MAN5_PREFIX MAN6_PREFIX MAN7_PREFIX MAN8_PREFIX SHARE_PREFIX STATE_PREFIX" main() { local OUTFILE # Defaults for options APP_NAME=app ADE_MSG_VERBOSELEVEL=2 FORMAT=plain MODE=direct INDIRECT_FILENAME= # Option processing while [ "X$1" != X ]; do case $1 in --format=*) FORMAT=${1#*=} ;; --direct) MODE=direct ;; --indirect=*) MODE=indirect INDIRECT_FILENAME=${1##*=} ;; --indirect) MODE=indirect ;; -a) APP_NAME=$2; shift ;; --app-name=*) APP_NAME=${1#*=} ;; --debug=*) ADE_MSG_VERBOSELEVEL=${1#*=} ;; -d) ADE_MSG_VERBOSELEVEL=$2; shift ;; -v|--verbose) ADE_MSG_VERBOSELEVEL=3 ;; --) shift; break ;; -*) usage ;; *) break ;; esac shift done UC_APP_NAME=${APP_NAME^^} LC_APP_NAME=${APP_NAME,,} # Argument processing (supplied arguments are the settings to # be displayed; if none are supplied we want all, but what "all" # means we don't know yet). [ "X$1" = X ] || DESIRED_VARS="$@" # Stash the passed settings to accomplish two things: # 1) get an ordered list of variable names # 2) record but do not apply any values supplied STDIN_ASSIGMENTS=( $(cat) ) for STDIN_ASSIGMENT in "${STDIN_ASSIGMENTS[@]}"; do ade_app_config_debug 10 "main: read [$STDIN_ASSIGMENT] from stdin but not applied/derived to environment yet" done if [ "X$1" != X ]; then DESIRED_VARS="$@" ade_app_config_debug 10 "main: read [$DESIRED_VARS] from command line; these'll be what we output" else DESIRED_VARS= for STDIN_ASSIGMENT in "${STDIN_ASSIGMENTS[@]}"; do STDIN_VAR=${STDIN_ASSIGMENT%%=*} DESIRED_VARS="$DESIRED_VARS $STDIN_VAR" done ade_app_config_debug 10 "main: no variable names were on the command line; so we'll output the variables that were listed on stdin" fi # Loop over the variable part of the stdin assignments in the order # they are supplied. for STDIN_ASSIGMENT in "${STDIN_ASSIGMENTS[@]}"; do STDIN_VAR=${STDIN_ASSIGMENT%%=*} # If the variable is in the environment and not empty then # put it into our environment. Well, in fact we don't need # to do anything because it is *already* in the environment. if eval "[ \"X\$$STDIN_VAR\" != X ]"; then ade_app_config_debug 10 "main: $STDIN_VAR: already in the environment; no action needed" # In the environment but empty means we actively want a value # to be derived below! elif eval "[ \"X\${$STDIN_VAR+ISSET}\" = XISSET ]"; then ade_app_config_debug 10 "main: $STDIN_VAR: set in environment to empty value; we'll derive a value shortly ..." # That leaves not in the environment at all. So we'll use the the stdin-specified # (possibly empty) value. else ade_app_config_debug 10 "main: $STDIN_VAR: not set in environment so taking (possibly empty) value from stdin ..." eval "$STDIN_ASSIGMENT" fi # If it's still not-set/empty then we have no choice but to derivate a sensible value. if eval "[ \"X\$$STDIN_VAR\" = X ]"; then ade_app_config_debug 10 "main: $STDIN_VAR: still empty; deriving sensible value ..." case $STDIN_VAR in ${UC_APP_NAME}_PREFIX) eval "${UC_APP_NAME}_PREFIX=\${${UC_APP_NAME}_PREFIX:-/usr}" ;; ${UC_APP_NAME}_BIN_PREFIX) eval "${UC_APP_NAME}_BIN_PREFIX=\${${UC_APP_NAME}_BIN_PREFIX:-\$${UC_APP_NAME}_PREFIX/bin}" ;; ${UC_APP_NAME}_DOC_PREFIX) eval "${UC_APP_NAME}_DOC_PREFIX=\${${UC_APP_NAME}_DOC_PREFIX:-\$${UC_APP_NAME}_PREFIX/share/doc/${LC_APP_NAME}}" ;; ${UC_APP_NAME}_ETC_PREFIX) if eval "[ \"X\$${UC_APP_NAME}_PREFIX\" = X/usr ]"; then eval "${UC_APP_NAME}_ETC_PREFIX=\${${UC_APP_NAME}_ETC_PREFIX:-/etc/${LC_APP_NAME}}" else eval "${UC_APP_NAME}_ETC_PREFIX=\${${UC_APP_NAME}_ETC_PREFIX:-\$${UC_APP_NAME}_PREFIX/etc/${LC_APP_NAME}}" fi ;; ${UC_APP_NAME}_INCLUDE_PREFIX) eval "${UC_APP_NAME}_INCLUDE_PREFIX=\${${UC_APP_NAME}_INCLUDE_PREFIX:-\$${UC_APP_NAME}_PREFIX/include/${LC_APP_NAME}}" ;; ${UC_APP_NAME}_LIB_PREFIX) eval "${UC_APP_NAME}_LIB_PREFIX=\${${UC_APP_NAME}_LIB_PREFIX:-\$${UC_APP_NAME}_PREFIX/lib/${LC_APP_NAME}}" ;; ${UC_APP_NAME}_LOCK_PREFIX) if eval "[ \"X\$${UC_APP_NAME}_PREFIX\" = X/usr ]"; then eval "${UC_APP_NAME}_LOCK_PREFIX=\${${UC_APP_NAME}_LOCK_PREFIX:-/var/run}" else eval "${UC_APP_NAME}_LOCK_PREFIX=\${${UC_APP_NAME}_LOCK_PREFIX:-\$${UC_APP_NAME}_STATE_PREFIX/var/run}" fi ;; ${UC_APP_NAME}_LOG_PREFIX) if eval "[ \"X\$${UC_APP_NAME}_PREFIX\" = X/usr ]"; then eval "${UC_APP_NAME}_LOG_PREFIX=\${${UC_APP_NAME}_LOG_PREFIX:-/var/log/${LC_APP_NAME}}" else eval "${UC_APP_NAME}_LOG_PREFIX=\${${UC_APP_NAME}_LOG_PREFIX:-\$${UC_APP_NAME}_STATE_PREFIX/log}" fi ;; ${UC_APP_NAME}_MAN_PREFIX) eval "${UC_APP_NAME}_MAN_PREFIX=\${${UC_APP_NAME}_MAN_PREFIX:-\$${UC_APP_NAME}_PREFIX/share/man}" ;; ${UC_APP_NAME}_MAN1_PREFIX) eval "${UC_APP_NAME}_MAN1_PREFIX=\${${UC_APP_NAME}_MAN1_PREFIX:-\$${UC_APP_NAME}_MAN_PREFIX/man1}" ;; ${UC_APP_NAME}_MAN2_PREFIX) eval "${UC_APP_NAME}_MAN2_PREFIX=\${${UC_APP_NAME}_MAN2_PREFIX:-\$${UC_APP_NAME}_MAN_PREFIX/man2}" ;; ${UC_APP_NAME}_MAN3_PREFIX) eval "${UC_APP_NAME}_MAN3_PREFIX=\${${UC_APP_NAME}_MAN3_PREFIX:-\$${UC_APP_NAME}_MAN_PREFIX/man3}" ;; ${UC_APP_NAME}_MAN4_PREFIX) eval "${UC_APP_NAME}_MAN4_PREFIX=\${${UC_APP_NAME}_MAN4_PREFIX:-\$${UC_APP_NAME}_MAN_PREFIX/man4}" ;; ${UC_APP_NAME}_MAN5_PREFIX) eval "${UC_APP_NAME}_MAN5_PREFIX=\${${UC_APP_NAME}_MAN5_PREFIX:-\$${UC_APP_NAME}_MAN_PREFIX/man5}" ;; ${UC_APP_NAME}_MAN6_PREFIX) eval "${UC_APP_NAME}_MAN6_PREFIX=\${${UC_APP_NAME}_MAN6_PREFIX:-\$${UC_APP_NAME}_MAN_PREFIX/man6}" ;; ${UC_APP_NAME}_MAN7_PREFIX) eval "${UC_APP_NAME}_MAN7_PREFIX=\${${UC_APP_NAME}_MAN7_PREFIX:-\$${UC_APP_NAME}_MAN_PREFIX/man7}" ;; ${UC_APP_NAME}_MAN8_PREFIX) eval "${UC_APP_NAME}_MAN8_PREFIX=\${${UC_APP_NAME}_MAN8_PREFIX:-\$${UC_APP_NAME}_MAN_PREFIX/man8}" ;; ${UC_APP_NAME}_SHARE_PREFIX) eval "${UC_APP_NAME}_SHARE_PREFIX=\${${UC_APP_NAME}_SHARE_PREFIX:-\$${UC_APP_NAME}_PREFIX/share/${LC_APP_NAME}}" ;; ${UC_APP_NAME}_STATE_PREFIX) if eval "[ \"X\$${UC_APP_NAME}_PREFIX\" = X/usr ]"; then eval "${UC_APP_NAME}_STATE_PREFIX=\${${UC_APP_NAME}_STATE_PREFIX:-/var/lib/${LC_APP_NAME}}" else eval "${UC_APP_NAME}_STATE_PREFIX=\${${UC_APP_NAME}_STATE_PREFIX:-\$${UC_APP_NAME}_PREFIX/var}" fi ;; *) ade_app_config_error "$STDIN_VAR: no definition found either in environment or settings file" ;; esac fi done # Sanity checks # Encapsulated-make format cannot be used indirectly. #[ $FORMAT != encapsulated-make ] || [ $MODE = direct ] || ade_app_config_error "$FORMAT: format not available in '$MODE' mode" if [ $MODE = indirect -a "X$INDIRECT_FILENAME" = X ]; then INDIRECT_FILENAME=$(mktemp -t $PROGNAME.XXXXXXXX) fi # # Output prologue # # # Output body # # Because there are ade_app_config_error() calls in this loop, we cannot # pipe the loop's output into an if (because an exit # in the ade_app_config_error() will not exit). This means we need to # direct the loop's output *directly* to where we # want it to go (or use a temp file which I really don't # want to do in such an often called script. Ha! {varname} # comes to the rescue. if [ $MODE = direct ]; then # Unfortunately '&1' in a variable is not interpreted # correctly. One solution would be to use eval. Another # to use /dev/stdout. But that is probably Linux # specific. Actually, no; Solaris has it too. FD=1 else # Search bash man page for '{varname}' for an explanation of this. exec {FD}> $INDIRECT_FILENAME fi { if [ $FORMAT = encapsulated-make ]; then echo '$(foreach PACKED_ASSIGNMENT,' fi for DESIRED_VAR in $DESIRED_VARS; do UC_VAR=${DESIRED_VAR^^} LC_VAR=${DESIRED_VAR,,} eval "VALUE=\$$UC_VAR" # All *_PREFIX settings must be defined. Others (e.g. # FAD_SORT_CMD) are allowed not to be defined. ! [[ $DESIRED_VAR =~ _PREFIX$ ]] || [ "X$VALUE" != X ] || ade_app_config_error "$DESIRED_VAR: not defined (is this really the right name?)" case $FORMAT in shell) echo "$UC_VAR=$VALUE" ;; perl) echo "\$$LC_VAR = \"$VALUE\";" ;; python) echo "$LC_VAR = '$VALUE'" ;; #man) echo ".ds $LC_VAR $VALUE" ;; man) echo ".le value_length \\V[$UC_VAR]" echo ".ie ((\\n[value_length] == 0) \\{\\" echo ". ds $LC_VAR $VALUE" echo ".\\}" echo ".el \\{\\" echo ". ds $LC_VAR \\V[$UC_VAR]" echo ".\\}" echo ".rm value_length" ;; plain) echo "$VALUE" ;; make) echo "$UC_VAR = $VALUE" ;; encapsulated-make) echo "$UC_VAR = $VALUE" | sed 's/ /@/g' ;; cpp) echo "#define $UC_VAR \"$VALUE\"" ;; *) ade_app_config_error "$FORMAT: invalid format" ;; esac done if [ $FORMAT = encapsulated-make ]; then echo ',$(eval $(subst @, ,$(PACKED_ASSIGNMENT))))' fi } >&$FD [ $FD = 1 ] || exec {FD}<&- # # Output epilogue # if [ $MODE = indirect ]; then case $FORMAT in shell) echo ". $INDIRECT_FILENAME" ;; perl) echo "require '$INDIRECT_FILENAME';" ;; python) echo "import runpy" echo "locals().update({k:v for k,v in runpy.run_path('$INDIRECT_FILENAME').items() if k.startswith('${APP_NAME}_')})" ;; man) echo ".so $INDIRECT_FILENAME" ;; plain) echo "$INDIRECT_FILENAME" ;; make) echo "include $INDIRECT_FILENAME" ;; encapsulated-make) echo "include $INDIRECT_FILENAME" ;; cpp) echo "#include \"$INDIRECT_FILENAME\"" ;; esac fi } usage() { echo "Usage: $PROGNAME [ -d | --debug= | -v | --verbose ] [ --format= ] [ --[in]direct ] [ -a | --app-name= ] [ ... ]" >&2 exit 2 } # These messaging functions cannot be provided by ADE (or miniade) # because this script is so low-level. However, we do give them # prefixes in order to prevent my should-this-script-be-using-miniade # checks from flagging this file. ade_app_config_error() { echo "$PROGNAME: ERROR: $1">&2; exit 1 } ade_app_config_debug() { [ $ADE_MSG_VERBOSELEVEL -lt $1 ] || echo "$PROGNAME: DEBUG[$1]: $2">&2 } main "$@"