#!/bin/bash # $HeadURL$ $LastChangedRevision$ # Modules . $(miniade) || { echo "${0##*/}: ERROR: miniade failed (hint: run 'miniade' to see error)" >&2; exit 1; } # Configurable stuff # Other globals main() { local MY_ARGS local FORMAT MODE INDIRECT_FILENAME APP_NAME PROGNAME # Defaults for options APP_NAME=app FORMAT=plain MODE=direct INDIRECT_FILENAME= # Process options special_opts_handler() { case $1 in --format=*) FORMAT=${1#*=} ;; --direct) MODE=direct ;; --indirect=*) MODE=indirect INDIRECT_FILENAME=${1##*=} ;; --indirect) MODE=indirect ;; -a) APP_NAME=$2; extra_shift ;; --app-name=*) APP_NAME=${1#*=} ;; *) return 1 ;; esac } miniade_process_options --help-handler=help --special-opts-handler=special_opts_handler MY_ARGS "$@" && set -- "${MY_ARGS[@]}" # 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 )" miniade_debug 10 "main: ALL_VARS=( ${ALL_VARS[*]} )" miniade_debug 10 "slurping stdin ..." STDIN_VARS=() declare -A STDIN_VALS STDIN_VALS=() while read STDIN_ASS; do miniade_debug 10 "main: STDIN_ASS=$STDIN_ASS" # 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)=(.*)$ ]] || miniade_error "$STDIN_ASS: invalid assignment" VAR=${BASH_REMATCH[1]} VAL=${BASH_REMATCH[3]} miniade_debug 10 "main: VAR=[$VAR], VAL=[$VAL]" FOUND=false for VAR2 in "${ALL_VARS[@]}"; do if [ $VAR = $VAR2 ]; then FOUND=true break fi done $FOUND || miniade_error "$VAR: unexpected variable name" STDIN_VARS+=( $VAR ) STDIN_VALS[$VAR]=$VAL done [ "${#DESIRED_VARS[@]}" != 0 ] || DESIRED_VARS=( "${STDIN_VARS[@]}" ) miniade_debug 10 "main: DESIRED_VARS=( ${DESIRED_VARS[*]} )" miniade_debug 10 "main: STDIN_VALS/keys=( ${!STDIN_VALS[*]} )" miniade_debug 10 "main: STDIN_VALS/values=( ${STDIN_VALS[*]} )" # Derive all variables miniade_debug 10 "setting all variables from environment or stdin or derivation ..." for VAR in "${ALL_VARS[@]}"; do miniade_debug 10 "main: VAR=$VAR" # 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 miniade_debug 10 "main: $VAR: inherited through environment" # If the variable is assigned in the standard input then we use that. elif [ "X${STDIN_VALS[$VAR]}" != X ]; then miniade_debug 10 "main: $VAR: assigned on standard input" eval "$VAR=\"\${STDIN_VALS[\$VAR]}\"" # Else derive else miniade_debug 10 "main: $VAR: attempting to derive ..." 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" ;; *) miniade_error "$VAR: failed to evaluate" ;; esac miniade_debug 10 "main: $VAR: derived" fi done if [ $MODE = indirect -a "X$INDIRECT_FILENAME" = X ]; then miniade_get_progname PROGNAME INDIRECT_FILENAME=$(mktemp -t $PROGNAME.XXXXXXXX) fi # Guts if [ $MODE = direct ]; then miniade_debug 10 "main: will use stdout" FD=1 else # Open a filehandle onto the indirect filename. # (Search bash(1) for '{varname}' explanation.) miniade_debug 10 "main: opening a file for indirect mode ..." exec {FD}> $INDIRECT_FILENAME fi { if [ $FORMAT = "encapsulated-make" ]; then echo '$(foreach PACKED_ASSIGNMENT,' fi miniade_debug 10 "main: looping over desired variables ..." for VAR in "${DESIRED_VARS[@]}"; do eval "VAL=\$$VAR" miniade_debug 10 "main: VAR=$VAR, VAL=$VAL" 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\"" ;; *) miniade_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() { local PROGNAME miniade_get_progname PROGNAME echo "Usage: $PROGNAME [ ] [ --format= ] [ --[in]direct ] [ -a | --app-name= ] [ ... ]" exit 0 } main "$@"