#!/bin/bash # $HeadURL$ $LastChangedRevision$ # Modules # This script may not use miniade! See comments near the bottom of this script for explanation. # Configurable stuff # Other globals main() { local MY_ARGS local FORMAT MODE INDIRECT_FILENAME APP_NAME # Defaults for options APP_NAME=app FORMAT=plain MODE=direct INDIRECT_FILENAME= # Process options while [ $# -ge 1 ]; do case $1 in # Standard options (many have no effect) -h|--help) help ;; -d) shift ;; --debug=*) : ;; -v|--verbose) : ;; -p|--paths) exit 0 ;; -V|--version) exit 0 ;; # Application-specific options --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#*=} ;; --) shift; break ;; -*) bad_usage ;; *) break ;; esac shift done # Process arguments DESIRED_VARS=( "${@^^}" ) # Sanity checks and derivations UC_APP_NAME=${APP_NAME^^} LC_APP_NAME=${APP_NAME,,} # The order is important in ALL_VARS: those that are # referenced by others (e.g. LOG_PREFIX needs STATE_PREFIX) # come first. eval "ALL_VARS=( ${UC_APP_NAME}_PREFIX ${UC_APP_NAME}_{BIN,DOC,ETC,INCLUDE,LIB,STATE,LOCK,LOG,SHARE,MAN,MAN1,MAN2,MAN3,MAN4,MAN5,MAN6,MAN7,MAN8}_PREFIX )" STDIN_VARS=() declare -A STDIN_VALS STDIN_VALS=() while read STDIN_ASS; do # Ignore empty lines and comments, either preceded by tabs or spaces. { ! [[ $STDIN_ASS =~ ^[\ $'\t']*($|#) ]]; } || continue [[ $STDIN_ASS =~ ^(${UC_APP_NAME}_(|[A-Z][A-Z0-9_]*_)PREFIX)=(.*)$ ]] || error "$STDIN_ASS: invalid assignment" VAR=${BASH_REMATCH[1]} VAL=${BASH_REMATCH[3]} FOUND=false for VAR2 in "${ALL_VARS[@]}"; do if [ $VAR = $VAR2 ]; then FOUND=true break fi done $FOUND || error "$VAR: unexpected variable name" STDIN_VARS+=( $VAR ) STDIN_VALS[$VAR]=$VAL done [ "${#DESIRED_VARS[@]}" != 0 ] || DESIRED_VARS=( "${STDIN_VARS[@]}" ) # Derive all variables for VAR in "${ALL_VARS[@]}"; do # If the variable is assigned in the environment then we use that (and because # we already have it in the enviromment there is nothing more to do). if eval "[ \"X\$$VAR\" != X ]"; then : # If the variable is assigned in the standard input then we use that. elif [ "X${STDIN_VALS[$VAR]}" != X ]; then eval "$VAR=\"\${STDIN_VALS[\$VAR]}\"" # Else derive else case $VAR in *_BIN_PREFIX) eval "$VAR=\$${UC_APP_NAME}_PREFIX/bin" ;; *_DOC_PREFIX) eval "$VAR=\$${UC_APP_NAME}_PREFIX/share/doc/$LC_APP_NAME" ;; *_ETC_PREFIX) if eval "[[ \$${UC_APP_NAME}_PREFIX = /usr ]]"; then eval "$VAR=/etc/$LC_APP_NAME" elif eval "[[ \$${UC_APP_NAME}_PREFIX = /usr/local ]]"; then eval "$VAR=\$${UC_APP_NAME}_PREFIX/etc/$LC_APP_NAME" else eval "$VAR=\$${UC_APP_NAME}_PREFIX/etc" fi ;; *_INCLUDE_PREFIX) eval "$VAR=\$${UC_APP_NAME}_PREFIX/include/$LC_APP_NAME" ;; *_LIB_PREFIX) eval "$VAR=\$${UC_APP_NAME}_PREFIX/lib/$LC_APP_NAME" ;; *_LOCK_PREFIX) eval "$VAR=/var/run" ;; *_LOG_PREFIX) if eval "[[ \$${UC_APP_NAME}_PREFIX = /usr ]]"; then eval "$VAR=/var/log/$LC_APP_NAME" else eval "$VAR=\$${UC_APP_NAME}_STATE_PREFIX/log" fi ;; *_MAN1_PREFIX) eval "$VAR=\$${UC_APP_NAME}_MAN_PREFIX/man1" ;; *_MAN2_PREFIX) eval "$VAR=\$${UC_APP_NAME}_MAN_PREFIX/man2" ;; *_MAN3_PREFIX) eval "$VAR=\$${UC_APP_NAME}_MAN_PREFIX/man3" ;; *_MAN4_PREFIX) eval "$VAR=\$${UC_APP_NAME}_MAN_PREFIX/man4" ;; *_MAN5_PREFIX) eval "$VAR=\$${UC_APP_NAME}_MAN_PREFIX/man5" ;; *_MAN6_PREFIX) eval "$VAR=\$${UC_APP_NAME}_MAN_PREFIX/man6" ;; *_MAN7_PREFIX) eval "$VAR=\$${UC_APP_NAME}_MAN_PREFIX/man7" ;; *_MAN8_PREFIX) eval "$VAR=\$${UC_APP_NAME}_MAN_PREFIX/man8" ;; *_SHARE_PREFIX) eval "$VAR=\$${UC_APP_NAME}_PREFIX/share/$LC_APP_NAME" ;; *_STATE_PREFIX) if eval "[[ \$${UC_APP_NAME}_PREFIX = /usr ]]"; then eval "$VAR=/var/lib/$LC_APP_NAME" else eval "$VAR=\$${UC_APP_NAME}_PREFIX/var" fi ;; *_MAN_PREFIX) eval "$VAR=\$${UC_APP_NAME}_PREFIX/share/man" ;; # *_PREFIX must be at the end to avoid substring matches on other terms. *_PREFIX) eval "$VAR=/usr" ;; *) error "$VAR: failed to evaluate" ;; esac fi done if [ $MODE = indirect -a "X$INDIRECT_FILENAME" = X ]; then INDIRECT_FILENAME=$(mktemp -t ${0##*/}.XXXXXXXX) fi # Guts if [ $MODE = direct ]; then FD=1 else # Open a filehandle onto the indirect filename. # (Search bash(1) for '{varname}' explanation.) exec {FD}> $INDIRECT_FILENAME fi { if [ $FORMAT = "encapsulated-make" ]; then echo '$(foreach PACKED_ASSIGNMENT,' fi for VAR in "${DESIRED_VARS[@]}"; do eval "VAL=\$$VAR" case $FORMAT in shell) echo "$VAR=$VAL" ;; perl) # Some languages define variables in lowe case. echo "\$${VAR,,} = \"$VAL\";" ;; python) echo "${VAR,,} = '$VAL'" ;; man) echo ".le value_length \\V[$VAR]" echo ".ie ((\\n[value_length] == 0) \\{\\" echo ". ds ${VAR,,} $VAL" echo ".\\}" echo ".el \\{\\" echo ". ds ${VAR,,} \\V[$VAR]" echo ".\\}" echo ".rm value_length" ;; plain) echo "$VAL" ;; make) echo "$VAR = $VAL" ;; encapsulated-make) echo "$VAR = $VAL" | sed 's/ /@/g' ;; cpp) echo "#define $VAR \"$VAL\"" ;; *) error "$FORMAT: invalid format" ;; esac done if [ $FORMAT = encapsulated-make ]; then echo ',$(eval $(subst @, ,$(PACKED_ASSIGNMENT))))' fi } >&$FD # For indirect, we need to close the indirect file, which is # still open and we need to generating the indirecting instructions # in the appropriate language. if [ $MODE = indirect ]; then exec {FD}<&- 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 } help() { echo "Usage: ${0##*/} [ ] [ --format= ] [ --[in]direct ] [ -a | --app-name= ] [ ... ]" exit 0 } # ADE and miniade are intended to be similar but independent. The consequence # is that this script, which is part of ADE, should not depend on miniade. # Also, since this script *helps* other scripts to find the ADE function # libraries, it cannot itself *use* those libraries (to do so would cause # chicken-and-egg recursion). So it must implement whatever it needs # (mainly: messaging functions, option processing) itself. Since this script # is not a module to be included by other files then such functions will # not be -prefixed. We also do not refer to any of # the standard variable names (e.g. PROG*NAME ('*' added to stop psrf flagging # this file)). error() { echo "${0##*/}: ERROR: $1" >&2 exit 1 } bad_usage() { echo "${0##*/}: ERROR: type '${0##*/} --help' for correct usage." >&2 exit 1 } main "$@"