123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410 |
- #!/bin/bash
-
-
- ##-----------##
- ## FRONT-END ##
- ##-----------##
-
- debug() {
- #
- # You already know what it does.
- #
- # BTW, following are equivalent:
- #
- # debug "var1=$var1" "var2=$var2" "result=$result"
- # debug -v var1 var2 result
- # debug -v "var@ result"
- #
- $FFOO_DEBUG || return 0
- __echo "$@"
- }
-
- debug_pipe() {
- #
- # Debug the whole pipe.
- #
- grep . \
- | while IFS= read line;
- do
- debug "|$1: '$line'"
- echo "$line"
- done
- }
-
- die() {
- #
- # A Perl-style death
- #
- __echo -t
- __echo $*
- exit 9
- }
-
- filter() {
- debug "\$*=$*"
- while read item;
- do $* $item && echo "$item"; done
- }
-
-
- usage_is() {
- #
- # Echo out usage patterns and exit 1
- #
- # Define usage() in your script and use this in body
- #
- __echo -u "$@";
- exit 1
- }
-
- think() {
- #
- # If verose is on, think loud.
- #
- # Use "-l" to split every parameter to separate line, (useful
- # or longer warnings)
- #
- $FFOO_VERBOSE || return 0
- __echo "$@"
- }
-
- warn() {
- #
- # Warn them
- #
- # Use "-l" to split every parameter to separate line, (useful
- # or longer warnings)
- #
- # Resist temptation to prefix "warning" or similar BS here.
- # STDERR is *made* for warnings.
- #
- __echo "$@"
- }
-
-
- ##----------##
- ## BACK-END ##
- ##----------##
-
- __cat() {
- # cat without starting a process
- while IFS= read line;
- do echo "$line"; done
- }
-
- __echo() {
- #
- # A smarter echo backend
- #
- # A smarter backend for debug, warn, think and die.
- #
- # -f file echo output of a file (- for stdin)
- # -c cmd echo output of a command
- # -l line [line...] take each line and
- # echo it separately
- # -v vars show contents of each var
- # -d call `decorate` with name of function
- # that called __echo and each argument
- # given
- #
- ffoo import mkpretty_${FFOO_MKPRETTY}
- local caller=${FUNCNAME[2]}
- local front=${FUNCNAME[1]}
- case "$caller" in
- usage) caller="${FUNCNAME[3]}"; ;&
- __echo_*) caller="${FUNCNAME[3]}"; ;&
- debug_pipe) caller="${FUNCNAME[3]}"; ;&
- main) caller="$(basename $0)"; ;;
- *) caller="$caller()" ;;
- esac
- test "$front" == "usage" && front=usage_is
- local mkpretty=__cat
- local src="args"
- while true; do case $1 in
- -c|--cmd) src=cmd; shift; break ;;
- -f|--files) src=files; shift; break ;;
- -l|--lines) src=lines; shift; break ;;
- -t|--trace) src=trace; shift; break ;;
- -u|--usage) src=usage; shift; break ;;
- -v|--vars) src=vars; shift; break ;;
- *) break ;;
- esac done
- $want_pretty && mkpretty=mkpretty_$front
- case $front in
- warn|debug|die|usage_is) __echo_$src "$@" | $mkpretty >&2 ;;
- think) __echo_$src "$@" | $mkpretty ;;
- *) echo "do not call __echo* directly" >&2; exit 2 ;;
- esac
- }
-
- __echo_args() {
- echo "$@"
- }
-
- __echo_cmd() {
- local c=\$
- test $(id -u) -eq 0 && c=\#
- echo "$c $*"
- $@
- }
-
- __echo_files() {
- local fp
- for fp in "$@";
- do
- echo "-- $fp --"
- cat $1
- done
- }
-
- __echo_lines() {
- local l;
- for l in "$@"; do __echo "$l"; done
- }
-
- __echo_trace() {
- $FFOO_DEBUG || return 0
- local -a tr=(${FUNCNAME[@]})
- unset tr[0]; unset tr[1]; unset tr[2];
- local tmp=$(echo "${tr[*]}" | tr ' ' '\n' | tac )
- echo "== trace =="
- echo "$tmp" | sed -e 's/^/-> /g'
- }
-
- __echo_usage() {
- local u
- for u in "$@";
- do echo "usage: $caller $u"
- done
- }
-
- __echo_vars() {
- local vn
- for vn in "$@";
- do
- local heel="${vn:0-1}" # last char
- local toes="${vn%%$heel}" # all but last char
- case "$heel" in
- @)
- # FIXME: review+fix the eval (even at cost of
- # dropping the feature)
- local vars=$(eval "echo \"\${!$toes$heel}\"")
- __echo_vars $vars
- ;;
- *)
- debug "$vn='$(echo -n ${!vn})'"
- ;;
- esac
- done
- }
-
-
- echo_hr() {
- #
- # A horizontal ruler out of char "$1" all across terminal.
- #
- test 0$COLUMNS -gt 0 || return
- local char="$1"
- local i
- for (( i=1; $i<$COLUMNS; i=$i+1 )); do echo -n "$char"; done
- echo
- }
-
- mute_known() {
- #
- # Mute known messages
- #
- # For those yums and rpms that don't know theit manners.
- # Use with care!
- #
- grep -vxf <(iniread -s mute -k $1 mute.ini)
- }
-
- append_if_missing() {
- #
- # Append line to the file but only if it's not already there.
- #
- # Handy for your fstabs, or whatever line-based confs Handy
- # for your fstabs, or whatever line-based confs
- #
- local line=$1
- local file=$2
- grep -qsx "$line" $file || echo "$line" >> $file
- }
-
- collapse_tilde() {
- #
- # Exchange home back to "~".
- #
- # Nice to save them users from some eye pain.
- #
- perl -pe "s|^$HOME|~|"
- }
-
- expand_tilde() {
- #
- # Exchange "~" for home.
- #
- perl -pe "s|^[[:space:]]*~|$HOME|"
- }
-
- __iniread__cat() {
- # cat without starting a process
- while IFS= read line;
- do echo "$line"; done
- }
-
- __iniread__flt_comments() {
- grep -v -e "^[[:space:]]*[#;]" -e "^[[:space:]]*$"
- }
-
- __iniread__flt_key() {
- # filter values from key=value pair
- local line
- local key
- local value
- while IFS= read line;
- do
- line=$(sed -re 's/^\s*//' <<<"$line")
- key=$(sed -re 's/\s*=.*//; s/^\s*//' <<<"$line")
- if $strict;
- then
- value=$(sed -re 's/[^=]*=//' <<<"$line")
- else
- value=$(sed -re 's/[^=]*=\s*//' <<<"$line")
- fi
- if test "$key" = "$wantkey";
- then
- echo "$value"
- fi
- done
- }
-
- __iniread__flt_section() {
- # filter per section
- local section_ok=false
- local line
- while IFS= read line;
- do
- if grep -qse "^\[$wantsection\]" <<<"$line";
- then
- section_ok=true
- elif grep -qse "^\[" <<<"$line";
- then
- section_ok=false
- elif $section_ok;
- then
- $strict || line="$(sed -re 's/^\s*//' <<<"$line")"
- echo "$line"
- fi
- done
- }
-
- __iniread__merge() {
- if test -z "$1";
- then # read only stdin
- cat
- return
- fi
- local arg trydir trypath
- for arg in "$@";
- do
- debug -v arg
- case $arg in
- -|*/*) # stdin, or path (with slash)
- cat $arg
- ;;
- *) # name given, find all its incarnations
- debug -v FFOO_INIPATH
- echo "$FFOO_INIPATH" \
- | tr ':' '\n' \
- | while read trydir;
- do
- trypath="$trydir/$arg"
- debug -v trypath
- cat $trypath 2>/dev/null
- done
- ;;
- esac
- done
- true
- }
-
- iniread() {
- #
- # A flexible (not just) .ini file reader
- #
- # Can read anything from commented plaintext to keyless section INI,
- # sectionless keyed INI or sectioned keyed INI, including multi-line
- # and whitespace-safe chunks.
- #
- # Is constantly becoming smarter and smarter.
- #
- local wantsection=""
- local wantkey=""
- local strict=false
- local section_ok=true
- local one_line=false
- while true;
- do
- case $1 in
- --)
- break
- ;;
- -1|--one-line)
- one_line=true
- shift 1
- ;;
- -k|--key)
- wantkey="$2"
- shift 2
- ;;
- -p|--path)
- wantkey="$(echo $2 | rev | cut -d. -f1 | rev)"
- wantsection="${2%.$wantkey}"
- shift 2
- ;;
- -s|--section)
- wantsection="$2"
- section_ok=false
- shift 2
- ;;
- -S|--strict)
- strict=true
- shift 1
- ;;
- -l|--list-sections)
- #TODO: list sections
- warn "--list-sections is not implemented"
- shift
- ;;
- -L|--list-keys)
- #TODO: list keys as section/key (with -s, list keys only)
- warn "--list-keys is not implemented"
- shift
- ;;
- "")
- break
- ;;
- *)
- break
- ;;
- esac
- done
-
- flt_section=__iniread__cat
- flt_key=__iniread__cat
- limit_line=__iniread__cat
- test -n "$wantsection" && flt_section=__iniread__flt_section
- test -n "$wantkey" && flt_key=__iniread__flt_key
- $one_line && limit_line="head -1"
-
- debug -v wantkey wantsection
- debug "\$@='$@'"
-
- __iniread__merge "$@" \
- | __iniread__flt_comments \
- | $flt_section \
- | $flt_key \
- | $limit_line
- }
|