Blob Blame History Raw
# -*- mode: sh; -*-

#
# Public domain
#
# Written by Aleksey Cheusov <vle@gmx.net>
# based on the code from FAQ of comp.unix.shell newsgroup
#
# Set of shell functions for running pipe and checking
# exit status of ALL programs, not only last one.
#
# Version 0.6.0
#

# 
__shquote (){
    __cmd=`printf '%s\n' "$1" | sed "s|'|'\\\\\''|g"`
    printf "%s\n" "'$__cmd'"
}

__pipestatus_err_msg (){
    if test "$PIPESTATUS_VERBOSE"; then
	echo "Pipe failed, pipestatus_all='$pipestatus_all'" 1>&2
    fi
}

# run pipe and set pipestatus_1, pipestatus_2, ... and pipesize variables
# Example: runpipe_base prog1 arg11 arg12 '|' prog2 arg21 arg22 '|' prog3
# Always return zero exit status
runpipe_base (){
    #
    pipesize=0

    # whole command
    __pipestatus_com=

    # token count
    __pipestatus_k=1

    # program in pipe (between |)
    __pipestatus_l=

    # counter
    __pipestatus_j=1

    # generating whole command
    for __pipestatus_a in "$@"; do
        if [ "_$__pipestatus_a" = '_|' ]; then
            __pipestatus_com="$__pipestatus_com {
   if $__pipestatus_l 3>&-"'; then
      echo "pipestatus_'$__pipestatus_j'=0" 1>&3
   else
      echo "pipestatus_'$__pipestatus_j'=$?" 1>&3
   fi
} 4>&- |
'
            __pipestatus_j=`expr $__pipestatus_j + 1`
	    __pipestatus_l=
        else
            __pipestatus_l="$__pipestatus_l `__shquote \"$__pipestatus_a\"`"
        fi
        __pipestatus_k=`expr $__pipestatus_k + 1`
    done
    __pipestatus_com="if $__pipestatus_com $__pipestatus_l 3>&- 1>&4 4>&-"'; then
      echo "pipestatus_'"$__pipestatus_j"'=0"
   else
      echo "pipestatus_'"$__pipestatus_j"'=$?"
   fi'

    #
#    echo "$__pipestatus_com"

    # '|| true' - trick for 'set -e'
    exec 4>&1 
    eval `exec 3>&1; eval "$__pipestatus_com" || true`
    exec 4>&- 

    #
    pipesize=$__pipestatus_j

    # pipestatus_all
    __pipestatus_j=2
    pipestatus_all=$pipestatus_1
    while [ "$__pipestatus_j" -le "$pipesize" 2>/dev/null ]; do
	eval "pipestatus_all=\"$pipestatus_all \$pipestatus_$__pipestatus_j\""
        __pipestatus_j=`expr $__pipestatus_j + 1`
    done

    return 0
}

# returns zero exit status if ALL progs in pipe return zero
check_status0 (){
    __pipestatus_j=1
    while [ "$__pipestatus_j" -le "$pipesize" ]; do
	eval "[ \$pipestatus_$__pipestatus_j -eq 0 ]" || {
	    __pipestatus_err_msg
	    return 1
	}
	__pipestatus_j=`expr $__pipestatus_j + 1`
    done

    return 0
}

# returns zero exit status if ALL progs in pipe return zero
runpipe0 (){
    runpipe_base "$@"
    check_status0
}

# match all statuses with the pattern
# example: check_status_re '0 . 0'
# . means "any status"
check_status_re (){
    __pipestatus_re=`echo $1 | sed 's/[.]/[0-9][0-9]*/g'`
    __pipestatus_j=1
    __pipestatus_ps=
    while [ "$__pipestatus_j" -le "$pipesize" ]; do
	eval '__pipestatus_ps="$__pipestatus_ps ${pipestatus_'$__pipestatus_j'}"'
	__pipestatus_j=`expr $__pipestatus_j + 1`
    done

    # trick for set -e
    if echo "$__pipestatus_ps" | grep -E "^ $__pipestatus_re"'$' > /dev/null
    then
	__pipestatus_ret=0
    else
	__pipestatus_ret=$?
	__pipestatus_err_msg
    fi

    # egrep not found?
    case "$__pipestatus_ret" in
	0|1)
	    ;;
	*)
	    exit 2; # fatal error with egrep
    esac

    return $__pipestatus_ret
}

# match all statuses with the pattern
# example: runpipe_re '0 . 0' prog1 '|' prog2 '|' prog3
# . means "any status"
runpipe_re (){
    __pipestatus_re="$1"
    shift

    runpipe_base "$@"
    check_status_re "$__pipestatus_re"
}

# return exit code of the last program in pipe
check_status (){
    eval return '$pipestatus_'${pipesize}
}

# similar to plain pipe but set 'pipestatus_XX' and 'pipesize' variables
runpipe (){
    runpipe_base "$@"
    check_status
}