#! /bin/bash
# Last edited on 2009-10-08 16:39:51 by stolfi
#===============================================================
usage="filter-files [-h] <filter> <file>..."

# Applies a <filter> command to a bunch of files, and compares each
# output with the original file.
# When the two differ, the <file> is renamed <file>~~ and the 
# filter output takes its place. Otherwise the <file> remains
# unchanged.

# It also lists all changes in the file
#   /tmp/filter-files-<pid>.log.

# the -h switch, if present, is passed to diff.
#===============================================================

diffopt=( )
if [[ "/$1" == "/-h"  ]]; then
  diffopt=( "$1" )
  shift
fi

cmd=( $1 ); shift

log="/tmp/filter-files-$$.log"
echo "cmd = [${cmd[@]}]" 1>&2
echo "fixing files..." 1>&2
echo '# File: '${log} > ${log}
echo '# Last modified by '$0' on '`date` >> ${log}
echo '# ' >> ${log}
if [[ $# -gt 10 ]]; then
  echo '# ' "$0 ${cmd[@]} ${@:0:10}" '...' >> ${log}
else
  echo '# ' "$0 ${cmd[@]} $@" >> ${log}
fi
echo '# ' >> ${log}
echo '# Changes (< = original, > = new): ' >> ${log}
echo '# ' >> ${log}
for infile in "$@" ; do
  echo -n "Fixing ${infile} ... " 1>&2
  echo ' ' >> ${log}
  echo -n "Fixing ${infile} ... " >> ${log}
  if [[ ! ( -f ${infile} ) ]]; then
    echo "${infile} is not a file\!" 1>&2
    continue
  fi
  if [[ ! ( -r ${infile} ) ]]; then
    echo "${infile} is unreadable\!" 1>&2
    continue
  fi
  backup="${infile}~~"
  oldbackup="${infile}~~~"
  result="${infile}~~~~"
  ${cmd[@]} < ${infile} > ${result}
  status=$?
  if [[ ${status} -ne 0  ]]; then
    /bin/rm ${result}
    echo "failed, status = ${status}." 1>&2
    echo "failed, status = ${status}." >> ${log}
    break
  else
    /usr/bin/cmp -s ${infile} ${result}
    status=$?
    if [[ ${status} -eq 0 ]]; then
      /bin/rm ${result}
      echo 'no changes.' 1>&2
      echo 'no changes.' >> ${log}
      continue
    else
      if [[ -e ${backup} ]]; then
        /bin/mv -f ${backup} ${oldbackup}
      fi
      /bin/mv ${infile} ${backup}
      /bin/mv ${result} ${infile}
      chmod --reference=${backup} ${infile}
      echo 'done.' 1>&2
      echo ' changed:' >> ${log}
      echo ' ' >>${log}
      /usr/bin/diff ${diffopt} ${backup} ${infile} \
        | sed \
            -e '/^---/d' \
            -e '1,$s/^[0-9].*//g' \
        >> ${log}
    fi
  fi
done
echo "Done (see ${log})." 1>&2
