#! /bin/bash #(C) 2009-2012 C. Junghans # junghans@votca.org # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # #version 0.1 04.08.10 -- initial version #version 0.1.1, 05.08.10 -- added -D and -o #version 0.1.2, 04.10.10 -- make -D work again and better help #version 0.1.3, 10.05.11 -- added --text to diff_opts to allow diff of binary files (issue #3) #version 0.1.4, 10.05.11 -- removed --text again and handle case of binary files #version 0.2.0, 15.04.12 -- clean up + bugfix thanks to Arne #version 0.2.1, 15.04.12 -- clean up + new bug report address #version 0.2.2, 20.04.12 -- fixed a bug if argument were dirs #version 0.2.3, 18.12.12 -- replace usage of mktemp with bash built-ins #version 0.2.4, 31.08.13 -- fixed deleted leading spaces #version 0.2.5, 06.09.13 -- do not expand escape sequences in diff #version 0.2.6, 18.09.13 -- allow 1st argument begin a file with --filter FAT_GREEN="" GREEN="" FAT_RED="" RED="" MAGENTA="" FAT_BLACK="" OFF="" NL=" " usage="Usage: ${0##*/} [OPTIONS] FILE1 FILE2" quiet="no" diff="no" filter="no" diff_opts='--new-file --unified --show-c-function --recursive' ab="no" out="-" style="wdiff" a2ps="" a2ps_opts="--prologue=color" color="yes" color_filter() { if [[ $a2ps ]]; then #seems like a bug in the a2ps style file sed -e "s/\[-/[wd-/g" -e "s/-\]/-wd]/g" -e "s/{+/{wd+/g" -e "s/+}/+wd}/g" $1 elif [[ $color = yes ]]; then sed -e "s/\[-/$RED/g" -e "s/-\]/$OFF/g" -e "s/{+/$GREEN/g" -e "s/+}/$OFF/g" $1 else cat $1 fi } die() { [[ $* ]] && echo "$*" exit 1 } qecho() { [[ $quiet = yes ]] || echo "$*" } show_help () { cat << eof A colorized version of wdiff $usage OPTIONS: -f, --filter Act as a wdiff color filter only and don't excute diff/wdiff internally, just colorize input (no ARGS = read from stdin) -d, --diff Preprocess input with diff and before giving it to wdiff (very useful for dirs). Option can be used in combination with --filter option meaning input is a patch. -D, --diffonly Process input with diff, but NOT with wdiff, so ${0##*/} basically acts like a colorized version of diff. Option can be used in combination with --filter option meaning input is a patch. --diffopts XXX Change opts of diff Default: '$diff_opts' --ab replace trunc of dirname by 'a' and 'b' --no-color Disable color (implies --a2psopts '--prologue=ul') -a, --a2ps Pipe the output to a2ps, which will produce ps code (also work with --filter) --a2psopts XXX Change opts of a2ps Default: '$a2ps_opts' -o, --out FILE Change output file Default: stdout -- Stop parsing options -h, --help Show this help -v, --version Show version --hg Show last log message for hg (or cvs) Examples: ${0##*/} -d dir1 dir2 ${0##*/} file1 file2 ${0##*/} --ab -D dir1 dir2 ${0##*/} -a --ab -D dir1 dir2 > file.ps wdiff file1 file2 | ${0##*/} -f diff -u file1 file2 | ${0##*/} -D -f Report bugs and comments at https://code.google.com/p/cj-overlay/issues/list or junghans@votca.org eof } shopt -s extglob while [[ ${1} = -?* ]]; do if [[ ${1} = --??*=* ]]; then # case --xx=yy set -- "${1%%=*}" "${1#*=}" "${@:2}" # --xx=yy to --xx yy elif [[ ${1} = -[^-]?* ]]; then # case -xy split if [[ ${1} = -[o]* ]]; then #short opts with arguments set -- "${1:0:2}" "${1:2}" "${@:2}" # -xy to -x y else #short opts without arguments set -- "${1:0:2}" "-${1:2}" "${@:2}" # -xy to -x -y fi fi case $1 in --ab) ab="yes" shift;; --no-color) unset FAT_GREEN GREEN FAT_RED RED MAGENTA OFF FAT_BLACK a2ps_opts="--prologue=ul" color="no" shift;; -f | --filter) filter="yes" shift ;; -d | --diff) diff="yes" shift ;; -D | --diffonly) diff="only" shift ;; -a | --a2ps) a2ps="a2ps" unset FAT_GREEN GREEN FAT_RED RED MAGENTA OFF FAT_BLACK shift ;; --a2psopts) a2ps_opts="$2" shift 2;; -o | --out) out="$2" [[ ! $out ]] && die "Missing filename after --out option" shift 2;; --diffopts) diff_opts="$2" shift ;; -q | --quiet) quiet="yes" shift ;; -h | --help) show_help exit 0;; --hg) echo "${0##*/}: $(sed -ne 's/^#version.* -- \(.*$\)/\1/p' $0 | sed -n '$p')" exit 0;; -v | --version) echo "${0##*/}, $(sed -ne 's/^#\(version.*\) -- .*$/\1/p' $0 | sed -n '$p') by C. Junghans" exit 0;; --) shift break;; *) die "Unknown option '$1'";; esac done [[ $1 = - ]] && filter="yes" && shift if [[ $filter = no ]]; then [[ ! $1 || ! $2 ]] && die "Please specify two files/dirs or add --filter option" #use -e as it could be file or dir [[ -e $1 ]] || die "Could not read file/dir '$1'" [[ -e $2 ]] || die "Could not read file/dir '$2'" [[ $3 ]] && die "I don't know what to do with arguments '${@:3}'" else [[ -n $1 && ! -f $1 ]] && die "Could not read file '$1'" [[ $2 ]] && die "I don't know what to do with arguments '$*' together --filter option" fi if [[ $diff != no ]]; then if [[ $filter = no ]]; then exec 3< <(diff $diff_opts "$1" "$2") #don't die here, because diff of binary files give exit code = 2 else [[ $1 ]] && exec 3<$1 || exec 3<&0 fi # don't do this if we have not files ;-) if [[ $ab = yes && $1 && $2 ]]; then #find the longest equal part in $1 and $2 from the end for ((i=1;i<=(${#1}<${#2}?${#1}:${#2});i++)); do [[ ${1:0-$i} != ${2:0-$i} ]] && break done ((i--)) a="${1:0:${#1}-$i}" b="${2:0:${#2}-$i}" else a=a; b=b fi # -r to not expand escape sequences in diff while read -r -u 3; do #small trick, because "read -u 3 i" would split the line and #leading space would be lost. i="${REPLY}" if [[ $i = "Files "*" and "*" differ" ]]; then # binary case i="${i/$a/a}" i="${i/$b/b}" echo "$i" elif [[ $i = diff* ]]; then # diff header line i="${i/ $diff_opts}" i="${i/$a/a}" echo "$FAT_BLACK${i/$b/b}$OFF" elif [[ $i = ---* ]]; then echo "${FAT_RED}${i/$a/a}${OFF}" elif [[ $i = +++* ]]; then echo "${FAT_GREEN}${i/$b/b}${OFF}" elif [[ $i = @@* ]]; then echo "${MAGENTA}${i}${OFF}" elif [[ $i = -* ]]; then [[ $diff = only ]] && echo "${RED}${i}${OFF}" || t1+="${i#-}$NL" elif [[ $i = +* ]]; then [[ $diff = only ]] && echo "${GREEN}${i}${OFF}" || t2+="${i#+}$NL" else # only true for diff != only # cut the last newline do avoid an empty line at the end (echo append newline) # echo -n would also work, but wdiff has strange behaviour if the 2nd file is # empty, it will not append newline, which make the output look strange [[ $t1 || $t2 ]] && { wdiff <(echo "${t1%$NL}") <(echo "${t2%$NL}") | color_filter; } t1= t2= [[ $diff = only ]] && echo "${i}" || echo "${i## }" fi done # thanks to Arne Babenhauserheide for pointing out this case is missing # if there was + or - lines at the end, which has not been printed yet [[ $t1 || $t2 ]] && { wdiff <(echo "${t1%$NL}") <(echo "${t2%$NL}") | color_filter; } elif [[ $filter = yes ]]; then color_filter $1 else wdiff "$1" "$2" | color_filter fi | if [[ $a2ps ]]; then a2ps $a2ps_opts "--pretty-print=$style" -o "$out" else [[ $out = - ]] && cat || cat > "$out" fi