#!/bin/sh
#
# differ - calculate differential of data in ASCII (or CSV) file
#
# Usage:  differ [-c 'columns'] [-d] [-a] file ...
#
# where:  -c 'columns'	specifies the column number(s) to be differentiated,
#			using a comma-separated list of numbers
#			(default is last column only)
#	  -d		specifies that columns to be differentiated are
#			duplicated, i.e. both original and differentiated
#			values will be output
#			(default is to replace originals with differentials)
#	  -a		specifies that values are to be differentiated by
#			looking ahead to the next sample
#			(default is to subtract the previous sample)
#	  file		specifies one or more ASCII file names to be processed
#			(no default, file must be specified, - for std input)
#
# Diffentiates data points in one or more columns of input by subtracting
# previous input sample.  Input and output is in ASCII format, separated
# by space, tab or comma.
#
# Copyright (c) 2006, Gilles Detillieux, Spinal Cord Research Centre,
# University of Manitoba.  All Rights Reserved.
#

copt=
dopt=0
aopt=0
while :
do
	case "$1" in
	-\?|-help|--help)	sed -n '3,/^# Univ/s/^#/ /p' "$0"; exit ;;
	-c[0-9]*)	copt=`expr "x$1" : 'x-c\(.*\)'`; shift ;;
	-c)	shift; copt="$1"; shift ;;
	-n[0-9]*)	nopt=`expr "x$1" : 'x-n\(.*\)'`; shift ;;
	-n)	shift; nopt="$1"; shift ;;
	-d)	dopt=1; shift ;;
	-a)	aopt=1; shift ;;
	-s)	sopt=1; shift ;;
	-)	break ;;
	-*)	set --; break ;;
	*)	break ;;
	esac
done

case "$#" in
0)	echo "Usage:  differ [-c 'columns'] [-d] [-a] file ...
	or differ --help	for detailed usage information" >&2; exit 1 ;;
esac

sed -e '1{h;s/^[ 	]*[-0-9.e+]*\([^-0-9.]*\).*/\1/p;g;}; s/,/ /g' ${@+"$@"} |
 awk 'BEGIN {
	dupcols = '"$dopt"';
	lookahead = '"$aopt"';
	columns = "'"$copt"'";
	colsep = ",";
	ncols = 0;
	ndiffcols = 0;
	lastcol = 0;
	sub(/^[ 	][ 	]*/, "", columns);
	while (columns != "") {
		col = columns;
		if (col ~ /^[-:]/) {
			sub(/^[-:]/, "", col);
			sub(/[-:, 	].*/, "", col);
			c = int(col);
			while (++lastcol < c) {
				diffcol[lastcol] = 1;
				++ndiffcols;
			}
		}
		sub(/[-:, 	].*/, "", col);
		if (col ~ /^[0-9]/) {
			lastcol = int(col);
			diffcol[lastcol] = 1;
			++ndiffcols;
		} else {
			print "'"$0"': invalid column number " col " in '"$copt"'"
			exit
		}
		sub(/^[-:]/, "", columns);
		sub(/^[0-9]*/, "", columns);
		sub(/^[, 	]*/, "", columns);
	}
      }
      NR == 1 && /^..*$/ {
	colsep = $0;
      }
      NR > 1 {
	if (ndiffcols == 0) {
		diffcol[NF] = 1;
		++ndiffcols;
	}
	if (ncols == 0) {
		ncols = NF;
		for (i = 1; i <= ncols; i++) {
		    if (lookahead)
			data[i] = $(i);
		    else
			data[i] = 0;
		}
		if (lookahead)
		    next;
	}
	for (i = 1; i <= ncols; i++) {
		if (i > 1)
		    printf("%s", colsep);
		if (diffcol[i]) {
		    if (dupcols)
			printf("%s%s", lookahead?data[i]:$(i), colsep);
		    printf("%g", $(i)-data[i]);
		} else {
		    printf("%s", lookahead?data[i]:$(i));
		}
		data[i] = $(i);
	}
	printf("\n");
      }
      END {
	if (lookahead) {
	    for (i = 1; i <= ncols; i++) {
		if (i > 1)
		    printf("%s", colsep);
		if (diffcol[i]) {
		    if (dupcols)
			printf("%s%s", data[i], colsep);
		    printf("%g", -data[i]);
		} else {
		    printf("%s", data[i]);
		}
	    }
	}
      }'
