#!/bin/sh
# Filename: ctee
# Location: /usr/bin/
# Author: bgstack15@gmail.com
# Startdate: 2017-03-16 20:22:00
# Title: Script that Tees and Handles Color
# Purpose: Shows colorized output but saves to file the plain text
# Package: bgscripts
# History: 
#    2017-11-11a Added FreeBSD location support
#    2018-07-26a rewrite to work even for a switched user
#    2018-12-10 change directory
#    2020-04-19 remove trap 17 (breaks dash)
# Usage: Always needs stdin from a pipe.
#    If a command wants to send uncolored stdout to tee, use unbuffer.
#    unbuffer ls -lF --color=always | ctee
# Reference: ftemplate.sh 2017-01-11a; framework.sh 2017-01-11a
#   find process on the other end of a pipe: https://superuser.com/a/401619/318045
#   remove color: http://www.commandlinefu.com/commands/view/3584/remove-color-codes-special-characters-with-sed
# Improve:
fiversion="2017-01-17a"
cteeversion="2018-07-26a"

usage() {
   ${PAGER:-/usr/bin/less -F} 1>&2 <<ENDUSAGE
usage: some-program | ctee.sh [-auV] [-d </dev/tty/example>] [outfile1]
version ${cteeversion}
 -a append  Set CTEE_APPEND=1
 -n noappend  Set CTEE_APPEND=0
 -d /dev/pts/5 Set CTEE_DEBUG_TTY
 -u usage   Show this usage block.
 -V version Show script version number.
This script operates tee and preserves color on the output while sending uncolored output to the file.
Sometimes a program needs to be used with unbuffer to display color to a pipe.
Return values:
0 Normal
1 Help or version info displayed
2 Count or type of flaglessvals is incorrect
3 Incorrect OS type 4 Unable to find dependency
5 Not run as root or sudo
Environment variables:
CTEE_APPEND [0|1]  If 1, append. Default behavior is overwrite.
CTEE_DEBUG_TTY     Output debug information to this file or special device. Default is /dev/null.
ENDUSAGE
}

# DEFINE FUNCTIONS
clean_ctee() {
   # use at end of entire script if you need to clean up tmpfiles
   # rm -f "${CTEE_tmpfile1}" "${tmpfile2}" 2>/dev/null

   # Delayed cleanup
   if test -z "${FETCH_NO_CLEAN}" ;
   then
      nohup /bin/bash <<EOF 1>/dev/null 2>&1 &
sleep "${CTEE_CLEANUP_SEC:-1}" ; /bin/rm -r "${CTEE_TMPDIR:-NOTHINGTODELETE}" 1>/dev/null 2>&1 ;
EOF
   fi
}

parseFlag() {
   flag="$1"
   hasval=0
   case ${flag} in
      # INSERT FLAGS HERE
      "d" | "debug" | "DEBUG" | "dd" ) getval ; CTEE_DEBUG_TTY="${tempval}" ;;
      "u" | "usage" | "help" | "h" ) usage; exit 1;;
      "V" | "fcheck" | "version" ) ferror "${scriptfile} version ${cteeversion}"; exit 1;;
      "a" | "append" ) CTEE_APPEND=1;;
      "n" | "noappend" | "no-append" | "no" | "overwrite" | "notappend" | "over-write" ) CTEE_APPEND=0;;
      "c" | "conf" | "conffile" | "config" ) getval ; conffile="${tempval}";;
   esac
   
   debuglev 10 && { test ${hasval} -eq 1 && ferror "flag: ${flag} = ${tempval}" || ferror "flag: ${flag}"; }
}

# DETERMINE LOCATION OF FRAMEWORK
f_needed=20171111
while read flocation ; do if test -e ${flocation} ; then __thisfver="$( sh ${flocation} --fcheck 2>/dev/null )" ; if test ${__thisfver} -ge ${f_needed} ; then frameworkscript="${flocation}" ; break; else printf "Obsolete: %s %s\n" "${flocation}" "${__this_fver}" 1>&2 ; fi ; fi ; done <<EOFLOCATIONS
./framework.sh
${scriptdir}/framework.sh
$HOME/bin/bgscripts/framework.sh
$HOME/bin/framework.sh
$HOME/bgscripts/framework.sh
$HOME/framework.sh
/usr/local/bin/bgscripts/framework.sh
/usr/local/bin/framework.sh
/usr/bin/bgscripts/framework.sh
/usr/bin/framework.sh
/bin/bgscripts/framework.sh
/usr/local/share/bgscripts/framework.sh
/usr/share/bgscripts/framework.sh
/usr/libexec/bgscripts/framework.sh
EOFLOCATIONS
test -z "${frameworkscript}" && echo "$0: framework not found. Aborted." 1>&2 && exit 4

# INITIALIZE VARIABLES
# variables set in framework:
# today server thistty scriptdir scriptfile scripttrim
# is_cronjob stdin_piped stdout_piped stderr_piped sendsh sendopts
. ${frameworkscript} || echo "$0: framework did not run properly. Continuing..." 1>&2
outfile1=
CTEE_APPEND=0
CTEE_DEBUG_TTY=/dev/null
define_if_new default_conffile "/etc/default/ctee"
define_if_new defuser_conffile ~/.cteerc
test -z "${CTEE_TMPDIR}" && CTEE_TMPDIR="$( mktemp -d )"
CTEE_tmpfile1="$( TMPDIR="${CTEE_TMPDIR}" mktemp )"

# VALIDATE PARAMETERS
# objects before the dash are options, which get filled with the optvals
# to debug flags, use option DEBUG. Variables set in framework: fallopts
validateparams outfile1 - "$@"

# LEARN EX_DEBUG
test -z "${__debug_set_by_param}" && fisnum "${CTEE_DEBUG}" && debug="${CTEE_DEBUG}"

# CONFIRM TOTAL NUMBER OF FLAGLESSVALS IS CORRECT
if test ${thiscount} -lt 1;
then
   outfile1=/dev/null
fi

# LOAD CONFIG FROM SIMPLECONF
# This section follows a simple hierarchy of precedence, with first being used:
#    1. parameters and flags
#    2. environment
#    3. config file
#    4. default user config: ~/.config/script/script.conf
#    5. default config: /etc/script/script.conf
if test -f "${conffile}";
then
   get_conf "${conffile}"
else
   if test "${conffile}" = "${default_conffile}" || test "${conffile}" = "${defuser_conffile}"; then :; else test -n "${conffile}" && ferror "${scriptfile}: Ignoring conf file which is not found: ${conffile}."; fi
fi
test -f "${defuser_conffile}" && get_conf "${defuser_conffile}"
test -f "${default_conffile}" && get_conf "${default_conffile}"

# SET TRAPS
#trap "CTRLC" 2
#trap "CTRLZ" 18
trap "__ec=$? ; clean_ctee ; trap '' 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 18 19 20 ; exit ${__ec} ;" 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 18 19 20

# MAIN LOOP
rm -rf "${CTEE_tmpfile1}" ; mkfifo "${CTEE_tmpfile1}"
case "${CTEE_APPEND}" in
   1)
      { tee "${CTEE_tmpfile1}" | sed -u -r "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?){0,5}[m|K]//g" >> "${outfile1}" ; } | cat "${CTEE_tmpfile1}"
      ;;
   *) 
      { tee "${CTEE_tmpfile1}" | sed -u -r "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?){0,5}[m|K]//g" > "${outfile1}" ; } | cat "${CTEE_tmpfile1}"
      ;;
esac
