Index: /branches/opihi-2-9/Ohana/src/opihi/Makefile
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/Makefile	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/Makefile	(revision 11389)
@@ -0,0 +1,81 @@
+
+### this is the top-level makefile for the opihi collection of programs
+
+default: all
+
+### the include file dependencies need to be cleaned up still
+
+mana:     	 lib.data lib.shell cmd.basic cmd.data cmd.astro
+dimm:     	 lib.data lib.shell cmd.basic cmd.data cmd.astro
+dvo:      	 lib.data lib.shell cmd.basic cmd.data cmd.astro
+pantasks: 	 lib.data lib.shell cmd.basic cmd.data cmd.astro
+pantasks_server: lib.data lib.shell cmd.basic cmd.data cmd.astro
+pantasks_client: lib.data lib.shell cmd.basic cmd.data cmd.astro
+pclient:  	 lib.data lib.shell cmd.basic
+pcontrol: 	 lib.data lib.shell cmd.basic
+
+LIBS = lib.data lib.shell cmd.basic cmd.data cmd.astro
+
+PROGRAM = mana dvo pantasks pclient pcontrol
+SPECIAL = pantasks_client pantasks_server
+
+EXTRAS = dimm
+
+all:
+	for i in $(PROGRAM) $(SPECIAL); do make $$i || exit; done
+	make pantasks_client
+	make pantasks_server
+
+libs:
+	for i in $(LIBS); do make $$i || exit; done
+
+extras:
+	for i in $(EXTRAS); do make $$i || exit; done
+
+install:
+	for i in $(PROGRAM) $(SPECIAL); do make $$i.install || exit; done
+	make pantasks_client.install
+	make pantasks_server.install
+
+extras-install:
+	for i in $(EXTRAS); do make $$i.install || exit; done
+
+clean:
+	for i in $(PROGRAM) $(SPECIAL) $(EXTRAS) $(LIBS); do make $$i.clean || exit; done
+
+libs-uninstall:
+	for i in $(LIBS); do make $$i.uninstall || exit; done
+
+dist: clean
+	for i in $(PROGRAM) $(SPECIAL) $(EXTRAS) $(LIBS); do make $$i.dist || exit; done
+	rm -rf bin
+	rm -rf lib
+
+#############################################################
+
+pantasks_client pantasks_server:
+	if [ -d pantasks ]; then (cd pantasks && make $@); fi
+
+pantasks_client.install: pantasks_client
+	if [ -d pantasks ]; then (cd pantasks && make $@); fi
+
+pantasks_server.install: pantasks_server
+	if [ -d pantasks ]; then (cd pantasks && make $@); fi
+
+$(PROGRAM) $(LIBS) $(EXTRAS):
+	if [ -d "$@" ]; then (cd $@ && make); fi
+
+%.install:
+	if [ -d "$*" ]; then make $*; fi
+	if [ -d "$*" ]; then (cd $* && make install); fi
+
+%.clean:
+	if [ -d "$*" ]; then (cd $* && make clean); fi
+
+%.dist:
+	if [ -d "$*" ]; then (cd $* && make dist); fi
+
+%.uninstall:
+	if [ -d "$*" ]; then (cd $* && make uninstall); fi
+
+.PHONY: $(PROGRAM) $(LIBS) pantasks_server pantasks_client
Index: /branches/opihi-2-9/Ohana/src/opihi/Makefile.Common
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/Makefile.Common	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/Makefile.Common	(revision 11389)
@@ -0,0 +1,73 @@
+
+# utilities #################################################
+# .SUFFIXES: .$(ARCH).o
+
+CFLAGS  =       -I$(INC) -I$(DESTINC) $(INCDIRS) -DDATADIR_DEFAULT=$(DATA)
+
+$(BIN)/%.$(ARCH):
+	@if [ ! -d $(BIN) ]; then mkdir -p $(BIN); fi
+	$(CC) -o $@ $^ $(LFLAGS)
+	@echo "compiled $*"
+	@echo ""
+
+$(DESTBIN)/%: $(BIN)/%.$(ARCH) 
+	@if [ ! -d $(DESTBIN) ]; then mkdir -p $(DESTBIN); fi
+	rm -f $(DESTBIN)/$*
+	cp $(BIN)/$*.$(ARCH) $(DESTBIN)/$*
+	@echo "installed $*"
+	@echo ""
+
+$(LIB)/%.$(ARCH).a:
+	@if [ ! -d $(LIB) ]; then mkdir -p $(LIB); fi
+	rm -f $@
+	ar rcv $@ $^ 
+	$(RANLIB) $@
+	@echo "compiled library $*"
+	@echo ""
+
+$(DESTLIB)/%.a: $(LIB)/%.$(ARCH).a
+	@if [ ! -d $(DESTLIB) ]; then mkdir -p $(DESTLIB); fi
+	rm -f $@
+	cp $< $@
+
+lib%.clean:
+	rm -f $(LIB)/lib$*.$(ARCH).a
+	rm -f $($*)
+	@echo ""
+
+%.help:
+	@echo "installing help files for $*"
+	@if [ ! -d $(DATA)/help ]; then mkdir -p $(DATA)/help; fi
+	@rm -f $(HOME)/$*/help/*~
+	@rm -f $(HOME)/$*/help/#*
+	@for i in `find $(HOME)/$*/help -maxdepth 1 -type f`; do cp -f $$i $(DATA)/help; done
+
+%.modules:
+	@echo "installing modules for $*"
+	@if [ ! -d $(DATA)/modules ]; then mkdir -p $(DATA)/modules; fi
+	@if [ ! -d $(HOME)/modules/$* ]; then echo "no modules for $*"; fi
+	@if [   -d $(HOME)/modules/$* ]; then rm -f $(HOME)/modules/$*/*~; fi
+	@if [   -d $(HOME)/modules/$* ]; then rm -f $(HOME)/modules/$*/#*; fi
+	@if [   -d $(HOME)/modules/$* ]; then for i in `find $(HOME)/modules/$* -name CVS -prune -o -type f -print`; do cp -f $$i $(DATA)/modules; done; fi
+
+%.clean:
+	rm -f $(BIN)/$*.$(ARCH)
+	@echo ""
+
+%.$(ARCH).o : %.c
+	$(CC) -o $@ -c $*.c $(CFLAGS)
+
+clean:
+	rm -f $(BIN)/*.$(ARCH)
+	rm -f $(LIB)/*.$(ARCH).a
+	rm -f `find . -name "*.o"`
+	rm -f `find . -name "*~"`
+	rm -f `find . -name "#*"`
+
+dist: clean
+	rm -rf $(BIN)/*
+	rm -rf $(LIB)/*
+
+clean-help:
+	@if [ ! -d $(DATA)/help ]; then mkdir -p $(DATA)/help; fi
+	rm -f $(DATA)/help/*
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/Makefile
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/Makefile	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/Makefile	(revision 11389)
@@ -0,0 +1,72 @@
+include ../../../Configure
+
+HOME    =       $(ROOT)/src/opihi
+BIN     =       $(HOME)/bin
+LIB     =       $(HOME)/lib
+INC     =       $(HOME)/include
+SRC     =       $(HOME)/cmd.astro
+
+# astro user commands ########################
+
+srcs = \
+$(SRC)/init.$(ARCH).o             \
+$(SRC)/biassub.$(ARCH).o	   \
+$(SRC)/cgrid.$(ARCH).o		   \
+$(SRC)/coords.$(ARCH).o	   \
+$(SRC)/cplot.$(ARCH).o		   \
+$(SRC)/csystem.$(ARCH).o	   \
+$(SRC)/ctimes.$(ARCH).o	   \
+$(SRC)/cval.$(ARCH).o		   \
+$(SRC)/czplot.$(ARCH).o	   \
+$(SRC)/drizzle.$(ARCH).o	   \
+$(SRC)/flux.$(ARCH).o		   \
+$(SRC)/fixwrap.$(ARCH).o	   \
+$(SRC)/gauss.$(ARCH).o		   \
+$(SRC)/getvel.$(ARCH).o	   \
+$(SRC)/getlst.$(ARCH).o	   \
+$(SRC)/medianmap.$(ARCH).o	   \
+$(SRC)/mkgauss.$(ARCH).o	   \
+$(SRC)/multifit.$(ARCH).o	   \
+$(SRC)/objload.$(ARCH).o	   \
+$(SRC)/outline2.$(ARCH).o	   \
+$(SRC)/outline.$(ARCH).o	   \
+$(SRC)/polar.$(ARCH).o		   \
+$(SRC)/precess.$(ARCH).o	   \
+$(SRC)/profile.$(ARCH).o	   \
+$(SRC)/region.$(ARCH).o	   \
+$(SRC)/rotcurve.$(ARCH).o	   \
+$(SRC)/scale.$(ARCH).o		   \
+$(SRC)/sexigesimal.$(ARCH).o	   \
+$(SRC)/spec.$(ARCH).o		   \
+$(SRC)/star.$(ARCH).o		   \
+$(SRC)/transform.$(ARCH).o        \
+$(SRC)/imsub.$(ARCH).o		   \
+$(SRC)/imfit.$(ARCH).o		   \
+$(SRC)/imfit-fgauss.$(ARCH).o	   \
+$(SRC)/imfit-pgauss.$(ARCH).o	   \
+$(SRC)/imfit-Pgauss.$(ARCH).o	   \
+$(SRC)/imfit-qgauss.$(ARCH).o	   \
+$(SRC)/imfit-Qgauss.$(ARCH).o	   \
+$(SRC)/imfit-sgauss.$(ARCH).o	   \
+$(SRC)/imfit-Sgauss.$(ARCH).o	   \
+$(SRC)/imfit-qfgauss.$(ARCH).o	   \
+$(SRC)/imfit-qrgauss.$(ARCH).o	   
+
+# dependancy rules for include files ########################
+incs = \
+$(INC)/opihi.h \
+$(INC)/external.h \
+$(INC)/shell.h \
+$(INC)/dvomath.h \
+$(INC)/convert.h \
+$(INC)/display.h 
+
+libastrocmd: $(DESTLIB)/libastrocmd.a 
+$(DESTLIB)/libastrocmd.a: $(LIB)/libastrocmd.$(ARCH).a
+$(LIB)/libastrocmd.$(ARCH).a: $(srcs)
+$(srcs): $(incs)
+
+uninstall:
+	rm -f $(DESTLIB)/libastrocmd.a
+
+include ../Makefile.Common
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/biassub.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/biassub.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/biassub.c	(revision 11389)
@@ -0,0 +1,126 @@
+# include "astro.h"
+
+int biassub (int argc, char **argv) {
+  
+  int i, j, k, N, dir, nlong, nwide, start;
+  int sx, sy, nx, ny, NX, NY, NoVector, Nval;
+  float *V, *DV, dV, *vect, *segment, val;
+  Vector *xvec, *yvec;
+  Buffer *buf;
+
+  xvec = yvec = NULL;
+  NoVector = TRUE;
+  if ((N = get_argument (argc, argv, "-v"))) {
+    NoVector = FALSE;
+    remove_argument (N, &argc, argv);
+    if ((xvec = SelectVector (argv[N], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+    remove_argument (N, &argc, argv);
+    if ((yvec = SelectVector (argv[N], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 7) {
+    gprint (GP_ERR, "USAGE: biassub <buffer> sx sy nx ny dir [-v N V]\n");
+    gprint (GP_ERR, "  optional storage of vector and sequence in N and V\n");
+    return (FALSE);
+  }
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+
+  sx = atof (argv[2]);
+  sy = atof (argv[3]);
+  nx = atof (argv[4]);
+  ny = atof (argv[5]);
+  dir = atof (argv[6]);
+  if ((dir != 0) && (dir != 1)) {
+    gprint (GP_ERR, " dir must be either 0 (x) or 1 (y)\n");
+    return (FALSE);
+  }
+  if (dir) {
+    start = sy;
+    nwide = nx;
+    nlong = ny;
+  } else {
+    start = sx;
+    nwide = ny;
+    nlong = nx;
+  }    
+  gprint (GP_LOG, "start: %d %d  size: %d %d\n", sx, sy, nx, ny);
+
+    if ((sx < 0) || (sy < 0) || 
+      (sx+nx > buf[0].matrix.Naxis[0]) || 
+      (sy+ny > buf[0].matrix.Naxis[1])) {
+    gprint (GP_ERR, "region out of range\n");
+    return (FALSE);
+  }
+
+  ALLOCATE (vect, float, nlong);
+  ALLOCATE (segment, float, nwide);
+
+  NX = buf[0].matrix.Naxis[0];
+  NY = buf[0].matrix.Naxis[1];
+  if (dir) {
+    for (j = sy; j < sy + ny; j++) {
+      V = (float *)(buf[0].matrix.buffer) + j*NX + sx; 
+      for (i = 0; i < nx; i++, V++) {
+	segment[i] = *V;
+      }
+      fsort (segment, nwide);
+      val = Nval = 0;
+      for (k = 0.25*nwide; k <=0.75*nwide; k++) {
+	val += segment[k];
+	Nval ++;
+      }
+      vect[j-sy] = val / Nval;
+    }
+  } else {
+    for (i = 0; i < nx; i++) {
+      V = (float *)(buf[0].matrix.buffer) + sy*NX + sx + i; 
+      for (j = 0; j < ny; j++, V+=NX) {
+	segment[j] = *V;
+      }
+      fsort (segment, nwide);
+      val = Nval = 0;
+      for (k = 0.25*nwide; k <=0.75*nwide; k++) {
+	val += segment[k];
+	Nval ++;
+      }
+      vect[i] = val / Nval;
+    }
+  }
+
+  if (!NoVector) {
+    xvec[0].Nelements = yvec[0].Nelements = nlong;
+    REALLOCATE (xvec[0].elements, float, nlong);
+    REALLOCATE (yvec[0].elements, float, nlong);
+    for (i = 0; i < nlong; i++) {
+      xvec[0].elements[i] = i + start;
+      yvec[0].elements[i] = vect[i];
+    }
+  }
+
+  if (dir) {
+    /* here we run all the way across in X for the defined Y range */
+    for (j = sy; j < sy + ny; j++) {
+      V = (float *)(buf[0].matrix.buffer) + j*NX; 
+      dV = vect[j];
+      for (i = 0; i < NX; i++, V++) {
+	*V -= dV;
+      }
+    }
+  } else {
+    /* here we run all the way across in Y for the defined X range */
+    for (j = 0; j < NY; j++) {
+      V = (float *)(buf[0].matrix.buffer) + j*NX + sx; 
+      DV = vect;
+      for (i = 0; i < nx; i++, V++, DV++) {
+	*V -= *DV;
+      }
+    }
+  }
+
+  free (segment);
+  free (vect);
+
+  return (TRUE);
+}
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/cgrid.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/cgrid.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/cgrid.c	(revision 11389)
@@ -0,0 +1,402 @@
+# include "astro.h"
+# define CHECKELEMENTS \
+  if (N == NELEMENTS) { \
+    NELEMENTS +=200; \
+    REALLOCATE (Xvec.elements, float, NELEMENTS); \
+    REALLOCATE (Yvec.elements, float, NELEMENTS); \
+  }
+
+int cgrid (int argc, char **argv) {
+  
+  double range, lrange, factor, mantis, power, fmantis;
+  double firstRA, firstDEC, minorRA, minorDEC;
+  double r, d, dR, dD, D;
+  double x, y;
+  Vector Xvec, Yvec;
+  int NorthPole, SouthPole, N, OnPic, LOnPic, status, NELEMENTS, First;
+  Graphdata graphmode;
+
+  if (!style_args (&graphmode, &argc, argv, 0)) return FALSE;
+
+  if (argc != 1) {
+    gprint (GP_ERR, "USAGE: cgrid [style]\n");
+    return (FALSE);
+  }
+  SetGraph (graphmode);
+
+  /* are we plotting one of the poles? */
+  NorthPole = SouthPole = FALSE;
+  status = RD_to_XY (&x, &y, 0.0, 90.0, &graphmode.coords);
+  if ((x >= graphmode.xmin) && (x <= graphmode.xmax) && 
+      (y >= graphmode.ymin) && (y <= graphmode.ymax) && status)
+    NorthPole = TRUE;
+  status = RD_to_XY (&x, &y, 0.0, -90.0, &graphmode.coords);
+  if ((x >= graphmode.xmin) && (x <= graphmode.xmax) && 
+      (y >= graphmode.ymin) && (y <= graphmode.ymax) && status)
+    SouthPole = TRUE;
+
+  /* set spacings for RA */
+  minorRA = minorDEC = 0.1;
+  range = MIN (fabs(graphmode.xmax-graphmode.xmin), fabs(graphmode.ymax-graphmode.ymin));
+  if (NorthPole || SouthPole) range = 360;
+  lrange = log10(MAX(fabs(range), 1e-30));
+  factor = (int) (lrange);
+  if (lrange < 0) { factor -= 1; }
+  mantis = lrange - factor;
+  power = pow(10.0, factor);
+  fmantis = pow(10.0, mantis);
+  if ((fmantis >= 1.0) && (fmantis <=  2.0)) {
+    minorRA = 0.1 * power;
+  }
+  if ((fmantis > 2.0) && (fmantis <=  4.0)) {
+    minorRA = 0.2 * power;
+  }
+  if ((fmantis > 4.0) && (fmantis <=  6.0)) {
+    minorRA = 0.5 * power;
+  }
+  if ((fmantis > 6.0) && (fmantis <=  10.0)) {
+    minorRA = 0.5 * power;
+  }
+  dR = range / 100.0;
+  /* set spacings for DEC */
+  range = MIN (fabs(graphmode.xmax-graphmode.xmin), fabs(graphmode.ymax-graphmode.ymin));
+  lrange = log10(MAX(fabs(range), 1e-30));
+  factor = (int) (lrange);
+  if (lrange < 0) { factor -= 1; }
+  mantis = lrange - factor;
+  power = pow(10.0, factor);
+  fmantis = pow(10.0, mantis);
+  if ((fmantis >= 1.0) && (fmantis <=  2.0)) {
+    minorDEC = 0.1 * power;
+  }
+  if ((fmantis > 2.0) && (fmantis <=  4.0)) {
+    minorDEC = 0.2 * power;
+  }
+  if ((fmantis > 4.0) && (fmantis <=  6.0)) {
+    minorDEC = 0.5 * power;
+  }
+  if ((fmantis > 6.0) && (fmantis <=  10.0)) {
+    minorDEC = 0.5 * power;
+  }
+  dD = range / 100.0;
+
+  /* choose a starting point */
+  if ((int)(graphmode.coords.crval1/minorRA) == (graphmode.coords.crval1/minorRA)) {
+    firstRA = graphmode.coords.crval1;
+  } else {
+    firstRA = minorRA + minorRA*((int)(graphmode.coords.crval1/minorRA));
+  }
+  if ((int)(graphmode.coords.crval2/minorDEC) == (graphmode.coords.crval2/minorDEC)) {
+    firstDEC = graphmode.coords.crval2;
+  } else {
+    firstDEC = minorDEC + minorDEC*((int)(graphmode.coords.crval2/minorDEC));
+  }
+  if (SouthPole) firstDEC = -90;
+  if (NorthPole) firstDEC = 90;
+  
+  /* prepare vectors to hold data */
+  NELEMENTS = 200;
+  ALLOCATE (Xvec.elements, float, NELEMENTS);
+  ALLOCATE (Yvec.elements, float, NELEMENTS);
+  N = 0;
+  
+  /***  do consecutive RA lines, first increasing **/
+  OnPic = TRUE;
+  for (r = firstRA; (r <= firstRA + 180) && (OnPic); r += minorRA) {
+    /* first, DEC increasing */
+    LOnPic = TRUE;
+    OnPic = FALSE;
+    First = TRUE;
+    for (d = firstDEC; (d < 90 + dD) && (LOnPic || NorthPole || SouthPole); d += dD) {
+      D = MAX (-90, MIN(90, d));
+      status = fRD_to_XY (&Xvec.elements[N], &Yvec.elements[N], r, D, &graphmode.coords);
+      /*
+      if ((fabs(Xvec.elements[N] - Xvec.elements[N-1]) > 10) && (fabs(Yvec.elements[N] - Yvec.elements[N-1]) > 10))
+	First = TRUE;
+	*/
+      if ((Xvec.elements[N] >= graphmode.xmin) && (Xvec.elements[N] <= graphmode.xmax) && 
+	  (Yvec.elements[N] >= graphmode.ymin) && (Yvec.elements[N] <= graphmode.ymax) && status) {
+	N++;
+	CHECKELEMENTS;
+	OnPic = TRUE;
+	if (!First) {
+	  Xvec.elements[N] = Xvec.elements[N-1];
+	  Yvec.elements[N] = Yvec.elements[N-1];
+	  N++;
+	  CHECKELEMENTS;
+	} else {
+	  if (N > 1) {
+	    Xvec.elements[N-2] = Xvec.elements[N-1];
+	    Yvec.elements[N-2] = Yvec.elements[N-1];
+	    N--;
+	  }
+	  First = FALSE;
+	}
+      } else {
+	LOnPic = FALSE;
+	First = TRUE;
+      }
+    }
+    /* next, DEC decreasing */
+    First = TRUE;
+    LOnPic = TRUE;
+    for (d = firstDEC; (d > -90 - dD) && (LOnPic || NorthPole || SouthPole); d -= dD) {
+      D = MAX (-90, MIN(90, d));
+      status = fRD_to_XY (&Xvec.elements[N], &Yvec.elements[N], r, D, &graphmode.coords);
+      /*
+      if ((fabs(Xvec.elements[N] - Xvec.elements[N-1]) > 10) && (fabs(Yvec.elements[N] - Yvec.elements[N-1]) > 10))
+	First = TRUE;
+	*/
+      if ((Xvec.elements[N] >= graphmode.xmin) && (Xvec.elements[N] <= graphmode.xmax) && 
+	  (Yvec.elements[N] >= graphmode.ymin) && (Yvec.elements[N] <= graphmode.ymax) && status) {
+	N++;
+	CHECKELEMENTS;
+	OnPic = TRUE;
+	if (!First) {
+	  Xvec.elements[N] = Xvec.elements[N-1];
+	  Yvec.elements[N] = Yvec.elements[N-1];
+	  N++;
+	  CHECKELEMENTS;
+	} else {
+	  if (N > 1) {
+	    Xvec.elements[N-2] = Xvec.elements[N-1];
+	    Yvec.elements[N-2] = Yvec.elements[N-1];
+	    N--;
+	  }
+	  First = FALSE;
+	}
+      } else {
+	LOnPic = FALSE;
+	First = TRUE;
+      } 
+    }
+  }
+
+  /***  do consecutive RA lines, decreasing **/
+  OnPic = TRUE;
+  for (r = firstRA; (r >=  firstRA - 180) && (OnPic); r -= minorRA) {
+    /* first, DEC increasing */
+    First = TRUE;
+    LOnPic = TRUE;
+    OnPic = FALSE;
+    for (d = firstDEC; (d < 90 + dD) && (LOnPic || NorthPole || SouthPole); d += dD) {
+      D = MAX (-90, MIN(90, d));
+      status = fRD_to_XY (&Xvec.elements[N], &Yvec.elements[N], r, D, &graphmode.coords);
+      /*
+      if ((fabs(Xvec.elements[N] - Xvec.elements[N-1]) > 10) && (fabs(Yvec.elements[N] - Yvec.elements[N-1]) > 10))
+	First = TRUE;
+	*/
+      if ((Xvec.elements[N] >= graphmode.xmin) && (Xvec.elements[N] <= graphmode.xmax) && 
+	  (Yvec.elements[N] >= graphmode.ymin) && (Yvec.elements[N] <= graphmode.ymax) && status) {
+	N++;
+	CHECKELEMENTS;
+	OnPic = TRUE;
+	if (!First) {
+	  Xvec.elements[N] = Xvec.elements[N-1];
+	  Yvec.elements[N] = Yvec.elements[N-1];
+	  N++;
+	  CHECKELEMENTS;
+	} else {
+	  if (N > 1) {
+	    Xvec.elements[N-2] = Xvec.elements[N-1];
+	    Yvec.elements[N-2] = Yvec.elements[N-1];
+	    N--;
+	  }
+	  First = FALSE;
+	}
+      } else {
+	LOnPic = FALSE;
+	First = TRUE;
+      }
+    }
+    /* next, DEC decreasing */
+    First = TRUE;
+    LOnPic = TRUE;
+    for (d = firstDEC; (d > -90 - dD) && (LOnPic || NorthPole || SouthPole); d -= dD) {
+      D = MAX (-90, MIN(90, d));
+      status = fRD_to_XY (&Xvec.elements[N], &Yvec.elements[N], r, D, &graphmode.coords);
+      /*
+      if ((fabs(Xvec.elements[N] - Xvec.elements[N-1]) > 10) && (fabs(Yvec.elements[N] - Yvec.elements[N-1]) > 10))
+	First = TRUE;
+	*/
+      if ((Xvec.elements[N] >= graphmode.xmin) && (Xvec.elements[N] <= graphmode.xmax) && 
+	  (Yvec.elements[N] >= graphmode.ymin) && (Yvec.elements[N] <= graphmode.ymax) && status) {
+	N++;
+	CHECKELEMENTS;
+	OnPic = TRUE;
+	if (!First) {
+	  Xvec.elements[N] = Xvec.elements[N-1];
+	  Yvec.elements[N] = Yvec.elements[N-1];
+	  N++;
+	  CHECKELEMENTS;
+	} else {
+	  if (N > 1) {
+	    Xvec.elements[N-2] = Xvec.elements[N-1];
+	    Yvec.elements[N-2] = Yvec.elements[N-1];
+	    N--;
+	  }
+	  First = FALSE;
+	}
+      } else {
+	LOnPic = FALSE;
+	First = TRUE;
+      }
+    }
+  }
+
+  /***  do consecutive DEC lines, first increasing **/
+  OnPic = TRUE;
+  for (d = firstDEC; (d < 90 + dD) && (OnPic); d += minorDEC) {
+    D = MAX (-90, MIN(90, d));
+    /* first, RA increasing */
+    LOnPic = TRUE;
+    OnPic = FALSE;
+    First = TRUE;
+    for (r = firstRA; (r < firstRA + 180) && (LOnPic || NorthPole || SouthPole); r += dR) {
+      status = fRD_to_XY (&Xvec.elements[N], &Yvec.elements[N], r, D, &graphmode.coords);
+      /*
+      if ((fabs(Xvec.elements[N] - Xvec.elements[N-1]) > 10) && (fabs(Yvec.elements[N] - Yvec.elements[N-1]) > 10))
+	First = TRUE;
+	*/
+      if ((Xvec.elements[N] >= graphmode.xmin) && (Xvec.elements[N] <= graphmode.xmax) && 
+	  (Yvec.elements[N] >= graphmode.ymin) && (Yvec.elements[N] <= graphmode.ymax) && status) {
+	N++;
+	CHECKELEMENTS;
+	OnPic = TRUE;
+	if (!First) {
+	  Xvec.elements[N] = Xvec.elements[N-1];
+	  Yvec.elements[N] = Yvec.elements[N-1];
+	  N++;
+	  CHECKELEMENTS;
+	} else {
+	  if (N > 1) {
+	    Xvec.elements[N-2] = Xvec.elements[N-1];
+	    Yvec.elements[N-2] = Yvec.elements[N-1];
+	    N--;
+	  }
+	  First = FALSE;
+	}
+      } else {
+	LOnPic = FALSE;
+	First = TRUE;
+      }
+    }
+    /* next, RA decreasing */
+    First = TRUE;
+    LOnPic = TRUE;
+    for (r = firstRA; (r > firstRA - 180) && (LOnPic || NorthPole || SouthPole); r -= dR) {
+      status = fRD_to_XY (&Xvec.elements[N], &Yvec.elements[N], r, D, &graphmode.coords);
+      /*
+      if ((fabs(Xvec.elements[N] - Xvec.elements[N-1]) > 10) && (fabs(Yvec.elements[N] - Yvec.elements[N-1]) > 10))
+	First = TRUE;
+	*/
+      if ((Xvec.elements[N] >= graphmode.xmin) && (Xvec.elements[N] <= graphmode.xmax) && 
+	  (Yvec.elements[N] >= graphmode.ymin) && (Yvec.elements[N] <= graphmode.ymax) && status) {
+	N++;
+	CHECKELEMENTS;
+	OnPic = TRUE;
+	if (!First) {
+	  Xvec.elements[N] = Xvec.elements[N-1];
+	  Yvec.elements[N] = Yvec.elements[N-1];
+	  N++;
+	  CHECKELEMENTS;
+	} else {
+	  if (N > 1) {
+	    Xvec.elements[N-2] = Xvec.elements[N-1];
+	    Yvec.elements[N-2] = Yvec.elements[N-1];
+	    N--;
+	  }
+	  First = FALSE;
+	}
+      } else {
+	LOnPic = FALSE;
+	First = TRUE;
+      }
+    }
+  }
+
+  /***  do consecutive DEC lines, decreasing **/
+  OnPic = TRUE;
+  for (d = firstDEC; (d > -90 - dD) && (OnPic); d -= minorDEC) {
+    D = MAX (-90, MIN(90, d));
+    /* first, RA increasing */
+    LOnPic = TRUE;
+    OnPic = FALSE;
+    First = TRUE;
+    for (r = firstRA; (r < firstRA + 180) && (LOnPic || NorthPole || SouthPole); r += dR) {
+      status = fRD_to_XY (&Xvec.elements[N], &Yvec.elements[N], r, D, &graphmode.coords);
+      /*
+      if ((fabs(Xvec.elements[N] - Xvec.elements[N-1]) > 10) && (fabs(Yvec.elements[N] - Yvec.elements[N-1]) > 10))
+	First = TRUE;
+	*/
+      if ((Xvec.elements[N] >= graphmode.xmin) && (Xvec.elements[N] <= graphmode.xmax) && 
+	  (Yvec.elements[N] >= graphmode.ymin) && (Yvec.elements[N] <= graphmode.ymax) && status) {
+	N++;
+	CHECKELEMENTS;
+	OnPic = TRUE;
+	if (!First) {
+	  Xvec.elements[N] = Xvec.elements[N-1];
+	  Yvec.elements[N] = Yvec.elements[N-1];
+	  N++;
+	  CHECKELEMENTS;
+	} else {
+	  if (N > 1) {
+	    Xvec.elements[N-2] = Xvec.elements[N-1];
+	    Yvec.elements[N-2] = Yvec.elements[N-1];
+	    N--;
+	  }
+	  First = FALSE;
+	}
+      } else {
+	LOnPic = FALSE;
+	First = TRUE;
+      }
+    }
+    /* next, RA decreasing */
+    First = TRUE;
+    LOnPic = TRUE;
+    for (r = firstRA; (r > firstRA - 180) && (LOnPic || NorthPole || SouthPole); r -= dR) {
+      status = fRD_to_XY (&Xvec.elements[N], &Yvec.elements[N], r, D, &graphmode.coords);
+      /*
+      if ((fabs(Xvec.elements[N] - Xvec.elements[N-1]) > 10) && (fabs(Yvec.elements[N] - Yvec.elements[N-1]) > 10))
+	First = TRUE;
+	*/
+      if ((Xvec.elements[N] >= graphmode.xmin) && (Xvec.elements[N] <= graphmode.xmax) && 
+	  (Yvec.elements[N] >= graphmode.ymin) && (Yvec.elements[N] <= graphmode.ymax) && status) {
+	N++;
+	CHECKELEMENTS;
+	OnPic = TRUE;
+	if (!First) {
+	  Xvec.elements[N] = Xvec.elements[N-1];
+	  Yvec.elements[N] = Yvec.elements[N-1];
+	  N++;
+	  CHECKELEMENTS;
+	} else {
+	  if (N > 1) {
+	    Xvec.elements[N-2] = Xvec.elements[N-1];
+	    Yvec.elements[N-2] = Yvec.elements[N-1];
+	    N--;
+	  }
+	  First = FALSE;
+	}
+      } else {
+	LOnPic = FALSE;
+	First = TRUE;
+      }
+    }
+  }
+  
+  /* send the line segments as connect-points */
+  Xvec.Nelements = Yvec.Nelements = N;
+  graphmode.style = 2; /* points */
+  graphmode.ptype = 100; /* connect a pair */
+  graphmode.etype = 0;
+  PrepPlotting (N, &graphmode);
+  PlotVector (N, Xvec.elements);
+  PlotVector (N, Yvec.elements);
+
+  free (Xvec.elements);
+  free (Yvec.elements);
+  return (TRUE);
+
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/coords.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/coords.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/coords.c	(revision 11389)
@@ -0,0 +1,86 @@
+# include "astro.h"
+
+enum {NONE, SKY, PIXEL};
+
+int coords (int argc, char **argv) {
+
+  int mode, N, Quiet;
+  double X, Y, R, D;
+  char *MOSAIC;
+  Coords coords, moscoords;
+  Buffer *buf, *mosbuffer;
+
+  MOSAIC = NULL;
+  if ((N = get_argument (argc, argv, "-mosaic"))) {
+    remove_argument (N, &argc, argv);
+    MOSAIC = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  Quiet = FALSE;
+  if ((N = get_argument (argc, argv, "-q"))) {
+    Quiet = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "-quiet"))) {
+    Quiet = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  mode = NONE;
+  if ((N = get_argument (argc, argv, "-p"))) {
+    remove_argument (N, &argc, argv);
+    X = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+    Y = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+    mode = SKY;
+  }
+  if ((N = get_argument (argc, argv, "-c"))) {
+    if (mode == SKY) goto syntax;
+    remove_argument (N, &argc, argv);
+    R = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+    D = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+    mode = PIXEL;
+  }
+  if (mode == NONE) goto syntax;
+  if (argc != 2) goto syntax;
+
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) goto escape;
+  GetCoords (&coords, &buf[0].header);
+  if (!strcmp(&coords.ctype[4], "-WRP")) {
+    if (MOSAIC == NULL) {
+      gprint (GP_ERR, "must supply mosaic for WRP coords\n");
+      return (FALSE);
+    }
+    if ((mosbuffer = SelectBuffer (MOSAIC, OLDBUFFER, TRUE)) == NULL) goto escape;
+    GetCoords (&moscoords, &mosbuffer[0].header);
+    RegisterMosaic (&moscoords);
+  }
+  
+  if (mode == SKY) {
+    XY_to_RD (&R, &D, X, Y, &coords);
+    if (!Quiet) gprint (GP_LOG, "%10.6f %10.6f\n", R, D);
+    set_variable ("RA", R);
+    set_variable ("DEC", D);
+    return (TRUE);
+  }
+    
+  if (mode == PIXEL) {
+    RD_to_XY (&X, &Y, R, D, &coords);
+    if (!Quiet) gprint (GP_LOG, "%7.2f %7.2f\n", X, Y);
+    set_variable ("Xc", X);
+    set_variable ("Yc", Y);
+    return (TRUE);
+  }
+  return (FALSE);
+
+ syntax:
+  gprint (GP_ERR, "USAGE: coords [buffer] (-c R D) / (-p X Y)\n");
+  gprint (GP_ERR, "only one of -p or -c can be used\n");
+ escape:
+  if (MOSAIC != NULL) free (MOSAIC);
+  return (FALSE);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/cplot.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/cplot.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/cplot.c	(revision 11389)
@@ -0,0 +1,78 @@
+# include "astro.h"
+
+int cplot (int argc, char **argv) {
+  
+  int i, Npts, status;
+  float *x, *y, *r, *d, Rmin, Rmax;
+  Vector Xvec, Yvec, *xvec, *yvec;
+  Graphdata graphmode;
+
+  if (!style_args (&graphmode, &argc, argv, 0)) return FALSE;
+
+  if (argc != 3) {
+    gprint (GP_ERR, "USAGE: cplot <ra> <dec> [style]\n");
+    return (FALSE);
+  }
+  SetGraph (graphmode);
+
+  Rmin = graphmode.coords.crval1 - 182.0;
+  Rmax = graphmode.coords.crval1 + 182.0;
+
+  /* find vectors */
+  if ((xvec = SelectVector (argv[1], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((yvec = SelectVector (argv[2], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+
+  if (xvec[0].Nelements != yvec[0].Nelements) {
+    gprint (GP_ERR, "vectors are not the same length\n");
+    return (FALSE);
+  }
+
+  ALLOCATE (Xvec.elements, float, xvec[0].Nelements);
+  ALLOCATE (Yvec.elements, float, xvec[0].Nelements);
+    
+  Xvec.Nelements = xvec[0].Nelements;
+  Yvec.Nelements = xvec[0].Nelements;
+  
+  r = xvec[0].elements;
+  d = yvec[0].elements;
+  x = Xvec.elements;
+  y = Yvec.elements;
+  
+  Npts = 0;
+  for (i = 0; i < Xvec.Nelements; i++, r++, d++) {
+    while (*r < Rmin) *r += 360.0;
+    while (*r > Rmax) *r -= 360.0;
+    status = fRD_to_XY (x, y, *r, *d, &graphmode.coords);
+    if (!status) {
+      if (graphmode.ptype == 100) {
+	if (i % 2) {
+	  // for odd points, skip previous also
+	  x--;
+	  y--;
+	  Npts--;
+	} else {
+	  // for even points, skip previous also
+	  i++;
+	  r++;
+	  d++;
+	}
+      }
+      continue;
+    }
+    x++;
+    y++;
+    Npts++;
+  }
+  Xvec.Nelements = Npts;
+
+  graphmode.etype = 0;
+  PrepPlotting (Npts, &graphmode);
+  PlotVector (Npts, Xvec.elements);
+  PlotVector (Npts, Yvec.elements);
+  
+  free (Xvec.elements);
+  free (Yvec.elements);
+    
+  return (TRUE);
+}
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/csystem.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/csystem.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/csystem.c	(revision 11389)
@@ -0,0 +1,141 @@
+# include "astro.h"
+
+int csystem (int argc, char **argv) {
+
+  /* USAGE: csystem [C/G/E/H] [C/G/E/H] [epoch] */
+  int i;
+  double X, Y, Xo, xo, phi, T;
+  double sin_x, sin_y, cos_x, cos_y;
+  float *x, *y;
+  struct timeval now;
+  struct tm *local;
+  Vector *xvec, *yvec;
+   
+  if (argc != 5) {
+    gprint (GP_ERR, "USAGE: csystems [C/G/E/H] [C/G/E/H] X Y\n");
+    return (FALSE);
+  }
+
+  Xo = xo = phi = 0;
+  switch (argv[1][0]) {
+  case 'C':
+    switch (argv[2][0]) {
+    case 'C': 
+      gprint (GP_ERR, "same coordinate system\n");
+      return (TRUE);
+      break;
+    case 'G':
+      phi = -62.6*RAD_DEG;
+      Xo = 282.25;
+      xo = 33;
+      break;
+    case 'E':
+      gettimeofday (&now, (struct timezone *) NULL);
+      local = localtime (&now.tv_sec);
+      T = local[0].tm_year / 100.0;
+      phi = -1*(23.452294 - 0.013013*T - 0.000001639*T*T + 0.000000503*T*T*T);
+      phi *= RAD_DEG;
+      Xo = xo = 0.0;
+      break;
+    }
+    break;
+  case 'E':
+    switch (argv[2][0]) {
+    case 'C': 
+      gettimeofday (&now, (struct timezone *) NULL);
+      local = localtime (&now.tv_sec);
+      T = local[0].tm_year / 100.0;
+      phi = 23.452294 - 0.013013*T - 0.000001639*T*T + 0.000000503*T*T*T;
+      phi *= RAD_DEG;
+      Xo = xo = 0.0;
+      break;
+    case 'G':
+      gprint (GP_ERR, "error: conversions between galactic and ecliptic not implemented\n");
+      return (FALSE);
+      phi = -62.6*RAD_DEG;
+      Xo = 282.25;
+      xo = 33;
+      break;
+    case 'E':
+      phi = Xo = xo = 0.0;
+      break;
+    }
+    break;
+  case 'G':
+    switch (argv[2][0]) {
+    case 'C': 
+      phi = 62.6*RAD_DEG;
+      Xo = 33;
+      xo = 282.25;
+      break;
+    case 'G':
+      phi = Xo = xo = 0.0;
+      break;
+    case 'E':
+      gprint (GP_ERR, "error: conversions between galactic and ecliptic not implemented\n");
+      return (FALSE);
+      gettimeofday (&now, (struct timezone *) NULL);
+      local = localtime (&now.tv_sec);
+      T = local[0].tm_year / 100.0;
+      phi = -1*(23.452294 - 0.013013*T - 0.000001639*T*T + 0.000000503*T*T*T);
+      Xo = xo = 0.0;
+      break;
+    }
+  }
+ 
+  Xo *= RAD_DEG;
+
+  if (SelectScalar (argv[3], &X)) {
+      if (!SelectScalar (argv[4], &Y)) return (FALSE);
+      
+      X *= RAD_DEG;
+      Y *= RAD_DEG;
+
+      sin_y = cos(Y)*sin(X - Xo)*sin(phi) + sin(Y)*cos(phi);
+      cos_y = sqrt (1 - sin_y*sin_y);
+      sin_x = (cos(Y)*sin(X - Xo)*cos(phi) - sin(Y)*sin(phi)) /  cos_y;
+      cos_x = cos(Y)*cos(X - Xo) / cos_y;
+      
+      X = (DEG_RAD * atan2 (sin_x, cos_x) + xo + 360);
+      
+      while (X >= 360.0)
+	  X -= 360;
+      Y = DEG_RAD * atan2 (sin_y, cos_y);
+
+      gprint (GP_LOG, "%10.6f %10.6f\n", X, Y);
+      return (TRUE);
+  }
+
+  /* find vectors */
+  if ((xvec = SelectVector (argv[3], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((yvec = SelectVector (argv[4], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+
+  if (xvec[0].Nelements != yvec[0].Nelements) {
+    gprint (GP_ERR, "vectors %s and %s not the same length\n", argv[3], argv[4]);
+    return (FALSE);
+  }
+  
+  x = xvec[0].elements;
+  y = yvec[0].elements;
+
+  for (i = 0; i < xvec[0].Nelements; i++, x++, y++) {
+    X = *x*RAD_DEG;
+    Y = *y*RAD_DEG;
+
+    sin_y = cos(Y)*sin(X - Xo)*sin(phi) + sin(Y)*cos(phi);
+    cos_y = sqrt (1 - sin_y*sin_y);
+    sin_x = (cos(Y)*sin(X - Xo)*cos(phi) - sin(Y)*sin(phi)) /  cos_y;
+    cos_x = cos(Y)*cos(X - Xo) / cos_y;
+    
+    X = (DEG_RAD * atan2 (sin_x, cos_x) + xo + 360);
+    
+    while (X >= 360.0)
+      X -= 360;
+    Y = DEG_RAD * atan2 (sin_y, cos_y);
+    *x = X;
+    *y = Y;
+  }
+
+  return (TRUE);
+
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/ctimes.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/ctimes.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/ctimes.c	(revision 11389)
@@ -0,0 +1,66 @@
+# include "astro.h"
+
+int ctimes (int argc, char **argv) {
+
+  int Reference, TimeFormat, N;
+  double value;
+  time_t time, TimeReference;
+  char *date, *Variable;
+
+  Variable = (char *) NULL;
+  if ((N = get_argument (argc, argv, "-var"))) {
+    remove_argument (N, &argc, argv);
+    Variable = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 3) {
+    gprint (GP_ERR, "USAGE: ctimes [-ref (value) / -abs (date)] [-var name]\n");
+    return (FALSE);
+  }
+
+  GetTimeFormat (&TimeReference, &TimeFormat);
+
+  Reference = FALSE;
+  if (!strcmp (argv[1], "-ref")) Reference = TRUE;
+
+  if (Reference) {
+
+    value = atof (argv[2]);
+    time = TimeRef (value, TimeReference, TimeFormat);
+    date = sec_to_date (time);
+    
+    if (Variable != (char *) NULL) {
+      set_str_variable (Variable, date);
+      free (Variable);
+    } else {
+      gprint (GP_ERR, "time: %s\n", date);
+    }
+
+    free (date);
+    return (TRUE);
+
+  } else {
+
+    if (strcmp (argv[1], "-abs")) {
+      gprint (GP_ERR, "syntax error\n");
+      return (FALSE);
+    }
+
+    if (!str_to_time (argv[2], &time)) { 
+      gprint (GP_ERR, "syntax error\n");
+      return (FALSE);
+    }
+    
+    value = TimeValue (time, TimeReference, TimeFormat);
+    
+    if (Variable != (char *) NULL) {
+      set_variable (Variable, value);
+      free (Variable);
+      return (TRUE);
+    }
+    gprint (GP_ERR, "time: %f\n", value);
+    return (TRUE);
+  }
+}
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/cval.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/cval.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/cval.c	(revision 11389)
@@ -0,0 +1,51 @@
+# include "astro.h"
+
+int cval (int argc, char **argv) {
+  
+  int i, j, Nx;
+  int sx, sy, nx, ny, xo, yo, dx, dy;
+  float *V, cval, val, sn, sky;
+  Buffer *buf;
+
+  if (argc != 7) {
+    gprint (GP_ERR, "USAGE: cval <buffer> x y dx dy sky\n");
+    return (FALSE);
+  }
+
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+
+  xo = atof (argv[2]);
+  yo = atof (argv[3]);
+  dx = atof (argv[4]);
+  dy = atof (argv[5]);
+  sky = atof (argv[6]);
+
+  sx = xo - dx;
+  sy = yo - dy;
+  nx = 2*dx + 1;
+  ny = 2*dy + 1;
+  if ((sx < 0) || (sy < 0) || 
+      (sx+nx > buf[0].matrix.Naxis[0]) || 
+      (sy+ny > buf[0].matrix.Naxis[1])) {
+    gprint (GP_ERR, "region out of range\n");
+    return (FALSE);
+  }
+
+  V = (float *)buf[0].matrix.buffer;
+  Nx = buf[0].matrix.Naxis[0];
+  val = V[xo + yo*Nx];
+
+  sn = 0;
+  cval = 0;
+  for (j = sy; j < sy + ny; j++) {
+    for (i = sx; i < sx + nx; i++) {
+      cval += (val - V[i + j*Nx]) / sqrt(V[i + j*Nx]);
+      sn += SQ (V[i + j*Nx] - sky) / V[i + j*Nx];
+    }
+  }
+
+  gprint (GP_ERR, "cval: %f  sn: %f\n", cval, sqrt(sn));
+
+  return (TRUE);
+}
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/czplot.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/czplot.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/czplot.c	(revision 11389)
@@ -0,0 +1,73 @@
+# include "astro.h"
+
+int czplot (int argc, char **argv) {
+  
+  int i, Npts;
+  double min, range, Rmin, Rmax;
+  float *in, *out, *r, *d, *x, *y;
+  Vector Xvec, Yvec, Zvec, *xvec, *yvec, *zvec;
+  Graphdata graphmode;
+
+  if (!style_args (&graphmode, &argc, argv, 0)) return FALSE;
+
+  if (argc != 6) {
+    gprint (GP_ERR, "USAGE: czplot <x> <y> <z> min max\n");
+    return (FALSE);
+  }
+  SetGraph (graphmode);
+
+  min = atof(argv[4]);
+  range = atof(argv[5]) - min;
+  Rmin = graphmode.coords.crval1 - 180.0;
+  Rmax = graphmode.coords.crval1 + 180.0;
+
+  /* find vectors */
+  if ((xvec = SelectVector (argv[1], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((yvec = SelectVector (argv[2], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((zvec = SelectVector (argv[3], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+
+  if (xvec[0].Nelements != yvec[0].Nelements) {
+    gprint (GP_ERR, "vectors %s and %s not the same length\n", argv[1], argv[2]);
+    return (FALSE);
+  }
+  if (xvec[0].Nelements != zvec[0].Nelements) {
+    gprint (GP_ERR, "vectors %s and %s not the same length\n", argv[1], argv[3]);
+    return (FALSE);
+  }
+  Xvec.Nelements = xvec[0].Nelements;
+  Yvec.Nelements = xvec[0].Nelements;
+  Zvec.Nelements = zvec[0].Nelements;
+  ALLOCATE (Xvec.elements, float, Xvec.Nelements);
+  ALLOCATE (Yvec.elements, float, Yvec.Nelements);
+  ALLOCATE (Zvec.elements, float, Zvec.Nelements);
+  
+  r   = xvec[0].elements;
+  d   = yvec[0].elements;
+  in  = zvec[0].elements;
+  x   = Xvec.elements;
+  y   = Yvec.elements;
+  out = Zvec.elements;
+  for (i = 0; i < Zvec.Nelements; i++, in++, out++, r++, d++, x++, y++) {
+    *out = MIN (1.0, MAX (0.01, (*in - min) / range));
+    while (*r < Rmin) *r += 360.0;
+    while (*r > Rmax) *r -= 360.0;
+    fRD_to_XY (x, y, *r, *d, &graphmode.coords);
+  }
+
+  graphmode.style = 2;
+  graphmode.size = -1; /* point size determined by Zvec */
+  graphmode.etype = 0;
+  Npts = Xvec.Nelements;
+  PrepPlotting (Npts, &graphmode);
+
+  PlotVector (Npts, Xvec.elements);
+  PlotVector (Npts, Yvec.elements);
+  PlotVector (Npts, Zvec.elements);
+
+  free (Xvec.elements);
+  free (Yvec.elements);
+  free (Zvec.elements);
+
+  return (TRUE);
+
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/drizzle.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/drizzle.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/drizzle.c	(revision 11389)
@@ -0,0 +1,302 @@
+# include "astro.h"
+
+/*** needs mosaic astrometry ***/
+
+static double XO, XX, XY;
+static double YO, YX, YY;
+static int ZERO;
+
+static int ROTATE;
+static double rot_phi, rot_alpha, rot_delta;
+static double rot_cdp, rot_sdp;
+
+int map_output_to_input (int Npix, double df);
+int map_input_to_output (int Npix, double df);
+int set_linear_terms (Coords *in, Coords *out, int i, int j, int Npix);
+void apply_terms (double *Xout, double *Yout, double Xin, double Yin);
+
+Coords coords_in, coords_out;
+Buffer *in, *out, *wt, *mask;
+
+int drizzle (int argc, char **argv) {
+
+  int Nlinear, Np, N;
+  double scale_in, scale_out, df;
+
+  ZERO = FALSE;
+  if ((N = get_argument (argc, argv, "-zero"))) {
+    ZERO = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  ROTATE = FALSE;
+  if ((N = get_argument (argc, argv, "-roll"))) {
+    /* -roll phi alpha_pole delta_pole */
+    /* XXX need to clarify the meaning of phi, alpha, delta */
+    ROTATE = TRUE;
+    remove_argument (N, &argc, argv);
+    rot_phi   = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+    rot_alpha = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+    rot_delta = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+
+    rot_cdp = cos(RAD_DEG*rot_delta);
+    rot_sdp = sin(RAD_DEG*rot_delta);
+  }
+
+  mask = NULL;
+  if ((N = get_argument (argc, argv, "-mask"))) {
+    remove_argument (N, &argc, argv);
+    if ((mask = SelectBuffer (argv[N], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 5) {
+    gprint (GP_ERR, "USAGE: transform <from> <to> <weight> (Nlinear)\n");
+    gprint (GP_ERR, "  output buffer must exist with target astrometry header\n");
+    gprint (GP_ERR, "  Nlinear is the pixel scale for linear astrometric transformation\n");
+    return (FALSE);
+  }
+
+  if ((in  = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  if ((out = SelectBuffer (argv[2], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  if ((wt  = SelectBuffer (argv[3], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  Nlinear = atoi (argv[4]);
+
+  GetCoords (&coords_in, &in[0].header);
+  GetCoords (&coords_out, &out[0].header);
+
+  /* for the moment, disable WRP / DIS */
+  if (!strcmp(&coords_in.ctype[4], "-WRP") || !strcmp(&coords_out.ctype[4], "-WRP")) {
+    gprint (GP_ERR, "WRP mode not implemented for astrom\n");
+    return (FALSE);
+  }
+  
+  scale_in = sqrt(fabs(coords_in.cdelt1*coords_in.cdelt2*(coords_in.pc1_1*coords_in.pc2_2 - coords_in.pc1_2*coords_in.pc2_1)));
+  scale_out = sqrt(fabs(coords_out.cdelt1*coords_out.cdelt2*(coords_out.pc1_1*coords_out.pc2_2 - coords_out.pc1_2*coords_out.pc2_1)));
+  
+  gprint (GP_ERR, "%f - %f\n", scale_in, scale_out);
+
+  if (scale_in > scale_out) {
+    Np = MAX (1, 3*scale_out / scale_in);
+    df = 1.0 / Np;
+    map_output_to_input (Nlinear, df);
+  } else {
+    Np = MAX (1, 3*scale_in / scale_out);
+    df = 1.0 / Np;
+    map_input_to_output (Nlinear, df);
+  }
+  return (TRUE);
+}
+
+/* mode 1: input pixels >> output pixels: loop over output pixels */
+/* mode 2: input pixels << output pixels: loop over input pixels */
+/* mode 3: input pixels ~= output pixels: drizzle input to output */
+
+/* loop over the input pixels, map input output image */
+int map_output_to_input (int Npix, double df) {
+
+  int i, j, Ni, No, Nx, Ny, nx, ny;
+  float *Vin, *Vout, *Vwt, *Vmk;
+  double x, y, X, Y;
+
+  /* loop over output pixels */
+  /* set up pointers for buffers */
+  Vin  = (float *) in[0].matrix.buffer;
+  Vout = (float *) out[0].matrix.buffer;
+  Vwt  = (float *) wt[0].matrix.buffer;
+  Vmk  = NULL;
+  Vmk = (mask == NULL) ? NULL : (float *) mask[0].matrix.buffer;
+
+  nx = in[0].header.Naxis[0];
+  ny = in[0].header.Naxis[1];
+  Nx = out[0].header.Naxis[0];
+  Ny = out[0].header.Naxis[1];
+
+  if (ZERO) {
+    bzero (Vout, Nx*Ny*sizeof(float));
+    bzero (Vwt,  Nx*Ny*sizeof(float));
+  }
+
+  gprint (GP_ERR, "mapping output to input\n");
+
+  for (j = 0; j < Ny; j+=Npix) {
+    for (i = 0; i < Nx; i+=Npix) {
+      
+      /* define linear transformation in region */
+      if (!set_linear_terms (&coords_out, &coords_in, i, j, Npix)) continue;
+
+      for (X = i; (X < i + Npix) && (X < Nx); X += df) {
+	for (Y = j; (Y < j + Npix) && (Y < Ny); Y += df) {
+	  
+	  No = (int)X + ((int)Y)*Nx;
+	  apply_terms (&x, &y, X, Y);
+	  if (x < 0) continue;
+	  if (x >= nx) continue;
+	  if (y < 0) continue;
+	  if (y >= ny) continue;
+	  Ni = (int)x + ((int)y)*nx;
+
+	  if (Vmk && Vmk[Ni]) continue;
+	  Vout[No] += Vin[Ni];
+	  Vwt[No] ++;
+	}
+      }
+    }
+  }
+  return (TRUE);
+}
+
+/* loop over the input pixels, map input output image */
+int map_input_to_output (int Npix, double df) {
+
+  int i, j, Ni, No, Nx, Ny, nx, ny;
+  float *Vin, *Vout, *Vwt, *Vmk;
+  double x, y, X, Y;
+
+  /* loop over output pixels */
+  /* set up pointers for buffers */
+  Vin  = (float *) in[0].matrix.buffer;
+  Vout = (float *) out[0].matrix.buffer;
+  Vwt  = (float *) wt[0].matrix.buffer;
+  Vmk  = NULL;
+  Vmk = (mask == NULL) ? NULL : (float *) mask[0].matrix.buffer;
+
+  Nx = in[0].header.Naxis[0];
+  Ny = in[0].header.Naxis[1];
+  nx = out[0].header.Naxis[0];
+  ny = out[0].header.Naxis[1];
+
+  if (ZERO) {
+    bzero (Vout, nx*ny*sizeof(float));
+    bzero (Vwt,  nx*ny*sizeof(float));
+  }
+
+  gprint (GP_ERR, "mapping input to output\n");
+
+  for (j = 0; j < Ny; j+=Npix) {
+    for (i = 0; i < Nx; i+=Npix) {
+      
+      /* define linear transformation in region */
+      if (!set_linear_terms (&coords_in, &coords_out, i, j, Npix)) continue;
+
+      for (X = i; (X < i + Npix) && (X < Nx); X += df) {
+	for (Y = j; (Y < j + Npix) && (Y < Ny); Y += df) {
+	  
+	  Ni = (int)X + ((int)Y)*Nx;
+	  apply_terms (&x, &y, X, Y);
+	  if (x < 0) continue;
+	  if (x >= nx) continue;
+	  if (y < 0) continue;
+	  if (y >= ny) continue;
+	  No = (int)x + ((int)y)*nx;
+
+	  if (Vmk && Vmk[Ni]) continue;
+	  Vout[No] += Vin[Ni];
+	  Vwt[No] ++;
+	}
+      }
+    }
+  }
+  return (TRUE);
+}
+
+int rotate_coords (double *phi, double *theta, double alpha, double delta) {
+
+  double sda, cda, cd, sd, sth;
+  double x, y;
+  
+  sda = sin(RAD_DEG*(alpha - rot_alpha));
+  cda = cos(RAD_DEG*(alpha - rot_alpha));
+  sd = sin(RAD_DEG*delta);
+  cd = cos(RAD_DEG*delta);
+  
+  sth = -cd*sda*rot_cdp + sd*rot_sdp;
+  y   = +cd*sda*rot_sdp + sd*rot_cdp;
+  x   = +cd*cda;
+
+  *theta = DEG_RAD*asin(sth);
+  *phi   = DEG_RAD*atan2(y,x) + rot_phi;
+  
+  while (*phi <   0.0) *phi += 360.0;
+  while (*phi > 360.0) *phi -= 360.0;
+  return (TRUE);
+}
+
+/* find the linear astrometric fix between images at this location */
+int set_linear_terms (Coords *in, Coords *out, int i, int j, int Npix) {
+
+  int n;
+  double x, y, x2, y2, xy, X, Y, Xx, Xy, Yx, Yy;
+  double Xin, Yin, Xout, Yout;
+  double Sx2, Sy2, Sxy, SXx, SXy, SYx, SYy;
+  double N, r, d, phi, theta;
+
+  Xin = Yin = 0;
+  N = x = y = x2 = y2 = xy = X = Y = Xx = Xy = Yx = Yy = 0;
+
+  /* define several test points, fit a line to the input,output pairs */
+  for (n = 0; n < 3; n++) {
+
+    switch (n) {
+    case 0:
+      Xin = i;
+      Yin = j;
+      break;
+    case 1:
+      Xin = i + Npix;
+      Yin = j;
+      break;
+    case 2:
+      Xin = i;
+      Yin = j + Npix;
+      break;
+    }
+
+    if (!XY_to_RD (&r, &d, Xin, Yin, in)) return (FALSE);
+    if (ROTATE) { 
+      rotate_coords (&phi, &theta, r, d);
+      r = phi;
+      d = theta;
+    }
+    if (!RD_to_XY (&Xout, &Yout, r, d, out)) return (FALSE);
+
+    x  += Xin;
+    y  += Yin;
+    x2 += Xin*Xin;
+    y2 += Yin*Yin;
+    xy += Xin*Yin;
+    X  += Xout;
+    Y  += Yout;
+    Xx += Xout*Xin;
+    Xy += Xout*Yin;
+    Yx += Yout*Xin;
+    Yy += Yout*Yin;
+    N  += 1.0;
+  }
+
+  Sx2 = x2 - x*x/N;
+  Sy2 = y2 - y*y/N;
+  Sxy = xy - x*y/N;
+  SXx = Xx - X*x/N;
+  SXy = Xy - X*y/N;
+  SYx = Yx - Y*x/N;
+  SYy = Yy - Y*y/N;
+  
+  XX = (SXx*Sy2 - SXy*Sxy) / (Sx2*Sy2 - Sxy*Sxy);
+  XY = (SXy*Sx2 - SXx*Sxy) / (Sx2*Sy2 - Sxy*Sxy);
+  XO = X/N - XX*x/N - XY*y/N;
+
+  YX = (SYx*Sy2 - SYy*Sxy) / (Sx2*Sy2 - Sxy*Sxy);
+  YY = (SYy*Sx2 - SYx*Sxy) / (Sx2*Sy2 - Sxy*Sxy);
+  YO = Y/N - YX*x/N - YY*y/N;
+  return (TRUE);
+}
+
+
+void apply_terms (double *Xout, double *Yout, double Xin, double Yin) {
+  *Xout = XO + XX*Xin + XY*Yin;
+  *Yout = YO + YX*Xin + YY*Yin;
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/fixwrap.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/fixwrap.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/fixwrap.c	(revision 11389)
@@ -0,0 +1,110 @@
+# include "astro.h"
+
+int fixwrap (int argc, char **argv) {
+  
+  int i, j, Nflip, n, Ny, Nx, flip, sat, rowfix;
+  float *Vin, *outf, *outb, dO;
+  Buffer *in;
+
+  if (argc != 3) {
+    gprint (GP_ERR, "USAGE: fixwrap <in> (rowfix)\n");
+    return (FALSE);
+  }
+
+  if ((in = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  rowfix = atoi (argv[2]);
+
+  Nx = in[0].matrix.Naxis[0];
+  Ny = in[0].matrix.Naxis[1];
+
+  ALLOCATE (outf, float, MAX(Nx, Ny));
+  ALLOCATE (outb, float, MAX(Nx, Ny));
+
+  for (j = 0; j < Ny; j++) {
+    Vin  = (float *)(in[0].matrix.buffer)  + j*Nx;
+
+    /* measure forward flips */ 
+    sat = FALSE;
+    for (i = 0; i < Nx; i++) {
+      if ((i < 1056) || (i > 2079)) {
+	outf[i] = Vin[i];
+	continue;
+      }
+
+      dO = 2*outf[i-1] - outf[i-2] - Vin[i];
+      flip = (fabs(dO - 0x8000) < fabs(dO));
+
+      /* going onto saturation */
+      if (!sat && (Vin[i] > 32766.5) && (Vin[i+1]  > 32766.5)) sat  = TRUE;
+      if (!sat && (Vin[i] > 32766.5) && (Vin[i-Nx] > 65534.5)) sat  = TRUE;
+
+      /* exiting saturation region */
+      if ( sat && (Vin[i] < 32766.5) && (Vin[i-1] < 32766.5)) sat = FALSE;
+
+      if (sat) flip = TRUE;
+
+      outf[i] = flip ? (Vin[i] + 0x8000) : Vin[i];
+    }
+
+    /* measure backward flips */ 
+    sat = FALSE;
+    for (i = Nx - 1; i >= 0; i--) {
+      if ((i < 1056) || (i > 2077)) {
+	outb[i] = Vin[i];
+	continue;
+      }
+
+      dO = 2*outb[i+1] - outb[i+2] - Vin[i];
+      flip = (fabs(dO - 0x8000) < fabs(dO));
+
+      /* going onto saturation */
+      if (!sat && (Vin[i] > 32766.5) && (Vin[i-1] > 32766.5)) sat  = TRUE;
+
+      /* exiting saturation region */
+      if ( sat && (Vin[i] < 32766.5) && (Vin[i+1] < 32766.5)) sat = FALSE;
+
+      if (sat) flip = TRUE;
+
+      outb[i] = flip ? (Vin[i] + 0x8000) : Vin[i];
+    }
+
+    /* compare forward and backward flips: where they disagree, use column to predict */
+    for (i = 0; (j > 1) && (i < Nx); i++) {
+      if ((i < 1056) || (i > 2077)) continue;
+      if (outf[i] != outb[i]) {
+	/* use this column to predict, not the row */
+	dO = 2*Vin[i - Nx] - Vin[i-2*Nx] - Vin[i];
+	flip = (fabs(dO - 0x8000) < fabs(dO));
+	outf[i] = flip ? Vin[i] + 0x8000 : Vin[i];
+	outb[i] = outf[i];  /* save this for the row segments below */
+      }
+    }
+
+    /* compare this row and previous (now fixed) row. if large segments are flipped, fix them */
+    for (i = 0; rowfix && (j > 1) && (i < Nx); i++) {
+      if ((i < 1056) || (i > 2077)) continue;
+
+      if (fabs(outf[i] - Vin[i-Nx]) > 15000) {
+	Nflip = 0;
+	for (n = i - 8; n < i + 9; n++) {
+	  if (fabs(outb[n] - Vin[n-Nx]) > 15000) {
+	    Nflip ++;
+	  }
+	}
+	if (Nflip > 5) {
+	  if (outf[i] - Vin[i-Nx] > 15000) {
+	    outf[i] -= 0x8000;
+	  } else {
+	    outf[i] += 0x8000;
+	  }	    
+	}
+      }
+    }
+    for (i = 0; i < Nx; i++) {
+      Vin[i] = outf[i];
+    }
+  }
+
+  return (TRUE);
+}
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/flux.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/flux.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/flux.c	(revision 11389)
@@ -0,0 +1,76 @@
+# include "astro.h"
+
+int flux (int argc, char **argv) {
+  
+  int i, j, k, xmin, ymin, xmax, ymax;
+  void *oldsignal;
+  double ax, ay, s, S, flux;
+  double bx[5], by[5], x[5], y[5], bb[5];
+  float *V;
+  FILE *f;
+  Buffer *buf;
+
+  if (argc != 3) {
+    gprint (GP_ERR, "USAGE: flux <buffer> (region)\n");
+    return (FALSE);
+  }
+
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+
+  f = fopen (argv[2], "r");
+  if (f == (FILE *) NULL) {
+    gprint (GP_ERR, "file %s not found\n", argv[2]);
+    return (FALSE);
+  }
+
+  xmin = buf[0].matrix.Naxis[0];
+  xmax = 0;
+  ymin = buf[0].matrix.Naxis[1];
+  ymax = 0;
+  for (i = 0; i < 4; i++) {
+    fscanf (f, "%lf %lf", &x[i], &y[i]);
+    xmin = MAX (0, MIN (xmin, x[i] - 1));
+    ymin = MAX (0, MIN (ymin, y[i] - 1));
+    xmax = MIN (MAX (xmax, x[i] + 1), buf[0].matrix.Naxis[0]);
+    ymax = MIN (MAX (ymax, y[i] + 1), buf[0].matrix.Naxis[1]);
+  }
+  fclose (f);
+
+  x[4] = x[0]; y[4] = y[0];
+  for (i = 0; i < 4; i++) {
+    bx[i] = x[i+1] - x[i];
+    by[i] = y[i+1] - y[i];
+  }
+  bx[4] = bx[0]; by[4] = by[0];
+  for (i = 0; i < 4; i++) {
+    bb[i] = hypot (bx[i], by[i]) * SIGN (bx[i]*by[i+1] - bx[i+1]*by[i]);
+  }
+  gprint (GP_ERR, "%f %f %f %f\n", bb[0], bb[1], bb[2], bb[3]);
+
+  /* this only works for convex contours --
+   we have to add up the angles for concave contours */
+  flux = 0;
+  oldsignal = signal (SIGINT, handle_interrupt);
+  interrupt = FALSE;
+  for (j = ymin; (j < ymax) && !interrupt; j++) {
+    V = (float *)(buf[0].matrix.buffer) + j*buf[0].matrix.Naxis[0] + xmin; 
+    for (i = xmin; (i < xmax) && !interrupt; i++, V++) {
+      S = 1.0;
+      for (k = 0; k < 4; k++) {
+	ax = i - x[k];
+	ay = j - y[k];
+	s = (ay*bx[k] - ax*by[k]) / bb[k] + 0.5;
+	/* s = b x a / |b|, with the correct sign (above) so inside is positive */
+	s = MAX (0.0, MIN (1.0, s));  /* s is between 0.0 and 1.0 */
+	S *= s;
+      }
+      flux += S * (*V);
+    }
+  }
+  signal (SIGINT, oldsignal);
+
+  gprint (GP_LOG, "flux: %f\n", flux);
+  set_variable ("FLUX", flux);
+  return (TRUE);
+}
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/gauss.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/gauss.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/gauss.c	(revision 11389)
@@ -0,0 +1,62 @@
+# include "astro.h"
+
+int gauss (int argc, char **argv) {
+
+  char key[20];
+  int i, N, Npix, Nborder, Nspot;
+  double X, Y, Z, max;
+  int Ximage, Nimage;
+  Buffer *buf;
+
+  Nimage = -1;
+  if ((N = get_argument (argc, argv, "-n"))) {
+    remove_argument (N, &argc, argv);
+    Nimage = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if (!GetImage (&Ximage, &Nimage)) return (FALSE);
+
+  Nborder = 3;
+  if ((N = get_argument (argc, argv, "-border"))) {
+    remove_argument (N, &argc, argv);
+    Nborder  = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  Nborder = MAX (Nborder, 1);
+  
+  max = 60000;
+  if ((N = get_argument (argc, argv, "-sat"))) {
+    remove_argument (N, &argc, argv);
+    max  = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  
+  if ((argc != 2) && (argc != 3)) {
+    gprint (GP_ERR, "USAGE: gauss Npix [Nspots] [-border N] [-sat cnts]\n");
+    return (FALSE);
+  }
+  
+  if (Ximage < 1) {
+    gprint (GP_ERR, "no active TV\n");
+    return (FALSE);
+  }
+
+  Nspot = 0;
+  Npix = atof (argv[1]);
+  if (argc == 3) {
+    Nspot = atof (argv[2]);
+  }
+
+  if ((buf = SelectBuffer (GetImageName(), OLDBUFFER, TRUE)) == NULL) return (FALSE);
+
+  KiiCursorOn (Ximage);
+
+  for (i = 0; (i < Nspot) || (Nspot == 0); i++) {
+    KiiCursorRead (Ximage, &X, &Y, key);
+    if (!strcasecmp (key, "Q")) break;
+    Z = get_aperture_stats (&buf[0].matrix, (int)(X+0.5), (int)(Y+0.5), Npix, Nborder, max);
+  }
+  KiiCursorOff (Ximage);
+  return (TRUE);
+}
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/getlst.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/getlst.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/getlst.c	(revision 11389)
@@ -0,0 +1,41 @@
+# include "astro.h"
+
+int getlst (int argc, char **argv) {
+
+  int N;
+  time_t time;
+  double jd, lst, longitude;
+  char *Variable;
+
+  Variable = NULL;
+  if ((N = get_argument (argc, argv, "-var"))) {
+    remove_argument (N, &argc, argv);
+    Variable = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if (argc != 3) goto syntax;
+
+  if (!str_to_time (argv[1], &time)) {
+      if (Variable != NULL) free (Variable);
+      return (FALSE);
+  }
+
+  longitude = atof (argv[2]);
+
+  jd = sec_to_jd (time);
+  fprintf (stderr, "jd: %f\n", jd);
+
+  lst = ohana_lst (jd, longitude);
+
+  if (Variable != NULL) {
+      set_variable (Variable, lst);
+      free (Variable);
+      return (TRUE);
+  }
+  gprint (GP_ERR, "lst: %f\n", lst);
+  return (TRUE);
+
+ syntax:
+  gprint (GP_ERR, "USAGE: getlst (time) (longitude) [-var name]\n");
+  return (FALSE);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/getvel.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/getvel.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/getvel.c	(revision 11389)
@@ -0,0 +1,81 @@
+# include "astro.h"
+
+int getvel (int argc, char **argv) {
+  
+  int i, n, Ncurve;
+  int nx, ny;
+  double L, V, Vo, dV, Bo, dB;
+  double xo, yo;
+  double sl, cl, wo, Ro, Rs, wr, r, fr, d, x;
+  double R[100], T[100], W[100];
+  FILE *f;
+  Buffer *buf;
+
+  if (argc != 5) {
+    gprint (GP_ERR, "USAGE: rotcurve buf X Y curve.txt\n");
+    return (FALSE);
+  }
+
+  f = fopen (argv[4], "r");
+  if (f == (FILE *) NULL) {
+    gprint (GP_ERR, "can't find rotation curve data file %s\n", argv[4]);
+    return (FALSE);
+  }
+  for (i = 0; fscanf (f, "%lf %lf", &R[i], &T[i]) != EOF; i++) {
+    W[i] = T[i] / R[i];
+  }  
+  fclose (f);
+  Ncurve = i;
+
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  nx = buf[0].matrix.Naxis[0];
+  ny = buf[0].matrix.Naxis[1];
+
+  /* we expect the input image to have units of velocity, lattitude, and longitude */
+  gfits_scan (&buf[0].header, "CRVAL1", "%lf", 1, &Vo);
+  gfits_scan (&buf[0].header, "CDELT1", "%lf", 1, &dV);
+  gfits_scan (&buf[0].header, "CRPIX1", "%lf", 1, &xo);
+  gfits_scan (&buf[0].header, "CRVAL2", "%lf", 1, &Bo);
+  gfits_scan (&buf[0].header, "CDELT2", "%lf", 1, &dB);
+  gfits_scan (&buf[0].header, "CRPIX2", "%lf", 1, &yo);
+  gfits_scan (&buf[0].header, "CRVAL3", "%lf", 1, &L);
+  Vo *= 0.001;
+  dV *= 0.001;
+
+  while (L >= 360) {L -= 360.0;}
+  while (L < 0.0)  {L += 360.0;}
+  gprint (GP_ERR, "L: %f\n", L);
+
+  cl = cos (L*RAD_DEG);
+  sl = sin (L*RAD_DEG);
+  wo = 25.0;
+  Ro = 10.0;
+  Rs = Ro*sl;
+  x = atof (argv[2]);
+  /* this method depends on wr monotonically decreasing */
+
+  V = (x - xo) * dV + Vo;
+  wr = V/Rs + wo;
+  for (n = 0; (n < Ncurve) && (wr < W[n]); n++);
+  if ((n == 0) || (n == Ncurve)) {
+    gprint (GP_ERR, "velocity out of reasonable range\n");
+    gprint (GP_ERR, "%f %f %f %f\n", V, wr, W[0], W[Ncurve-1]);
+    return (TRUE);
+  }
+  r = (wr - W[n]) *  (R[n-1] - R[n]) / (W[n-1] - W[n]) + R[n];
+  fr = (Ro/r);
+  if (r < fabs(Rs)) { /* can't be on rotation curve */
+    gprint (GP_ERR, "velocity out of reasonable range\n");
+    gprint (GP_ERR, "%f %f %f %f %f %f %f\n", V, wr, W[0], W[Ncurve-1], r, fr, Rs);
+    return (TRUE);
+  }
+  if (r < Ro)
+    d = Ro*cl - sqrt(r*r - Rs*Rs);
+  else 
+    d = Ro*cl + sqrt(r*r - Rs*Rs);
+  
+  gprint (GP_ERR, "dist: %f, vel: %f\n", d, V);
+
+  return (TRUE);
+
+} 
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/help/biassub
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/help/biassub	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/help/biassub	(revision 11389)
@@ -0,0 +1,9 @@
+
+  biassub buffer sx sy nx ny dir [-v N V]
+
+  Apply a bias correction.  The region defines a vector 
+  (median is taken perpendicular to the dir direction) which 
+  is subtracted from the image.
+
+
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/help/cgrid
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/help/cgrid	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/help/cgrid	(revision 11389)
@@ -0,0 +1,6 @@
+
+  cgrid
+
+  draws a grid in RA and DEC on window 0 approriate for the current
+  region.
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/help/coords
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/help/coords	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/help/coords	(revision 11389)
@@ -0,0 +1,19 @@
+
+  coords <buffer> (filename)
+
+  "coords" loads astrometric parameters for the given buffer from the
+header of the named file.  The parameters are applied to the buffer,
+and will register in the Ki'i window if the buffer it tv'ed again.
+This is particularly convenient for intercomparing coordinate system
+or in the event the astrometry is stored in a different file (eg, a
+stripped off header).  Currently, the only format of coordinate
+information that is looked for are gene's linear transformation: RA_O,
+RA_X, RA_Y, DEC_O, DEC_X, DEC_Y such that the RA,DEC of an object is
+given by:
+
+RA  = RA_O  + x*RA_X  + y*RA_Y
+DEC = DEC_O + x*DEC_X + y*DEC_Y.
+
+
+  See also: rd, tv
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/help/flux
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/help/flux	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/help/flux	(revision 11389)
@@ -0,0 +1,7 @@
+
+   flux buffer (file)
+
+   calculate the flux enclosed by the contour given in the file.  The
+   file contains the coordinates of the polygon corners.
+
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/help/gauss
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/help/gauss	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/help/gauss	(revision 11389)
@@ -0,0 +1,15 @@
+
+   gauss Npix [Nspots] [-border N] [-sat cnts]
+
+   calculate statistics on stars, assuming a Gaussian profile.  The
+   user types a key on a star in the Kii window, and the resulting
+   information is printed on the screen.  This is really aperture
+   photometry.  Npix defines the aperture width (square aperture), the
+   optional -border defines the number of pixels in an annulus used to
+   find the background, -sat defines the value of a saturated pixel.
+   If the Nspots option is given, exactly Nspots stars are chosen.
+   Otherwise, the user may type on stars until the 'q' is typed.  The
+   results of the last star are stored the a set of Mana variables.
+
+   See also: star, cursor
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/help/profile
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/help/profile	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/help/profile	(revision 11389)
@@ -0,0 +1,6 @@
+
+   profile <buffer> <X vector> <Y vector> x y N
+
+   Find the radial profile of an image at the location x, y.  the
+   radius is placed in the X vector and the pixel value is placed in
+   the Y vector.   
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/help/region
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/help/region	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/help/region	(revision 11389)
@@ -0,0 +1,18 @@
+
+  region RA DEC Radius [projection]
+
+  define the current sky region and optionally the projection.  
+  RA, DEC and Radius are all values in decimal degrees.  The possible 
+  values for "projection" are:
+
+  TAN - a tangent plane projection (default, and typical for optical images)
+  SIN - a sine plane projection (more appropriate for polar regions)
+  AIT - aitoff projection (good for the full sky)
+  GLS - ?? (also good for the full sky)
+
+  optional orientation flags:
+
+  -ew : display with East Left (default)
+  +ew : display with East Right 
+  -ns : display with North Down
+  +ns : display with North Up (default)
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/imfit-Pgauss.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/imfit-Pgauss.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/imfit-Pgauss.c	(revision 11389)
@@ -0,0 +1,66 @@
+# include "imfit.h"
+
+float PgaussTD (float, float, float *, int, float *);
+void  PgaussCL ();
+
+void  Pgauss_setup (char *name) {
+
+  if (strcmp(name, "Pgauss")) return;
+
+  fitfunc = PgaussTD;
+  imfit_cleanup = PgaussCL;
+  Npar = 4;
+  Nfpar = 3;
+
+  /* allocate free and fixed parameters */
+  ALLOCATE (par, float, MAX (Npar, 1));
+  bzero (par, Npar*sizeof(float));
+  ALLOCATE (fpar, float, MAX (Nfpar, 1));
+  bzero (fpar, Nfpar*sizeof(float));
+
+  par[0] = get_variable_default ("Xg", 0);
+  par[1] = get_variable_default ("Yg", 0);
+  par[2] = get_variable_default ("Zpk", 10000);
+  par[3] = get_variable_default ("Sg", 0.0);
+  sky = &par[3];
+
+  fpar[0] = 2.35 / get_variable_default ("SXg", 2.0);
+  fpar[1] = 2.35 / get_variable_default ("SYg", 2.0);
+  fpar[2] = get_variable_default ("SXYg", 0);
+}
+
+void PgaussCL () {
+  set_variable ("Xg",   par[0]);
+  set_variable ("Yg",   par[1]);
+  set_variable ("Zpk",  par[2]);
+  set_variable ("Sg",   par[3]);
+}
+
+/* pseudo 2D gaussian -- x, y, (sx), (sy), (sxy), I, sky */
+float PgaussTD (float x, float y, float *par, int Npar, float *dpar) {
+
+  float X, Y, px, py;
+  float z, r, q, f;
+
+  /* par -> fpar: (2,0), (3,1), (4,2) */
+
+  X = x - par[0];
+  Y = y - par[1];
+  
+  px = fpar[0]*X;
+  py = fpar[1]*Y;
+
+  z = 0.5*SQ(px) + 0.5*SQ(py) + fpar[2]*X*Y;
+  r = 1.0 / (1 + z + 0.5*z*z*(1 + z/3)); /* ~ exp (-Z) */
+  f = par[2]*r + par[3];
+  q = par[2]*r*r*(1 + z + 0.5*z*z);
+  /* note difference from gaussian: q = par[5]*r */
+
+  if (dpar != NULL) {
+    dpar[0] = q*(2*px*fpar[0] + fpar[2]*Y);
+    dpar[1] = q*(2*py*fpar[1] + fpar[2]*X);
+    dpar[2] = +r;
+    dpar[3] = +1;
+  }
+  return (f);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/imfit-Qgauss.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/imfit-Qgauss.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/imfit-Qgauss.c	(revision 11389)
@@ -0,0 +1,68 @@
+# include "imfit.h"
+
+float QgaussTD (float, float, float *, int, float *);
+void  QgaussCL ();
+
+void Qgauss_setup (char *name) {
+
+  if (strcmp(name, "Qgauss")) return;
+
+  fitfunc = QgaussTD;
+  imfit_cleanup = QgaussCL;
+  Npar = 4;
+  Nfpar = 5;
+
+  /* allocate free and fixed parameters */
+  ALLOCATE (par, float, MAX (Npar, 1));
+  bzero (par, Npar*sizeof(float));
+  ALLOCATE (fpar, float, MAX (Nfpar, 1));
+  bzero (fpar, Nfpar*sizeof(float));
+
+  par[0]  = get_variable_default ("Xg", 0);
+  par[1]  = get_variable_default ("Yg", 0);
+  par[2]  = get_variable_default ("Zpk", 10000);
+  par[3]  = get_variable_default ("Sg", 0.0);
+
+  fpar[0] = 2.35 / get_variable_default ("SXg", 15.0);
+  fpar[1] = 2.35 / get_variable_default ("SYg", 15.0);
+  fpar[2] = get_variable_default ("SXYg", 0.0);
+  fpar[3] = get_variable_default ("Sr", 1.0);
+  fpar[4] = get_variable_default ("Npow", 2.25);
+
+  sky = &par[3];
+}
+
+void QgaussCL () {
+  set_variable ("Xg",  par[0]);
+  set_variable ("Yg",  par[1]);
+  set_variable ("Zpk", par[2]);
+  set_variable ("Sg",  par[3]);
+}
+
+/* one component, two slopes: (1 + z^M + z^N)^(-1) -- x, y, sx, sy, sxy, I, sky, sr */
+float QgaussTD (float x, float y, float *par, int Npar, float *dpar) {
+
+  float X, Y, px, py;
+  float z, r, q, f;
+
+  X = x - par[0];
+  Y = y - par[1];
+  
+  px = fpar[0]*X;
+  py = fpar[1]*Y;
+
+  z = 0.5*SQ(px) + 0.5*SQ(py) + fpar[2]*X*Y;
+
+  r = 1.0 / (1 + fpar[3]*z + pow(z,fpar[4]));
+  f = par[2]*r + par[3];
+  q = par[2]*SQ(r)*(fpar[3] + fpar[4]*pow(z,(fpar[4]-1)));
+
+  if (dpar != NULL) {
+    dpar[0] = q*(2*px*fpar[0] + fpar[2]*Y);
+    dpar[1] = q*(2*py*fpar[1] + fpar[2]*X);
+    dpar[2] = +r;
+    dpar[3] = +1;
+  }
+  return (f);
+}
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/imfit-Sgauss.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/imfit-Sgauss.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/imfit-Sgauss.c	(revision 11389)
@@ -0,0 +1,74 @@
+# include "imfit.h"
+
+float SgaussTD (float, float, float *, int, float *);
+void  SgaussCL ();
+
+void Sgauss_setup (char *name) {
+
+  if (strcmp(name, "Sgauss")) return;
+
+  fitfunc = SgaussTD;
+  imfit_cleanup = SgaussCL;
+  Npar = 4;
+  Nfpar = 7;
+
+  /* allocate free and fixed parameters */
+  ALLOCATE (par, float, MAX (Npar, 1));
+  bzero (par, Npar*sizeof(float));
+  ALLOCATE (fpar, float, MAX (Nfpar, 1));
+  bzero (fpar, Nfpar*sizeof(float));
+
+  par[0] = get_variable_default ("Xg", 0);
+  par[1] = get_variable_default ("Yg", 0);
+  par[2] = get_variable_default ("Zpk", 10000);
+  par[3] = get_variable_default ("Sg", 0.0);
+
+  fpar[0] = 2.35 / get_variable_default ("SXg", 15.0);
+  fpar[1] = 2.35 / get_variable_default ("SYg", 15.0);
+  fpar[2] = get_variable_default ("SXYg", 0.0);
+  fpar[3] = 2.35 / get_variable_default ("SXf", 15.0);
+  fpar[4] = 2.35 / get_variable_default ("SYf", 15.0);
+  fpar[5] = get_variable_default ("SXYf", 0.0);
+  fpar[6] = get_variable_default ("Npow", 2.25);
+
+  sky = &par[3];
+}
+
+void SgaussCL () {
+  set_variable ("Xg",   par[0]);
+  set_variable ("Yg",   par[1]);
+  set_variable ("Zpk",  par[2]);
+  set_variable ("Sg",   par[3]);
+}
+
+/* two components: (1 + z_1 + z_2^N)^(-1) -- x, y, sx1, sy1, sxy1, I, sky, sx2, sy2, sxy2 */
+float SgaussTD (float x, float y, float *par, int Npar, float *dpar) {
+
+  float X, Y, px1, py1, px2, py2;
+  float z1, z2, r, q1, q2, f;
+
+  X = x - par[0];
+  Y = y - par[1];
+  
+  px1 = fpar[0]*X;
+  py1 = fpar[1]*Y;
+  px2 = fpar[3]*X;
+  py2 = fpar[4]*Y;
+
+  z1 = 0.5*SQ(px1) + 0.5*SQ(py1) + fpar[2]*X*Y;
+  z2 = 0.5*SQ(px2) + 0.5*SQ(py2) + fpar[5]*X*Y;
+
+  r = 1.0 / (1 + z1 + pow(z2,fpar[6]));
+  f = par[2]*r + par[3];
+
+  q1 = par[2]*SQ(r);
+  q2 = par[2]*SQ(r)*fpar[6]*pow(z2,(fpar[6]-1));
+
+  if (dpar != NULL) {
+    dpar[0] = q1*(2*px1*fpar[0] + fpar[2]*Y) + q2*(2*px2*fpar[3] + fpar[5]*Y);
+    dpar[1] = q1*(2*py1*fpar[1] + fpar[2]*X) + q2*(2*py2*fpar[4] + fpar[5]*X);
+    dpar[2] = +r;
+    dpar[3] = +1;
+  }
+  return (f);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/imfit-fgauss.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/imfit-fgauss.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/imfit-fgauss.c	(revision 11389)
@@ -0,0 +1,68 @@
+# include "imfit.h"
+
+float fgaussTD (float, float, float *, int, float *);
+void  fgaussCL ();
+
+void fgauss_setup (char *name) {
+
+  if (strcmp(name, "fgauss")) return;
+
+  fitfunc = fgaussTD;
+  imfit_cleanup = fgaussCL;
+  Npar = 7;
+  Nfpar = 0;
+
+  /* allocate free and fixed parameters */
+  ALLOCATE (par, float, MAX (Npar, 1));
+  bzero (par, Npar*sizeof(float));
+  ALLOCATE (fpar, float, MAX (Nfpar, 1));
+  bzero (fpar, Nfpar*sizeof(float));
+
+  par[0] = get_variable_default ("Xg", 0);
+  par[1] = get_variable_default ("Yg", 0);
+  par[2] = 2.35 / get_variable_default ("SXg", 2.0);
+  par[3] = 2.35 / get_variable_default ("SYg", 2.0);
+  par[4] = get_variable_default ("SXYg", 0);
+  par[5] = get_variable_default ("Zpk", 10000);
+  par[6] = get_variable_default ("Sg", 0.0);
+  sky = &par[6];
+}
+
+void fgaussCL () {
+  set_variable ("Xg",   par[0]);
+  set_variable ("Yg",   par[1]);
+  set_variable ("SXg",  2.35 / par[2]);
+  set_variable ("SYg",  2.35 / par[3]);
+  set_variable ("SXYg", par[4]);
+  set_variable ("Zpk",  par[5]);
+  set_variable ("Sg",   par[6]);
+}
+
+/* real 2D gaussian -- x, y, sx, sy, sxy, I, sky */
+float fgaussTD (float x, float y, float *par, int Npar, float *dpar) {
+
+  float X, Y, px, py;
+  float z, r, q, f;
+
+  X = x - par[0];
+  Y = y - par[1];
+  
+  px = par[2]*X;
+  py = par[3]*Y;
+
+  z = 0.5*SQ(px) + 0.5*SQ(py) + par[4]*X*Y;
+  r = exp (-z);
+  q = par[5]*r;
+  f = q + par[6];
+
+  if (dpar != NULL) {
+    dpar[0] = q*(2*px*par[2] + par[4]*Y);
+    dpar[1] = q*(2*py*par[3] + par[4]*X);
+    dpar[2] = -2*q*px*X;
+    dpar[3] = -2*q*py*Y;
+    dpar[4] = -q*X*Y;
+    dpar[5] = +r;
+    dpar[6] = +1;
+  }
+  return (f);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/imfit-pgauss.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/imfit-pgauss.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/imfit-pgauss.c	(revision 11389)
@@ -0,0 +1,69 @@
+# include "imfit.h"
+
+float pgaussTD (float, float, float *, int, float *);
+void  pgaussCL ();
+
+void  pgauss_setup (char *name) {
+
+  if (strcmp(name, "pgauss")) return;
+
+  fitfunc = pgaussTD;
+  imfit_cleanup = pgaussCL;
+  Npar = 7;
+  Nfpar = 0;
+
+  /* allocate free and fixed parameters */
+  ALLOCATE (par, float, MAX (Npar, 1));
+  bzero (par, Npar*sizeof(float));
+  ALLOCATE (fpar, float, MAX (Nfpar, 1));
+  bzero (fpar, Nfpar*sizeof(float));
+
+  par[0] = get_variable_default ("Xg", 0.0);
+  par[1] = get_variable_default ("Yg", 0.0);
+  par[2] = 2.35 / get_variable_default ("SXg", 2.0);
+  par[3] = 2.35 / get_variable_default ("SYg", 2.0);
+  par[4] = get_variable_default ("SXYg", 0.0);
+  par[5] = get_variable_default ("Zpk", 10000);
+  par[6] = get_variable_default ("Sg", 0.0);
+  sky = &par[6];
+}
+
+void pgaussCL () {
+  set_variable ("Xg",   par[0]);
+  set_variable ("Yg",   par[1]);
+  set_variable ("SXg",  2.35 / par[2]);
+  set_variable ("SYg",  2.35 / par[3]);
+  set_variable ("SXYg", par[4]);
+  set_variable ("Zpk",  par[5]);
+  set_variable ("Sg",   par[6]);
+}
+
+/* pseudo 2D gaussian -- x, y, sx, sy, sxy, I, sky */
+float pgaussTD (float x, float y, float *par, int Npar, float *dpar) {
+
+  float X, Y, px, py;
+  float z, r, q, f;
+
+  X = x - par[0];
+  Y = y - par[1];
+  
+  px = par[2]*X;
+  py = par[3]*Y;
+
+  z = 0.5*SQ(px) + 0.5*SQ(py) + par[4]*X*Y;
+  r = 1.0 / (1 + z + 0.5*z*z*(1 + z/3)); /* ~ exp (-Z) */
+  f = par[5]*r + par[6];
+  q = par[5]*r*r*(1 + z + 0.5*z*z);
+  /* note difference from gaussian: q = par[5]*r */
+
+  if (dpar != NULL) {
+    dpar[0] = q*(2*px*par[2] + par[4]*Y);
+    dpar[1] = q*(2*py*par[3] + par[4]*X);
+    dpar[2] = -2*q*px*X;
+    dpar[3] = -2*q*py*Y;
+    dpar[4] = -q*X*Y;
+    dpar[5] = +r;
+    dpar[6] = +1;
+  }
+  return (f);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/imfit-qfgauss.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/imfit-qfgauss.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/imfit-qfgauss.c	(revision 11389)
@@ -0,0 +1,74 @@
+# include "imfit.h"
+
+float qfgaussTD (float, float, float *, int, float *);
+void  qfgaussCL ();
+
+void qfgauss_setup (char *name) {
+
+  if (strcmp(name, "qfgauss")) return;
+
+  fitfunc = qfgaussTD;
+  imfit_cleanup = qfgaussCL;
+  Npar = 7;
+  Nfpar = 2;
+
+  /* allocate free and fixed parameters */
+  ALLOCATE (par, float, MAX (Npar, 1));
+  bzero (par, Npar*sizeof(float));
+  ALLOCATE (fpar, float, MAX (Nfpar, 1));
+  bzero (fpar, Nfpar*sizeof(float));
+
+  par[0]  = get_variable_default ("Xg", 0);
+  par[1]  = get_variable_default ("Yg", 0);
+  par[2]  = 2.35 / get_variable_default ("SXg", 2.0);
+  par[3]  = 2.35 / get_variable_default ("SYg", 2.0);
+  par[4]  = get_variable_default ("SXYg", 0);
+  par[5]  = get_variable_default ("Zpk", 10000);
+  par[6]  = get_variable_default ("Sg", 0.0);
+
+  fpar[0] = get_variable_default ("Npow", 2.25);
+  fpar[1]  = get_variable_default ("Sr", 1.0);
+
+  sky = &par[6];
+}
+
+void qfgaussCL () {
+  set_variable ("Xg",   par[0]);
+  set_variable ("Yg",   par[1]);
+  set_variable ("SXg",  2.35 / par[2]);
+  set_variable ("SYg",  2.35 / par[3]);
+  set_variable ("SXYg", par[4]);
+  set_variable ("Zpk",  par[5]);
+  set_variable ("Sg",   par[6]);
+}
+
+/* one component, two slopes: (1 + z^M + z^N)^(-1) -- x, y, sx, sy, sxy, I, sky */
+float qfgaussTD (float x, float y, float *par, int Npar, float *dpar) {
+
+  float X, Y, px, py;
+  float z, r, q, f;
+
+  X = x - par[0];
+  Y = y - par[1];
+  
+  px = par[2]*X;
+  py = par[3]*Y;
+
+  z = 0.5*SQ(px) + 0.5*SQ(py) + par[4]*X*Y;
+
+  r = 1.0 / (1 + fpar[1]*z + pow(z,fpar[0]));
+  f = par[5]*r + par[6];
+  q = par[5]*SQ(r)*(fpar[1] + fpar[0]*pow(z,(fpar[0]-1)));
+
+  if (dpar != NULL) {
+    dpar[0] = q*(2*px*par[2] + par[4]*Y);
+    dpar[1] = q*(2*py*par[3] + par[4]*X);
+    dpar[2] = -2*q*px*X*2;
+    dpar[3] = -2*q*py*Y*2;
+    dpar[4] = -q*X*Y;
+    dpar[5] = +r;
+    dpar[6] = +1;
+  }
+  return (f);
+}
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/imfit-qgauss.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/imfit-qgauss.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/imfit-qgauss.c	(revision 11389)
@@ -0,0 +1,75 @@
+# include "imfit.h"
+
+float qgaussTD (float, float, float *, int, float *);
+void  qgaussCL ();
+
+void qgauss_setup (char *name) {
+
+  if (strcmp(name, "qgauss")) return;
+
+  fitfunc = qgaussTD;
+  imfit_cleanup = qgaussCL;
+  Npar = 8;
+  Nfpar = 1;
+
+  /* allocate free and fixed parameters */
+  ALLOCATE (par, float, MAX (Npar, 1));
+  bzero (par, Npar*sizeof(float));
+  ALLOCATE (fpar, float, MAX (Nfpar, 1));
+  bzero (fpar, Nfpar*sizeof(float));
+
+  par[0]  = get_variable_default ("Xg", 0);
+  par[1]  = get_variable_default ("Yg", 0);
+  par[2]  = 2.35 / get_variable_default ("SXg", 2.0);
+  par[3]  = 2.35 / get_variable_default ("SYg", 2.0);
+  par[4]  = get_variable_default ("SXYg", 0);
+  par[5]  = get_variable_default ("Zpk", 10000);
+  par[6]  = get_variable_default ("Sg", 0.0);
+  par[7]  = get_variable_default ("Sr", 1.0);
+  fpar[0] = get_variable_default ("Npow", 2.25);
+
+  sky = &par[6];
+}
+
+void qgaussCL () {
+  set_variable ("Xg",   par[0]);
+  set_variable ("Yg",   par[1]);
+  set_variable ("SXg",  2.35 / par[2]);
+  set_variable ("SYg",  2.35 / par[3]);
+  set_variable ("SXYg", par[4]);
+  set_variable ("Zpk",  par[5]);
+  set_variable ("Sg",   par[6]);
+  set_variable ("Sr", par[7]);
+}
+
+/* one component, two slopes: (1 + z^M + z^N)^(-1) -- x, y, sx, sy, sxy, I, sky, sr */
+float qgaussTD (float x, float y, float *par, int Npar, float *dpar) {
+
+  float X, Y, px, py;
+  float z, r, q, f;
+
+  X = x - par[0];
+  Y = y - par[1];
+  
+  px = par[2]*X;
+  py = par[3]*Y;
+
+  z = 0.5*SQ(px) + 0.5*SQ(py) + par[4]*X*Y;
+
+  r = 1.0 / (1 + par[7]*z + pow(z,fpar[0]));
+  f = par[5]*r + par[6];
+  q = par[5]*SQ(r)*(par[7] + fpar[0]*pow(z,(fpar[0]-1)));
+
+  if (dpar != NULL) {
+    dpar[0] = q*(2*px*par[2] + par[4]*Y);
+    dpar[1] = q*(2*py*par[3] + par[4]*X);
+    dpar[2] = -2*q*px*X*2;
+    dpar[3] = -2*q*py*Y*2;
+    dpar[4] = -q*X*Y;
+    dpar[5] = +r;
+    dpar[6] = +1;
+    dpar[7] = -par[5]*SQ(r)*z;
+  }
+  return (f);
+}
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/imfit-qrgauss.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/imfit-qrgauss.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/imfit-qrgauss.c	(revision 11389)
@@ -0,0 +1,110 @@
+# include "imfit.h"
+
+float qrgaussTD (float, float, float *, int, float *);
+void  qrgaussCL ();
+
+void qrgauss_setup (char *name) {
+
+  if (strcmp(name, "qrgauss")) return;
+
+  fitfunc = qrgaussTD;
+  imfit_cleanup = qrgaussCL;
+  Npar = 8;
+  Nfpar = 1;
+
+  /* allocate free and fixed parameters */
+  ALLOCATE (par, float, MAX (Npar, 1));
+  bzero (par, Npar*sizeof(float));
+  ALLOCATE (fpar, float, MAX (Nfpar, 1));
+  bzero (fpar, Nfpar*sizeof(float));
+
+  par[0]  = get_variable_default ("Xg", 0);
+  par[1]  = get_variable_default ("Yg", 0);
+  par[2]  = 2.35 / get_variable_default ("SXg", 2.0);
+  par[3]  = 2.35 / get_variable_default ("SYg", 2.0);
+  par[4]  = get_variable_default ("SXYg", 0);
+  par[5]  = get_variable_default ("Zpk", 10000);
+  par[6]  = get_variable_default ("Sg", 0.0);
+  par[7]  = get_variable_default ("Npow", 2.25);
+
+  fpar[0] = get_variable_default ("Sr", 1.0);
+
+  sky = &par[6];
+}
+
+void qrgaussCL () {
+  set_variable ("Xg",   par[0]);
+  set_variable ("Yg",   par[1]);
+  set_variable ("SXg",  2.35 / par[2]);
+  set_variable ("SYg",  2.35 / par[3]);
+  set_variable ("SXYg", par[4]);
+  set_variable ("Zpk",  par[5]);
+  set_variable ("Sg",   par[6]);
+  set_variable ("Npow", par[7]);
+}
+
+float qrgaussTD (float x, float y, float *par, int Npar, float *dpar) {
+
+  float X, Y, px, py;
+  float z, r, q, f;
+
+  X = x - par[0];
+  Y = y - par[1];
+  
+  px = par[2]*X;
+  py = par[3]*Y;
+
+  z = 0.5*SQ(px) + 0.5*SQ(py) + par[4]*X*Y;
+
+  r = 1.0 / (1 + fpar[0]*z + pow(z,par[7]));
+  f = par[5]*r + par[6];
+  q = par[5]*SQ(r)*(fpar[0] + par[7]*pow(z,(par[7]-1)));
+
+  if (dpar != NULL) {
+    dpar[0] = q*(2*px*par[2] + par[4]*Y);
+    dpar[1] = q*(2*py*par[3] + par[4]*X);
+    dpar[2] = -2*q*px*X*2;
+    dpar[3] = -2*q*py*Y*2;
+    dpar[4] = -q*X*Y;
+    dpar[5] = +r;
+    dpar[6] = +1;
+    dpar[7] = -5*par[5]*SQ(r)*log(z)*pow(z,par[7]);
+  }
+  return (f);
+}
+
+
+# if (0)
+/* one component, two slopes: (1 + z^M + z^N)^(-1) -- x, y, sx, sy, sxy, I, sky, sr */
+float qrgaussTD (float x, float y, float *par, int Npar, float *dpar) {
+
+  float X, Y, px, py;
+  float z, r, q, f;
+
+  /* if (par[7] < 1.0) par[7] = 1.0; */
+
+  X = x - par[0];
+  Y = y - par[1];
+  
+  px = par[2]*X;
+  py = par[3]*Y;
+
+  z = 0.5*SQ(px) + 0.5*SQ(py) + par[4]*X*Y;
+
+  r = 1.0 / (1 + fpar[0]*z + pow(z,par[7]) + 0.05*z*z*z);
+  f = par[5]*r + par[6];
+  q = par[5]*SQ(r)*(fpar[0] + par[7]*pow(z,(par[7]-1)) + 0.15*z*z);
+
+  if (dpar != NULL) {
+    dpar[0] = q*(2*px*par[2] + par[4]*Y);
+    dpar[1] = q*(2*py*par[3] + par[4]*X);
+    dpar[2] = -2*q*px*X*2;
+    dpar[3] = -2*q*py*Y*2;
+    dpar[4] = -q*X*Y;
+    dpar[5] = +r;
+    dpar[6] = +1;
+    dpar[7] = -5*par[5]*SQ(r)*log(z)*pow(z,par[7]);
+  }
+  return (f);
+}
+# endif
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/imfit-rgauss.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/imfit-rgauss.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/imfit-rgauss.c	(revision 11389)
@@ -0,0 +1,86 @@
+# include "imfit.h"
+
+float rgaussTD (float, float, float *, int, float *);
+void  rgaussCL ();
+
+void rgauss_setup (char *name) {
+
+  if (strcmp(name, "rgauss")) return;
+
+  fitfunc = rgaussTD;
+  cleanup = rgaussCL;
+  Npar = 10;
+  Nfpar = 1;
+
+  /* allocate free and fixed parameters */
+  ALLOCATE (par, float, MAX (Npar, 1));
+  bzero (par, Npar*sizeof(float));
+  ALLOCATE (fpar, float, MAX (Nfpar, 1));
+  bzero (fpar, Nfpar*sizeof(float));
+
+  par[0] = get_variable_default ("Xg", 0);
+  par[1] = get_variable_default ("Yg", 0);
+  par[2] = 2.35 * sqrt(2.0) / get_variable_default ("SXg", 2.0);
+  par[3] = 2.35 * sqrt(2.0) / get_variable_default ("SYg", 2.0);
+  par[4] = 0.0;
+  par[5] = get_variable_default ("Zpk", 10000);
+  par[6] = get_variable_default ("Sg", 0.0);
+  par[7] = 2.35 * sqrt(2.0) / get_variable_default ("SXf", 15.0);
+  par[8] = 2.35 * sqrt(2.0) / get_variable_default ("SYf", 15.0);
+  par[9] = get_variable_default ("SXYf", 0.0);
+
+  fpar[0] = get_variable_default ("Npow", 2.25);
+
+  sky = &par[6];
+}
+
+/* two components: (1 + z_1 + 0.5*z_1^2 + z_2^N)^(-1) -- x, y, sx1, sy1, sxy1, I, sky, sx2, sy2, sxy2 */
+float rgaussTD (float x, float y, float *par, int Npar, float *dpar) {
+
+  float X, Y, px1, py1, px2, py2;
+  float z1, z2, r, q1, q2, f;
+
+  X = x - par[0];
+  Y = y - par[1];
+  
+  px1 = par[2]*X;
+  py1 = par[3]*Y;
+  px2 = par[7]*X;
+  py2 = par[8]*Y;
+
+  z1 = 0.5*SQ(px1) + 0.5*SQ(py1) + par[4]*X*Y;
+  z2 = 0.5*SQ(px2) + 0.5*SQ(py2) + par[9]*X*Y;
+
+  r = 1.0 / (1 + z1 + 0.5*SQ(z1)+ pow(z2,fpar[0]));
+  f = par[5]*r + par[6];
+
+  q1 = par[5]*SQ(r)*(1 + z1);
+  q2 = par[5]*SQ(r)*fpar[0]*pow(z2,(fpar[0]-1));
+
+  if (dpar != NULL) {
+    dpar[0] = q1*(2*px1*par[2] + par[4]*Y) + q2*(2*px2*par[7] + par[9]*Y);
+    dpar[1] = q1*(2*py1*par[3] + par[4]*X) + q2*(2*py2*par[8] + par[9]*X);
+    dpar[2] = -2*q1*px1*X;
+    dpar[3] = -2*q1*py1*Y;
+    dpar[4] = -q1*X*Y;
+    dpar[5] = +r;
+    dpar[6] = +1;
+    dpar[7] = -2*q2*px2*X;
+    dpar[8] = -2*q2*py2*Y;
+    dpar[9] = -q2*X*Y;
+  }
+  return (f);
+}
+
+int rgaussCL () {
+  set_variable ("Xg",   par[0]);
+  set_variable ("Yg",   par[1]);
+  set_variable ("SXg",  2.35 * sqrt(2.0) / par[2]);
+  set_variable ("SYg",  2.35 * sqrt(2.0) / par[3]);
+  set_variable ("SXYg", par[4]);
+  set_variable ("Zpk",  par[5]);
+  set_variable ("Sg",   par[6]);
+  set_variable ("SXf", 2.35 * sqrt(2.0) / par[7]);
+  set_variable ("SYf", 2.35 * sqrt(2.0) / par[8]);
+  set_variable ("SXYf", par[9]);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/imfit-serbulge.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/imfit-serbulge.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/imfit-serbulge.c	(revision 11389)
@@ -0,0 +1,102 @@
+# include "imfit.h"
+
+float serbulgeTD (float, float, float *, int, float *);
+void  serbulgeCL ();
+
+void serbulge_setup (char *name) {
+
+  if (strcmp(name, "serbulge")) return;
+
+  fitfunc = serbulgeTD;
+  cleanup = serbulgeCL;
+  Npar = 12;
+  Nfpar = 0;
+
+  /* allocate free and fixed parameters */
+  ALLOCATE (par, float, MAX (Npar, 1));
+  bzero (par, Npar*sizeof(float));
+  ALLOCATE (fpar, float, MAX (Nfpar, 1));
+  bzero (fpar, Nfpar*sizeof(float));
+
+  par[0] = get_variable_default ("Xg", 0);
+  par[1] = get_variable_default ("Yg", 0);
+  par[2] = 2.35 * sqrt(2.0) / get_variable_default ("SXg", 2.0);
+  par[3] = 2.35 * sqrt(2.0) / get_variable_default ("SYg", 2.0);
+  par[4] = 0.0;
+  par[5] = get_variable_default ("Zpk", 10000) / 2.0;
+
+  par[6] = get_variable_default ("Sg", 0.0);
+
+  par[7] = 2.35 * sqrt(2.0) / get_variable_default ("SXf", 15.0);
+  par[8] = 2.35 * sqrt(2.0) / get_variable_default ("SYf", 15.0);
+  par[9] = get_variable_default ("SXYf", 0.0);
+  par[10] = get_variable_default ("Zpk", 10000) / 2.0;
+
+  par[11] = get_variable_default ("Sr", 1.0);
+
+  sky = &par[6];
+}
+
+/*                                  0  1    2   3   4      5    6     7   8   9       10  11 */
+/* sersic galaxy model w/ bulge: -- x, y, (sx, sy, sxy)_1, I_1, sky, (sx, sy, sxy)_2, I_2, n */
+/* exp (-b (r/r_e)^(1/n)) + pgauss (r) */
+float serbulgeTD (float x, float y, float *par, int Npar, float *dpar) {
+
+  float X, Y, px1, px2, py1, py2;
+  float z1, z2, r1, r2, t, q1, q2, f;
+
+  X = x - par[0];
+  Y = y - par[1];
+  
+  px1 = par[2]*X;
+  py1 = par[3]*Y;
+  px2 = par[7]*X;
+  py2 = par[8]*Y;
+
+  z1 = 0.5*SQ(px1) + 0.5*SQ(py1) + par[4]*X*Y;
+  z2 = 0.5*SQ(px2) + 0.5*SQ(py2) + par[9]*X*Y;
+
+  /* bulge component */
+  r1 = 1.0 / (1 + z1 + 0.5*z1*z1*(1 + z1/3)); /* ~ exp (-Z) */
+
+  /* disk component */
+  t = pow (z2, par[11]);
+  r2 = exp (-t);
+
+  f = par[5]*r1 + par[10]*r2 + par[6];
+
+  q1 = par[5]*r1*r1*(1 + z1 + 0.5*z1*z1);
+  q2 = par[10]*r2*par[11]*pow(z2, par[11]-1);
+
+  if (dpar != NULL) {
+    dpar[0] = q1*(2*px1*par[2] + par[4]*Y) + q2*(2*px2*par[7] + par[9]*Y);
+    dpar[1] = q1*(2*py1*par[3] + par[4]*X) + q2*(2*py2*par[8] + par[9]*X);
+    dpar[2] = -2*q1*px1*X;
+    dpar[3] = -2*q1*py1*Y;
+    dpar[4] = -q1*X*Y;
+    dpar[5] = +r1;
+    dpar[6] = +1;
+    dpar[7] = -2*q2*px2*X*50;
+    dpar[8] = -2*q2*py2*Y*50;
+    dpar[9] = -q2*X*Y*50;
+    dpar[10] = +r2*50;
+    dpar[11] = -q2*log(z2)*t*50;
+  }
+  return (f);
+}
+
+int serbulgeCL () {
+  set_variable ("Xg",   par[0]);
+  set_variable ("Yg",   par[1]);
+  set_variable ("SXg",  2.35 * sqrt(2.0) / par[2]);
+  set_variable ("SYg",  2.35 * sqrt(2.0) / par[3]);
+  set_variable ("SXYg", par[4]);
+  set_variable ("Zb",   par[5]);
+  set_variable ("Sg",   par[6]);
+
+  set_variable ("SXf",  2.35 * sqrt(2.0) / par[7]);
+  set_variable ("SYf",  2.35 * sqrt(2.0) / par[8]);
+  set_variable ("SXYf", par[9]);
+  set_variable ("Zd",   par[10]);
+  set_variable ("Sr",   par[11]);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/imfit-sersic.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/imfit-sersic.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/imfit-sersic.c	(revision 11389)
@@ -0,0 +1,74 @@
+# include "imfit.h"
+
+float sersicTD (float, float, float *, int, float *);
+void  sersicCL ();
+
+void sersic_setup (char *name) {
+
+  if (strcmp(name, "sersic")) return;
+
+  fitfunc = sersicTD;
+  cleanup = sersicCL;
+  Npar = 8;
+  Nfpar = 0;
+
+  /* allocate free and fixed parameters */
+  ALLOCATE (par, float, MAX (Npar, 1));
+  bzero (par, Npar*sizeof(float));
+  ALLOCATE (fpar, float, MAX (Nfpar, 1));
+  bzero (fpar, Nfpar*sizeof(float));
+
+  par[0] = get_variable_default ("Xg", 0);
+  par[1] = get_variable_default ("Yg", 0);
+  par[2] = 2.35 * sqrt(2.0) / get_variable_default ("SXg", 2.0);
+  par[3] = 2.35 * sqrt(2.0) / get_variable_default ("SYg", 2.0);
+  par[4] = 0.0;
+  par[5] = get_variable_default ("Zpk", 10000);
+  par[6] = get_variable_default ("Sg", 0.0);
+  par[7] = get_variable_default ("Sr", 1.0);
+
+  sky = &par[6];
+}
+
+/* sersic galaxy model -- x, y, sx, sy, sxy, I, sky, n */
+/* exp (-b (r/r_e)^(1/n)) */
+float sersicTD (float x, float y, float *par, int Npar, float *dpar) {
+
+  float X, Y, px, py;
+  float z, r, t, q, f;
+
+  X = x - par[0];
+  Y = y - par[1];
+  
+  px = par[2]*X;
+  py = par[3]*Y;
+
+  z = 0.5*SQ(px) + 0.5*SQ(py) + par[4]*X*Y;
+  t = pow (z, par[7]);
+  r = exp (-t);
+  f = par[5]*r + par[6];
+  q = par[5]*r*par[7]*pow(z, par[7]-1);
+
+  if (dpar != NULL) {
+    dpar[0] = q*(2*px*par[2] + par[4]*Y);
+    dpar[1] = q*(2*py*par[3] + par[4]*X);
+    dpar[2] = -2*q*px*X;
+    dpar[3] = -2*q*py*Y;
+    dpar[4] = -q*X*Y;
+    dpar[5] = +r;
+    dpar[6] = +1;
+    dpar[7] = -q*log(z)*t;
+  }
+  return (f);
+}
+
+int sersicCL () {
+  set_variable ("Xg",   par[0]);
+  set_variable ("Yg",   par[1]);
+  set_variable ("SXg",  2.35 * sqrt(2.0) / par[2]);
+  set_variable ("SYg",  2.35 * sqrt(2.0) / par[3]);
+  set_variable ("SXYg", par[4]);
+  set_variable ("Zpk",  par[5]);
+  set_variable ("Sg",   par[6]);
+  set_variable ("Sr", par[7]);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/imfit-sgauss.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/imfit-sgauss.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/imfit-sgauss.c	(revision 11389)
@@ -0,0 +1,98 @@
+# include "imfit.h"
+# define FFACTOR 200
+# define FSCALE 1.2
+
+float sgaussTD (float, float, float *, int, float *);
+void  sgaussCL ();
+
+void sgauss_setup (char *name) {
+
+  if (strcmp(name, "sgauss")) return;
+
+  fitfunc = sgaussTD;
+  imfit_cleanup = sgaussCL;
+  Npar = 10;
+  Nfpar = 2;
+
+  /* allocate free and fixed parameters */
+  ALLOCATE (par, float, MAX (Npar, 1));
+  bzero (par, Npar*sizeof(float));
+  ALLOCATE (fpar, float, MAX (Nfpar, 1));
+  bzero (fpar, Nfpar*sizeof(float));
+
+  par[0] = get_variable_default ("Xg", 0);
+  par[1] = get_variable_default ("Yg", 0);
+  par[2] = 2.35 / get_variable_default ("SXg", 2.0);
+  par[3] = 2.35 / get_variable_default ("SYg", 2.0);
+  par[4] = get_variable_default ("SXYg", 0);
+  par[5] = get_variable_default ("Zpk", 10000);
+  par[6] = get_variable_default ("Sg", 0.0);
+  par[7] = 2.35 / get_variable_default ("SXf", 15.0);
+  par[8] = 2.35 / get_variable_default ("SYf", 15.0);
+  par[9] = get_variable_default ("SXYf", 0.0);
+
+  fpar[0] = get_variable_default ("Npow", 2.25);
+  fpar[1] = get_variable_default ("Npin", 1.00); // drop this?
+
+  sky = &par[6];
+}
+
+void sgaussCL () {
+  set_variable ("Xg",   par[0]);
+  set_variable ("Yg",   par[1]);
+  set_variable ("SXg",  2.35 / par[2]);
+  set_variable ("SYg",  2.35 / par[3]);
+  set_variable ("SXYg", par[4]);
+  set_variable ("Zpk",  par[5]);
+  set_variable ("Sg",   par[6]);
+  set_variable ("SXf", 2.35 / par[7]);
+  set_variable ("SYf", 2.35 / par[8]);
+  set_variable ("SXYf", par[9]);
+}
+
+/* two components: (1 + z_1 + z_2^N)^(-1) -- x, y, sx1, sy1, sxy1, I, sky, sx2, sy2, sxy2 */
+float sgaussTD (float x, float y, float *par, int Npar, float *dpar) {
+
+  float X, Y, px1, py1, px2, py2;
+  float z1, z2, r, q1, q2, f, f1, f2;
+
+  X = x - par[0];
+  Y = y - par[1];
+  
+  px1 = par[2]*X;
+  py1 = par[3]*Y;
+  px2 = par[7]*X;
+  py2 = par[8]*Y;
+
+  z1 = 0.5*SQ(px1) + 0.5*SQ(py1) + par[4]*X*Y;
+  z2 = 0.5*SQ(px2) + 0.5*SQ(py2) + par[9]*X*Y;
+
+  r = 1.0 / (1 + z1 + pow(z2,fpar[0]));
+  f = par[5]*r + par[6];
+
+  q1 = par[5]*SQ(r);
+  q2 = par[5]*SQ(r)*fpar[0]*pow(z2,(fpar[0]-1));
+
+  if (dpar != NULL) {
+    dpar[0] = q1*(2*px1*par[2] + par[4]*Y) + q2*(2*px2*par[7] + par[9]*Y);
+    dpar[1] = q1*(2*py1*par[3] + par[4]*X) + q2*(2*py2*par[8] + par[9]*X);
+
+    /* these fudge factors impede the growth of par[2] beyond par[7] */
+    f1 = fabs(par[7]) / fabs(par[2]);
+    f2 = (f1 < FSCALE) ? 1 : FFACTOR*(f1 - FSCALE) + 1;
+    dpar[2] = -2*q1*px1*X*f2;
+
+    f1 = fabs(par[8]) / fabs(par[3]);
+    f2 = (f1 < FSCALE) ? 1 : FFACTOR*(f1 - FSCALE) + 1;
+    dpar[3] = -2*q1*py1*Y*f2;
+
+    dpar[4] = -q1*X*Y;
+    dpar[5] = +r;
+    dpar[6] = +1;
+    dpar[7] = -2*q2*px2*X;
+    dpar[8] = -2*q2*py2*Y;
+    dpar[9] = -q2*X*Y;
+  }
+  return (f);
+}
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/imfit-test.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/imfit-test.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/imfit-test.c	(revision 11389)
@@ -0,0 +1,314 @@
+  if (ShapeVariation) {
+    /* find dChi/dSx and dChi/dSy given by increasing shape terms by 5% */
+    float tp1, tp2, chix, chiy;
+    chix = chiy = 0;
+    if (fitfunc == sgaussTD) {
+      tp1 = par[2];
+      tp2 = par[7];
+      par[2] = par[2]*1.05;
+      par[7] = par[7]*1.05;
+      chix = mrq2dchi (x, y, z, dz, Npts, par, Npar, fitfunc) - chisq;
+      par[2] = tp1;
+      par[7] = tp2;
+
+      tp1 = par[3];
+      tp2 = par[8];
+      par[3] = par[3]*1.05;
+      par[8] = par[8]*1.05;
+      chiy = mrq2dchi (x, y, z, dz, Npts, par, Npar, fitfunc) - chisq;
+      par[3] = tp1;
+      par[8] = tp2;
+    }
+    if (fitfunc == pgaussTD) {
+      tp1 = par[2];
+      par[2] = par[2]*1.05;
+      chix = mrq2dchi (x, y, z, dz, Npts, par, Npar, fitfunc) - chisq;
+      par[2] = tp1;
+
+      tp1 = par[3];
+      par[3] = par[3]*1.05;
+      chiy = mrq2dchi (x, y, z, dz, Npts, par, Npar, fitfunc) - chisq;
+      par[3] = tp1;
+    }
+    if (fitfunc == SgaussTD) {
+      tp1 = par[0];
+      tp2 = par[3];
+      par[0] = par[0]*1.05;
+      par[3] = par[3]*1.05;
+      chix = mrq2dchi (x, y, z, dz, Npts, par, Npar, fitfunc) - chisq;
+      par[0] = tp1;
+      par[3] = tp2;
+
+      tp1 = par[1];
+      tp2 = par[4];
+      par[1] = par[1]*1.05;
+      par[4] = par[4]*1.05;
+      chiy = mrq2dchi (x, y, z, dz, Npts, par, Npar, fitfunc) - chisq;
+      par[1] = tp1;
+      par[4] = tp2;
+    }
+    if (fitfunc == PgaussTD) {
+      tp1 = par[0];
+      par[0] = par[0]*1.05;
+      chix = mrq2dchi (x, y, z, dz, Npts, par, Npar, fitfunc) - chisq;
+      par[0] = tp1;
+
+      tp1 = par[1];
+      par[1] = par[1]*1.05;
+      chiy = mrq2dchi (x, y, z, dz, Npts, par, Npar, fitfunc) - chisq;
+      par[1] = tp1;
+    }
+    set_variable ("dChiX", chix/chisq);
+    set_variable ("dChiY", chiy/chisq);
+  }
+
+# if (0)
+/* pars: x, y, sx, sy, sxy, I, sky */
+float fgalaxyTD (float x, float y, float *par, int Npar, float *dpar) {
+
+  float X, Y, Z, E, F, q, R, f, p2, p3;
+
+  X = x - par[0];
+  Y = y - par[1];
+  
+  p2 = X / par[2];
+  p3 = Y / par[3];
+
+  Z = sqrt (0.5*p2*X + X*Y*par[4] + 0.5*p3*Y);                 /* R */
+  E = 1.0 / (1 + Z);   
+
+  q = par[5] * E;
+  R = q*E;
+  F = 0.5 / Z;
+  
+  f = q + par[6];
+
+  dpar[0] = F*R*(p2 + par[4]*Y);
+  dpar[1] = F*R*(p3 + par[4]*X);
+  dpar[2] = F*0.5*R*p2*p2;
+  dpar[3] = F*0.5*R*p3*p3;
+  dpar[4] = -R*X*Y*F;
+    
+  dpar[5] = E;
+  dpar[6] = 1;
+  return (f);
+}
+
+/* pars: x, y, sx, sy, sxy, I, sky */
+float fbarTD (float x, float y, float *par, int Npar, float *dpar) {
+
+  float X, Y, Z, E, F, q, R, f, p2, p3;
+
+  X = x - par[0];
+  Y = y - par[1];
+  
+  p2 = X / par[2];
+  p3 = Y / par[3];
+
+  Z = 0.5*p2*X + X*Y*par[4] + 0.5*p3*Y;                 /* R */
+  E = 1.0 / (1 + Z*Z*Z);   
+
+  q = par[5] * E;
+  F = 3*Z*Z;
+  R = q*E*F;
+  
+  f = q + par[6];
+
+  dpar[0] = R*(p2 + par[4]*Y);
+  dpar[1] = R*(p3 + par[4]*X);
+  dpar[2] = 0.5*R*p2*p2;
+  dpar[3] = 0.5*R*p3*p3;
+  dpar[4] = -R*X*Y;
+    
+  dpar[5] = E;
+  dpar[6] = 1;
+  return (f);
+}
+
+/* convert from x,y to major,minor */
+void fix_ellipsegauss_pars (float *par, int Npar) {
+
+  float p2, p4, angle, t1, t2, tmp, area;
+
+  /* par[0], par[1] = Xo, Yo - stay the same */
+
+  p2 = 1/par[2];
+  p4 = 1/par[3];
+
+  angle = 0.5 * atan2 (-2*par[4], p4 - p2); 
+
+  tmp = sqrt (SQ(p2 - p4) + 4*SQ(par[4]));
+  t1 = (p2 + p4 + tmp) / 2;
+  t2 = t1 - tmp;
+
+  par[2] = 2.35482*sqrt(1/t2);
+  par[3] = 2.35482*sqrt(1/t1);
+  par[4] = DEG_RAD * angle;
+
+  area = 2*M_PI/sqrt(t1*t2);
+
+  par[5] *= area;
+
+}
+# endif
+
+/***  options for later
+
+  Subtract = FALSE;
+  if ((N = get_argument (argc, argv, "-sub"))) {
+    remove_argument (N, &argc, argv);
+    Subtract  = TRUE;
+  }
+
+  DFact = 1;
+  if ((N = get_argument (argc, argv, "-D"))) {
+    remove_argument (N, &argc, argv);
+    DFact  = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  fitfunc = fgaussTD;
+  if ((N = get_argument (argc, argv, "-gal"))) {
+    remove_argument (N, &argc, argv);
+    fitfunc = fgalaxyTD; 
+  }
+  if ((N = get_argument (argc, argv, "-bar"))) {
+    remove_argument (N, &argc, argv);
+    fitfunc = fbarTD; 
+  }
+
+
+  f1 = 1;
+  if ((c = get_variable ("BETA1")) != (char *) NULL) f1 = atof (c);
+
+  f2 = 1;
+  if ((c = get_variable ("BETA2")) != (char *) NULL) f2 = atof (c);
+
+  if (Subtract) {
+    tmpsky = par[6];
+    par[6] = 0;
+    for (N = j = 0; j < ny; j++) {
+      V = (float *)(buf[0].matrix.buffer) + (j+sy)*buf[0].matrix.Naxis[0] + sx; 
+      for (i = 0; i < nx; i++, V++, N++) {
+	dx = i + sx;
+	dy = j + sy;
+	*V -= fitfunc (dx, dy, par, Npar, (float *) NULL);
+      }
+    }
+    par[6] = tmpsky;
+  }
+
+***/
+
+# if (0)
+
+/* these two tests were not very succcessful.  the first did not model the shape well because 
+   it could not match the change in roundness with radius.  the second did not work because the 
+   parameters were degenerate (amplitude and slope of second component) */
+
+/* test: fixed, non-integer higher-order term -- x, y, sx, sy, sxy, I, sky, f1, f2 */
+float qgaussTD (float x, float y, float *par, int Npar, float *dpar) {
+
+  float X, Y, px, py;
+  float z, r, q, f, k;
+
+  X = x - par[0];
+  Y = y - par[1];
+  
+  px = par[2]*X;
+  py = par[3]*Y;
+
+  z = 0.5*SQ(px) + 0.5*SQ(py) + par[4]*X*Y;
+  k = pow(z,1.75*par[8]);
+  r = 1.0 / (1 + z + par[7]*k); /* ~ exp (-Z) */
+  q = par[5]*r*r*(1 + 1.75*par[7]*par[8]*pow(z,1.75*par[8]-1));
+  /* note difference from gaussian: q = par[5]*r */
+  f = par[5]*r + par[6];
+
+  dpar[0] = q*(2*px*par[2] + par[4]*Y);
+  dpar[1] = q*(2*py*par[3] + par[4]*X);
+  dpar[2] = -2*q*px*X;
+  dpar[3] = -2*q*py*Y;
+  dpar[4] = -q*X*Y;
+  dpar[5] = +r;
+  dpar[6] = +1;
+  dpar[7] = -10*par[5]*r*r*k;
+  dpar[8] = -10*par[5]*r*r*par[7]*k*1.75*log(z);
+
+  return (f);
+}
+
+/* test: two component model: inner pseudo gaussian with outer z^1.75 x, y, sx, sy, sxy, I, sky */
+float rgaussTD (float x, float y, float *par, int Npar, float *dpar) {
+
+  float X, Y, px1, py1, px2, py2;
+  float z1, z2, r1, r2, q1, q2, f;
+
+  X = x - par[0];
+  Y = y - par[1];
+  
+  px1 = par[2]*X;
+  py1 = par[3]*Y;
+  px2 = par[8]*X;
+  py2 = par[9]*Y;
+
+  z1 = 0.5*SQ(px1) + 0.5*SQ(py1) + par[4]*X*Y;
+  z2 = 0.5*SQ(px2) + 0.5*SQ(py2) + par[10]*X*Y;
+
+  r1 = 1.0 / (1 + z1 + 0.5*SQ(z1)*(1 + z1/3)); /* ~ exp (-Z) */
+  r2 = 1.0 / (1 + pow(z2,1.75));
+
+  f = par[5]*r1 + par[6] + par[7]*r2;
+
+  q1 = par[5]*SQ(r1)*(1 + z1 + 0.5*SQ(z1));
+  q2 = par[7]*SQ(r2)*(1.75*pow(z2,0.75));
+
+  dpar[	0] = q1*(2*px1*par[2] + par[4]*Y) + q2*(2*px2*par[8] + par[10]*Y);
+  dpar[	1] = q1*(2*py1*par[3] + par[4]*X) + q2*(2*py2*par[9] + par[10]*X);
+  dpar[	2] = -2*q1*px1*X;
+  dpar[	3] = -2*q1*py1*Y;
+  dpar[	4] = -q1*X*Y;
+  dpar[	5] = +r1;
+  dpar[	6] = +1;
+  dpar[	7] = +r2*2;
+  dpar[	8] = -2*q2*px2*X*2;
+  dpar[	9] = -2*q2*py2*Y*2;
+  dpar[10] = -q2*X*Y;
+
+  return (f);
+}
+
+# endif
+
+  /* forcing values to have a rational range
+  ALLOCATE (parmin, float, Npar);
+  ALLOCATE (parmax, float, Npar);
+  bzero (parmin, Npar*sizeof(float));
+  bzero (parmax, Npar*sizeof(float));
+  parmin[0] = parmin[1] = 0;
+  parmax[0] = buf[0].matrix.Naxis[0];
+  parmax[1] = buf[0].matrix.Naxis[1];
+
+  parmin[2] = parmin[3] = 0.01;
+  parmax[2] = parmax[3] = 100.0;
+  parmin[4] = -1000;
+  parmax[4] = -1000;
+  
+  parmin[5] = 1;
+  parmax[5] = 1e5;
+
+  parmin[6] = 0.0;
+  parmax[6] = 1e5;
+
+  if (Npar == 9) {
+    parmin[7] = parmin[8] = 0.01;
+    parmax[7] = parmax[8] = 10.0;
+  }
+  if (Npar == 10) {
+    parmin[7] = parmin[8] = 0.01;
+    parmax[7] = parmax[8] = 10.0;
+    parmin[9] = -1000;
+    parmax[9] = -1000;
+  }
+  */
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/imfit-tgauss.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/imfit-tgauss.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/imfit-tgauss.c	(revision 11389)
@@ -0,0 +1,81 @@
+# include "imfit.h"
+
+float tgaussTD (float, float, float *, int, float *);
+void  tgaussCL ();
+
+void tgauss_setup (char *name) {
+
+  if (strcmp(name, "tgauss")) return;
+
+  fitfunc = tgaussTD;
+  cleanup = tgaussCL;
+  Npar = 10;
+  Nfpar = 2;
+
+  par[0] = get_variable_default ("Xg", 0);
+  par[1] = get_variable_default ("Yg", 0);
+  par[2] = 2.35 * sqrt(2.0) / get_variable_default ("SXg", 2.0);
+  par[3] = 2.35 * sqrt(2.0) / get_variable_default ("SYg", 2.0);
+  par[4] = 0.0;
+  par[5] = get_variable_default ("Zpk", 10000);
+  par[6] = get_variable_default ("Sg", 0.0);
+  par[7] = 2.35 * sqrt(2.0) / get_variable_default ("SXf", 15.0);
+  par[8] = 2.35 * sqrt(2.0) / get_variable_default ("SYf", 15.0);
+  par[9] = get_variable_default ("SXYf", 0.0);
+
+  fpar[0] = get_variable_default ("Npow", 2.25);
+  fpar[1] = get_variable_default ("Npin", 1.00); // drop this?
+
+  sky = &par[6];
+}
+
+/* two components: (1 + z_1^M + z_2^N)^(-1) -- x, y, sx1, sy1, sxy1, I, sky, sx2, sy2, sxy2 */
+float tgaussTD (float x, float y, float *par, int Npar, float *dpar) {
+
+  float X, Y, px1, py1, px2, py2;
+  float z1, z2, r, q1, q2, f;
+
+  X = x - par[0];
+  Y = y - par[1];
+  
+  px1 = par[2]*X;
+  py1 = par[3]*Y;
+  px2 = par[7]*X;
+  py2 = par[8]*Y;
+
+  z1 = 0.5*SQ(px1) + 0.5*SQ(py1) + par[4]*X*Y;
+  z2 = 0.5*SQ(px2) + 0.5*SQ(py2) + par[9]*X*Y;
+
+  r = 1.0 / (1 + pow(z1,fpar[1]) + pow(z2,fpar[0]));
+  f = par[5]*r + par[6];
+
+  q1 = par[5]*SQ(r)*fpar[1]*pow(z1,(fpar[1]-1));
+  q2 = par[5]*SQ(r)*fpar[0]*pow(z2,(fpar[0]-1));
+
+  if (dpar != NULL) {
+    dpar[0] = q1*(2*px1*par[2] + par[4]*Y) + q2*(2*px2*par[7] + par[9]*Y);
+    dpar[1] = q1*(2*py1*par[3] + par[4]*X) + q2*(2*py2*par[8] + par[9]*X);
+    dpar[2] = -2*q1*px1*X*2;
+    dpar[3] = -2*q1*py1*Y*2;
+    dpar[4] = -q1*X*Y;
+    dpar[5] = +r;
+    dpar[6] = +1;
+    dpar[7] = -2*q2*px2*X;
+    dpar[8] = -2*q2*py2*Y;
+    dpar[9] = -q2*X*Y;
+  }
+  return (f);
+}
+
+int tgaussCL () {
+  set_variable ("Xg",   par[0]);
+  set_variable ("Yg",   par[1]);
+  set_variable ("SXg",  2.35 * sqrt(2.0) / par[2]);
+  set_variable ("SYg",  2.35 * sqrt(2.0) / par[3]);
+  set_variable ("SXYg", par[4]);
+  set_variable ("Zpk",  par[5]);
+  set_variable ("Sg",   par[6]);
+  set_variable ("SXf",  2.35 * sqrt(2.0) / par[7]);
+  set_variable ("SYf",  2.35 * sqrt(2.0) / par[8]);
+  set_variable ("SXYf", par[9]);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/imfit-vgauss.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/imfit-vgauss.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/imfit-vgauss.c	(revision 11389)
@@ -0,0 +1,70 @@
+# include "imfit.h"
+
+float vgaussTD (float, float, float *, int, float *);
+void  vgaussCL ();
+
+void  vgauss_setup (char *name) {
+
+  if (strcmp(name, "vgauss")) return;
+
+  fitfunc = vgaussTD;
+  cleanup = vgaussCL;
+  Npar = 9;
+  Nfpar = 0;
+
+  par[0] = get_variable_default ("Xg", 0);
+  par[1] = get_variable_default ("Yg", 0);
+  par[2] = 2.35 * sqrt(2.0) / get_variable_default ("SXg", 2.0);
+  par[3] = 2.35 * sqrt(2.0) / get_variable_default ("SYg", 2.0);
+  par[4] = 0.0;
+  par[5] = get_variable_default ("Zpk", 10000);
+  par[6] = get_variable_default ("Sg", 0.0);
+  par[7] = 1;
+  par[8] = 1;
+  sky = &par[6];
+}
+
+/* pseudo 2D gaussian with floating 2nd and 3rd order terms -- x, y, sx, sy, sxy, I, sky, f1, f2 */
+float vgaussTD (float x, float y, float *par, int Npar, float *dpar) {
+
+  float X, Y, px, py;
+  float z, r, q, f, k;
+
+  X = x - par[0];
+  Y = y - par[1];
+  
+  px = par[2]*X;
+  py = par[3]*Y;
+
+  z = 0.5*SQ(px) + 0.5*SQ(py) + par[4]*X*Y;
+  k = 0.5*z*z*(1 + par[8]*z/3);
+  r = 1.0 / (1 + z + par[7]*k); /* ~ exp (-Z) */
+  f = par[5]*r + par[6];
+  q = par[5]*r*r*(1 + par[7]*z*(1 + par[8]*z/2));
+  /* note difference from gaussian: q = par[5]*r */
+
+  if (dpar != NULL) {
+    dpar[0] = q*(2*px*par[2] + par[4]*Y);
+    dpar[1] = q*(2*py*par[3] + par[4]*X);
+    dpar[2] = -2*q*px*X;
+    dpar[3] = -2*q*py*Y;
+    dpar[4] = -q*X*Y;
+    dpar[5] = +r;
+    dpar[6] = +1;
+    dpar[7] = -100*par[5]*r*r*k;
+    dpar[8] = -100*par[5]*r*r*par[7]*(z*z*z)/6;
+  }
+  return (f);
+}
+
+int vgaussCL () {
+  set_variable ("Xg",   par[0]);
+  set_variable ("Yg",   par[1]);
+  set_variable ("SXg",  2.35 * sqrt(2.0) / par[2]);
+  set_variable ("SYg",  2.35 * sqrt(2.0) / par[3]);
+  set_variable ("SXYg", par[4]);
+  set_variable ("Zpk",  par[5]);
+  set_variable ("Sg",   par[6]);
+  set_variable ("SXf", par[7]);
+  set_variable ("SYf", par[8]);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/imfit.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/imfit.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/imfit.c	(revision 11389)
@@ -0,0 +1,185 @@
+# include "imfit.h"
+
+int imfit (int argc, char **argv) {
+
+  int i, j, N, Npts, Save, VERBOSE, ShapeVariation;
+  int sx, sy, nx, ny, Nx, Ny;
+  float chisq, ochisq, dchisq, Gain, RDnoise, SatThreshold;
+  float *x, *y, *z, *dz, *V;
+  Buffer *buf;
+
+  Save = FALSE;
+  if ((N = get_argument (argc, argv, "-save"))) {
+    remove_argument (N, &argc, argv);
+    Save = TRUE;
+  }
+
+  ShapeVariation = FALSE;
+  if ((N = get_argument (argc, argv, "-shapes"))) {
+    remove_argument (N, &argc, argv);
+    ShapeVariation = TRUE;
+  }
+
+  SatThreshold = 0xffff;
+  if ((N = get_argument (argc, argv, "-sat"))) {
+    remove_argument (N, &argc, argv);
+    SatThreshold = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  /* Gain in e/DN */
+  Gain = 1.0;
+  if ((N = get_argument (argc, argv, "-gain"))) {
+    remove_argument (N, &argc, argv);
+    Gain = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  /* RD noise in DN */
+  RDnoise = 0.0;
+  if ((N = get_argument (argc, argv, "-rdnoise"))) {
+    remove_argument (N, &argc, argv);
+    RDnoise = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  VERBOSE = FALSE;
+  if ((N = get_argument (argc, argv, "-v"))) {
+    remove_argument (N, &argc, argv);
+    VERBOSE = TRUE;
+  }
+
+  /* set fitting function */
+  fgauss_setup ("fgauss");
+  if ((N = get_argument (argc, argv, "-func"))) {
+    fitfunc = NULL;
+    remove_argument (N, &argc, argv);
+    fgauss_setup (argv[N]);
+    pgauss_setup (argv[N]);
+    Pgauss_setup (argv[N]);
+    sgauss_setup (argv[N]);
+    Sgauss_setup (argv[N]);
+    qgauss_setup (argv[N]);
+    Qgauss_setup (argv[N]);
+    qfgauss_setup (argv[N]);
+    qrgauss_setup (argv[N]);
+    if (fitfunc == NULL) {
+      gprint (GP_ERR, "unknown function %s\n", argv[N]);
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 6) {
+    gprint (GP_ERR, "USAGE: imfit <buffer> sx sy nx ny\n");
+    return (FALSE);
+  }
+
+  /* non-optional arguments */
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  sx = atof (argv[2]);
+  sy = atof (argv[3]);
+  nx = atof (argv[4]);
+  ny = atof (argv[5]);
+  Nx = buf[0].matrix.Naxis[0];
+  Ny = buf[0].matrix.Naxis[1];
+
+  /* check if region is valid */
+  if (sx + 0.5*nx < 0) goto range;
+  if (sy + 0.5*ny < 0) goto range;
+  if (sx + 0.5*nx >= Nx) goto range;
+  if (sy + 0.5*ny >= Ny) goto range;
+
+  /* convert array z[x,y] to x[i], y[i], z[i] */
+  N = 0;
+  Npts = nx*ny;
+  ALLOCATE (x,  float, 2*Npts);
+  ALLOCATE (y,  float, 2*Npts);
+  ALLOCATE (z,  float, 2*Npts);
+  ALLOCATE (dz, float, 2*Npts);
+  for (j = 0; j < ny; j++) {
+    if (j + sy < 0) continue;
+    if (j + sy >= Ny) continue;
+    V = (float *)(buf[0].matrix.buffer) + (j+sy)*buf[0].matrix.Naxis[0] + sx; 
+    for (i = 0; i < nx; i++) {
+      if (i + sx < 0) continue;
+      if (i + sx >= Nx) continue;
+      if (*V > SatThreshold) goto next;
+      dz[N] = (SQ(RDnoise) + *V/Gain);
+      if (dz[N] <= 0) goto next;
+      dz[N] = 1.0 / dz[N];
+      x[N] = i + sx;
+      y[N] = j + sy;
+      z[N] = *V;
+      N++;
+    next:
+      V++;
+    }
+  }
+  Npts = N;
+
+  /* run fit routine */
+  ochisq = mrq2dinit (x, y, z, dz, Npts, par, Npar, fitfunc, VERBOSE);
+  dchisq = ochisq;
+  chisq  = ochisq;
+  for (i = 0; (i < 25) && ((dchisq <= 0.0) || (dchisq > 0.01*(Npts - Npar))); i++) {
+    chisq = mrq2dmin (x, y, z, dz, Npts, par, Npar, fitfunc, VERBOSE);
+    dchisq = ochisq - chisq;
+    ochisq = chisq;
+  }  
+  set_int_variable ("Niter",  i);
+
+  /** create output image (keep in sky) **/
+  if (Save) {
+    Buffer *out;
+    float *Vi, *Vo, vr, vf;
+
+    if ((out = SelectBuffer ("out",   ANYBUFFER, TRUE)) == NULL) return (FALSE);
+    free (out[0].header.buffer);
+    free (out[0].matrix.buffer);
+
+    strcpy (out[0].file, "(empty)");
+    CreateBuffer (out, 2*nx, 2*ny, -32, 0.0, 1.0);
+
+    /* four panels: 1) raw image. 2) fit  3) raw - fit   4) ?? */
+    Vi = (float *)buf[0].matrix.buffer;
+    Vo = (float *)out[0].matrix.buffer;
+    for (j = 0; j < ny; j++) {
+      for (i = 0; i < nx; i++) {
+	vf = fitfunc ((float)(i+sx), (float)(j+sy), par, Npar, NULL);
+	vr = Vi[(i+sx)+(j+sy)*Nx];
+	Vo[(i   )+(j   )*2*nx] = vr;
+	Vo[(i+nx)+(j   )*2*nx] = vf;
+	Vo[(i   )+(j+ny)*2*nx] = vr - vf + *sky;
+	Vo[(i+nx)+(j+ny)*2*nx] = fabs(vr-vf) + *sky;
+      }
+    }
+  }
+
+  /* save parameters to opihi variables */
+  imfit_cleanup ();
+
+  set_variable ("ChiSq", chisq/(Npts - Npar));
+
+  if (VERBOSE) {
+    for (i = 0; i < Npar; i++) {
+      gprint (GP_ERR, "%g ", par[i]);
+    }
+    gprint (GP_ERR, "\n");
+  }
+
+  free (x);
+  free (y);
+  free (z);
+  free (dz);
+  free (par);
+  free (fpar);
+
+  mrq2dfree (Npar);
+  return (TRUE);
+
+range:
+  gprint (GP_ERR, "region out of range\n");
+  return (FALSE);
+}
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/imsub.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/imsub.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/imsub.c	(revision 11389)
@@ -0,0 +1,79 @@
+# include "imfit.h"
+
+int imsub (int argc, char **argv) {
+
+  int i, j, N, VERBOSE;
+  int sx, sy, nx, ny, Nx, Ny;
+  float value;
+  float *V;
+  Buffer *buf;
+
+  VERBOSE = FALSE;
+  if ((N = get_argument (argc, argv, "-v"))) {
+    remove_argument (N, &argc, argv);
+    VERBOSE = TRUE;
+  }
+
+  /* set fitting function */
+  fgauss_setup ("fgauss");
+  if ((N = get_argument (argc, argv, "-func"))) {
+    fitfunc = NULL;
+    remove_argument (N, &argc, argv);
+    fgauss_setup (argv[N]);
+    pgauss_setup (argv[N]);
+    Pgauss_setup (argv[N]);
+    sgauss_setup (argv[N]);
+    Sgauss_setup (argv[N]);
+    qgauss_setup (argv[N]);
+    Qgauss_setup (argv[N]);
+    qfgauss_setup (argv[N]);
+    qrgauss_setup (argv[N]);
+    if (fitfunc == NULL) {
+      gprint (GP_ERR, "unknown function %s\n", argv[N]);
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 6) {
+    gprint (GP_ERR, "USAGE: imfit <buffer> sx sy nx ny\n");
+    return (FALSE);
+  }
+
+  /* non-optional arguments */
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  sx = atof (argv[2]);
+  sy = atof (argv[3]);
+  nx = atof (argv[4]);
+  ny = atof (argv[5]);
+  Nx = buf[0].matrix.Naxis[0];
+  Ny = buf[0].matrix.Naxis[1];
+
+  /* check if region is valid */
+  if (sx >= Nx) goto range;
+  if (sy >= Ny) goto range;
+  if (sx + nx < 0) goto range;
+  if (sy + ny < 0) goto range;
+
+  /* subtract model fit, but not local sky */
+  for (j = 0; j < ny; j++) {
+    if (j + sy < 0) continue;
+    if (j + sy >= Ny) continue;
+    V = (float *)(buf[0].matrix.buffer) + (j+sy)*buf[0].matrix.Naxis[0] + sx; 
+    for (i = 0; i < nx; i++, V++) {
+      if (i + sx < 0) continue;
+      if (i + sx >= Nx) continue;
+      value = fitfunc ((float)(i+sx), (float)(j+sy), par, Npar, NULL);
+      *V -= value;
+    }
+  }
+
+  free (par);
+  free (fpar);
+  return (TRUE);
+
+range:
+  gprint (GP_ERR, "region out of range\n");
+  return (FALSE);
+}
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/init.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/init.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/init.c	(revision 11389)
@@ -0,0 +1,85 @@
+# include "astro.h"
+
+int biassub		    PROTO((int, char **));
+int cgrid		    PROTO((int, char **));
+int coords		    PROTO((int, char **));
+int cplot		    PROTO((int, char **));
+int csystem		    PROTO((int, char **));
+int ctimes		    PROTO((int, char **));
+int cval		    PROTO((int, char **));
+int czplot		    PROTO((int, char **));
+int drizzle		    PROTO((int, char **));
+int flux		    PROTO((int, char **));
+int fixwrap		    PROTO((int, char **));
+int gauss		    PROTO((int, char **));
+int gaussfit		    PROTO((int, char **));
+int getvel		    PROTO((int, char **));
+int getlst		    PROTO((int, char **));
+int imfit		    PROTO((int, char **));
+int imsub		    PROTO((int, char **));
+int medianmap		    PROTO((int, char **));
+int mkgauss		    PROTO((int, char **));
+int multifit		    PROTO((int, char **));
+int objload		    PROTO((int, char **));
+int outline		    PROTO((int, char **));
+int polar		    PROTO((int, char **));
+int precess		    PROTO((int, char **));
+int profile		    PROTO((int, char **));
+int region		    PROTO((int, char **));
+int rotcurve		    PROTO((int, char **));
+int scale		    PROTO((int, char **));
+int sexigesimal		    PROTO((int, char **));
+int spec		    PROTO((int, char **));
+int star		    PROTO((int, char **));
+int times		    PROTO((int, char **));
+int transform		    PROTO((int, char **));
+
+static Command cmds[] = {  
+  {"biassub", 	  biassub,      "subtract medianed overscan row or column"},
+  {"cgrid",       cgrid,        "plot sky coordinate grid"},
+  {"coords",  	  coords,       "load coordinates for buffer from file"},
+  {"cplot",       cplot,        "plot vectors in sky coordinates"},
+  {"csystem", 	  csystem,      "convert between coordinate systems"},
+  {"ctimes",  	  ctimes,       "convert between time formats"},
+  {"cval",        cval,         "cosmic ray flux?"},
+  {"czplot",  	  czplot,       "plot scaled vectors in sky coordinates"},
+  {"drizzle", 	  drizzle,      "transform image to image"},
+  {"flux",    	  flux,         "flux in a convex contour"},
+  {"fixwrap",  	  fixwrap,      "fix megacam over-wrapped pixels"},
+  {"gauss",   	  gauss,        "get statistics on a star, assuming gaussian profile"},
+  {"getvel",      getvel,       "rotcurve to velocities"},
+  {"getlst",      getlst,       "return LST given time and longitude"},
+  {"imfit",   	  imfit,        "fit function"},
+  {"imsub",   	  imsub,        "subtract function"},
+  {"medianmap",   medianmap,    "small median image"},
+  {"mkgauss",     mkgauss,      "generate a 2-D gaussian centered in image"},
+  {"multifit",    multifit,     "fit multi-order spectrum"},
+  {"objload",     objload,      "plot obj data on Ximage "},
+  {"outline",     outline,      "fit outline region"},
+  {"polar",       polar,        "convert polar image to cartesian"},
+  {"precess",     precess,      "precess coordinates"},
+  {"profile",     profile,      "radial profile at X, Y"},
+  {"region",      region,       "define sky region for plot"},
+  {"rotcurve",    rotcurve,     "convert CO images to polar coords"},
+  {"scale",       scale,        "get / set real bzero / bscale values"},
+  {"sexigesimal", sexigesimal,  "convert to/from sexigesimal/decimal"},
+  {"spec",    	  spec,         "extract a spectrum"},
+  {"star",    	  star,         "star stats at rough coords"},
+  {"transform",   transform,    "geometric transformation of image"},
+}; 
+
+/* not currently implemented 
+  {"gaussfit",    gaussfit,     "fit a gaussian to pixels in a region"},
+  {"testfit",     testfit, ""},
+  {"times", , ""},
+*/
+
+void InitAstro () {
+  
+  int i;
+
+  for (i = 0; i < sizeof (cmds) / sizeof (Command); i++) {
+    AddCommand (&cmds[i]);
+  }
+
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/medianmap.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/medianmap.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/medianmap.c	(revision 11389)
@@ -0,0 +1,112 @@
+# include "astro.h"
+
+int medianmap (int argc, char **argv) {
+  
+  float *temp, *tp;
+  int i, j, k, I0, I1, J0, J1, I, J, n, N;
+  int nx, ny, Nx, Ny, NX, NY, Ignore;
+  float Mv, Nv, Mv2, value, min, max, IgnoreValue;
+  float *In, *Out, *ip;
+  float fx, fy;
+  Buffer *in, *out;
+
+  IgnoreValue = 0;
+  Ignore = FALSE;
+  if ((N = get_argument (argc, argv, "-ignore"))) {
+    Ignore = TRUE;
+    remove_argument (N, &argc, argv);
+    IgnoreValue = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  min = 0.45;
+  max = 0.55;
+  if ((N = get_argument (argc, argv, "-range"))) {
+    remove_argument (N, &argc, argv);
+    min  = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+    max  = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 5) {
+    gprint (GP_ERR, "USAGE: medianmap (in) (out) Nx Ny [-range min max]\n");
+    gprint (GP_ERR, "       Nx, Ny specify dimensions of output image\n");
+    gprint (GP_ERR, "       min, max specify fractional range for sorted average\n");
+    return (FALSE);
+  }
+
+  if ((in  = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  if ((out = SelectBuffer (argv[2], ANYBUFFER, TRUE)) == NULL) return (FALSE);
+
+  Nx = atof (argv[3]);
+  Ny = atof (argv[4]);
+  NX = in[0].header.Naxis[0];
+  NY = in[0].header.Naxis[1];
+
+  /* duplicate the (in) buffer to the (out), with different size */
+  /* this should probably be a function in misc */
+  gfits_free_matrix (&out[0].matrix);
+  gfits_free_header (&out[0].header);
+  out[0].bitpix = in[0].bitpix;
+  out[0].unsign = in[0].unsign;
+  out[0].bscale = in[0].bscale;
+  out[0].bzero  = in[0].bzero;
+  gfits_copy_header (&in[0].header, &out[0].header);
+  gfits_modify (&out[0].header, "NAXIS1", "%d", 1, Nx);
+  gfits_modify (&out[0].header, "NAXIS2", "%d", 1, Ny);
+  out[0].header.Naxis[0] = Nx;
+  out[0].header.Naxis[1] = Ny;
+  gfits_create_matrix (&out[0].header, &out[0].matrix);
+
+  In = (float *) in[0].matrix.buffer;
+  Out = (float *) out[0].matrix.buffer;
+
+  fx = (float) Nx / NX;
+  fy = (float) Ny / NY;
+
+  nx = 1 + 1/fx;
+  ny = 1 + 1/fy;
+
+  ALLOCATE (temp, float, 2*nx*ny);
+
+  Nv = Mv = Mv2 = 0.0;
+
+  for (j = 0; j < Ny; j++) {
+    J0 = j / fy;
+    J1 = (j + 1) / fy;
+    for (i = 0; i < Nx; i++) {
+      
+      I0 = i / fx;
+      I1 = (i + 1) / fx;
+
+      n = 0;
+      tp = temp;
+      for (J = J0; J < J1; J++) {
+	ip = &In[J*NX + I0];
+	for (I = I0; I < I1; I++, tp++, ip++) {
+	  if (Ignore && (fabs (*ip - IgnoreValue) < 0.01)) continue;
+	  *tp = *ip;
+	  n++;
+	}
+      }
+
+      fsort (temp, n);
+
+      value = 0;
+      N = 0;
+      for (k = min*n; k < max*n; k++) {
+	value += temp[k];
+	N ++;
+      }
+      if (N == 0)
+	Out[j*Nx + i] = 0;
+      else 
+	Out[j*Nx + i] = value / N;
+    }
+  }
+
+  return (TRUE);
+
+}
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/mkgauss.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/mkgauss.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/mkgauss.c	(revision 11389)
@@ -0,0 +1,71 @@
+# include "astro.h"
+
+int mkgauss (int argc, char **argv) {
+  
+  int i, j, Nx, Ny, N;
+  float *in;
+  double Sig_x, Sig_y, Theta;
+  double root1, root2, R, A1, A2, A3;
+  double Sx, Sy, Sxy;
+  double x, y, r, f, Xo, Yo;
+  Buffer *buf;
+
+  Xo = Yo = 0;
+  if ((N = get_argument (argc, argv, "-c"))) {
+    remove_argument (N, &argc, argv);
+    Xo = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+    Yo = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  if ((argc < 3) || (argc > 5)) {
+    gprint (GP_ERR, "USAGE: mkgauss (buffer) (sigma) [[sy/sx] angle]\n");
+    return (FALSE);
+  }
+
+  /* select input / output buffers */
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  Nx = buf[0].header.Naxis[0];
+  Ny = buf[0].header.Naxis[1];
+  
+  /* gaussian parameters */
+  Sig_x = atof (argv[2]);
+  Sig_y = Sig_x;
+  Theta = 0.0;
+  if (argc > 3) {
+    Sig_y = Sig_x*atof (argv[3]);
+    if (argc == 5) {
+      Theta = atof (argv[4]);
+    }
+  }
+
+  /* given Sig_x, Sig_y, Theta, find Sx, Sy, Sxy */
+  root1 = SQ(1.0 / Sig_y);
+  root2 = SQ(1.0 / Sig_x);
+
+  R = 0.5 * (root1 - root2);
+  A1 = 0.25*(root1 + root2) - 0.5*R*cos(2*RAD_DEG*Theta);
+  A2 = 0.25*(root1 + root2) + 0.5*R*cos(2*RAD_DEG*Theta);
+  A3 = -R*sin(2*RAD_DEG*Theta);
+
+  Sx = 0.5/A1;
+  Sy = 0.5/A2;
+  Sxy = A3;
+
+  /* f = exp (-r), r = (x^2 / 2Sx) + (y^2 / 2Sy) + Sxy*x*y */
+
+  in = (float *) buf[0].matrix.buffer;
+  for (j = 0; j < Ny; j++) {
+    for (i = 0; i < Nx; i++, in++) {
+
+      x = i - Xo;
+      y = j - Yo;
+      r = 0.5*x*x/Sx + 0.5*y*y/Sy + x*y*Sxy;
+      f = exp (-r);
+      *in += f;
+    }
+  }
+
+  return (TRUE);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/multifit.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/multifit.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/multifit.c	(revision 11389)
@@ -0,0 +1,179 @@
+# include "astro.h"
+
+int multifit (int argc, char **argv) {
+  
+  char *p, name[64];
+  double **a, **b, v;
+  int i, j, I, J, n, valid;
+  Vector **Nc, **Nmb, **NMb, **Nwb, **Nmh, **Nml, **Nwo;
+  int *nterm;
+  int Ndim, Norder, Nx, Ny;
+
+  if (argc != 2) {
+    gprint (GP_ERR, "USAGE: multifit (Norder)\n");
+    return (FALSE);
+  }
+
+  Ndim = 0;
+  Norder = atoi (argv[1]);
+  ALLOCATE (nterm, int, Norder);
+  for (i = 0; i < Norder; i++) {
+    sprintf (name, "nterm:%d", i);
+    p = get_variable (name);
+    nterm[i] = atoi (p); 
+    Ndim += nterm[i];
+    free (p);
+  }
+
+  ALLOCATE (a, double *, Ndim);
+  ALLOCATE (b, double *, Ndim);
+  for (i = 0; i < Ndim; i++) {
+    ALLOCATE (a[i], double, Ndim);
+    ALLOCATE (b[i], double, 1);
+    bzero (a[i], Ndim*sizeof(double));
+    bzero (b[i], sizeof(double));
+  }
+ 
+  ALLOCATE (Nc,  Vector *, Norder);
+  ALLOCATE (NMb, Vector *, Norder);
+  ALLOCATE (Nmb, Vector *, Norder);
+  ALLOCATE (Nwb, Vector *, Norder);
+  ALLOCATE (Nmh, Vector *, Norder - 1);
+  ALLOCATE (Nml, Vector *, Norder - 1);
+  ALLOCATE (Nwo, Vector *, Norder - 1);
+  
+  for (i = 0; i < Norder; i++) {
+    sprintf (name, "c%d", i);
+    if ((Nc[i]  = SelectVector (name, ANYVECTOR, TRUE)) == NULL) goto escape;
+    sprintf (name, "Mb%d", i);
+    if ((NMb[i] = SelectVector (name, OLDVECTOR, TRUE)) == NULL) goto escape;
+    sprintf (name, "mb%d", i);
+    if ((Nmb[i] = SelectVector (name, OLDVECTOR, TRUE)) == NULL) goto escape;
+    sprintf (name, "wb%d", i);
+    if ((Nwb[i] = SelectVector (name, OLDVECTOR, TRUE)) == NULL) goto escape;
+  }
+  for (i = 0; i < Norder - 1; i++) {
+    sprintf (name, "ml%d", i);
+    if ((Nml[i] = SelectVector (name, OLDVECTOR, TRUE)) == NULL) goto escape;
+    sprintf (name, "mh%d", i);
+    if ((Nmh[i] = SelectVector (name, OLDVECTOR, TRUE)) == NULL) goto escape;
+    sprintf (name, "wo%d", i);
+    if ((Nwo[i] = SelectVector (name, OLDVECTOR, TRUE)) == NULL) goto escape;
+  }
+
+  Ny = 0;
+  for (i = 0; i < Norder; i++) {
+    for (j = 0; j < nterm[i]; j++, Ny++) {
+      Nx = 0;
+      valid = FALSE;
+      for (I = 0; I < Norder; I++) {
+	if (I == i - 1) { 
+	  for (J = 0; J < nterm[I]; J++) {
+	    v = 0;
+	    for (n = 0; n < Nwo[i-1][0].Nelements; n++) {
+	      v += -pow (Nwo[i-1][0].elements[n], (double)(j+J));
+	    }
+	    a[Ny][Nx] = v;
+	    Nx ++;
+	  }
+	  valid = TRUE;
+	}
+	if (I == i + 1) { 
+	  for (J = 0; J < nterm[I]; J++) {
+	    v = 0;
+	    for (n = 0; n < Nwo[i][0].Nelements; n++) {
+	      v += -pow (Nwo[i][0].elements[n], (double)(j+J));
+	    }
+	    a[Ny][Nx] = v;
+	    Nx ++;
+	  }
+	  valid = TRUE;
+	}
+	if (I == i) { 
+	  for (J = 0; J < nterm[I]; J++) {
+	    v = 0;
+	    for (n = 0; n < Nwb[i][0].Nelements; n++) {
+	      v += pow (Nwb[i][0].elements[n], (double)(j+J));
+	    }
+	    if (i > 0) {
+	      for (n = 0; n < Nwo[i-1][0].Nelements; n++) {
+		v += pow (Nwo[i-1][0].elements[n], (double)(j+J));
+	      }
+	    }
+	    if (i < Norder - 1) {
+	      for (n = 0; n < Nwo[i][0].Nelements; n++) {
+		v += pow (Nwo[i][0].elements[n], (double)(j+J));
+	      }
+	    }
+	    a[Ny][Nx] = v;
+	    Nx ++;
+	  }
+	  valid = TRUE;
+	}
+	if (!valid) {
+	  Nx += nterm[I];
+	}
+      }
+    }
+  }
+
+  Ny = 0;
+  for (i = 0; i < Norder; i++) {
+    for (j = 0; j < nterm[i]; j++, Ny++) {
+      v = 0;
+      for (n = 0; n < Nwb[i][0].Nelements; n++) {
+	v += NMb[i][0].elements[n]*pow (Nwb[i][0].elements[n], (double)j);
+	v -= Nmb[i][0].elements[n]*pow (Nwb[i][0].elements[n], (double)j);
+      }
+      if (i > 0) {
+	for (n = 0; n < Nwo[i-1][0].Nelements; n++) {
+	  v += Nmh[i-1][0].elements[n] * pow (Nwo[i-1][0].elements[n], (double)j);
+	  v -= Nml[i-1][0].elements[n] * pow (Nwo[i-1][0].elements[n], (double)j);
+	}
+      }
+      if (i < Norder - 1) {
+	for (n = 0; n < Nwo[i][0].Nelements; n++) {
+	  v += Nml[i][0].elements[n] * pow (Nwo[i][0].elements[n], (double)j);
+	  v -= Nmh[i][0].elements[n] * pow (Nwo[i][0].elements[n], (double)j);
+	}
+      }
+      b[Ny][0] = v;
+    }
+  }
+  dgaussj (a, Ndim, b, 1);
+
+  Ny = 0;
+  for (i = 0; i < Norder; i++) {
+    Nc[i][0].Nelements = nterm[i];
+    REALLOCATE (Nc[i][0].elements, float, nterm[i]);
+    for (j = 0; j < nterm[i]; j++, Ny++) {
+      Nc[i][0].elements[j] = b[Ny][0];
+    }
+  }
+
+  for (i = 0; i < Ndim; i++) {
+    free (a[i]);
+    free (b[i]);
+  }
+  free (a);
+  free (b);
+  free (nterm);
+  free (Nc);
+  free (NMb);
+  free (Nmb);
+  free (Nwb);
+  free (Nmh);
+  free (Nml);
+  free (Nwo);
+  
+  return (TRUE);
+  
+ escape: 
+  gprint (GP_ERR, "syntax error\n");
+  return (FALSE);
+  
+}
+
+
+
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/objload.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/objload.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/objload.c	(revision 11389)
@@ -0,0 +1,74 @@
+# include "dvoshell.h"
+# define CHAR_LINE 104
+# define NBLOCK 100
+
+int objload (int argc, char **argv) {
+  
+  int i, N, Objtype, type, Nline, status;
+  FILE *f;
+  char *buffer, *line;
+  int Ximage, Nimage, Noverlay, NOVERLAY;
+  KiiOverlay *overlay;
+  
+  Nimage = -1;
+  if ((N = get_argument (argc, argv, "-n"))) {
+    remove_argument (N, &argc, argv);
+    Nimage = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if (!GetImage (&Ximage, &Nimage)) return (FALSE);
+
+  Objtype = 0;
+  if ((N = get_argument (argc, argv, "-t"))) {
+    remove_argument (N, &argc, argv);
+    Objtype = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 3) {
+    gprint (GP_ERR, "USAGE: objload (overlay) <filename>\n");
+    return (FALSE);
+  }
+
+  f = fopen (argv[2], "r");
+  if (f == (FILE *) NULL) {
+    gprint (GP_ERR, "ERROR: can't find object file %s\n", argv[2]);
+    return (FALSE);
+  }
+
+  /* read average values from first line */
+  ALLOCATE (line, char, 129);
+  scan_line (f, line);
+
+  ALLOCATE (buffer, char, CHAR_LINE*NBLOCK);
+
+  Noverlay = 0;
+  NOVERLAY = 1000;
+  ALLOCATE (overlay, KiiOverlay, Noverlay);
+  
+  /* read in data from obj file */
+  while ((Nline = fread (buffer, CHAR_LINE, NBLOCK, f)) > 0) {
+    for (i = 0; i < Nline; i++) {
+      /* we are now using all entries on the *.obj line */
+      status = sscanf (&buffer[i*CHAR_LINE], "%d %f %f",  &type, &overlay[Noverlay].x, &overlay[Noverlay].y);
+      if (Objtype && (Objtype != type)) continue;
+      overlay[Noverlay].type = KII_OVERLAY_BOX;
+      overlay[Noverlay].dx = 5.0;
+      overlay[Noverlay].dy = 5.0;
+      Noverlay ++;
+      CHECK_REALLOCATE (overlay, KiiOverlay, NOVERLAY, Noverlay, 1000);
+    }
+  }
+  fclose (f);
+  free (buffer);
+
+  KiiLoadOverlay (Ximage, overlay, Noverlay, argv[1]);
+
+  free (overlay);
+  free (buffer);
+  free (line);
+
+  gprint (GP_ERR, "loaded %d objects\n", Noverlay);
+  return (TRUE);
+}
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/outline.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/outline.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/outline.c	(revision 11389)
@@ -0,0 +1,290 @@
+# include "astro.h"
+
+float par[5];
+float dpar[5];
+float Dpar[5];
+float outline_chi (float, float *, int, int, float *);
+
+int outline (int argc, char **argv) {
+  
+  int i, j, k, Npar, BigChange, ABigChange;
+  float Io, *in, ochisq, dchi, chisq, chisq_p, chisq_m, dp, tmp_par;
+  float curve, frac;
+  Buffer *buf;
+
+  if (argc != 9) {
+    gprint (GP_ERR, "USAGE: outline x y dx dy dxy Io (buffer) Npar\n");
+    return (FALSE);
+  }
+
+  if ((buf = SelectBuffer (argv[7], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+
+  par[0] = atof(argv[1]);
+  par[1] = atof(argv[2]);
+  par[2] = atof(argv[3]);
+  par[3] = atof(argv[4]);
+  par[4] = atof(argv[5]);
+  Io = atof(argv[6]);
+  Npar = atof (argv[8]);
+
+  dpar[0] = 10;
+  dpar[1] = 10;
+  dpar[2] = 10;
+  dpar[3] = 10;
+  dpar[4] = 10;
+
+  Dpar[0] = 10;
+  Dpar[1] = 10;
+  Dpar[2] = 10;
+  Dpar[3] = 10;
+  Dpar[4] = 10;
+
+  in = (float *) buf[0].matrix.buffer;
+
+  chisq = outline_chi (Io, in, buf[0].matrix.Naxis[0], buf[0].matrix.Naxis[1], &frac);
+  gprint (GP_ERR, "chisq (1): %f\n", chisq);
+  
+  for (j = 0; j < 15; j++) {
+
+    /*
+    if (!(j % 3)) {
+      chisq = outline_chi (Io, in, buf[0].matrix.Naxis[0], buf[0].matrix.Naxis[1], &frac);
+      for (k = 0; (k < 3) && (fabs (frac) > 0.3); k++) {
+	tmp1 = par[2];
+	tmp2 = par[3];
+	par[2] *= 1 + 0.1*frac;
+	par[3] *= 1 + 0.1*frac;
+	nchisq = outline_chi (Io, in, buf[0].matrix.Naxis[0], buf[0].matrix.Naxis[1], &frac);
+	if (nchisq > chisq) {
+	  par[2] = tmp1;
+	  par[3] = tmp2;
+	  k = 3;
+	} else {
+	  chisq = nchisq;
+	}
+	gprint (GP_ERR, "frac: %f  %f %f   %f\n", frac, par[2], par[3], chisq);
+      }
+    }
+    */
+    
+    ABigChange = FALSE;
+    ochisq = chisq;
+    for (i = 4; i >= 0; i--) {
+      /* find +chisq, -chisq for this par & adjust par as needed */
+
+      for (k = 0, BigChange = TRUE; (k < 3) && BigChange; k++) {
+	tmp_par = par[i];
+	par[i] = tmp_par + dpar[i];
+	chisq_p = outline_chi (Io, in, buf[0].matrix.Naxis[0], buf[0].matrix.Naxis[1], &frac);
+	par[i] = tmp_par - dpar[i];
+	chisq_m = outline_chi (Io, in, buf[0].matrix.Naxis[0], buf[0].matrix.Naxis[1], &frac);
+	
+	/* have we braketted a minimum? (curve < 0) */
+	curve = (chisq_p - chisq) * (chisq - chisq_m);
+	if (curve > 0) {
+	  dp = 2*dpar[i];
+	} else {
+	  dp = 0.5 * dpar[i] * (chisq_m - chisq_p) / (chisq_m + chisq_p - 2*chisq);
+	}      
+	if (chisq_m + chisq_p - 2*chisq == 0) dp = 0;
+	/* don't let extrapolation go too far */
+	if (fabs (dp) > 2*fabs(dpar[i])) { dp = SIGN(dp) * fabs (2*dpar[i]); }
+	
+	par[i] = tmp_par + dp;
+	chisq = outline_chi (Io, in, buf[0].matrix.Naxis[0], buf[0].matrix.Naxis[1], &frac);
+	
+	BigChange = FALSE;
+	if (chisq <= 1.001*ochisq) {
+	  /* got better */
+	  dchi = (ochisq - chisq) / ochisq; 
+	  if ((dchi > 0.03) || (curve > 0)) BigChange = TRUE;
+	} else {
+	  par[i] = tmp_par;
+	  chisq = ochisq;
+	  if (chisq_m < chisq) {
+	    chisq = chisq_m;
+	    par[i] = tmp_par - dpar[i];
+	  }	
+	  if (chisq_p < chisq) {
+	    chisq = chisq_p;
+	    par[i] = tmp_par + dpar[i];
+	  }	
+	}	
+	/*
+	gprint (GP_ERR, "try: %d  %f   ", i, chisq);
+	for (k = 0; k < 5; k++) {
+	  gprint (GP_ERR, "%f ", par[k]);
+	}
+	gprint (GP_ERR, "\n");
+	*/
+	ochisq = chisq;
+	ABigChange |= BigChange;
+      }
+      if (!BigChange) dpar[i] *= 0.8;
+    }
+
+    if (ABigChange) {
+      for (i = 0; i < 5; i++) {
+	dpar[i] = Dpar[i];
+      }
+    }
+
+    gprint (GP_ERR, "try: %d  %f   ", j, chisq);
+    for (i = 0; i < 5; i++) {
+      gprint (GP_ERR, "%f ", par[i]);
+    }
+    gprint (GP_ERR, "\n          ");
+    for (i = 0; i < 5; i++) {
+      gprint (GP_ERR, "%f ", dpar[i]);
+    }
+    gprint (GP_ERR, "\n");
+    dchi -= chisq;
+
+  }
+
+    /* code to draw dots on Ximage */
+    {
+      int Nimage, Ximage;
+      float xp, yp, x, y;
+      float dx, dy, theta, t, dt;
+      int Noverlay, NOVERLAY;
+      KiiOverlay *overlay;
+      
+      Nimage = -1;
+      if (!GetImage (&Ximage, &Nimage)) return (FALSE);
+      
+      Noverlay = 0;
+      NOVERLAY = 1000;
+      ALLOCATE (overlay, KiiOverlay, Noverlay);
+  
+      dx = par[2];
+      dy = par[3];
+      dt = 1 / MAX (dx, dy);
+      theta = par[4];
+      
+      for (t = 0; t < 6.3; t += dt) {
+	xp = dx * cos (t);
+	yp = dy * sin (t);
+	
+	x = xp * cos (theta * RAD_DEG) - yp * sin (theta * RAD_DEG) + par[0];
+	y = xp * sin (theta * RAD_DEG) + yp * cos (theta * RAD_DEG) + par[1];
+	
+	overlay[Noverlay].type = KII_OVERLAY_BOX;
+	overlay[Noverlay].x = x;
+	overlay[Noverlay].y = y;
+	overlay[Noverlay].dx = 1.0;
+	overlay[Noverlay].dy = 1.0;
+
+	Noverlay ++;
+	CHECK_REALLOCATE (overlay, KiiOverlay, NOVERLAY, Noverlay, 1000);
+      }
+      KiiLoadOverlay (Ximage, overlay, Noverlay, "red");
+      free (overlay);
+    }
+
+  return (TRUE);
+
+}
+
+/* par[0] = x
+   par[1] = y
+   par[2] = dx
+   par[3] = dy
+   par[4] = dxy
+   
+   ellipse is:  
+
+   ((X-x)/dx)^2 + ((Y-y)/dy)^2 + (X-x)(Y-y)dxy = 1
+  
+   (yp/dy)^2 + xp yp dxy + (xp/dx)^2 - 1 = 0
+
+   yp^2 + yp xp dxy dy^2 + xp^2 (dy/dx)^2 - dy^2 = 0
+
+*/
+
+float outline_chi (float Io, float *in, int Nx, int Ny, float *frac) {
+
+  int npts, xo, yo, x, y;
+  float xp, yp, dx, dy, theta;
+  float t, dt, dv, Dv;
+  float chisq, v, Frac;
+
+  /* 
+  if (!SelectVector (&Nvec, "diffs", ANYVECTOR)) return (FALSE);
+  if (!SelectVector (&Nvec2, "angle", ANYVECTOR)) return (FALSE);
+  if (!SelectVector (&Nvecx, "xdif", ANYVECTOR)) return (FALSE);
+  if (!SelectVector (&Nvecy, "ydif", ANYVECTOR)) return (FALSE);
+  */
+
+  dx = par[2];
+  dy = par[3];
+  theta = par[4];
+  dt = 1 / MAX (dx, dy);
+
+  Frac = 0;
+  chisq = 0;
+  npts = 0;
+  xo = -1; yo = -1;  /* an impossible coordinate */
+
+  /*
+  Npts = 1000;
+  REALLOCATE (vectors[Nvec].elements, float, Npts);
+  REALLOCATE (vectors[Nvec2].elements, float, Npts);
+  REALLOCATE (vectors[Nvecx].elements, float, Npts);
+  REALLOCATE (vectors[Nvecy].elements, float, Npts);
+  */
+
+  for (t = 0; t < 6.3; t += dt) {
+    xp = dx * cos (t);
+    yp = dy * sin (t);
+    
+    x = xp * cos (theta * RAD_DEG) - yp * sin (theta * RAD_DEG) + par[0];
+    y = xp * sin (theta * RAD_DEG) + yp * cos (theta * RAD_DEG) + par[1];
+    
+    if ((x == xo) && (y == yo)) continue;
+    xo = x; yo = y;
+
+    if ((x >= 0) && (x < Nx) && (y >= 0) && (y < Ny)) {
+      v = in[y*Nx + x];
+      if (v > 0) {
+	Dv = v - Io;
+	dv = v + 0.2 * fabs (Dv);
+	chisq += Dv * Dv / dv;
+	if (Dv > sqrt(dv)) Frac += 1.0;
+	if (Dv < sqrt(dv)) Frac -= 1.0;
+	/*
+	vectors[Nvec].elements[npts] = Dv;
+	vectors[Nvec2].elements[npts] = t*DEG_RAD;
+	vectors[Nvecx].elements[npts] = x;
+	vectors[Nvecy].elements[npts] = y;
+	*/
+	npts ++;
+	/* 
+	if (npts == Npts - 1) {
+	  Npts += 1000;
+	  REALLOCATE (vectors[Nvec].elements, float, Npts);
+	  REALLOCATE (vectors[Nvec2].elements, float, Npts);
+	  REALLOCATE (vectors[Nvecx].elements, float, Npts);
+	  REALLOCATE (vectors[Nvecy].elements, float, Npts);
+	}
+	*/
+      }
+    }
+  }
+  /* 
+  vectors[Nvec].Nelements = npts;
+  vectors[Nvec2].Nelements = npts;
+  vectors[Nvecx].Nelements = npts;
+  vectors[Nvecy].Nelements = npts;
+  */
+
+  chisq = chisq / npts;
+  *frac = Frac / npts;
+  if (npts == 0) {
+    chisq = 1e8;
+    *frac = -1.0;
+  }
+
+  return (chisq);
+
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/outline2.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/outline2.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/outline2.c	(revision 11389)
@@ -0,0 +1,342 @@
+# include "astro.h"
+
+int Npts;
+float *xs, *ys, *zs;
+float par[5];
+float dpar[5];
+float Dpar[5];
+float outline_chi (float, float *);
+int plot_outline ();
+
+int outline (int argc, char **argv) {
+  
+  int i, j, k, Nx, Ny, NPTS, BigChange;
+  float dIo, Io, ochisq, dchi, chisq, chisq_p, chisq_m, dp;
+  float tmp_par, curve, value;
+  float *in;
+  Buffer *buf;
+
+  if (argc != 9) {
+    gprint (GP_ERR, "USAGE: outline x y dx dy dxy Io dIo (buffer)\n");
+    return (FALSE);
+  }
+
+  if ((buf = SelectBuffer (argv[8], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+
+  par[0] = atof(argv[1]);
+  par[1] = atof(argv[2]);
+  par[2] = atof(argv[3]);
+  par[3] = atof(argv[4]);
+  par[4] = atof(argv[5]);
+  Io = atof(argv[6]);
+  dIo = atof(argv[7]);
+
+  dpar[0] = 10;
+  dpar[1] = 10;
+  dpar[2] = 10;
+  dpar[3] = 10;
+  dpar[4] = 10;
+
+  Dpar[0] = 10;
+  Dpar[1] = 10;
+  Dpar[2] = 10;
+  Dpar[3] = 10;
+  Dpar[4] = 10;
+
+  in = (float *) buf[0].matrix.buffer;
+
+  /* find all pixels within range Io-dIo : Io+dIo, in region about center guess */
+
+  Nx = buf[0].matrix.Naxis[0];  
+  Ny = buf[0].matrix.Naxis[1];
+  Npts = 0;
+  NPTS = 1000;
+  ALLOCATE (xs, float, NPTS);
+  ALLOCATE (ys, float, NPTS);
+  ALLOCATE (zs, float, NPTS);
+  for (j = par[1]-2*par[3]; j < par[1]+2*par[3]; j++) {
+    if (j < 0) continue;
+    if (j >= buf[0].matrix.Naxis[1]) continue;
+    for (i = par[0]-2*par[2]; i < par[0]+2*par[2]; i++) {
+      if (i < 0) continue;
+      if (i >= buf[0].matrix.Naxis[0]) continue;
+      value = in[i + Nx*j];
+      if (fabs (value - Io) < dIo) {
+	xs[Npts] = i;
+	ys[Npts] = j;
+	zs[Npts] = value;
+	Npts ++;
+	if (Npts == NPTS) {
+	  NPTS += 1000;
+	  REALLOCATE (xs, float, NPTS);
+	  REALLOCATE (ys, float, NPTS);
+	  REALLOCATE (zs, float, NPTS);
+	}
+      }
+    }
+  }
+
+  if (Npts == 0) {
+    gprint (GP_ERR, "no valid points in box, try again\n");
+    free (xs);
+    free (ys);
+    free (zs);
+    return (FALSE);
+  }
+
+  plot_outline ();
+  chisq = outline_chi (Io, in);
+  gprint (GP_ERR, "starting chisq: %f for %d pts\n", chisq, Npts);
+
+# if (1)
+  for (j = 0; j < 15; j++) {
+    
+    ochisq = chisq;
+    for (i = 0; i < 5; i++) {
+      /* find +chisq, -chisq for this par & adjust par as needed */
+
+      for (k = 0, BigChange = TRUE; (k < 3) && BigChange; k++) {
+	tmp_par = par[i];
+	par[i] = tmp_par + dpar[i];
+	chisq_p = outline_chi (Io, in);
+	par[i] = tmp_par - dpar[i];
+	chisq_m = outline_chi (Io, in);
+	
+	/* have we braketted a minimum? (curve < 0) */
+	curve = (chisq_p - chisq) * (chisq - chisq_m);
+	if (curve > 0) {
+	  dp = 2*dpar[i];
+	} else {
+	  dp = 0.5 * dpar[i] * (chisq_m - chisq_p) / (chisq_m + chisq_p - 2*chisq);
+	}      
+	if (chisq_m + chisq_p - 2*chisq == 0) dp = 0;
+	/* don't let extrapolation go too far */
+	if (fabs (dp) > 2*fabs(dpar[i])) { dp = SIGN(dp) * fabs (2*dpar[i]); }
+	
+	par[i] = tmp_par + dp;
+	chisq = outline_chi (Io, in);
+	
+	BigChange = FALSE;
+	if (chisq <= 1.001*ochisq) {
+	  /* got better */
+	  dchi = (ochisq - chisq) / ochisq; 
+	  if ((dchi > 0.03) || (curve > 0)) BigChange = TRUE;
+	} else {
+	  par[i] = tmp_par;
+	  chisq = ochisq;
+	  if (chisq_m < chisq) {
+	    chisq = chisq_m;
+	    par[i] = tmp_par - dpar[i];
+	  }	
+	  if (chisq_p < chisq) {
+	    chisq = chisq_p;
+	    par[i] = tmp_par + dpar[i];
+	  }	
+	}	
+	ochisq = chisq;
+      }
+      if (!BigChange) dpar[i] *= 0.8;
+    }
+
+    gprint (GP_ERR, "try: %d  %f   ", j, chisq);
+    for (i = 0; i < 5; i++) {
+      gprint (GP_ERR, "%f ", par[i]);
+    }
+    gprint (GP_ERR, "\n          ");
+    for (i = 0; i < 5; i++) {
+      gprint (GP_ERR, "%f ", dpar[i]);
+    }
+    gprint (GP_ERR, "\n");
+    dchi -= chisq;
+
+  }
+# endif
+
+  free (xs);
+  free (ys);
+  free (zs);
+  
+  plot_outline ();
+  return (TRUE);
+
+}
+
+/* par[0] = x
+   par[1] = y
+   par[2] = dx
+   par[3] = dy
+   par[4] = dxy
+   
+    xp = par[2] * cos (t);
+    yp = par[3] * sin (t);
+    
+    x = xp * cos (par[4] * RAD_DEG) - yp * sin (par[4] * RAD_DEG) + par[0];
+    y = xp * sin (par[4] * RAD_DEG) + yp * cos (par[4] * RAD_DEG) + par[1];
+
+*/
+
+# if (1)
+
+float outline_chi (float Io, float *in) {
+
+  int i;
+  float theta, phi;
+  float xp, yp, x, y;
+  float chisq, R2;
+
+  chisq = 0;
+
+  for (i = 0; i < Npts; i++) {
+    
+    phi = atan2 (ys[i] - par[1], xs[i] - par[0]) - RAD_DEG * par[4];
+    /* find a point:
+
+       xp, yp such that atan (r2 sin(phi), r1 cos(phi)) == theta 
+
+       tan (theta) = r2 sin(phi) / r1 cos (phi)
+
+       (r1/r2) tan(theta) = sin(phi) / cos (phi);
+       (r1/r2) tan(theta) = tan (phi)
+
+       phi = atan2 (r1 sin(theta), r2 cos(theta))
+    */
+
+    theta = atan2 (par[2]*sin(phi), par[3]*cos(phi));
+
+    /* this is the point on the ellipse at the same angle as ref point */
+    /* this is wrong, but close -- tends to make ellipses too fat */
+    xp = par[2] * cos (theta);
+    yp = par[3] * sin (theta);
+    
+    x = xp * cos (par[4] * RAD_DEG) - yp * sin (par[4] * RAD_DEG) + par[0];
+    y = xp * sin (par[4] * RAD_DEG) + yp * cos (par[4] * RAD_DEG) + par[1];
+
+    R2 = sqrt (SQ (x - xs[i]) + SQ (y - ys[i]));
+
+    /*
+    Dv = zs[i] - Io;
+    dv = fabs(zs[i]);
+    F2 = Dv * Dv / dv;
+    */
+
+    chisq += R2;
+
+  }
+
+  chisq = chisq / Npts;
+  return (chisq);
+
+}
+
+# else 
+
+float outline_chi (float Io, float *in) {
+
+  int i;
+  float theta, theta1, theta2;
+  float xp, yp, x, y;
+  float chisq, dv, Dv, R2, F2, R, dR;
+
+  int Nvec, Nvec2, Nvecx, Nvecy, Nv, nv;
+
+  chisq = 0;
+
+  nv = 0;
+  Nv = 1000;
+  if (!SelectVector (&Nvec, "dR", ANYVECTOR)) return (FALSE);
+  if (!SelectVector (&Nvec2, "dF", ANYVECTOR)) return (FALSE);
+  if (!SelectVector (&Nvecx, "x", ANYVECTOR)) return (FALSE);
+  if (!SelectVector (&Nvecy, "y", ANYVECTOR)) return (FALSE);
+  REALLOCATE (vectors[Nvec].elements, float, Nv);
+  REALLOCATE (vectors[Nvec2].elements, float, Nv);
+  REALLOCATE (vectors[Nvecx].elements, float, Nv);
+  REALLOCATE (vectors[Nvecy].elements, float, Nv);
+
+  for (i = 0; i < Npts; i++) {
+    
+    theta1 = atan2 (ys[i] - par[1], xs[i] - par[0]) - RAD_DEG * par[4];
+    theta = atan2 (par[2]*sin(theta1), par[3]*cos(theta1));
+
+    xp = par[2] * cos (theta);
+    yp = par[3] * sin (theta);
+    
+    x = xp * cos (par[4] * RAD_DEG) - yp * sin (par[4] * RAD_DEG) + par[0];
+    y = xp * sin (par[4] * RAD_DEG) + yp * cos (par[4] * RAD_DEG) + par[1];
+
+    R2 = SQ (x - xs[i]) + SQ (y - ys[i]);
+
+    /* 
+    Dv = fabs (zs[i] - Io) + 1;
+    dv = zs[i] + 0.2 * fabs (Dv);
+    F2 = Dv * Dv / dv;
+    */
+
+    vectors[Nvec].elements[nv] = x;
+    vectors[Nvec2].elements[nv] = y;
+    vectors[Nvecx].elements[nv] = xs[i];
+    vectors[Nvecy].elements[nv] = ys[i];
+    nv ++;
+    if (nv == Nv - 1) {
+      Nv += 1000;
+      REALLOCATE (vectors[Nvec].elements, float, Nv);
+      REALLOCATE (vectors[Nvec2].elements, float, Nv);
+      REALLOCATE (vectors[Nvecx].elements, float, Nv);
+      REALLOCATE (vectors[Nvecy].elements, float, Nv);
+    }
+
+    /* typical distance might be 1 - 10 pix,
+       typical z error might be 100 cts */
+    chisq += R2; 
+
+  }
+  vectors[Nvec].Nelements = nv;
+  vectors[Nvec2].Nelements = nv;
+  vectors[Nvecx].Nelements = nv;
+  vectors[Nvecy].Nelements = nv;
+
+  chisq = chisq / Npts;
+  return (chisq);
+
+}
+# endif
+
+int plot_outline () {
+  
+  int Nimage, Ximage;
+  float xp, yp, x, y;
+  float dx, dy, theta, t, dt;
+  int Noverlay, NOVERLAY;
+  KiiOverlay *overlay;
+  
+  Nimage = -1;
+  if (!GetImage (&Ximage, &Nimage)) return (FALSE);
+  
+  Noverlay = 0;
+  NOVERLAY = 1000;
+  ALLOCATE (overlay, KiiOverlay, Noverlay);
+  
+  dx = par[2];
+  dy = par[3];
+  dt = 1 / MAX (dx, dy);
+  theta = par[4];
+  
+  for (t = 0; t < 6.3; t += dt) {
+    xp = dx * cos (t);
+    yp = dy * sin (t);
+    
+    x = xp * cos (theta * RAD_DEG) - yp * sin (theta * RAD_DEG) + par[0];
+    y = xp * sin (theta * RAD_DEG) + yp * cos (theta * RAD_DEG) + par[1];
+    
+    overlay[Noverlay].type = KII_OVERLAY_BOX;
+    overlay[Noverlay].x = x;
+    overlay[Noverlay].y = y;
+    overlay[Noverlay].dx = 1.0;
+    overlay[Noverlay].dy = 1.0;
+
+    Noverlay ++;
+    CHECK_REALLOCATE (overlay, KiiOverlay, NOVERLAY, Noverlay, 1000);
+  }
+  KiiLoadOverlay (Ximage, overlay, Noverlay, "red");
+  free (overlay);
+  return (TRUE);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/polar.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/polar.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/polar.c	(revision 11389)
@@ -0,0 +1,71 @@
+# include "astro.h"
+
+int polar (int argc, char **argv) {
+  
+  double Lo, dL, Do, dD, Mo, dM, No, dN;
+  double xo, yo, Xo, Yo;
+  double x, y, r, t;
+  float *Vin, *Vout, *Vmask;
+  int i, j, nx, ny, Nx, Ny;
+  int X, Y;
+  Buffer *in, *out, *mask;
+
+  if (argc != 4) {
+    gprint (GP_ERR, "USAGE: polar in out\n");
+    return (FALSE);
+  }
+
+  if ((in   = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  if ((out  = SelectBuffer (argv[2], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  if ((mask = SelectBuffer (argv[3], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+
+  Nx = out[0].matrix.Naxis[0];
+  Ny = out[0].matrix.Naxis[1];
+  nx = mask[0].matrix.Naxis[0];
+  ny = mask[0].matrix.Naxis[1];
+  if ((Nx != nx) && (Ny != ny)) {
+    gprint (GP_ERR, "output and mask must have same dimensions\n");
+    return (FALSE);
+  }
+  nx = in[0].matrix.Naxis[0];
+  ny = in[0].matrix.Naxis[1];
+
+  /* we expect the output image to have units of longitude and distance */
+  gfits_scan (&in[0].header, "CRVAL1", "%lf", 1, &Lo);
+  gfits_scan (&in[0].header, "CDELT1", "%lf", 1, &dL);
+  gfits_scan (&in[0].header, "CRPIX1", "%lf", 1, &xo);
+  gfits_scan (&in[0].header, "CRVAL2", "%lf", 1, &Do);
+  gfits_scan (&in[0].header, "CDELT2", "%lf", 1, &dD);
+  gfits_scan (&in[0].header, "CRPIX2", "%lf", 1, &yo);
+
+  /* we expect the input image to have units of distance X and Y */
+  gfits_scan (&out[0].header, "CRVAL1", "%lf", 1, &Mo);
+  gfits_scan (&out[0].header, "CDELT1", "%lf", 1, &dM);
+  gfits_scan (&out[0].header, "CRPIX1", "%lf", 1, &Xo);
+  gfits_scan (&out[0].header, "CRVAL2", "%lf", 1, &No);
+  gfits_scan (&out[0].header, "CDELT2", "%lf", 1, &dN);
+  gfits_scan (&out[0].header, "CRPIX2", "%lf", 1, &Yo);
+
+  Vin  = (float *)in[0].matrix.buffer;
+  Vout = (float *)out[0].matrix.buffer;
+  Vmask = (float *)mask[0].matrix.buffer;
+  for (j = 0; j < Ny; j++) {
+    for (i = 0; i < Nx; i++, Vout++, Vmask++) {
+      x = (i - Xo) * dM + Mo;
+      y = (j - Yo) * dN + No;
+      r = hypot(x, y);
+      t = DEG_RAD*atan2 (y, x);
+      while (t < 360.0) {t += 360.0;}
+      while (t > 360.0) {t -= 360.0;}
+      X = (t - Lo) / dL + xo;
+      Y = (r - Do) / dD + yo;
+      if ((X >= 0) && (X < nx) && (Y >= 0) && (Y < ny)) {
+	*Vout += Vin[Y*nx + X];
+	*Vmask += 1;
+      }
+    }
+  }
+
+ return (TRUE);
+
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/precess.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/precess.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/precess.c	(revision 11389)
@@ -0,0 +1,112 @@
+# include "astro.h"
+
+int precess (int argc, char **argv) {
+
+  int i, Julian, Besselian;
+  double T, in_epoch, out_epoch;
+  double A, D, RA, DEC, zeta, z, theta;
+  double SA, CA, SD, CD;
+  Vector *xvec, *yvec;
+
+  Besselian = Julian = 0;
+  Besselian = get_argument (argc, argv, "B");
+  Julian    = get_argument (argc, argv, "J");
+
+  in_epoch = out_epoch = 2000.0;
+  if (argc != 5) {
+    gprint (GP_ERR, "USAGE:  precess (from) (to) RA DEC \n");
+    gprint (GP_ERR, "   you may use B for B1950.0 or J for J2000.0\n");
+    return (FALSE);
+  }
+
+  if (!Julian && !Besselian) { /* assume Julian! */
+    in_epoch  = get_epoch (argv[1], 'J');
+    out_epoch = get_epoch (argv[2], 'J');
+  }
+
+  if ((Julian == 1) && !Besselian) {
+    in_epoch  = 2000.0;
+    out_epoch = get_epoch(argv[2], 'J');
+  }
+
+  if ((Julian == 2) && !Besselian) {
+    in_epoch  = get_epoch(argv[1], 'J');
+    out_epoch = 2000.0;
+  }
+
+  if ((Besselian == 1) && !Julian) {
+    in_epoch  = BtoJ(1950.0); 
+    out_epoch = get_epoch(argv[2], 'B'); 
+  }
+
+  if ((Besselian == 2) && !Julian) {
+    in_epoch  = get_epoch(argv[1], 'B'); 
+    out_epoch = BtoJ(1950.0); 
+  }
+  
+  if (Julian && Besselian) {
+    if (Julian > Besselian) {
+      in_epoch  = BtoJ(1950.0); 
+      out_epoch = 2000.0;
+    }
+    else {
+      in_epoch  = 2000.0;
+      out_epoch = BtoJ(1950.0); 
+    }
+  }
+
+  gprint (GP_ERR, "converting from J%f to J%f\n", in_epoch, out_epoch);
+
+  T = (out_epoch - in_epoch) / 100.0;
+  
+  zeta  = RAD_DEG*(0.6406161*T + 0.0000839*T*T + 0.0000050*T*T*T);
+  theta = RAD_DEG*(0.5567530*T - 0.0001185*T*T - 0.0000116*T*T*T);
+  z     =          0.6406161*T + 0.0003041*T*T + 0.0000051*T*T*T;
+
+  if (ISNUM(argv[3][0]) && ISNUM(argv[4][0])) {
+    A = atof (argv[3]);
+    D = atof (argv[4]);
+    SD =  cos(RAD_DEG*A + zeta)*sin(theta)*cos(RAD_DEG*D) + cos(theta)*sin(RAD_DEG*D);
+    CD = sqrt (1 - SD*SD);
+    SA =  sin(RAD_DEG*A + zeta)*cos(RAD_DEG*D)/CD;
+    CA = (cos(RAD_DEG*A + zeta)*cos(theta)*cos(RAD_DEG*D) - sin(theta)*sin(RAD_DEG*D))/CD;
+
+    DEC = DEG_RAD*asin(SD);
+    RA  = DEG_RAD*atan2(SA, CA) + z;
+
+    if (RA < 0)
+      RA += 360;
+    gprint (GP_LOG, "%f %f -> %f %f\n", A, D, RA, DEC);
+    return (TRUE);
+  }    
+
+  /* find vectors */
+  if ((xvec = SelectVector (argv[3], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((yvec = SelectVector (argv[4], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+
+  if (xvec[0].Nelements != yvec[0].Nelements) {
+    gprint (GP_ERR, "vectors %s and %s not the same length\n", argv[3], argv[4]);
+    return (FALSE);
+  }
+  
+  for (i = 0; i < xvec[0].Nelements; i++) {
+    A = xvec[0].elements[i];
+    D = yvec[0].elements[i];
+    SD =  cos(RAD_DEG*A + zeta)*sin(theta)*cos(RAD_DEG*D) + cos(theta)*sin(RAD_DEG*D);
+    CD = sqrt (1 - SD*SD);
+    SA =  sin(RAD_DEG*A + zeta)*cos(RAD_DEG*D)/CD;
+    CA = (cos(RAD_DEG*A + zeta)*cos(theta)*cos(RAD_DEG*D) - sin(theta)*sin(RAD_DEG*D))/CD;
+
+    DEC = DEG_RAD*asin(SD);
+    RA  = DEG_RAD*atan2(SA, CA) + z;
+
+    if (RA < 0)
+      RA += 360;
+    
+    xvec[0].elements[i] = RA;
+    yvec[0].elements[i] = DEC; 
+  }
+
+  return (TRUE);
+
+}  
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/profile.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/profile.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/profile.c	(revision 11389)
@@ -0,0 +1,52 @@
+# include "astro.h"
+
+int profile (int argc, char **argv) {
+  
+  int i, j, N, Nx, Npt;
+  float *V;
+  double sx, sy;
+  Vector *xvec, *yvec;
+  Buffer *buf;
+
+  if (argc != 7) {
+    gprint (GP_ERR, "USAGE: profile <buffer> <X vector> <Y vector> x y N\n");
+    return (FALSE);
+  }
+
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  
+  sx = atof (argv[4]);
+  sy = atof (argv[5]);
+  N  = atof (argv[6]);
+
+  if (sx - N < 0) goto range_error;
+  if (sy - N < 0) goto range_error;
+  if (sx + N > buf[0].matrix.Naxis[0]) goto range_error;
+  if (sy + N > buf[0].matrix.Naxis[1]) goto range_error;
+
+  if ((xvec = SelectVector (argv[2], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((yvec = SelectVector (argv[3], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+
+  xvec[0].Nelements = yvec[0].Nelements = (int)SQ(2*N+1);
+  REALLOCATE (xvec[0].elements, float, 5*(int)SQ(2*N+1));
+  REALLOCATE (yvec[0].elements, float, 5*(int)SQ(2*N+1));
+  bzero (yvec[0].elements, (int)SQ(2*N+1)*sizeof(float)+1);
+  V = (float *)(buf[0].matrix.buffer); 
+  Npt = 0;
+  Nx = buf[0].matrix.Naxis[0];
+  for (i = sx - N; i < sx + N; i++) {
+    for (j = sy - N; j < sy + N; j++, Npt++) {
+      yvec[0].elements[Npt] = V[i + j*Nx];
+      xvec[0].elements[Npt] = hypot (i - sx, j - sy);
+    }
+  }
+
+  fsortpair (xvec[0].elements, yvec[0].elements, xvec[0].Nelements);
+
+  return (TRUE);
+
+range_error:
+  gprint (GP_ERR, "region out of range\n");
+  return (FALSE);
+}
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/region.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/region.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/region.c	(revision 11389)
@@ -0,0 +1,114 @@
+# include "astro.h"
+
+int region (int argc, char **argv) {
+  
+  char string[256];
+  double Ra, Dec, Radius;
+  double dx, dy;
+  int N, Ngraph, Xgraph;
+  Graphdata graphmode;
+
+  Ngraph = 0;
+  if (!GetGraph (&graphmode, &Xgraph, &Ngraph)) return (FALSE);
+
+  if ((N = get_argument (argc, argv, "-ew"))) {
+    remove_argument (N, &argc, argv);
+    graphmode.flipeast = TRUE;
+  }
+
+  if ((N = get_argument (argc, argv, "+ew"))) {
+    remove_argument (N, &argc, argv);
+    graphmode.flipeast = FALSE;
+  }
+
+  if ((N = get_argument (argc, argv, "-ns"))) {
+    remove_argument (N, &argc, argv);
+    graphmode.flipnorth = TRUE;
+  }
+
+  if ((N = get_argument (argc, argv, "+ns"))) {
+    remove_argument (N, &argc, argv);
+    graphmode.flipnorth = FALSE;
+  }
+
+  if ((argc != 4) && (argc != 5)) {
+    gprint (GP_ERR, "USAGE: region Ra Dec Radius [projection] [orientation]\n");
+    gprint (GP_ERR, " current: %f %f (%f x %f) (%s)\n", 
+	     graphmode.coords.crval1, graphmode.coords.crval2, 
+	     fabs(graphmode.xmax - graphmode.xmin), 
+	     fabs(graphmode.ymax - graphmode.ymin), 
+	     &graphmode.coords.ctype[5]);
+    return (FALSE);
+  }
+  
+  if (!str_to_radec (&Ra, &Dec, argv[1], argv[2])) return (FALSE);
+  Radius = atof (argv[3]);
+  strcpy (graphmode.coords.ctype, "RA---TAN");
+  if (argc == 5) {
+    if (!strcasecmp (argv[4], "SIN")) 
+      strcpy (graphmode.coords.ctype, "RA---SIN");
+    if (!strcasecmp (argv[4], "ZEA"))
+      strcpy (graphmode.coords.ctype, "RA---ZEA");
+    if (!strcasecmp (argv[4], "AIT")) 
+      strcpy (graphmode.coords.ctype, "RA---AIT");
+    if (!strcasecmp (argv[4], "GLS")) 
+      strcpy (graphmode.coords.ctype, "RA---GLS");
+    if (!strcasecmp (argv[4], "PAR")) 
+      strcpy (graphmode.coords.ctype, "RA---PAR");
+  }
+
+  
+  /* ask kapa for coordinate limits, so get the right aspect ratio */
+  KiiSendCommand (Xgraph, 4, "LIMS"); 
+  KiiScanMessage (Xgraph, "%lf %lf", &dx, &dy); 
+  dx = fabs (dx);
+  dy = fabs (dy); 
+
+  /* define limits for Ra, Dec at center, grid in degrees */
+  if (dy < dx) {
+    graphmode.xmin = -(dx/dy)*Radius;
+    graphmode.ymin = -Radius;
+    graphmode.xmax = (dx/dy)*Radius;
+    graphmode.ymax = Radius;
+  } else {
+    graphmode.xmin = -Radius;
+    graphmode.ymin = -(dy/dx)*Radius;
+    graphmode.xmax = Radius;
+    graphmode.ymax = (dy/dx)*Radius;
+  } 
+
+  set_variable ("XMIN", graphmode.xmin);
+  set_variable ("XMAX", graphmode.xmax);
+  set_variable ("YMIN", graphmode.ymin);
+  set_variable ("YMAX", graphmode.ymax);
+
+  set_variable ("RMIN", Ra  + graphmode.xmin);
+  set_variable ("RMAX", Ra  + graphmode.xmax);
+  set_variable ("DMIN", Dec + graphmode.ymin);
+  set_variable ("DMAX", Dec + graphmode.ymax);
+
+  set_int_variable ("EAST_RIGHT", !graphmode.flipeast);
+  set_int_variable ("NORTH_UP", !graphmode.flipnorth);
+
+  graphmode.coords.pc1_1 = (graphmode.flipeast) ? -1 : 1;
+  graphmode.coords.pc2_2 = (graphmode.flipnorth) ? -1 : 1;
+
+  graphmode.coords.pc1_2 = graphmode.coords.pc2_1 = 0.0;
+  graphmode.coords.crval1 = Ra;
+  graphmode.coords.crval2 = Dec;
+  graphmode.coords.crpix1 = 0.0;
+  graphmode.coords.crpix2 = 0.0;
+  graphmode.coords.cdelt1 = graphmode.coords.cdelt2 = 1.0;
+
+  KapaClear (Xgraph, TRUE);
+  KapaSetLimits (Xgraph, &graphmode);
+
+  /* drop this? */
+  sprintf (string, "%8.4f %8.4f (%f)", Ra, Dec, Radius);
+  KapaSendLabel (Xgraph, string, 2);
+
+  SetGraph (graphmode);
+  return (TRUE);
+}
+
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/rotcurve.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/rotcurve.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/rotcurve.c	(revision 11389)
@@ -0,0 +1,120 @@
+# include "astro.h"
+
+int rotcurve (int argc, char **argv) {
+  
+  int i, j, X, Y, n, Ncurve;
+  float *Vin, *Vout, *Vmask;
+  int nx, ny, Nx, Ny, N;
+  double L, dL, Lo, V, Vo, dV, Bo, dB, Do, dD;
+  double xo, yo, Xo, Yo;
+  double sl, cl, wo, Ro, Rs, wr, r, fr, d, min;
+  double R[100], T[100], W[100];
+  FILE *f;
+  Buffer *in, *out, *mask;
+
+  min = -1000;
+  if ((N = get_argument (argc, argv, "-min"))) {
+    remove_argument (N, &argc, argv);
+    min = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 5) {
+    gprint (GP_ERR, "USAGE: rotcurve in out mask curve.txt\n");
+    return (FALSE);
+  }
+
+  f = fopen (argv[4], "r");
+  if (f == (FILE *) NULL) {
+    gprint (GP_ERR, "can't find rotation curve data file %s\n", argv[4]);
+    return (FALSE);
+  }
+  for (i = 0; fscanf (f, "%lf %lf", &R[i], &T[i]) != EOF; i++) {
+    W[i] = T[i] / R[i];
+  }  
+  fclose (f);
+  Ncurve = i;
+
+  if ((in   = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  if ((out  = SelectBuffer (argv[2], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  if ((mask = SelectBuffer (argv[3], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+
+  Nx = out[0].matrix.Naxis[0];
+  Ny = out[0].matrix.Naxis[1];
+  nx = mask[0].matrix.Naxis[0];
+  ny = mask[0].matrix.Naxis[1];
+  if ((Nx != nx) && (Ny != ny)) {
+    gprint (GP_ERR, "output and mask must have same dimensions\n");
+    return (FALSE);
+  }
+  nx = in[0].matrix.Naxis[0];
+  ny = in[0].matrix.Naxis[1];
+
+  /* we expect the input image to have units of velocity, lattitude, and longitude */
+  gfits_scan (&in[0].header, "CRVAL1", "%lf", 1, &Vo);
+  gfits_scan (&in[0].header, "CDELT1", "%lf", 1, &dV);
+  gfits_scan (&in[0].header, "CRPIX1", "%lf", 1, &xo);
+  gfits_scan (&in[0].header, "CRVAL2", "%lf", 1, &Bo);
+  gfits_scan (&in[0].header, "CDELT2", "%lf", 1, &dB);
+  gfits_scan (&in[0].header, "CRPIX2", "%lf", 1, &yo);
+  gfits_scan (&in[0].header, "CRVAL3", "%lf", 1, &L);
+  Vo *= 0.001;
+  dV *= 0.001;
+
+  /* we expect the output image to have units of longitude and distance */
+  gfits_scan (&out[0].header, "CRVAL1", "%lf", 1, &Lo);
+  gfits_scan (&out[0].header, "CDELT1", "%lf", 1, &dL);
+  gfits_scan (&out[0].header, "CRPIX1", "%lf", 1, &Xo);
+  gfits_scan (&out[0].header, "CRVAL2", "%lf", 1, &Do);
+  gfits_scan (&out[0].header, "CDELT2", "%lf", 1, &dD);
+  gfits_scan (&out[0].header, "CRPIX2", "%lf", 1, &Yo);
+
+  while (L >= 360) {L -= 360.0;}
+  while (L < 0.0)  {L += 360.0;}
+  X = (L - Lo) / dL + Xo;
+  if ((X >= Nx) || (X < 0)) {
+    gprint (GP_ERR, "X out of range\n");
+    return (FALSE);
+  }
+  gprint (GP_ERR, "L: %f (%d)\n", L, X);
+
+  cl = cos (L*RAD_DEG);
+  sl = sin (L*RAD_DEG);
+  wo = 25.0;
+  Ro = 10.0;
+  Rs = Ro*sl;
+  /* this method depends on wr monotonically decreasing */
+
+  Vin  = (float *)in[0].matrix.buffer;
+  Vout = (float *)out[0].matrix.buffer;
+  Vmask = (float *)mask[0].matrix.buffer;
+  for (j = 0; j < ny; j++) {
+    for (i = 0; i < nx; i++, Vin++) {
+      if (*Vin <= min) continue;
+      V = (i - xo) * dV + Vo;
+      wr = V/Rs + wo;
+      for (n = 0; (n < Ncurve) && (wr < W[n]); n++);
+      if ((n == 0) || (n == Ncurve)) {
+	continue;
+      }
+      r = (wr - W[n]) *  (R[n-1] - R[n]) / (W[n-1] - W[n]) + R[n];
+      fr = (Ro/r);
+      if (r < fabs(Rs)) { /* can't be on rotation curve */
+	continue;
+      }
+      if (r < Ro)
+	d = Ro*cl - sqrt(r*r - Rs*Rs);
+      else 
+	d = Ro*cl + sqrt(r*r - Rs*Rs);
+      Y = (d - Do) / dD + Yo;
+      if ((Y < Ny) && (Y >= 0)) {
+	Vout[Y*Nx + X] += *Vin;
+	Vmask[Y*Nx + X] += 1.0;
+      }
+    }
+  }
+
+
+  return (TRUE);
+
+} 
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/scale.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/scale.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/scale.c	(revision 11389)
@@ -0,0 +1,43 @@
+# include "astro.h"
+
+int scale (int argc, char **argv) {
+
+  Buffer *buf;
+
+  if (argc != 5) {
+    gprint (GP_ERR, "USAGE: scale (buffer) (key) [-r/-w] (value)\n");
+    return (FALSE);
+  }  
+
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+
+  if (strcasecmp (argv[2], "bzero") && strcasecmp (argv[2], "bscale")) {
+    gprint (GP_ERR, "use bzero or bscale only\n");
+    return (FALSE);
+  }
+    
+  if (strcmp (argv[3], "-r") && strcmp (argv[3], "-w")) {
+    gprint (GP_ERR, "use -r or -w only\n");
+    return (FALSE);
+  }
+    
+  if (!strcmp (argv[3], "-r")) {
+    if (!strcasecmp (argv[2], "bzero")) {
+      set_variable (argv[4], (double) buf[0].bzero);
+    } else {
+      set_variable (argv[4], (double) buf[0].bscale);
+    }      
+  } else {
+    if (!strcasecmp (argv[2], "bzero")) {
+      buf[0].bzero = atof (argv[4]);
+    } else {
+      buf[0].bscale = atof (argv[4]);
+    }      
+  }
+
+  return (TRUE);
+}
+
+/* get or set external bzero / bscale values 
+   (these keywords are set to 0,1 internally, 
+   so we can't just manipulate them like other keywords */
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/sexigesimal.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/sexigesimal.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/sexigesimal.c	(revision 11389)
@@ -0,0 +1,49 @@
+# include "astro.h"
+
+int sexigesimal (int argc, char **argv) {
+  
+  int HMS, N;
+  double value;
+  char string[80];
+
+  HMS = TRUE;
+  if ((N = get_argument (argc, argv, "-hms"))) {
+    HMS = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "-hh"))) {
+    HMS = FALSE;
+    remove_argument (N, &argc, argv);
+  }
+
+  if ((argc != 3) && (argc != 2)) {
+    gprint (GP_ERR, "USAGE: sexigesimal (from) [to]\n");
+    return (FALSE);
+  }
+
+  if (HMS) {
+    if (!dms_to_ddd (&value, argv[1])) {
+      gprint (GP_ERR, "syntax error in input\n");
+      return (FALSE);
+    }
+    if (argc == 3) {
+      set_variable (argv[2], value);
+    } else {
+      gprint (GP_LOG, "%10.6f\n", value);
+    }
+    return (TRUE);
+  } else {
+    value = atof (argv[1]);
+    hms_format (string, value);
+    if (argc == 3) {
+      set_str_variable (argv[2], string);
+    } else {
+      gprint (GP_LOG, "%s\n", string);
+    }
+    return (TRUE);
+  }      
+
+  return (TRUE);
+
+}
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/spec.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/spec.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/spec.c	(revision 11389)
@@ -0,0 +1,112 @@
+# include "astro.h"
+
+int spec (int argc, char **argv) {
+
+  int i, j, Xo, X1, y1, y2, Nx, Ny;
+  int Nlong, Ngap, Nrow, N, Nring;
+  float *buffer, *V;
+  double sky, sky2, S, SX, F, R, Npts;
+  Vector *xvec, *yvec;
+  Buffer *buf;
+
+  Nlong = 31;
+  if ((N = get_argument (argc, argv, "-Nlong"))) {
+    remove_argument (N, &argc, argv);
+    Nlong  = 0.5*atof(argv[N]);
+    Nlong = 2*Nlong + 1;  /* force an odd number */
+    remove_argument (N, &argc, argv);
+  }
+  
+  Ngap = 15;
+  if ((N = get_argument (argc, argv, "-Ngap"))) {
+    remove_argument (N, &argc, argv);
+    Ngap  = 0.5*atof(argv[N]);
+    Ngap = 2*Ngap + 1;  /* force an odd number */
+    remove_argument (N, &argc, argv);
+  }
+  
+  Nrow = 1;
+  if ((N = get_argument (argc, argv, "-Nrow"))) {
+    remove_argument (N, &argc, argv);
+    Nrow  = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  
+  if (argc != 7) {
+    gprint (GP_ERR, "USAGE: spec buffer x y1 y2 X Y [-Nlong N] [-Ngap N] [-Nrow N]\n");
+    return (FALSE);
+  }
+  
+  if ((Nrow < 1) || (Nlong < 2) || (Ngap < 1) || (Nlong - Ngap < 2)) {
+    gprint (GP_ERR, "bad values for options\n");
+    return (FALSE);
+  }
+
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  Nx = buf[0].matrix.Naxis[0];
+  Ny = buf[0].matrix.Naxis[1];
+
+  Xo = atof (argv[2]);
+  y1 = atof (argv[3]);
+  y2 = atof (argv[4]);
+
+  if ((xvec = SelectVector (argv[5], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((yvec = SelectVector (argv[6], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+
+  N = y2 - y1;
+  REALLOCATE (xvec[0].elements, float, N);
+  REALLOCATE (yvec[0].elements, float, N);
+  xvec[0].Nelements = N;
+  yvec[0].Nelements = N;
+  
+  ALLOCATE (buffer, float, Nlong);
+
+  for (j = 0; j < y2 - y1; j++) {
+    V = (float *) (buf[0].matrix.buffer) + Nx*(y1 + j) + Xo - (int)(0.5*Nlong);
+    /* find sky on edge */
+    for (i = 0, Nring = 0; i < 0.5*(Nlong - Ngap); i++, V++, Nring++) {
+      buffer[i] = *V;
+    }
+    fsort (buffer, Nring);
+    for (Npts = sky = 0, i = 0.25*Nring; i < 0.75*Nring; i++, Npts += 1.0) {
+      sky += buffer[i];
+    }
+    sky = sky / Npts;
+    /* find center column for this row */
+    for (S = SX = i = 0, Nring = 0; i < Ngap; i++, V++, Nring++) {
+      S += (*V - sky);
+      SX += (*V - sky)*(i + Xo - 0.5*Ngap);
+    }
+    X1 = SX / S;
+    gprint (GP_ERR, "%4d %4d %5.1f ", j+y1, X1, sky);
+    /*    X1 = MAX (MIN (X1, Xo + 0.5+Ngap), Xo - 0.5+Ngap); */
+    V = (float *) (buf[0].matrix.buffer) + Nx*(y1 + j) + X1 - (int)(0.5*Nlong);
+    /* find sky on edges */
+    for (i = 0, Nring = 0; i < 0.5*(Nlong - Ngap); i++, V++, Nring++) {
+      buffer[Nring] = *V;
+    }
+    V = (float *) (buf[0].matrix.buffer) + Nx*(y1 + j) + X1 + (int)(0.5*Ngap);
+    for (i = 0; i < 0.5*(Nlong - Ngap); i++, V++, Nring++) {
+      buffer[Nring] = *V;
+    }
+    fsort (buffer, Nring);
+    for (Npts = sky = sky2 = 0, i = 0.25*Nring; i < 0.75*Nring; i++, Npts += 1.0) {
+      sky += buffer[i];
+      sky2 += buffer[i]*buffer[i];
+    }
+    sky = sky / Npts;
+    sky2 = (sky2 / Npts - sky*sky);
+    /* find weighted flux */
+    V = (float *) (buf[0].matrix.buffer) + Nx*(y1 + j) + X1 - (int)(0.5*Ngap);
+    for (F = R = i = 0; i < Ngap; i++, V++) {
+      F += (*V - sky) / sky2;
+      R += 1.0 / sky2;
+    }
+    xvec[0].elements[j] = j + y1; 
+    yvec[0].elements[j] = F / R; 
+    gprint (GP_ERR, " %5.1f %7.1f  %6.2f\n", sky, sky2, (F/R));
+  }    
+
+  free (buffer);
+  return (TRUE);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/star.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/star.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/star.c	(revision 11389)
@@ -0,0 +1,41 @@
+# include "astro.h"
+
+int star (int argc, char **argv) {
+
+  int x, y, N, dx, Nborder;
+  double Z, max;
+  Buffer *buf;
+
+  Nborder = 3;
+  if ((N = get_argument (argc, argv, "-border"))) {
+    remove_argument (N, &argc, argv);
+    Nborder  = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  Nborder = MAX (Nborder, 1);
+  
+  max = 60000;
+  if ((N = get_argument (argc, argv, "-sat"))) {
+    remove_argument (N, &argc, argv);
+    max  = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  
+  if ((argc != 4) && (argc != 5)) {
+    gprint (GP_ERR, "USAGE: star (buffer) x y [dx] [-border N] [-sat cnts]\n");
+    return (FALSE);
+  }
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+
+  dx = 11;
+  x = atof (argv[2]);
+  y = atof (argv[3]);
+  if (argc == 5) {
+    dx = atof (argv[4]);
+  }
+
+  Z = get_aperture_stats (&buf[0].matrix, x, y, dx, Nborder, max);
+  
+  return (TRUE);
+}
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/testfit.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/testfit.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/testfit.c	(revision 11389)
@@ -0,0 +1,161 @@
+# include "astro.h"
+
+/* local private functions */
+float fgaussOD (float, float *, int, float *);
+
+int imfit (int argc, char **argv) {
+
+  float par[4], *v1, *v2, *dy, chisq, **covar;
+  int i, Npts, Npar;
+  Vector *xvec, *yvec, *svec;
+
+  if (argc != 4) {
+    gprint (GP_ERR, "USAGE: imfit <x> <y> <dy>\n");
+    return (FALSE);
+  }
+  
+  if ((xvec = SelectVector (argv[1], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((yvec = SelectVector (argv[2], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((svec = SelectVector (argv[3], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+
+  Npts = xvec[0].Nelements;
+  ALLOCATE (dy, float, Npts);
+  v1 = svec[0].elements;
+  v2 = dy;
+  
+  for (i = 0; i < Npts; i++, v1++, v2++) *v2 = 1.0 / (*v1 * *v1);
+  
+  par[0] = 7;
+  par[1] = 2;
+  par[2] = 6;
+  par[3] = 1;
+  Npar = 4;
+
+  mrqinit (xvec[0].elements, yvec[0].elements, dy, Npts, par, Npar, fgaussOD);
+
+  for (i = 0; i < 10; i++) {
+
+    chisq = mrqmin (xvec[0].elements, yvec[0].elements, dy, Npts, par, Npar, fgaussOD);
+    gprint (GP_ERR, "chisq: %f, %f %f %f %f\n", chisq, par[0], par[1], par[2], par[3]);
+
+  }  
+
+  covar = mrqcovar (Npar);
+
+  for (i = 0; i < Npar; i++) {
+    gprint (GP_ERR, "%d  %f  %f\n", i, par[i], covar[i][i]);
+  }
+
+  mrqfree (Npar);
+  return (TRUE);
+}
+
+
+/* pars: x, y, sx, sy, sxy, sky I, */
+float fgaussOD (float x, float *par, int Npar, float *dpar) {
+
+  float X, S, Z, R, f;
+
+  X = x - par[0];
+  S = 1.0 / (par[1]*par[1]);
+  Z = -0.5*X*X*S;
+  R = exp (Z);
+  f = par[2]*R + par[3];
+
+  dpar[0] = par[2]*R*X*S;
+  dpar[1] = dpar[0]*X/par[1];
+  dpar[2] = R;
+  dpar[3] = 1;
+  
+  return (f);
+
+}
+
+# if (0)
+
+/* pars: x, y, sx, sy, sxy, sky I, */
+float testF (float x, float *par, int Npar, float *dpar) {
+
+  float f;
+
+  f = par[0]*x + par[1];
+
+  dpar[0] = x;
+  dpar[1] = 1;
+  
+  return (f);
+
+}
+
+
+/* pars: x, y, sx, sy, sxy, sky I, */
+float fgaussTD (float x, float y, float *par, int Npar) {
+
+  X = x - par[0];
+  Y = y - par[1];
+  
+  t1 = X / par[2];
+  t2 = Y * Y / par[3];
+  t3 = Y * par[4] * 2.0;
+
+  r = 0.5 * ((t1 + t3)*X + t2);
+  f = par[5] + par[6] / (1.0 + r*(1.0 + 0.5*r*(1.0 + 0.33333333*r)));
+  
+  return (f);
+
+}
+
+float chisq (float *buf, float *sig, int Nx, int Ny, float (func)(), float *par, int Npar) {
+
+  float *ptr;
+
+  X = 0;
+  ptr = buf;
+  for (i = 0; i < Nx; i++) {
+    for (j = 0; j < Ny; j++, ptr++, sig++) {
+      f = *ptr - func ((float) i, (float) j, par, Npar);
+      X += (f * f) / *sig;
+    }
+  }    
+  return (X);
+}
+
+  int i, j, Nbuf, status;
+  char *string;
+  double Npix, N1, N2, max, min, range, median;
+  float *V;
+  int sx, sy, nx, ny, *hist, Nhist, bin;
+
+  if (argc != 6) {
+    gprint (GP_ERR, "USAGE: imfit <buffer> sx sy nx ny\n");
+    return (FALSE);
+  }
+
+  if (!SelectBuffer (&Nbuf, argv[1], OLDBUFFER)) return (FALSE);
+
+  sx = atof (argv[2]);
+  sy = atof (argv[3]);
+  nx = atof (argv[4]);
+  ny = atof (argv[5]);
+
+  Npix = N1 = N2 = 0;
+  if ((sx < 0) || (sy < 0) || 
+      (sx+nx > buffers[Nbuf].matrix.Naxis[0]) || 
+      (sy+ny > buffers[Nbuf].matrix.Naxis[1])) {
+    gprint (GP_ERR, "region out of range\n");
+    return (FALSE);
+  }
+
+  Npix = nx*ny;
+
+  ALLOCATE (tempbuf, float, Npix);
+
+  buf = tempbuf;
+  for (j = 0; j < ny; j++) {
+    V = (float *)(buffers[Nbuf].matrix.buffer) + (j+sy)*buffers[Nbuf].matrix.Naxis[0] + sx; 
+    for (i = 0; i < nx; i++, V++) {
+      *buf = *V;
+    }
+  }
+
+# endif
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/transform.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/transform.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/transform.c	(revision 11389)
@@ -0,0 +1,74 @@
+# include "astro.h"
+
+int transform (int argc, char **argv) {
+
+  int i, j, Nx, Ny;
+  Coords coords_in, coords_out;
+  double scale_in, scale_out;
+  int X, Y;
+  double x, y, r, d, dx, dy;
+  double frac;
+  char *Sout, *S;
+  float *Vin, *Vout;
+  Buffer *in, *out;
+
+  if (argc != 3) {
+    gprint (GP_ERR, "USAGE: transform <from> <to>\n");
+    return (FALSE);
+  }
+
+  if ((in  = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  if ((out = SelectBuffer (argv[2], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+
+  GetCoords (&coords_in, &in[0].header);
+  GetCoords (&coords_out, &out[0].header);
+
+  /* for the moment, disable WRP / DIS */
+  if (!strcmp(&coords_in.ctype[4], "-WRP") || !strcmp(&coords_out.ctype[4], "-WRP")) {
+    gprint (GP_ERR, "WRP mode not implemented for astrom\n");
+    return (FALSE);
+  }
+  
+  scale_in = sqrt(fabs(coords_in.cdelt1*coords_in.cdelt2*(coords_in.pc1_1*coords_in.pc2_2 - coords_in.pc1_2*coords_in.pc2_1)));
+  scale_out = sqrt(fabs(coords_out.cdelt1*coords_out.cdelt2*(coords_out.pc1_1*coords_out.pc2_2 - coords_out.pc1_2*coords_out.pc2_1)));
+
+  Vin  = (float *) in[0].matrix.buffer;
+  Vout = (float *) out[0].matrix.buffer;
+  Nx = out[0].header.Naxis[0];
+  Ny = out[0].header.Naxis[1];
+  bzero (Vout, Nx*Ny*sizeof(float));
+  ALLOCATE (S, char, Nx*Ny);
+  Sout = S;
+  bzero (Sout, Nx*Ny*sizeof(char));
+  frac = 0.333;
+
+  /* if (scale_in < scale_out) { */
+
+  for (j = 0; j < in[0].header.Naxis[1]; j++) {
+    gprint (GP_ERR, ".");
+    for (i = 0; i < in[0].header.Naxis[0]; i++, Vin++) {
+      for (dx = 0.0 + 0.5*frac; dx < 1.0 - 0.5*frac; dx += frac) {
+	for (dy = 0.0 + 0.5*frac; dy < 1.0 - 0.5*frac; dy += frac) {
+	  XY_to_RD (&r, &d, i + dx, j + dy, &coords_in);
+	  RD_to_XY (&x, &y, r, d, &coords_out);
+	  X = x; Y = y;
+	  if ((X > -1) && (X < Nx) && (Y > -1) && (Y < Ny)) {
+	    Vout[X + Y*Nx] += *Vin;
+	    Sout[X + Y*Nx] ++;
+	  }
+	}
+      }
+    }
+  }
+
+  Sout = S;
+  Vout = (float *) out[0].matrix.buffer;
+  for (i = 0; i < Nx*Ny; i++, Vout++, Sout++) {
+    *Vout = *Vout / *Sout;
+  }
+
+  free (S);
+    
+  return (TRUE);
+}
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/warp.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/warp.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.astro/warp.c	(revision 11389)
@@ -0,0 +1,237 @@
+# include "astro.h"
+
+/*** needs mosaic astrometry ***/
+
+static double XO, XX, XY;
+static double YO, YX, YY;
+int ZERO;
+
+int map_output_to_input (int Npix, double df);
+int map_input_to_output (int Npix, double df);
+void set_linear_terms (Coords *in, Coords *out, int i, int j, int Npix);
+void apply_terms (double *Xout, double *Yout, double Xin, double Yin);
+
+Coords coords_in, coords_out;
+Buffer *in, *out, *wt;
+
+int warp (int argc, char **argv) {
+
+  int Nlinear, Np, N;
+  double scale_in, scale_out, df;
+
+  ZERO = FALSE;
+  if ((N = get_argument (argc, argv, "-zero"))) {
+    ZERO = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 5) {
+    gprint (GP_ERR, "USAGE: transform <from> <to> <weight> (Nlinear)\n");
+    gprint (GP_ERR, "  output buffer must exist with target astrometry header\n");
+    gprint (GP_ERR, "  Nlinear is the pixel scale for linear astrometric transformation\n");
+    return (FALSE);
+  }
+
+  if ((in  = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  if ((out = SelectBuffer (argv[2], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  if ((wt  = SelectBuffer (argv[3], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  Nlinear = atoi (argv[4]);
+
+  GetCoords (&coords_in, &in[0].header);
+  GetCoords (&coords_out, &out[0].header);
+
+  /* for the moment, disable WRP / DIS */
+  if (!strcmp(&coords_in.ctype[4], "-WRP") || !strcmp(&coords_out.ctype[4], "-WRP")) {
+    gprint (GP_ERR, "WRP mode not implemented for astrom\n");
+    return (FALSE);
+  }
+  
+  scale_in = sqrt(fabs(coords_in.cdelt1*coords_in.cdelt2*(coords_in.pc1_1*coords_in.pc2_2 - coords_in.pc1_2*coords_in.pc2_1)));
+  scale_out = sqrt(fabs(coords_out.cdelt1*coords_out.cdelt2*(coords_out.pc1_1*coords_out.pc2_2 - coords_out.pc1_2*coords_out.pc2_1)));
+  
+  gprint (GP_ERR, "%f - %f\n", scale_in, scale_out);
+
+  if (scale_in > scale_out) {
+    Np = MAX (1, 3*scale_out / scale_in);
+    df = 1.0 / Np;
+    map_output_to_input (Nlinear, df);
+  } else {
+    Np = MAX (1, 3*scale_in / scale_out);
+    df = 1.0 / Np;
+    map_input_to_output (Nlinear, df);
+  }
+  return (TRUE);
+}
+
+/* mode 1: input pixels >> output pixels: loop over output pixels */
+/* mode 2: input pixels << output pixels: loop over input pixels */
+/* mode 3: input pixels ~= output pixels: drizzle input to output */
+
+/* loop over the input pixels, map input output image */
+int map_output_to_input (int Npix, double df) {
+
+  int i, j, Ni, No, Nx, Ny, nx, ny;
+  float *Vin, *Vout, *Vwt;
+  double x, y, X, Y;
+
+  /* loop over output pixels */
+  /* set up pointers for buffers */
+  Vin  = (float *) in[0].matrix.buffer;
+  Vout = (float *) out[0].matrix.buffer;
+  Vwt  = (float *) wt[0].matrix.buffer;
+
+  nx = in[0].header.Naxis[0];
+  ny = in[0].header.Naxis[1];
+  Nx = out[0].header.Naxis[0];
+  Ny = out[0].header.Naxis[1];
+
+  if (ZERO) {
+    bzero (Vout, Nx*Ny*sizeof(float));
+    bzero (Vwt,  Nx*Ny*sizeof(float));
+  }
+
+  for (j = 0; j < Ny; j+=Npix) {
+    for (i = 0; i < Nx; i+=Npix) {
+      
+      /* define linear transformation in region */
+      set_linear_terms (&coords_out, &coords_in, i, j, Npix);
+
+      for (X = i; (X < i + Npix) && (X < Nx); X += df) {
+	for (Y = j; (Y < j + Npix) && (Y < Ny); Y += df) {
+	  
+	  No = (int)X + ((int)Y)*Nx;
+	  apply_terms (&x, &y, X, Y);
+	  if (x < 0) continue;
+	  if (x >= nx) continue;
+	  if (y < 0) continue;
+	  if (y >= ny) continue;
+	  Ni = (int)x + ((int)y)*nx;
+
+	  Vout[No] += Vin[Ni];
+	  Vwt[No] ++;
+	}
+      }
+    }
+  }
+  return (TRUE);
+}
+
+/* loop over the input pixels, map input output image */
+int map_input_to_output (int Npix, double df) {
+
+  int i, j, Ni, No, Nx, Ny, nx, ny;
+  float *Vin, *Vout, *Vwt;
+  double x, y, X, Y;
+
+  /* loop over output pixels */
+  /* set up pointers for buffers */
+  Vin  = (float *) in[0].matrix.buffer;
+  Vout = (float *) out[0].matrix.buffer;
+  Vwt  = (float *) wt[0].matrix.buffer;
+
+  Nx = in[0].header.Naxis[0];
+  Ny = in[0].header.Naxis[1];
+  nx = out[0].header.Naxis[0];
+  ny = out[0].header.Naxis[1];
+
+  if (ZERO) {
+    bzero (Vout, nx*ny*sizeof(float));
+    bzero (Vwt,  nx*ny*sizeof(float));
+  }
+
+  for (j = 0; j < Ny; j+=Npix) {
+    for (i = 0; i < Nx; i+=Npix) {
+      
+      /* define linear transformation in region */
+      set_linear_terms (&coords_in, &coords_out, i, j, Npix);
+
+      for (X = i; (X < i + Npix) && (X < Nx); X += df) {
+	for (Y = j; (Y < j + Npix) && (Y < Ny); Y += df) {
+	  
+	  Ni = (int)X + ((int)Y)*Nx;
+	  apply_terms (&x, &y, X, Y);
+	  if (x < 0) continue;
+	  if (x >= nx) continue;
+	  if (y < 0) continue;
+	  if (y >= ny) continue;
+	  No = (int)x + ((int)y)*nx;
+
+	  Vout[No] += Vin[Ni];
+	  Vwt[No] ++;
+	}
+      }
+    }
+  }
+  return (TRUE);
+}
+
+/* find the linear astrometric fix between images at this location */
+void set_linear_terms (Coords *in, Coords *out, int i, int j, int Npix) {
+
+  int n;
+  double x, y, x2, y2, xy, X, Y, Xx, Xy, Yx, Yy;
+  double Xin, Yin, Xout, Yout;
+  double Sx2, Sy2, Sxy, SXx, SXy, SYx, SYy;
+  double N, r, d;
+
+  Xin = Yin = 0;
+  N = x = y = x2 = y2 = xy = X = Y = Xx = Xy = Yx = Yy = 0;
+
+  /* define several test points, fit a line to the input,output pairs */
+  for (n = 0; n < 3; n++) {
+
+    switch (n) {
+    case 0:
+      Xin = i;
+      Yin = j;
+      break;
+    case 1:
+      Xin = i + Npix;
+      Yin = j;
+      break;
+    case 2:
+      Xin = i;
+      Yin = j + Npix;
+      break;
+    }
+
+    XY_to_RD (&r, &d, Xin, Yin, in);
+    RD_to_XY (&Xout, &Yout, r, d, out);
+
+    x  += Xin;
+    y  += Yin;
+    x2 += Xin*Xin;
+    y2 += Yin*Yin;
+    xy += Xin*Yin;
+    X  += Xout;
+    Y  += Yout;
+    Xx += Xout*Xin;
+    Xy += Xout*Yin;
+    Yx += Yout*Xin;
+    Yy += Yout*Yin;
+    N  += 1.0;
+  }
+
+  Sx2 = x2 - x*x/N;
+  Sy2 = y2 - y*y/N;
+  Sxy = xy - x*y/N;
+  SXx = Xx - X*x/N;
+  SXy = Xy - X*y/N;
+  SYx = Yx - Y*x/N;
+  SYy = Yy - Y*y/N;
+  
+  XX = (SXx*Sy2 - SXy*Sxy) / (Sx2*Sy2 - Sxy*Sxy);
+  XY = (SXy*Sx2 - SXx*Sxy) / (Sx2*Sy2 - Sxy*Sxy);
+  XO = X/N - XX*x/N - XY*y/N;
+
+  YX = (SYx*Sy2 - SYy*Sxy) / (Sx2*Sy2 - Sxy*Sxy);
+  YY = (SYy*Sx2 - SYx*Sxy) / (Sx2*Sy2 - Sxy*Sxy);
+  YO = Y/N - YX*x/N - YY*y/N;
+
+}
+
+
+void apply_terms (double *Xout, double *Yout, double Xin, double Yin) {
+  *Xout = XO + XX*Xin + XY*Yin;
+  *Yout = YO + YX*Xin + YY*Yin;
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/Makefile
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/Makefile	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/Makefile	(revision 11389)
@@ -0,0 +1,64 @@
+include ../../../Configure
+
+HOME    =       $(ROOT)/src/opihi
+SRC     =       $(HOME)/cmd.basic
+BIN     =       $(HOME)/bin
+LIB     =       $(HOME)/lib
+INC     =       $(HOME)/include
+
+# basic user commands ########################
+
+srcs = \
+$(SRC)/init.$(ARCH).o       \
+$(SRC)/break.$(ARCH).o	     \
+$(SRC)/cd.$(ARCH).o	     \
+$(SRC)/config.$(ARCH).o     \
+$(SRC)/continue.$(ARCH).o   \
+$(SRC)/date.$(ARCH).o	     \
+$(SRC)/echo.$(ARCH).o	     \
+$(SRC)/file.$(ARCH).o	     \
+$(SRC)/getchr.$(ARCH).o     \
+$(SRC)/help.$(ARCH).o	     \
+$(SRC)/input.$(ARCH).o	     \
+$(SRC)/list.$(ARCH).o	     \
+$(SRC)/list_help.$(ARCH).o  \
+$(SRC)/list_vars.$(ARCH).o  \
+$(SRC)/local.$(ARCH).o	     \
+$(SRC)/macro.$(ARCH).o	     \
+$(SRC)/memory.$(ARCH).o     \
+$(SRC)/module.$(ARCH).o     \
+$(SRC)/output.$(ARCH).o     \
+$(SRC)/quit.$(ARCH).o	     \
+$(SRC)/run_for.$(ARCH).o    \
+$(SRC)/run_if.$(ARCH).o     \
+$(SRC)/run_while.$(ARCH).o  \
+$(SRC)/scan.$(ARCH).o	     \
+$(SRC)/shell.$(ARCH).o	     \
+$(SRC)/sprintf.$(ARCH).o    \
+$(SRC)/fprintf.$(ARCH).o    \
+$(SRC)/strlen.$(ARCH).o     \
+$(SRC)/substr.$(ARCH).o     \
+$(SRC)/strpop.$(ARCH).o     \
+$(SRC)/usleep.$(ARCH).o     \
+$(SRC)/sleep.$(ARCH).o	     \
+$(SRC)/wait.$(ARCH).o	     \
+$(SRC)/which.$(ARCH).o
+
+# dependancy rules for include files ########################
+incs = \
+$(INC)/opihi.h \
+$(INC)/external.h \
+$(INC)/shell.h \
+$(INC)/dvomath.h \
+$(INC)/convert.h \
+$(INC)/display.h 
+
+libbasiccmd: $(DESTLIB)/libbasiccmd.a 
+$(DESTLIB)/libbasiccmd.a: $(LIB)/libbasiccmd.$(ARCH).a
+$(LIB)/libbasiccmd.$(ARCH).a: $(srcs)
+$(srcs): $(incs)
+
+uninstall:
+	rm -f $(DESTLIB)/libbasiccmd.a
+
+include ../Makefile.Common
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/break.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/break.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/break.c	(revision 11389)
@@ -0,0 +1,27 @@
+# include "basic.h"
+
+int exec_break (int argc, char **argv) {
+
+  int N, value;
+
+  if ((N = get_argument (argc, argv, "-auto"))) {
+    remove_argument (N, &argc, argv);
+    value = -1;
+    if (!strcasecmp (argv[N], "on")) value = TRUE;
+    if (!strcasecmp (argv[N], "off")) value = FALSE;
+    if (value == -1) {
+      gprint (GP_ERR, "USAGE: break -auto [on / off]\n");
+      if (auto_break) 
+	gprint (GP_ERR, "auto break on\n");
+      else 
+	gprint (GP_ERR, "auto break off\n");
+      return (FALSE);
+    }
+    auto_break = value;
+    return (TRUE);
+  }
+
+  loop_break = TRUE;
+  return (FALSE);
+
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/cd.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/cd.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/cd.c	(revision 11389)
@@ -0,0 +1,68 @@
+# include "basic.h"
+
+int cd (int argc, char **argv) {
+
+  int N, VERBOSE, status;
+  char *cwd;
+
+  VERBOSE = TRUE;
+  if ((N = get_argument (argc, argv, "-q"))) {
+    remove_argument (N, &argc, argv);
+    VERBOSE = FALSE;
+  }
+
+  if (argc != 2) {
+    gprint (GP_ERR, "USAGE: cd <path>\n");
+    return (FALSE);
+  }
+
+  status = chdir (argv[1]);
+  if (!status) {
+    if ((cwd = getcwd (NULL, 64)) == NULL) {
+      gprint (GP_ERR, "error getting cwd\n");
+      return (FALSE);
+    }
+    if (VERBOSE) gprint (GP_LOG, "cwd: %s\n", cwd);
+    ohana_memregister (cwd);
+    free (cwd);
+    return (TRUE);
+  }
+
+  gprint (GP_ERR, "error changing to %s\n", argv[1]);
+  return (FALSE);
+
+}
+
+int pwd (int argc, char **argv) {
+
+  int N;
+  char *cwd, *var;
+
+  var = NULL;
+  if ((N = get_argument (argc, argv, "-var"))) {
+    remove_argument (N, &argc, argv);
+    var = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 1) {
+    gprint (GP_ERR, "USAGE: pwd [-var variable]\n");
+    return (FALSE);
+  }
+  
+  if ((cwd = getcwd(NULL, 64)) == NULL) {
+    gprint (GP_ERR, "error getting cwd\n");
+    if (var != NULL) free (var);
+    return (FALSE);
+  }
+  if (var == NULL) {
+      gprint (GP_LOG, "cwd: %s\n", cwd);
+  } else {
+      set_str_variable (var, cwd);
+      free (var);
+  }
+  ohana_memregister (cwd);
+  free (cwd);
+  return (TRUE);
+  
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/config.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/config.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/config.c	(revision 11389)
@@ -0,0 +1,9 @@
+# include "basic.h"
+
+int config (int argc, char **argv) {
+
+  if (!ConfigInit (&argc, argv)) return (FALSE);
+
+  return (TRUE);
+
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/continue.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/continue.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/continue.c	(revision 11389)
@@ -0,0 +1,12 @@
+# include "basic.h"
+
+int exec_next (int argc, char **argv) {
+  loop_next = TRUE;
+  return (TRUE);
+}
+
+int exec_last (int argc, char **argv) {
+  loop_last = TRUE;
+  return (TRUE);
+}
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/date.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/date.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/date.c	(revision 11389)
@@ -0,0 +1,56 @@
+# include "basic.h"
+
+int date (int argc, char **argv) {
+  
+  int N, SECONDS, REFTIME;
+  struct timeval now;
+  char *tstring, *varName;
+
+  SECONDS = FALSE;
+  if ((N = get_argument (argc, argv, "-seconds"))) {
+    remove_argument (N, &argc, argv);
+    SECONDS = TRUE;
+  } else {
+    ALLOCATE (tstring, char, 32);
+  }
+
+  REFTIME = 0;
+  if ((N = get_argument (argc, argv, "-reftime"))) {
+    remove_argument (N, &argc, argv);
+    REFTIME = atoi (argv[N]);
+    remove_argument (N, &argc, argv);
+  } 
+
+  varName = NULL;
+  if ((N = get_argument (argc, argv, "-var"))) {
+    remove_argument (N, &argc, argv);
+    varName = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 1) {
+    gprint (GP_ERR, "USAGE: date [-var variable] [-seconds] [-reftime seconds]\n");
+    return (FALSE);
+  }
+
+  gettimeofday (&now, NULL);
+  if (SECONDS) {
+    if (varName) {
+      set_int_variable (varName, now.tv_sec - REFTIME);
+    } else {
+      gprint (GP_ERR, "%d\n", now.tv_sec - REFTIME);
+    }
+  } else {
+    ctime_r (&now.tv_sec, tstring);
+    N = strlen (tstring) - 1;
+    tstring[N] = 0;
+
+    if (varName) {
+      set_str_variable (varName, tstring);
+    } else {
+      gprint (GP_ERR, "%s\n", tstring);
+    }
+    free (tstring);
+  }
+  return (TRUE);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/echo.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/echo.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/echo.c	(revision 11389)
@@ -0,0 +1,12 @@
+# include "basic.h"
+
+int echo (int argc, char **argv) {
+  
+  int i;
+
+  for (i = 1; i < argc; i++) {
+    gprint (GP_LOG, "%s ", argv[i]);
+  }
+  gprint (GP_LOG, "\n");
+  return (TRUE);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/file.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/file.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/file.c	(revision 11389)
@@ -0,0 +1,32 @@
+# include "basic.h"
+
+int file (int argc, char **argv) {
+  
+  /* usage: file (filename) [var] */
+
+  int status, vstat;
+  struct stat fstats;
+
+  if (argc < 2) {
+    gprint (GP_ERR, "USAGE: file (filename) [var]\n");
+    return (FALSE);
+  }
+
+  status = stat (argv[1], &fstats);
+
+  vstat = !status;
+
+  if (argc == 3) {
+      
+    set_int_variable (argv[2], vstat);
+
+  } else {
+
+    gprint (GP_ERR, "file %s is ", argv[1]);
+    if (!vstat) gprint (GP_ERR, "not ");
+    gprint (GP_ERR, "found\n");
+    
+  }
+  return (TRUE);
+}
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/fprintf.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/fprintf.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/fprintf.c	(revision 11389)
@@ -0,0 +1,81 @@
+# include "basic.h"
+# define NCHAR 1024
+
+// XXX this function should ALLOCATE the output buffers
+int fprintf_opihi (int argc, char **argv) {
+
+  int i;
+  char line[NCHAR], tmp[NCHAR], fmt[NCHAR];
+  char *p1, *p2, *q;
+
+  if (argc < 2) {
+    gprint (GP_ERR, "USAGE: fprintf format value value ...\n");
+    return (FALSE);
+  }
+
+  q  = line;
+  bzero (line, NCHAR);
+
+  p1 = argv[1];
+  for (i = 2; i < argc; i++) {
+    bzero (tmp, NCHAR);
+    bzero (fmt, NCHAR);
+
+    /* find next format character */
+    p2 = strchr (p1, '%');
+    if (p2 == (char *) NULL) {
+      gprint (GP_ERR, "mismatch between format and values\n");
+      return (FALSE);
+    }
+    if (strlen(q) + p2 - p1 > NCHAR) {
+      gprint (GP_ERR, "line too long");
+      return (FALSE);
+    }
+    memcpy (q, p1, p2-p1);
+    q = line + strlen(line);
+    
+    /* identify type (%NNNs %NNNNd %NNNNf) */
+    for (p1 = p2 + 1; (*p1 == '.') || (*p1 == '-') || (*p1 == '+') || (*p1 == ' ') || isdigit(*p1); p1++);
+    memcpy (fmt, p2, p1 - p2 + 1);
+    switch (*p1) {
+      case 'e':
+      case 'f':
+	sprintf (tmp, fmt, atof(argv[i]));
+	break;
+      case 's':
+	sprintf (tmp, fmt, argv[i]);
+	break;
+      case 'd':
+      case 'c':
+      case 'x':
+	sprintf (tmp, fmt, atoi(argv[i]));
+	break;
+      default:
+	gprint (GP_ERR, "syntax error in format (only e,f,s,d,c,x allowed)\n");
+	return (FALSE);
+    }
+    if (strlen(q) + strlen(tmp) > NCHAR) {
+      gprint (GP_ERR, "line too long");
+      return (FALSE);
+    }
+    memcpy (q, tmp, strlen(tmp));
+    q = line + strlen(line);
+    p1++;
+  }
+  p2 = strchr (p1, '%');
+  if (p2 != (char *) NULL) {
+    gprint (GP_ERR, "mismatch between format and values\n");
+    return (FALSE);
+  }
+  
+  p2 = p1 + strlen (p1);
+  if (strlen(q) + p2 - p1 > NCHAR) {
+    gprint (GP_ERR, "line too long");
+    return (FALSE);
+  }
+  memcpy (q, p1, p2-p1);
+  gprint (GP_LOG, "%s\n", line);
+
+  return (TRUE);
+}
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/getchr.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/getchr.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/getchr.c	(revision 11389)
@@ -0,0 +1,29 @@
+# include "basic.h"
+
+int getchr_func (int argc, char **argv) {
+
+  /* returns position of the first given character */ 
+  char *c;
+  int pos;
+
+  if ((argc != 3) && (argc != 4)) {
+    gprint (GP_ERR, "USAGE: getchr (string) (char) [var]\n");
+    return (FALSE);
+  }
+
+  c = strchr (argv[1], argv[2][0]);
+
+  if (c == (char *) NULL) {
+    pos = -1;
+  } else {
+    pos = c - argv[1];
+  }
+
+  if (argc == 4) {
+    set_int_variable (argv[3], pos);
+  } else {
+    gprint (GP_ERR, "%d\n", pos);
+  }
+  return (TRUE);
+
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/help.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/help.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/help.c	(revision 11389)
@@ -0,0 +1,39 @@
+# include "basic.h"
+
+int help (int argc, char **argv) {
+
+  int Nbytes;
+  FILE *f;
+  char *helpdir, *file, buff[512];
+
+  helpdir = get_variable ("HELPDIR");
+  if (helpdir == (char *) NULL) {
+    gprint (GP_ERR, "variable HELPDIR not found\n");
+    return (FALSE);
+  }
+
+  if (argc == 1) {
+    sprintf (buff, "ls %s", helpdir);
+    system (buff);
+    return (TRUE);
+  }
+
+  Nbytes = strlen(helpdir) + strlen(argv[1]) + 2;
+  ALLOCATE (file, char, Nbytes);
+  snprintf (file, Nbytes, "%s/%s", helpdir, argv[1]);
+
+  f = fopen (file, "r");
+  free (file);
+
+  if (f == NULL) {
+    gprint (GP_ERR, "No help for: %s\n", argv[1]);
+    return (FALSE);
+  }
+
+  while (scan_line (f, buff) != EOF)
+    gprint (GP_LOG, "%s\n", buff);
+
+  fclose (f);
+  return (TRUE);
+}
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/help/!
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/help/!	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/help/!	(revision 11389)
@@ -0,0 +1,6 @@
+
+  exec (line)
+
+  perform a system call.  this can also be invoked with "!".  
+  don't use ! in a macro or input script as it is interpreted as a
+  comment character. 
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/help/?
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/help/?	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/help/?	(revision 11389)
@@ -0,0 +1,6 @@
+
+  exec (line)
+
+  perform a system call.  this can also be invoked with "!".  
+  don't use ! in a macro or input script as it is interpreted as a
+  comment character. 
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/help/Opihi
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/help/Opihi	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/help/Opihi	(revision 11389)
@@ -0,0 +1,5 @@
+
+
+    Opihi
+
+  
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/help/Shell
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/help/Shell	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/help/Shell	(revision 11389)
@@ -0,0 +1,5 @@
+
+
+    Opihi
+
+  
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/help/Variables
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/help/Variables	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/help/Variables	(revision 11389)
@@ -0,0 +1,17 @@
+
+  Opihi shell variables (scalars):
+
+  The Opihi shell can have variables which are designated by a word
+following a dollar sign: $foo.  Certain Mana function create and set
+variables (ie, stats, cursor).  You can also set a variable to the
+result of an arithmetic expression or just a number like this:
+
+  $foo = 10.0
+  $bar = 5*$foo + 0.6
+
+Mana will replace the variables on a line before executing a command.
+See also "Math" for more description of arithmetic operations.
+
+  See Also:  Math
+
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/help/break
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/help/break	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/help/break	(revision 11389)
@@ -0,0 +1,7 @@
+
+  break
+
+  halts macro, if, or for processes and returns to the basic prompt.
+
+  See also: macro, if, for
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/help/cd
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/help/cd	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/help/cd	(revision 11389)
@@ -0,0 +1,9 @@
+
+   cd (path)
+
+   change current working directory. 
+
+   Note that Kii or Kapa will be launched in the original 
+   directory, which means PS files created by Kii or Kapa 
+   will land in that directory (perhaps an unexpected result).
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/help/echo
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/help/echo	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/help/echo	(revision 11389)
@@ -0,0 +1,10 @@
+
+  echo [anything]
+
+  prints the rest of the line, after variables and math expressions
+are parsed.  
+
+
+  See Also:  Opihi, math
+
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/help/exec
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/help/exec	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/help/exec	(revision 11389)
@@ -0,0 +1,6 @@
+
+   exec (or !) system function
+
+   perform a UNIX system call.  variables are parsed before 
+   the commands is passed to the UNIX shell.
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/help/for
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/help/for	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/help/for	(revision 11389)
@@ -0,0 +1,19 @@
+
+   for var (start) (stop) [delta]
+
+    perform a loop, with $var as the loop variable. 
+    the value of $var runs from (start) to (stop) inclusive, 
+    and is incremented by [delta] (1 by default).
+
+    The loop commands are entered until the appropriate "end" is typed;
+    if there are nested loops, macro definitions, or logical blocks,
+    the correct "end" is used!
+
+    for may be used at the command line, in a macro, or in an input
+    file with no ill effects.
+
+    the variable $var may be accessed during the loop execution.  if
+    the variable $var is assigned a value beyond (stop) during the
+    loop, the loop execution will end.
+
+    See also: macro, if
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/help/help
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/help/help	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/help/help	(revision 11389)
@@ -0,0 +1,7 @@
+
+   help (function)
+
+   print the contents of the help file.  
+   typing "help" without an argument will list the available help
+   files.  
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/help/if
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/help/if	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/help/if	(revision 11389)
@@ -0,0 +1,22 @@
+
+   if (logic)
+     (commands)
+   end
+
+   or:
+
+   if (logic)
+     (commands)
+   else 
+     (commnds)
+   end
+
+   logical block.  The commands are performed subject to the logical
+   condition.  The syntax is simplified C:  
+   examples: (x = 6), (x < 6) , (x ! 6), ((x = 6) | (x > 10))
+
+   there are no delimiter characters.
+
+   See also: for, macro
+
+   
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/help/input
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/help/input	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/help/input	(revision 11389)
@@ -0,0 +1,15 @@
+
+   input (filename)
+
+   execute a series of commands given in the file.
+
+   Two special examples:  
+   ~/.manarc is loaded on startup, which give the user a place to
+   define personal macros, or interesting variables, etc.
+
+   If mana is called in the form "mana file", the file is loaded
+   (after .manarc) before the user is given the command-line prompt.
+   This can be used to invoke mana in a shell script, but care should
+   be taken in a shell-script that the file ends with the word "exit"
+   or "quit", or strange things may happen...
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/help/macro
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/help/macro	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/help/macro	(revision 11389)
@@ -0,0 +1,11 @@
+
+   macro (name)
+
+   create a macro.  the commands are entered until the word 'end' is
+   reached.  nested if, for, and macro definitions use the
+   appropriately matched occurances of the 'end'.
+
+   Within a macro, the command-line arguments are refered to as $1,
+   $2, etc.  The number of command-line arguments is given by $0.
+
+   
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/help/memory
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/help/memory	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/help/memory	(revision 11389)
@@ -0,0 +1,12 @@
+
+  memory [x]
+
+  list the currently used memory.  This gives a (possibly very) long
+  listing of the size of every allocated piece of memory.  Placing
+  anything after the word "memory" gives a summary also.  This is
+  useful to see just how close you are to filling your computer's
+  entire memory (Does not include memory allocated to Kii!)
+
+  See Also: buffers
+
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/help/output
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/help/output	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/help/output	(revision 11389)
@@ -0,0 +1,10 @@
+
+  output (filename or "stdout")
+
+  redirect the output to a file (concat to the end of the file).  This
+  can also be done with the UNIX ">".  However, this command is useful
+  to send information to a file for a part of a Mana session.  For
+  example, you can save results of a "stats" command.
+
+  See Also: input, stats
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/help/pwd
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/help/pwd	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/help/pwd	(revision 11389)
@@ -0,0 +1,5 @@
+
+   pwd
+
+   print current working directory
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/help/scan
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/help/scan	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/help/scan	(revision 11389)
@@ -0,0 +1,5 @@
+
+   scan (filename) (variable) [Nline]
+
+   place the Nth line in the file in the named variable
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/help/wait
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/help/wait	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/help/wait	(revision 11389)
@@ -0,0 +1,5 @@
+
+  wait [anything]
+
+  wait echos the rest of the line and waits for <return> to be typed.
+Very useful for pausing the processing of an input file or a macro.
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/help/which
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/help/which	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/help/which	(revision 11389)
@@ -0,0 +1,5 @@
+
+   which (command)
+
+   give a short summary info line on a command
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/init.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/init.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/init.c	(revision 11389)
@@ -0,0 +1,120 @@
+# include "basic.h"
+
+int config          PROTO((int, char **));
+int exec_sleep      PROTO((int, char **));
+int exec_usleep     PROTO((int, char **));
+int cd              PROTO((int, char **));
+int date            PROTO((int, char **));
+int echo            PROTO((int, char **));
+int exec_last       PROTO((int, char **));
+int exec_next       PROTO((int, char **));
+int exec_break      PROTO((int, char **));
+int file            PROTO((int, char **));
+int getchr_func     PROTO((int, char **));
+int help       	    PROTO((int, char **));
+int input      	    PROTO((int, char **));
+int list       	    PROTO((int, char **));
+int list_help  	    PROTO((int, char **));
+int list_vars  	    PROTO((int, char **));
+int local           PROTO((int, char **)); /* data? */
+int macro      	    PROTO((int, char **));
+int memory          PROTO((int, char **));
+int module    	    PROTO((int, char **));
+int output     	    PROTO((int, char **));
+int pwd        	    PROTO((int, char **));
+int quit       	    PROTO((int, char **));
+int run_for    	    PROTO((int, char **));
+int run_if     	    PROTO((int, char **));
+int run_while  	    PROTO((int, char **));
+int scan       	    PROTO((int, char **));
+int shell      	    PROTO((int, char **));
+int sprintf_opihi   PROTO((int, char **));
+int fprintf_opihi   PROTO((int, char **));
+int strlen_func     PROTO((int, char **));
+int substr_func     PROTO((int, char **));
+int strpop          PROTO((int, char **));
+int wait_func  	    PROTO((int, char **));
+int which      	    PROTO((int, char **));
+
+/** mapping of the command names to command functions **/
+static Command cmds[] = {  
+  {"config",        config,             "(re)load config file?"},
+  {"sleep",         exec_sleep,         "sleep for N seconds"},
+  {"usleep",        exec_usleep,        "sleep for N microseconds"},
+  {"cd",      	    cd,                 "change directory"},
+  {"date",    	    date,               "get current date"},
+  {"echo",    	    echo,               "type this line *"},
+  {"break",   	    exec_break,         "escape from function *"},
+  {"continue",	    exec_next,          "next loop iteration"},
+  {"next",	    exec_next,          "next loop iteration"},
+  {"last",	    exec_last,          "last loop iteration"},
+  {"return",	    exec_last,          "exit from macro"},
+  {"file",          file,               "test file existence"},
+  {"getchr",        getchr_func,        "find character in string"},
+  {"help",    	    help,               "get help on a function *"},
+  {"input",   	    input,              "read command lines from a file *"},
+  {"list",    	    list,               "get variable list"},
+  {"?",       	    list_help,          "list commands *"},
+  {"??",      	    list_vars,          "list variables *"},
+  {"local",  	    local,              "define local variables"},
+  {"macro",   	    macro,              "deal with the macros *"}, 
+  {"memory",        memory,             "long listing of the allocated memory"},
+  {"module",        module,             "load script file from the modules directories"},
+  {"output",  	    output,             "redirect output to file"},
+  {"pwd",     	    pwd,                "print current working directory"},
+  {"exit",    	    quit,               "exit program *"}, 
+  {"quit",    	    quit,               "exit program *"},
+  {"for",     	    run_for,            "for loop"}, 
+  {"if",      	    run_if,             "logical cases *"}, 
+  {"while",   	    run_while,          "while loop"}, 
+  {"scan",    	    scan,               "scan line from keyboard or file to variable *"},
+  {"!",       	    shell,              "system call"},
+  {"exec",    	    shell,              "system call"},
+  {"sprintf",       sprintf_opihi,      "formatted print to a variable"},
+  {"fprintf",       fprintf_opihi,      "formatted print to standard output"},
+  {"strlen",        strlen_func,        "string length"},
+  {"substr",        substr_func,        "substring"},
+  {"strpop",        strpop,             "pop a string"},
+  {"wait",    	    wait_func,          "wait until return is typed"},
+  {"which",   	    which,              "show command *"}
+};
+
+void InitBasic () {
+  
+  int i;
+
+  InitCommands ();
+  InitMacros ();
+  InitBuffers ();
+  InitVectors ();
+  InitVariables ();
+  InitLists ();
+
+  for (i = 0; i < sizeof (cmds) / sizeof (Command); i++) {
+    AddCommand (&cmds[i]);
+  }
+  
+}
+
+void InitBasic_PantasksClient () {
+  
+  int i;
+
+  InitCommands ();
+  InitMacros ();
+  InitBuffers ();
+  InitVectors ();
+  InitVariables ();
+  InitLists ();
+
+  for (i = 0; i < sizeof (cmds) / sizeof (Command); i++) {
+    if (!strcmp (cmds[i].name, "quit")) goto valid;
+    if (!strcmp (cmds[i].name, "exit")) goto valid;
+    if (!strcmp (cmds[i].name, "exec")) goto valid;
+    if (!strcmp (cmds[i].name, "!")) goto valid;
+    continue;
+
+  valid:
+    AddCommand (&cmds[i]);
+  }
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/input.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/input.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/input.c	(revision 11389)
@@ -0,0 +1,53 @@
+# include "basic.h"
+# define D_NLINES 100
+
+int input (int argc, char **argv) {
+  
+  int i, NLINES, status;
+  FILE *infile;
+  Macro inlist;
+
+  if (argc != 2) {
+    gprint (GP_ERR, "USAGE: input <filename>\n");
+    return (FALSE);
+  }
+
+  infile = fopen (argv[1], "r");
+  if (infile == NULL) {
+    gprint (GP_ERR, "no file %s\n", argv[1]); 
+    return (FALSE);
+  }
+
+  /* read file into the current list */
+  NLINES = D_NLINES;
+  ALLOCATE (inlist.line, char *, NLINES);
+  ALLOCATE (inlist.line[0], char, 1024);
+  for (i = 0; (scan_line (infile, inlist.line[i]) != EOF);) {
+    stripwhite (inlist.line[i]);
+    if (inlist.line[i][0] == 0) continue;
+    if (inlist.line[i][0] == '#') continue;
+    if (inlist.line[i][0] == '!') continue;
+
+    REALLOCATE (inlist.line[i], char, strlen(inlist.line[i]) + 1);
+    if (i == NLINES - 1) {
+      NLINES += D_NLINES;
+      REALLOCATE (inlist.line, char *, NLINES)
+    }
+    i++;
+    ALLOCATE (inlist.line[i], char, 1024);
+  }
+  inlist.Nlines = i;
+  fclose (infile);
+
+  /* process this list */
+  status = exec_loop (&inlist);
+
+  /* cleanup list */
+  for (i = 0; i < inlist.Nlines; i++) {
+    free (inlist.line[i]);
+  }
+  free (inlist.line[i]); /* note that we always alloc one extra line */
+  free (inlist.line);
+  return (status);
+
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/list.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/list.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/list.c	(revision 11389)
@@ -0,0 +1,160 @@
+# include "basic.h"
+# define D_NLINES 100
+static char prompt[] = ">> ";
+
+int list (int argc, char **argv) {
+
+  int ThisList, depth, i, done, found;
+  char *input, line[1024];
+  int N, Nbytes, NBYTES, Nread, status;
+  int RunCommand;
+  char *A, *B, *val, *Cmd;
+  FILE *f;
+
+  Cmd = NULL;
+  RunCommand = FALSE;
+  if ((N = get_argument (argc, argv, "-x"))) {
+    remove_argument (N, &argc, argv);
+    Cmd = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+    RunCommand = TRUE;
+  }
+
+  // return an error if -add is given with no other args
+  if ((argc > 2) && (!strcmp (argv[2], "-split"))) {
+    if (argc == 3) {
+      gprint (GP_ERR, "USAGE: list (root) -split (word) (word) ...\n");
+      return (FALSE);
+    }
+    
+    for (i = 0; i < argc - 3; i++) {
+      sprintf (line, "%s:%d", argv[1], i);
+      set_str_variable (line, argv[i+3]);
+    }
+    sprintf (line, "%s:n", argv[1]);
+    set_int_variable (line, i);
+
+    return (TRUE);
+  }
+
+  // return an error if -add is given with no other args
+  if ((argc > 2) && (!strcmp (argv[2], "-add"))) {
+    if (argc == 3) {
+      gprint (GP_ERR, "USAGE: list (root) -add (word) (word) ...\n");
+      return (FALSE);
+    }
+    
+    sprintf (line, "%s:n", argv[1]);
+    N = get_int_variable (line, &found);
+    for (i = 0; i < argc - 3; i++) {
+      sprintf (line, "%s:%d", argv[1], N + i);
+      set_str_variable (line, argv[i+3]);
+    }
+    sprintf (line, "%s:n", argv[1]);
+    set_int_variable (line, N + i);
+
+    return (TRUE);
+  }
+
+  if (argc != 2) {
+    gprint (GP_ERR, "USAGE: list (root)                : supply list data, terminate with 'END'\n");
+    gprint (GP_ERR, "USAGE: list (root) -x (command)   : create list from shell output\n");
+    gprint (GP_ERR, "USAGE: list (root) -split (words) : create list from words\n");
+    gprint (GP_ERR, "USAGE: list (root) -add (words)   : extend a list\n");
+    return (FALSE);
+  }
+
+  if (RunCommand) {
+    
+    /* val will hold the result */
+    NBYTES = 1024;
+    ALLOCATE (val, char, NBYTES);
+    
+    /* need to loop until command produces no more output, 
+       REALLOCATING as needed. */
+    f = popen (Cmd, "r");
+    done = FALSE;
+    Nbytes = 0;
+    while (!done) {
+      Nread = fread (&val[Nbytes], 1, 1023, f);
+      if (Nread < 0) { 
+	gprint (GP_ERR, "error reading from command\n");
+	done = TRUE;
+      }
+      if (Nread > 0) {
+	Nbytes += Nread;
+	NBYTES = 1024 + Nbytes;
+	REALLOCATE (val, char, NBYTES);
+      }
+      if (Nread == 0) {
+	done = TRUE;
+      }
+      
+    }
+    val[Nbytes] = 0;
+    status = pclose (f);
+    free (Cmd);
+    
+    if (status) {
+      gprint (GP_ERR, "warning: exit status of command %d\n", status);
+    }
+      
+    A = B = val;
+    for (i = 0; B != (char *) NULL;) {
+      while (isspace (*A) && (*A != 0)) A++;
+      B = strchr (A, '\n');
+      if (B != (char *) NULL) { *B = 0; }
+      if (*A != 0) {
+	sprintf (line, "%s:%d", argv[1], i);
+	set_str_variable (line, A);
+	A = B + 1;
+	i++;
+      }
+    }      
+    free (val);
+    
+    sprintf (line, "%s:n", argv[1]);
+    set_int_variable (line, i);
+    return (TRUE);
+  }
+
+  /* read in loop */
+  depth = 0;
+  ThisList = current_list_depth();
+  for (i = 0, done = FALSE; !done; ) {
+
+    /* get the next line (from correct place) */
+    if (ThisList == 0) 
+      input = readline (prompt);
+    else 
+      input = get_next_listentry (ThisList);
+
+    if (input == (char *) NULL) {
+      if (ThisList == 0)  {
+	gprint (GP_ERR, "end list with 'END'\n");
+	continue;
+      } else {
+	return (FALSE);
+      }	
+    }
+    stripwhite (input);
+
+    /* test for end of nested list -- if not nested, END refers to this macro */
+    if (!strncasecmp (input, "END", 3)) {
+      depth --;
+      if (depth < 0) { /* we hit the last "END", loop is done */
+	sprintf (line, "%s:n", argv[1]);
+	set_int_variable (line, i);
+	free (input);
+	return (TRUE);
+      }
+    }
+
+    if (*input) { 
+      sprintf (line, "%s:%d", argv[1], i);
+      set_str_variable (line, input);
+      i++;
+    }
+  }
+  return (TRUE);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/list_help.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/list_help.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/list_help.c	(revision 11389)
@@ -0,0 +1,24 @@
+# include "basic.h"
+
+int list_help (int argc, char **argv) {
+
+  FILE *f;
+  int fd;
+  char filename[128], line[256];
+
+  sprintf (filename, "/tmp/status.XXXXXX");
+  if ((fd = mkstemp (filename)) == -1) {
+    gprint (GP_ERR, "error opening output\n");
+    return (FALSE);
+  }
+  f = fdopen (fd, "w");
+  if (f == (FILE *) NULL) f = stdout;
+  print_commands (f);
+  if (f != stdout) {
+    fclose (f);
+    sprintf (line, "more %s", filename);
+    system (line);
+  }
+  unlink (filename);
+  return (TRUE);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/list_vars.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/list_vars.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/list_vars.c	(revision 11389)
@@ -0,0 +1,8 @@
+# include "basic.h"
+
+int list_vars (int argc, char **argv) {
+
+  ListVariables ();
+  return (TRUE);
+}
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/local.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/local.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/local.c	(revision 11389)
@@ -0,0 +1,33 @@
+# include "basic.h"
+
+int local (int argc, char **argv) {
+
+  int i, N, STATIC;
+  char *p;
+
+  /* create a variable named MacroDepth.argv[1] */
+
+  STATIC = FALSE;
+  if ((N = get_argument (argc, argv, "-static"))) {
+    remove_argument (N, &argc, argv);
+    STATIC = TRUE;
+  }
+
+  if (argc < 2) {
+    gprint (GP_ERR, "USAGE: local (variable)\n");
+    return (FALSE);
+  }
+  
+  for (i = 1; i < argc; i++) {
+    if (STATIC) {
+      p = get_local_variable_ptr (argv[i]);
+      if (p == NULL) {
+	set_local_variable (argv[i], "NULL");
+      }
+    } else {
+      set_local_variable (argv[i], "NULL");
+    }      
+  }
+  return (TRUE);
+
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/macro.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/macro.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/macro.c	(revision 11389)
@@ -0,0 +1,43 @@
+# include "basic.h"
+
+int macro (int argc, char **argv) {
+
+  int i, N, status;
+  CommandF *cmd;
+
+  if ((argc != 2) && (argc != 3) && (argc != 4)) {
+    gprint (GP_ERR, "USAGE: macro (cmd)\n");
+    gprint (GP_ERR, "  (cmd) can be one of:\n");
+    gprint (GP_ERR, "    (name)         -- create macro (name)\n");
+    gprint (GP_ERR, "    create (name)  -- create macro (name)\n");
+    gprint (GP_ERR, "    delete (name)  -- delete macro (name)\n");
+    gprint (GP_ERR, "    list   (name)  -- list macro (name)\n");
+    gprint (GP_ERR, "    edit   (name)  -- edit macro (name) <not working yet!> *\n");
+    gprint (GP_ERR, "    read   (name)  -- read macro(s) from file (name) <not working yet!> *\n");
+    gprint (GP_ERR, "    write  (name)  -- write macro (name) to a file <not working yet!> *\n");
+    return (FALSE);
+  }
+
+  cmd = find_macro_command (argv[1]);
+  if (cmd != NULL) {
+    status = (*cmd) (argc - 1, argv + 1);
+  } else {
+    /* sub-command was not found, pass argv[1..N] to macro_create */
+    status = macro_create (argc, argv);
+  }
+
+  return (status);
+}
+
+/* macro is called with the command "macro".  
+   the command line word "macro" is meant to be followed the one of several 
+   possible options:
+   
+   macro create
+   macro delete
+   macro list
+   macro edit
+   macro read
+   macro write
+
+*/
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/memory.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/memory.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/memory.c	(revision 11389)
@@ -0,0 +1,47 @@
+# include "basic.h"
+
+int memory (int argc, char **argv) {
+  
+  if (argc < 2) goto usage;
+
+  if (!strcasecmp (argv[1], "all")) {
+    ohana_memdump (1);
+    return (TRUE);
+  }
+  if (!strcasecmp (argv[1], "leaks")) {
+    ohana_memdump (0);
+    return (TRUE);
+  }
+  if (!strcasecmp (argv[1], "check")) {
+    ohana_memcheck (0);
+    return (TRUE);
+  }
+  if (!strcasecmp (argv[1], "checkfree")) {
+    ohana_memcheck (1);
+    return (TRUE);
+  }
+  if (!strncasecmp ("variables", argv[1], strlen(argv[1]))) {
+    ListVariables ();
+    return (TRUE);
+  }
+  if (!strncasecmp ("vectors", argv[1], strlen(argv[1]))) {
+    ListVectors ();
+    return (TRUE);
+  }
+  if (!strncasecmp ("buffers", argv[1], strlen(argv[1]))) {
+    PrintBuffers (0);
+    return (TRUE);
+  }
+  if (!strncasecmp ("macros", argv[1], strlen(argv[1]))) {
+    ListMacros();
+    return (TRUE);
+  }
+  if (!strncasecmp ("commands", argv[1], strlen(argv[1]))) {
+    print_commands (stderr);
+    return (TRUE);
+  }
+
+usage:
+  gprint (GP_ERR, "USAGE: memory (all/leaks)\n");
+  return (FALSE);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/module.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/module.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/module.c	(revision 11389)
@@ -0,0 +1,77 @@
+# include "basic.h"
+# define D_NLINES 100
+
+/* module loads an opihi script files from the installed module tree */
+int module (int argc, char **argv) {
+  
+  int i, NLINES, Nmodules, Nbytes, status;
+  FILE *infile;
+  Macro inlist;
+  char modname[16], *modpath, *filename;
+
+  if (argc != 2) {
+    gprint (GP_ERR, "USAGE: module <filename>\n");
+    return (FALSE);
+  }
+
+  Nmodules = get_int_variable ("MODULES:n", &status);
+  if (!status) {
+    gprint (GP_ERR, "MODULES list not found\n");
+    return (FALSE);
+  }
+
+  /* search for requested file in MODULES:0 - MODULES:n */
+  for (i = 0; i < Nmodules; i++) {
+    snprintf (modname, 16, "MODULES:%d", i);
+    modpath = get_variable (modname);
+    if (modpath == NULL) {
+      gprint (GP_ERR, "MODULES list element %d not found\n", i);
+      return (FALSE);
+    }
+
+    Nbytes = strlen(modpath) + strlen(argv[1]) + 2;
+    ALLOCATE (filename, char, Nbytes);
+    snprintf (filename, Nbytes, "%s/%s", modpath, argv[1]);
+    
+    infile = fopen (filename, "r");
+    free (filename);
+
+    if (infile != NULL) break;
+  }
+  if (infile == NULL) {
+    gprint (GP_ERR, "module %s not found\n", argv[1]); 
+    return (FALSE);
+  }
+    
+  /* read file into the current list */
+  NLINES = D_NLINES;
+  ALLOCATE (inlist.line, char *, NLINES);
+  ALLOCATE (inlist.line[0], char, 1024);
+  for (i = 0; (scan_line (infile, inlist.line[i]) != EOF);) {
+    stripwhite (inlist.line[i]);
+    if (inlist.line[i][0] == 0) continue;
+    if (inlist.line[i][0] == '#') continue;
+    if (inlist.line[i][0] == '!') continue;
+
+    REALLOCATE (inlist.line[i], char, strlen(inlist.line[i]) + 1);
+    if (i == NLINES - 1) {
+      NLINES += D_NLINES;
+      REALLOCATE (inlist.line, char *, NLINES)
+    }
+    i++;
+    ALLOCATE (inlist.line[i], char, 1024);
+  }
+  inlist.Nlines = i;
+  fclose (infile);
+
+  /* process this list */
+  status = exec_loop (&inlist);
+
+  /* cleanup list */
+  for (i = 0; i < inlist.Nlines; i++) {
+    free (inlist.line[i]);
+  }
+  free (inlist.line[i]); /* note that we always alloc one extra line */
+  free (inlist.line);
+  return (status);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/output.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/output.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/output.c	(revision 11389)
@@ -0,0 +1,56 @@
+# include "basic.h"
+
+int output (int argc, char **argv) {
+  
+  int N, Noutput;
+  gpDest dest;
+  IOBuffer *buffer;
+  char *output, *current;
+
+  dest = GP_LOG;
+  if ((N = get_argument (argc, argv, "-err"))) {
+    dest = GP_ERR;
+    remove_argument (N, &argc, argv);
+  }
+
+  if ((N = get_argument (argc, argv, "-current"))) {
+    current = gprintGetName (dest);
+    remove_argument (N, &argc, argv);
+    set_str_variable (argv[N], current);
+    remove_argument (N, &argc, argv);
+    return (TRUE);
+  }
+
+  if ((N = get_argument (argc, argv, "-buffer"))) {
+    remove_argument (N, &argc, argv);
+    gprintSetBuffer (dest);
+    return (TRUE);
+  }
+    
+  /* set the output target and dump the current buffer there */
+  if ((N = get_argument (argc, argv, "-dump"))) {
+    buffer = gprintGetBuffer (dest);
+
+    /* save the current buffer contents */
+    Noutput = buffer[0].Nbuffer;
+    ALLOCATE (output, char, Noutput);
+    memcpy (output, buffer[0].buffer, Noutput);
+    
+    /* set the output target to the specified name */
+    remove_argument (N, &argc, argv);
+    gprintSetFile (dest, argv[N]);
+    remove_argument (N, &argc, argv);
+
+    /* send the output to the appropriate destination */
+    gwrite (output, 1, Noutput, dest);
+    return (TRUE);
+  }
+    
+  if (argc != 2) {
+    gprint (GP_ERR, "USAGE: output <filename> [-err] [-buffer] [-current var] [-dump filename]\n");
+    return (FALSE);
+  }
+
+  gprintSetFile (dest, argv[1]);
+  return (TRUE);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/quit.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/quit.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/quit.c	(revision 11389)
@@ -0,0 +1,16 @@
+# include "basic.h"
+
+int quit (int argc, char **argv) {
+
+  int state;
+
+  cleanup ();
+
+  state = 0;
+  if (argc > 1) {
+    state = atof (argv[1]);
+  } 
+
+  exit (state);
+
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/run_for.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/run_for.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/run_for.c	(revision 11389)
@@ -0,0 +1,122 @@
+# include "basic.h"
+# define D_NLINES 100
+static char prompt[] = ">> ";
+
+int run_for (int argc, char **argv) {
+
+  int ThisList, depth, i, done, status, found, NLINES, j;
+  double start, end, delta;
+  char *input;
+  double value, sign;
+  Macro loop;
+
+  if ((argc != 4) && (argc != 5)) {
+    gprint (GP_ERR, "USAGE: for (var) (start) (stop) [delta] -- terminate with 'END'\n");
+    return (FALSE);
+  }
+
+  start = atof (argv[2]);
+  end   = atof (argv[3]);
+  delta = 1.0;
+  if (argc == 5) delta = atof (argv[4]);
+  sign = SIGN(delta);
+
+  NLINES = D_NLINES;
+  ALLOCATE (loop.line, char *, NLINES);
+
+  /* read in loop */
+  depth = 0;
+  ThisList = current_list_depth();
+  for (i = 0, done = FALSE; !done; ) {
+
+    /* get the next line (from correct place) */
+    if (ThisList == 0) 
+      input = readline (prompt);
+    else 
+      input = get_next_listentry (ThisList);
+    stripwhite (input);
+
+    /* check for end-of-data syntax error */
+    if (input == (char *) NULL) {
+      if (ThisList == 0)  {
+	gprint (GP_ERR, "end loop with 'END'\n");
+	continue;
+      } else {
+	gprint (GP_ERR, "misbalanced loop\n");
+	for (j = 0; j < loop.Nlines; j++) {
+	  free (loop.line[j]);
+	}
+	free (loop.line);
+	return (FALSE);
+      }	
+    }
+    if (ThisList == 0) ohana_memregister (input);
+
+    /* test for new macro (or other list, in the future?) */
+    if (is_list (input)) depth ++;
+
+    /* test for end of nested list -- if not nested, END refers to this macro */
+    if (!strncasecmp (input, "END", 3)) {
+      depth --;
+      if (depth < 0) break;
+    }
+
+    /* if line has data, add to loop list */
+    if (*input) { 
+      loop.line[i] = input;
+      i++;
+      if (i == NLINES - 1) {
+	NLINES += D_NLINES;
+	REALLOCATE (loop.line, char *, NLINES);
+      }
+    }
+  }
+
+  /* cleanup loop data */
+  free (input);
+  loop.Nlines = i;
+  REALLOCATE (loop.line, char *, MAX (loop.Nlines, 1));
+
+  status = TRUE;
+  interrupt = FALSE;
+  for (value = start; (sign*value < sign*end) && !interrupt; value += delta) {
+    if ((int)value == value) 
+      set_int_variable (argv[1], (int) value);
+    else 
+      set_variable (argv[1], value);
+    status = exec_loop (&loop);
+    value = get_double_variable (argv[1], &found);
+    if (loop_next) continue;
+    if (loop_last) break;
+    if (loop_break) break;
+  }
+  loop_last = loop_next = FALSE; 
+  /* 'last' and 'next' should only affect one loop */
+  if (auto_break && !status) loop_break = TRUE;
+
+  /* cleanup list */
+  for (j = 0; j < loop.Nlines; j++) {
+    free (loop.line[j]);
+  }
+  free (loop.line);
+
+  if (loop_break) return (FALSE);
+  return (TRUE);
+}
+
+/*
+  If we are entering at the keyboard (ThisList == 0), use readline.
+  Otherwise, read from the current list, remove list lines.
+  execute when we hit the final "END" (the true END -- we count macro defines!!) 
+*/
+     
+/* while processing the loop, the loop status variables may be set
+   by the loop commands, or the loop may quite on a failed command,
+   setting the exec_loop return status to false. the loop status variables
+   are:
+   loop_next : stop this loop, but try another loop
+   loop_last : stop loop processing, but return true so external loop may continue
+   loop_break : stop loop processing, and return false so external loop will break
+   interrupt : external interrupt signal
+*/
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/run_if.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/run_if.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/run_if.c	(revision 11389)
@@ -0,0 +1,127 @@
+# include "basic.h"
+# define prompt    "if: "
+
+int run_if (int argc, char **argv) {
+
+  int ThisList, depth, done, status, InlineCommand;
+  int i, length, logic;
+  char *input, *val, *line;
+  int nloop, size;
+
+  InlineCommand = FALSE;
+
+  if (argc < 2) {
+    gprint (GP_ERR, "USAGE: if (conditional) : follow with commands, end with the word 'END'\n");
+    gprint (GP_ERR, "   OR: if (conditional) command\n");
+    return (FALSE);
+  }
+  if (argc > 2) {
+    InlineCommand = TRUE;
+  }
+
+  /* determine value of conditional expression */
+  val = dvomath (1, &argv[1], &size, 0);
+  if (val == NULL) {
+    gprint (GP_ERR, "syntax error in logic: %s\n", argv[1]);
+    return (FALSE);
+  }
+  logic = atof (val); /* is round-off error a danger? */ 
+  free (val);
+
+  if (InlineCommand) {
+    if (logic) {
+      /* re-build a command line from the remaining strings */
+      length = 0;
+      for (i = 2; i < argc; i++) {
+	length += strlen(argv[i]) + 1;
+      }
+      length++;
+      ALLOCATE (line, char, length);
+      memset (line, 0, length);
+      for (i = 2; i < argc; i++) {
+	if (i == 2) {
+	  strcpy (line, argv[i]);
+	} else {
+	  strcat (line, " ");
+	  strcat (line, argv[i]);
+	}
+      }
+      status = multicommand (line);
+      free (line);
+      return (status);
+    } else {
+      return (TRUE);
+    }
+  }    
+
+  /* read in if-list */
+  nloop = 0;
+  depth = 0;
+  ThisList = current_list_depth();
+
+  done = FALSE;
+  while (!done) {
+
+    nloop ++;
+    /* get the next line (from correct place) */
+    if (ThisList == 0) {
+      input = readline (prompt);
+    } else {
+      input = get_next_listentry (ThisList);
+    }
+
+    if ((ThisList == 0) && (input == (char *) NULL)) {
+      gprint (GP_ERR, "end if-block with 'END'\n");
+      continue;
+    }
+    if ((ThisList >  0) && (input == (char *) NULL)) {
+      gprint (GP_ERR, "missing 'END' in if-block\n");
+      input = strcreate ("end");
+    }
+    if (ThisList == 0) ohana_memregister (input);
+
+    stripwhite (input);
+
+    /* test for new macro, search for "end" statement */
+    if (!logic && is_list (input)) {
+      depth ++;
+      free (input);
+      continue;
+    }
+    
+    /* check for an "else", invert logic */
+    if ((depth == 0) && !strncasecmp (input, "ELSE", 4)) {
+      logic ^= TRUE;
+      free (input);
+      continue;
+    }
+
+    /* test for end of nested block -- if not nested, END refers to this if */
+    if (!strncasecmp (input, "END", 3)) {
+      depth --;
+      if (depth < 0) { 
+	/* we hit the last "END", if-block is done */
+	free (input);
+	return (TRUE);	
+      }
+      free (input);  /* a do-nothing line */
+      continue;
+    }
+
+    if (logic) {
+      if (*input) { 
+	status = multicommand (input);
+	if (ThisList == 0) add_history (input);
+	if (auto_break && !status) return (FALSE);
+      }
+    } 
+    free (input);
+  }
+  return (TRUE);
+}
+
+/*
+     If we are entering at the keyboard (ThisList == 0), use readline.
+     Otherwise, read from the current list, remove list lines.
+     End when we hit the final "END" (the true END -- we count macro defines!!) 
+     */
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/run_while.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/run_while.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/run_while.c	(revision 11389)
@@ -0,0 +1,106 @@
+# include "basic.h"
+# define D_NLINES 100
+static char prompt[] = ">> ";
+
+int run_while (int argc, char **argv) {
+
+  int ThisList, depth, i, done, status, NLINES, j;
+  char *input, *val, *logic_line;
+  int logic, size;
+  Macro loop;
+
+  if (argc != 2) {
+    gprint (GP_ERR, "USAGE: while (condition)\n");
+    return (FALSE);
+  }
+
+  val = dvomath (1, &argv[1], &size, 0);
+  if (val == NULL) return (FALSE);
+  logic = atof (val); /* warning: round-off error is a danger */
+  free (val);
+  
+  NLINES = D_NLINES;
+  ALLOCATE (loop.line, char *, NLINES);
+
+  /* read in loop */
+  depth = 0;
+  ThisList = current_list_depth();
+  for (i = 0, done = FALSE; !done; ) {
+
+    /* get the next line (from correct place) */
+    if (ThisList == 0) 
+      input = readline (prompt);
+    else 
+      input = get_next_listentry (ThisList);
+    stripwhite (input);
+
+    /* check for end-of-data syntax error */
+    if (input == (char *) NULL) {
+      if (ThisList == 0)  {
+	gprint (GP_ERR, "end 'while' loop with 'END'\n");
+	continue;
+      } else {
+	gprint (GP_ERR, "misbalanced 'while' loop\n");
+	for (j = 0; j < loop.Nlines; j++) {
+	  free (loop.line[j]);
+	}
+	free (loop.line);
+	return (FALSE);
+      }	
+    }
+    if (ThisList == 0) ohana_memregister (input);
+
+    /* test for new macro (or other list, in the future?) */
+    if (is_list (input)) depth ++;
+
+    /* test for end of nested list -- if not nested, END refers to this macro */
+    if (!strncasecmp (input, "END", 3)) {
+      depth --;
+      if (depth < 0) break;
+    }
+
+    /* if line has data, add to loop list */
+    if (*input) { 
+      loop.line[i] = input;
+      i++;
+      if (i == NLINES - 1) {
+	NLINES += D_NLINES;
+	REALLOCATE (loop.line, char *, NLINES);
+      }
+    }
+  }
+
+  /* cleanup loop data */
+  free (input);
+  loop.Nlines = i;
+  REALLOCATE (loop.line, char *, MAX (loop.Nlines, 1));
+
+  /* execute for loop */
+  do { 
+    status = exec_loop (&loop);
+    if (loop_next) continue;
+    if (loop_last) break;
+    if (loop_break) break;
+
+    logic_line = strcreate (argv[1]);
+    logic_line = expand_vars (logic_line);
+    val = dvomath (1, &logic_line, &size, 0);
+    free (logic_line);
+
+    if (val == NULL) return (FALSE);
+    logic = atof (val); /* warning: round-off error is a danger */
+    free (val);
+  } while (logic && !interrupt);
+  loop_last = loop_next = FALSE; 
+  /* 'last' and 'next' should only affect one loop */
+  if (auto_break && !status) loop_break = TRUE;
+
+  /* cleanup list */
+  for (j = 0; j < loop.Nlines; j++) {
+    free (loop.line[j]);
+  }
+  free (loop.line);
+
+  if (loop_break) return (FALSE);
+  return (TRUE);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/scan.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/scan.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/scan.c	(revision 11389)
@@ -0,0 +1,42 @@
+# include "basic.h"
+
+int scan (int argc, char **argv) {
+
+  int i, N, status;
+  char *line;
+  FILE *f;
+
+  if ((argc != 3) && (argc != 4)) {
+    gprint (GP_ERR, "USAGE: scan <filename> <var> [N]\n");
+    return (FALSE);
+  }
+
+  f = stdin;
+  if (strcmp (argv[1], "stdin")) {
+    f = fopen (argv[1], "r");
+    if (f == (FILE *) NULL) {
+      gprint (GP_ERR, "file %s not found\n", argv[1]);
+      return (FALSE);
+    }
+  }
+  
+  ALLOCATE (line, char, 1024);
+  N = 1;
+  if (argc == 4) 
+    N = atof(argv[3]);
+
+  for (i = 0; (i < N) && ((status = scan_line (f, line)) != EOF); i++);
+  if (i < N) {
+    set_str_variable (argv[2], "EOF");
+  } else {
+    set_str_variable (argv[2], line);
+  }
+  free (line);
+
+  if (f != stdin) {
+    fclose (f);
+  }
+  return (TRUE);
+ 
+
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/shell.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/shell.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/shell.c	(revision 11389)
@@ -0,0 +1,25 @@
+# include "basic.h"
+
+int shell (int argc, char **argv) {
+  
+  int i, status;
+  char line[2048], tmp[1024];
+
+  bzero (tmp, 1024);
+  bzero (line, 2048);
+
+  for (i = 1; i < argc; i++) {
+    sprintf (tmp, "%s ", argv[i]);
+    strcat (line, tmp);
+  }
+
+  strcat (line, "\n");
+  status = system (line);
+
+  if (status) {
+    return (FALSE);
+  } else {
+    return (TRUE);
+  }
+}
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/sleep.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/sleep.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/sleep.c	(revision 11389)
@@ -0,0 +1,15 @@
+# include "basic.h"
+
+int exec_sleep (int argc, char **argv) {
+
+  int i;
+
+  if (argc < 2) {
+    gprint (GP_ERR, "usage: sleep N\n");
+    return (FALSE);
+  }
+
+  i = atof (argv[1]);
+  sleep (i);
+  return (TRUE);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/sprintf.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/sprintf.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/sprintf.c	(revision 11389)
@@ -0,0 +1,82 @@
+# include "basic.h"
+# define NCHAR 1024
+
+/* convert line, tmp, fmt to dynamic strings? */
+
+int sprintf_opihi (int argc, char **argv) {
+
+  int i;
+  char line[NCHAR], tmp[NCHAR], fmt[NCHAR];
+  char *p1, *p2, *q;
+
+  if (argc < 3) {
+    gprint (GP_ERR, "USAGE: sprintf var format value value ...\n");
+    return (FALSE);
+  }
+
+  q  = line;
+  bzero (line, NCHAR);
+
+  p1 = argv[2];
+  for (i = 3; i < argc; i++) {
+    bzero (tmp, NCHAR);
+    bzero (fmt, NCHAR);
+
+    /* find next format character */
+    p2 = strchr (p1, '%');
+    if (p2 == (char *) NULL) {
+      gprint (GP_ERR, "mismatch between format and values\n");
+      return (FALSE);
+    }
+    if (strlen(q) + p2 - p1 > NCHAR) {
+      gprint (GP_ERR, "line too long");
+      return (FALSE);
+    }
+    memcpy (q, p1, p2-p1);
+    q = line + strlen(line);
+    
+    /* identify type (%NNNs %NNNNd %NNNNf) */
+    for (p1 = p2 + 1; (*p1 == '.') || (*p1 == '-') || (*p1 == '+') || (*p1 == ' ') || isdigit(*p1); p1++);
+    memcpy (fmt, p2, p1 - p2 + 1);
+    switch (*p1) {
+      case 'e':
+      case 'f':
+	sprintf (tmp, fmt, atof(argv[i]));
+	break;
+      case 's':
+	sprintf (tmp, fmt, argv[i]);
+	break;
+      case 'd':
+      case 'c':
+      case 'x':
+	sprintf (tmp, fmt, atoi(argv[i]));
+	break;
+      default:
+	gprint (GP_ERR, "syntax error in format (only e,f,s,d,c,x allowed)\n");
+	return (FALSE);
+    }
+    if (strlen(q) + strlen(tmp) > NCHAR) {
+      gprint (GP_ERR, "line too long");
+      return (FALSE);
+    }
+    memcpy (q, tmp, strlen(tmp));
+    q = line + strlen(line);
+    p1++;
+  }
+  p2 = strchr (p1, '%');
+  if (p2 != (char *) NULL) {
+    gprint (GP_ERR, "mismatch between format and values\n");
+    return (FALSE);
+  }
+  
+  p2 = p1 + strlen (p1);
+  if (strlen(q) + p2 - p1 > NCHAR) {
+    gprint (GP_ERR, "line too long");
+    return (FALSE);
+  }
+  memcpy (q, p1, p2-p1);
+  set_str_variable (argv[1], line);
+
+  return (TRUE);
+}
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/strchr.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/strchr.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/strchr.c	(revision 11389)
@@ -0,0 +1,29 @@
+# include "basic.h"
+
+int getchr_func (int argc, char **argv) {
+
+  /* returns position of the first given character */ 
+  char *c;
+  int pos;
+
+  if ((argc != 3) && (argc != 4)) {
+    gprint (GP_ERR, "USAGE: strchr (string) (char) [var]\n");
+    return (FALSE);
+  }
+
+  c = strchr (argv[1], argv[2][0]);
+
+  if (c == (char *) NULL) {
+    pos = -1;
+  } else {
+    pos = c - argv[1];
+  }
+
+  if (argc == 5) {
+    set_variable (argv[3], pos);
+  } else {
+    gprint (GP_ERR, "%d\n", pos);
+  }
+  return (TRUE);
+
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/strlen.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/strlen.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/strlen.c	(revision 11389)
@@ -0,0 +1,22 @@
+# include "basic.h"
+
+int strlen_func (int argc, char **argv) {
+
+  /* returns length of the given string */ 
+  int len;
+
+  if ((argc != 2) && (argc != 3)) {
+    gprint (GP_ERR, "USAGE: strlen (string) [var]\n");
+    return (FALSE);
+  }
+
+  len = strlen (argv[1]);
+
+  if (argc == 3) {
+    set_int_variable (argv[2], len);
+  } else {
+    gprint (GP_ERR, "%d\n", len);
+  }
+  return (TRUE);
+
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/strpop.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/strpop.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/strpop.c	(revision 11389)
@@ -0,0 +1,35 @@
+# include "basic.h"
+
+int strpop (int argc, char **argv) {
+
+  char *p, *q, *string;
+
+  if ((argc != 2) && (argc != 3)) {
+    gprint (GP_ERR, "USAGE: strpop (var) [out]\n");
+    return (FALSE);
+  }
+
+  /* string is a copy of the value on the variable stack */
+  string = get_variable (argv[1]);
+  if (string == NULL) return (FALSE);
+  
+  /* thisword is an allocated string */
+  p = thisword (string);
+
+  q = nextword (string);
+  if (q == NULL) {
+    set_str_variable (argv[1], "NULL");
+  } else {
+    set_str_variable (argv[1], q);
+  }
+  
+  if (argc == 3) {
+    set_str_variable (argv[2], p);
+  } else {
+    gprint (GP_LOG, "%s\n", p);
+  }
+
+  free (p);
+  free (string);
+  return (TRUE);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/substr.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/substr.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/substr.c	(revision 11389)
@@ -0,0 +1,37 @@
+# include "basic.h"
+
+int substr_func (int argc, char **argv) {
+
+  int N1, N2, len;
+  char *c, *string;
+
+  if ((argc != 4) && (argc != 5)) {
+    gprint (GP_ERR, "USAGE: substr (string) N1 N2 [var]\n");
+    return (FALSE);
+  }
+
+  N1 = atof (argv[2]);
+  N2 = atof (argv[3]);
+
+  len = strlen (argv[1]);
+  if ((N1 >= len) || (N1 + N2 > len)) {
+    c = (char *) NULL;
+  } else {
+    c = strncreate (&argv[1][N1], N2);
+  }
+
+  if (c == (char *) NULL) {
+    string = strcreate ("");
+  } else {
+    string = strcreate (c);
+  }
+
+  if (argc == 5) {
+    set_str_variable (argv[4], string);
+  } else {
+    gprint (GP_ERR, "%s\n", string);
+  }
+  free (string);
+  return (TRUE);
+
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/test/break.sh
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/test/break.sh	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/test/break.sh	(revision 11389)
@@ -0,0 +1,19 @@
+
+list tests
+ test1
+end
+
+# test that break will halt operation
+macro test1
+ $PASS = 1
+ break -auto off
+ for i 0 10
+   if ($i == 5)
+     break
+   end
+ end
+ if ($i != 5)
+   $PASS = 0
+ end
+end
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/test/cd.sh
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/test/cd.sh	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/test/cd.sh	(revision 11389)
@@ -0,0 +1,34 @@
+
+list tests
+ test1
+ test2
+end
+
+# test that cd will go into a new directory
+macro test1
+ $PASS = 1
+ exec mkdir test.dir
+ output /dev/null
+ cd test.dir
+ exec touch foo.test
+ cd ..
+ output stdout
+ file test.dir/foo.test exists
+ if ($exists != 1)
+   $PASS = 0
+ end
+ exec rm -f test.dir/foo.test
+ exec rmdir test.dir
+end
+
+# test that pwd output is correct
+macro test2
+ $PASS = 1
+ exec touch foo.test
+ pwd -var testdir
+ file $testdir\/foo.test exists
+ if ($exists != 1)
+  $PASS = 0
+ end
+ exec rm foo.test
+end
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/test/config.sh
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/test/config.sh	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/test/config.sh	(revision 11389)
@@ -0,0 +1,14 @@
+
+list tests
+ test1
+end
+
+# test that config does not return an error
+macro test1
+ $PASS = 1
+ config
+ if ($STATUS == 0)
+   $PASS = 0
+ end
+end
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/test/continue.sh
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/test/continue.sh	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/test/continue.sh	(revision 11389)
@@ -0,0 +1,18 @@
+
+list tests
+ test1
+end
+
+# test that continue skips within a loop
+macro test1
+ $PASS = 1
+ for i 0 10
+   if ($i > 5)
+      continue
+   end
+   $j = $i
+ end
+ if ($j != 5)
+   $PASS = 0
+ end
+end
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/test/date.sh
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/test/date.sh	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/test/date.sh	(revision 11389)
@@ -0,0 +1,33 @@
+
+list tests
+ test1
+ test2
+end
+
+# test that date does not return an error
+macro test1
+ $PASS = 1
+ date -var var
+ if ($STATUS == 0)
+   $PASS = 0
+ end
+end
+
+# test that date constructs a reasonable sample date
+macro test2
+ $PASS = 1
+ date -var date1
+ $date2 = `date`
+ list w1 -split $date1
+ list w2 -split $date2
+ # check the first 3 entries (day, month, date)
+ if ($w1:0 != $w2:0)
+   $PASS = 0
+ end
+ if ($w1:1 != $w2:1)
+   $PASS = 0
+ end
+ if ($w1:2 != $w2:2)
+   $PASS = 0
+ end
+end
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/test/echo.sh
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/test/echo.sh	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/test/echo.sh	(revision 11389)
@@ -0,0 +1,19 @@
+
+list tests
+ test1
+end
+
+# test that echo actually echoes
+macro test1
+ $PASS = 1
+ exec rm -f test.dat
+ output test.dat
+ echo foobar
+ output stdout
+ $line = `cat test.dat`
+ # exec rm -f test.dat
+ if ($line != foobar)
+   $PASS = 0
+ end
+end
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/test/file.sh
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/test/file.sh	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/test/file.sh	(revision 11389)
@@ -0,0 +1,19 @@
+
+list tests
+ test1
+end
+
+# test that the file test function works at all
+macro test1
+ $PASS = 1
+ exec touch foo.test
+ file foo.test exists
+ if ($exists != 1)
+   $PASS = 0
+ end
+ exec rm -f foo.test
+ file foo.test exists
+ if ($exists != 0)
+   $PASS = 0
+ end
+end
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/test/for.sh
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/test/for.sh	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/test/for.sh	(revision 11389)
@@ -0,0 +1,256 @@
+
+list tests
+ test1
+ test2
+ test3
+ test4
+ test5
+ memtest1
+ memtest2
+ memtest2a
+ memtest3
+end
+
+# do we loop up correctly?
+macro test1
+
+  local i
+
+  for i 0 100
+  end    
+  
+ if ($i == 99)
+   $PASS = 1
+ else
+   $PASS = 0
+ end
+
+end
+
+# do we loop down correctly?
+macro test2
+
+  local i
+
+  for i 100 0 -1
+  end    
+  
+ if ($i == 1)
+   $PASS = 1
+ else
+   $PASS = 0
+   echo "i : $i"
+ end
+
+end
+
+# do we loop up in small steps correctly?
+macro test3
+
+  local i N
+
+  $N = 0
+  for i 0 100 0.1
+   $N = $N + 1
+  end    
+  
+ if (($i == 99.9) && ($N == 1000))
+   $PASS = 1
+ else
+   $PASS = 0
+   echo "i: $i"
+   echo "N: $N"
+ end
+
+end
+
+# do we loop down in small steps correctly?
+macro test4
+
+  local i N
+
+  $N = 0
+  for i 100 0 -0.1
+   $N = $N + 1
+  end    
+  
+ if (($i == 0.1) && ($N == 1000))
+   $PASS = 1
+ else
+   $PASS = 0
+   echo "i: $i"
+   echo "N: $N"
+ end
+
+end
+
+# do we break from a loop correctly
+macro test5
+
+  break -auto off
+
+  local i N
+
+  $N = 0
+  for i 0 100
+   $N = $N + 1
+   if ($i == 30)
+     break
+   end
+  end    
+
+  $PASS = 1
+  
+  if (($i != 30) || ($N != 31))
+    $PASS = 0
+    echo "i: $i"
+    echo "N: $N"
+  end
+end
+
+# check memleaks
+macro memtest1
+
+ local i N
+
+
+ list word -x "ps -p $PID -o rss"
+ $startmem = $word:1
+
+ for i 0 10000
+ end    
+  
+ list word -x "ps -p $PID -o rss"
+ $endmem = $word:1
+
+ if ({$endmem - $startmem} < 10)
+   $PASS = 1
+ else
+   $PASS = 0
+   echo "growth: {$endmem-$startmem}"
+   echo "kB/loop: {($endmem-$startmem)/10000}"
+ end
+end
+
+# check memleaks with many loop lines
+macro memtest2
+
+ local i N
+
+ list word -x "ps -p $PID -o rss"
+ $startmem = $word:1
+
+ output /dev/null
+ for i 0 10000
+  echo "test line in loop"
+  echo "test line in loop"
+  echo "test line in loop"
+  echo "test line in loop"
+  echo "test line in loop"
+ end    
+ output stdout
+  
+ list word -x "ps -p $PID -o rss"
+ $endmem = $word:1
+
+ $PASS = 1
+
+ if ($endmem - $startmem > 10)
+   $PASS = 0
+   echo "growth: {$endmem-$startmem}"
+   echo "kB/loop: {($endmem-$startmem)/10000}"
+ end
+end
+
+# check memleaks with many loop lines
+macro memtest2a
+
+ local i N
+
+ list word -x "ps -p $PID -o rss"
+ $startmem = $word:1
+
+ output /dev/null
+ for i 0 10000
+  echo "test line in loop"
+  echo "test line in loop"
+ end    
+ output stdout
+  
+ list word -x "ps -p $PID -o rss"
+ $endmem = $word:1
+
+ $PASS = 1
+
+ if ($endmem - $startmem > 10)
+   $PASS = 0
+   echo "growth: {$endmem-$startmem}"
+   echo "kB/loop: {($endmem-$startmem)/10000}"
+ end
+end
+
+# check memleaks with many loop lines
+macro memtest2b
+
+ local i N
+
+ list word -x "ps -p $PID -o rss"
+ $startmem = $word:1
+
+ output /dev/null
+ for i 0 1000
+  exec echo "test line in loop" > /dev/null
+  exec echo "test line in loop" > /dev/null
+ end    
+ output stdout
+  
+ list word -x "ps -p $PID -o rss"
+ $endmem = $word:1
+
+ $PASS = 1
+
+ if ($endmem - $startmem > 10)
+   $PASS = 0
+   echo "growth: {$endmem-$startmem}"
+   echo "kB/loop: {($endmem-$startmem)/1000}"
+ end
+end
+
+# check memleaks on break
+macro memtest3
+
+ local i N
+
+ break -auto off
+
+ list word -x "ps -p $PID -o rss"
+ $startmem = $word:1
+
+ for i 0 10000
+  for j 0 5
+    break
+    echo "test line in loop"
+    echo "test line in loop"
+    echo "test line in loop"
+    echo "test line in loop"
+    echo "test line in loop"
+  end
+ end    
+  
+ list word -x "ps -p $PID -o rss"
+ $endmem = $word:1
+
+ $PASS = 1
+
+ if ($i != 9999)
+   $PASS = 0
+   echo "break jumped outer loop: i = $i" 
+ end
+
+ if ($endmem - $startmem > 10)
+   $PASS = 0
+   echo "growth: {$endmem-$startmem}"
+   echo "kB/loop: {($endmem-$startmem)/10000}"
+ end
+end
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/test/fprintf.sh
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/test/fprintf.sh	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/test/fprintf.sh	(revision 11389)
@@ -0,0 +1,84 @@
+
+list tests
+ test1
+ test2
+ test3
+ test4
+ test5
+end
+
+macro test1
+ exec rm -f test.dat
+ output test.dat
+ fprintf "test %03d" 50
+ output stdout
+ $line = `cat test.dat`
+ if ("$line" == "test 050")
+   $PASS = 1
+ else
+   $PASS = 0
+ end
+end
+
+macro test2
+ exec rm -f test.dat
+ output test.dat
+ fprintf "test %6.3f" 123.45678
+ output stdout
+ $line = `cat test.dat`
+ if ("$line" == "test 123.457")
+   $PASS = 1
+ else
+   $PASS = 0
+ end
+end
+
+macro test3
+ exec rm -f test.dat
+ output test.dat
+ fprintf "test %x" 32
+ output stdout
+ $line = `cat test.dat`
+ if ("$line" == "test 20")
+   $PASS = 1
+ else
+   $PASS = 0
+ end
+end
+
+macro test4
+ exec rm -f test.dat
+ output test.dat
+ fprintf "test %10s" foobar
+ output stdout
+ $line = `cat test.dat`
+ if ("$line" == "test     foobar")
+   $PASS = 1
+ else
+   $PASS = 0
+ end
+end
+
+# check for memory leaks
+macro test5
+
+ list word -x "ps -p $PID -o rss"
+ $startmem = $word:1
+
+ output /dev/null
+ for i 0 1000
+   fprintf "test %10s" foobar
+ end
+ output stdout
+
+ list word -x "ps -p $PID -o rss"
+ $endmem = $word:1
+
+ if ($endmem - $startmem < 10)
+   $PASS = 1
+ else
+   $PASS = 0
+   echo growth: {$endmem - $startmem}
+   echo kB/loop: {($endmem - $startmem)/1000}
+ end
+end
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/test/getchr.sh
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/test/getchr.sh	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/test/getchr.sh	(revision 11389)
@@ -0,0 +1,23 @@
+
+list tests
+ test1
+ test2
+end
+
+# index test
+macro test1
+ $PASS = 1
+ getchr "a long string.string" . var
+ if ($var != 13)
+   $PASS = 0
+ end
+end
+
+# null test
+macro test2
+ $PASS = 1
+ getchr "a long string.string" x var
+ if ($var != -1)
+   $PASS = 0
+ end
+end
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/test/if.sh
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/test/if.sh	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/test/if.sh	(revision 11389)
@@ -0,0 +1,263 @@
+
+list tests
+ test1
+ test2
+ test3
+ test4
+ test5
+ test6
+ test7
+ test8
+ test9
+ test10
+ test11
+ test12
+ test13
+ test14
+end
+
+# basic logical test
+macro test1
+
+ local a
+
+ $a = 1
+
+ if ($a == 1)
+   $PASS = 1
+ else
+   $PASS = 0
+ end
+end
+
+
+# basic logical test
+macro test2
+
+ local a b
+
+ $a = 1
+ $b = 2
+
+ if (($a == 1) && ($b == 2))
+   $PASS = 1
+ else
+   $PASS = 0
+ end
+end
+
+
+# basic logical test
+macro test3
+
+ local a b
+
+ $a = 1
+ $b = 5
+
+ if (($a == 1) && ($b < 10))
+   $PASS = 1
+ else
+   $PASS = 0
+ end
+end
+
+
+# basic logical test
+macro test4
+
+ local a
+
+ $a = 0
+
+ if ($a == 1)
+   $PASS = 0
+ else
+   $PASS = 1
+ end
+end
+
+
+# basic logical test
+macro test5
+
+ local a
+
+ $a = 1
+
+ if ($a > 0)
+   $PASS = 1
+ else
+   $PASS = 0
+ end
+end
+
+
+# basic logical test
+macro test6
+
+ local a
+
+ $a = 1
+
+ if ($a < 2)
+   $PASS = 1
+ else
+   $PASS = 0
+ end
+end
+
+
+# basic logical test
+macro test7
+
+ local a
+
+ $a = test
+
+ if ("$a" == "test")
+   $PASS = 1
+ else
+   $PASS = 0
+ end
+end
+
+
+# basic logical test
+macro test8
+
+ local a
+
+ $a = foobar
+
+ if ("$a" == "test")
+   $PASS = 0
+ else
+   $PASS = 1
+ end
+end
+
+
+# basic logical test
+macro test9
+
+ local a b
+
+ $a = 1
+ $b = 2
+
+ if (($a == 0) || ($b == 2))
+   $PASS = 1
+ else
+   $PASS = 0
+ end
+end
+
+
+# basic logical test
+macro test10
+
+ local a b
+
+ $a = 1
+ $b = 2
+
+ if (($a == 0) || ($b == 1))
+   $PASS = 0
+ else
+   $PASS = 1
+ end
+end
+
+
+# basic logical test
+macro test11
+
+ local a b
+
+ $a = 1
+ $b = 2
+
+ if (($a <= 0) || ($b >= 3))
+   $PASS = 0
+ else
+   $PASS = 1
+ end
+end
+
+
+# basic logical test
+macro test12
+
+ local a
+
+ $a = 1
+
+ if ($a != 1)
+   $PASS = 0
+ else
+   $PASS = 1
+ end
+end
+
+
+# check memleaks
+macro test13
+
+ local a b i N
+
+ list word -x "ps -p $PID -o rss"
+ $startmem = $word:1
+
+ output /dev/null
+ $a = 1
+ $b = 2
+ for i 0 10000
+   if (($a == 1) && ($b == 2))
+    echo "run"    
+   end
+ end    
+ output stdout
+  
+ list word -x "ps -p $PID -o rss"
+ $endmem = $word:1
+
+ if ({$endmem - $startmem} < 10)
+   $PASS = 1
+ else
+   $PASS = 0
+   echo "growth: {$endmem-$startmem}"
+   echo "kB/loop: {($endmem-$startmem)/10000}"
+ end
+end
+
+# memory test using break
+macro test14
+
+ local a b i N
+
+ list word -x "ps -p $PID -o rss"
+ $startmem = $word:1
+
+ output /dev/null
+ $a = 1
+ $b = 2
+ for i 0 10000
+   if (($a == 1) && ($b == 2))
+    break
+    echo "run"    
+   end
+ end    
+ output stdout
+  
+ list word -x "ps -p $PID -o rss"
+ $endmem = $word:1
+
+ if ({$endmem - $startmem} < 10)
+   $PASS = 1
+ else
+   $PASS = 0
+   echo "growth: {$endmem-$startmem}"
+   echo "kB/loop: {($endmem-$startmem)/10000}"
+ end
+end
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/test/list.sh
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/test/list.sh	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/test/list.sh	(revision 11389)
@@ -0,0 +1,176 @@
+list tests
+ test1
+ test2
+ test3
+ test4
+ memtest2
+ memtest3
+ memtest4
+end
+
+list check
+  this
+  is
+  a
+  list
+end
+
+# Does list work?
+macro test1
+ $PASS = 1
+ if ($check:n != 4)
+  $PASS = 0
+  echo "Number of list elements: $check:n"
+ end
+ if (("$check:0" != "this") || ("$check:1" != "is") || ("$check:2" != "a") || ("$check:3" != "list"))
+  $PASS = 0
+  echo "List element does not return correctly!"
+ end
+end
+
+# Test split option
+macro test2
+ $PASS = 1
+ list check2 -split This is a list
+ if ($check2:n != 4)
+  $PASS = 0
+  echo "Number of list elements: $check2:n"
+ end
+ if (("$check2:0" != "This") || ("$check2:1" != "is") || ("$check2:2" != "a") || ("$check2:3" != "list"))
+  $PASS = 0
+  echo "List element does not return correctly!"
+ end
+end
+
+# Test -x option for the ls command
+macro test3
+ $PASS = 1
+ list check3 -x "ls /dev/null"
+ if ($check3:n != 1)
+  $PASS = 0
+  echo "Number of list elements: $check3:n"
+ end
+ if ("$check3:0" != "/dev/null")
+  $PASS = 0
+  echo "List element does not return correctly!"
+ end
+end
+
+# Test -x for files
+macro test4
+ $PASS = 1
+ file list_test.txt fchk
+ if ($fchk)
+  exec rm list_test.txt
+ end
+ output list_test.txt
+ echo This
+ echo is
+ echo a
+ echo list
+ output stdout
+ list check4 -x "cat list_test.txt"
+ if ($check4:n != 4)
+  $PASS = 0
+  echo "Number of list elements: $check4:n"
+ end
+ if (("$check4:0" != "This ") || ("$check4:1" != "is ") || ("$check4:2" != "a ") || ("$check4:3" != "list "))
+  $PASS = 0
+  echo "List element does not return correctly!"
+ end
+ if ($PASS)
+  exec rm list_test.txt
+ end
+end
+
+# Memory test for list -split
+macro memtest2
+
+ local i
+
+ list word -x "ps -p $PID -o rss"
+ $startmem = $word:1
+
+ for i 0 10000
+  list check2 -split This is a list
+ end    
+  
+ list word -x "ps -p $PID -o rss"
+ $endmem = $word:1
+
+ $PASS = 1
+
+ if ($endmem - $startmem > 10)
+   $PASS = 0
+   echo "growth: {$endmem-$startmem}"
+   echo "kB/loop: {($endmem-$startmem)/10000}"
+ end
+
+end
+
+# Memory test for list -x
+macro memtest3
+
+ local i
+
+ list word -x "ps -p $PID -o rss"
+ $startmem = $word:1
+
+ for i 0 100
+  list check3 -x "ls /etc"
+ end    
+  
+ list word -x "ps -p $PID -o rss"
+ $endmem = $word:1
+
+ $PASS = 1
+
+ if ($endmem - $startmem > 10)
+   $PASS = 0
+   echo "growth: {$endmem-$startmem}"
+   echo "kB/loop: {($endmem-$startmem)/1000}"
+ end
+
+end
+
+# Memory test for list -x
+# XXX these need to be cleaned up to use the actual 
+# size of the list to calculate leakage...
+macro memtest4
+
+ file list_test.txt fchk
+ if ($fchk)
+  exec rm list_test.txt
+ end
+ output list_test.txt
+ echo This
+ echo is
+ echo a
+ echo list
+ output stdout
+
+ local i
+
+ list word -x "ps -p $PID -o rss"
+ $startmem = $word:1
+
+ for i 0 100
+  list check4 -x "cat list_test.txt"
+ end    
+  
+ list word -x "ps -p $PID -o rss"
+ $endmem = $word:1
+
+ $PASS = 1
+
+ if ($endmem - $startmem > 10)
+   $PASS = 0
+   echo "growth: {$endmem-$startmem}"
+   echo "kB/loop: {($endmem-$startmem)/1000}"
+ end
+
+ if ($PASS)
+  exec rm list_test.txt
+ end
+
+end
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/test/macro.sh
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/test/macro.sh	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/test/macro.sh	(revision 11389)
@@ -0,0 +1,48 @@
+list tests
+ test_prep
+ test1
+ memtest1
+end
+
+# Is the macro working?
+macro test_prep
+ $test_var1 = check1
+ $test_var2 = check2
+ $var_count = $0
+end
+
+macro test1
+ $PASS = 1
+ $var_count = 0
+ $test_var1 = blank
+ $test_var2 = blank
+ test_prep var1 var2 var3
+ if ($var_count != 4)
+  $PASS = 0
+  echo "Number of parameters (should be 4): $var_count"
+ end
+ if (("$test_var1" != "check1") || ("$test_var2" != "check2"))
+  $PASS = 0
+  echo "Paramaters not assigned correctly!: $test_var1 $test_var2"
+ end
+end
+
+# Memory Test for macro
+macro memtest1
+ $PASS = 1
+ list word -x "ps -p $PID -o rss"
+ $startmem = $word:1
+
+ for i 0 10000
+  test_prep
+ end    
+  
+ list word -x "ps -p $PID -o rss"
+ $endmem = $word:1
+
+ if ($endmem - $startmem > 10)
+   $PASS = 0
+   echo "growth: {$endmem-$startmem}"
+   echo "kB/loop: {($endmem-$startmem)/10000}"
+ end
+end
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/test/math.sh
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/test/math.sh	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/test/math.sh	(revision 11389)
@@ -0,0 +1,149 @@
+
+list tests
+ test1
+ test2
+ testmem1
+ testmem2
+ testmem3
+ testmem4
+end
+
+# test subtraction
+macro test1
+
+  $PASS = 1
+  local i
+
+  exec rm -f tmp.txt
+  output tmp.txt
+  echo {99 - 98}
+  output stdout
+
+  $i = `cat tmp.txt` 
+ 
+ if ($i != 1)
+   $PASS = 0
+   echo "i : $i"
+ end
+
+end
+
+# test addition, division, and multiplication
+macro test2
+
+ $PASS = 1
+ local a b c
+
+ $a = {2 + 4}
+ $b = {12 / 2}
+ $c = {2 * 3}
+
+ if (($a != 6) || ($b != 6) || ($c != 6))
+   $PASS = 0
+   echo "ALL VALUES NOT 6: a=$a\ b=$b\ c=$c\"
+ end
+
+end
+
+# check memleaks (set global)
+macro testmem1
+
+ $PASS = 1
+ local i
+
+ list word -x "ps -p $PID -o rss"
+ $startmem = $word:1
+
+ output /dev/null
+ for i 0 10000
+   echo {99 - 98}
+ end    
+ output stdout
+  
+ list word -x "ps -p $PID -o rss"
+ $endmem = $word:1
+
+ if ({$endmem - $startmem} > 10)
+   $PASS = 0
+   echo "growth: {$endmem-$startmem}"
+   echo "kB/loop: {($endmem-$startmem)/10000}"
+ end
+end
+
+# check memleaks (set global)
+macro testmem2
+
+ $PASS = 1
+ local i N
+
+ list word -x "ps -p $PID -o rss"
+ $startmem = $word:1
+
+ output /dev/null
+ for i 0 10000
+   $N = 99 - 98
+   $N = 1 + 1
+   $N = 2 * 2
+   $N = 22/7
+ end    
+ output stdout
+  
+ list word -x "ps -p $PID -o rss"
+ $endmem = $word:1
+
+ if ({$endmem - $startmem} > 10)
+   $PASS = 0
+   echo "growth: {$endmem-$startmem}"
+   echo "kB/loop: {($endmem-$startmem)/10000}"
+ end
+end
+
+# check memleaks (set global)
+macro testmem3
+
+ $PASS = 1
+ local i N
+
+ list word -x "ps -p $PID -o rss"
+ $startmem = $word:1
+
+ output /dev/null
+ for i 0 10000
+   $N = 99
+ end    
+ output stdout
+  
+ list word -x "ps -p $PID -o rss"
+ $endmem = $word:1
+
+ if ({$endmem - $startmem} > 10)
+   $PASS = 0
+   echo "growth: {$endmem-$startmem}"
+   echo "kB/loop: {($endmem-$startmem)/10000}"
+ end
+end
+
+# check memleaks (set global)
+macro testmem4
+
+ $PASS = 1
+ local i N
+
+ list word -x "ps -p $PID -o rss"
+ $startmem = $word:1
+
+ output /dev/null
+ for i 0 10000
+   $N = word
+ end    
+ output stdout
+  
+ list word -x "ps -p $PID -o rss"
+ $endmem = $word:1
+
+ if ({$endmem - $startmem} > 10)
+   $PASS = 0
+   echo "growth: {$endmem-$startmem}"
+   echo "kB/loop: {($endmem-$startmem)/10000}"
+ end
+end
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/test/scan.sh
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/test/scan.sh	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/test/scan.sh	(revision 11389)
@@ -0,0 +1,117 @@
+list tests
+ test1
+ memtest1
+ memtest2
+end
+
+# Does scan work?
+macro test1
+ $PASS = 1
+ file test_file.txt fchk
+ if ($fchk)
+  exec rm test_file.txt
+ end
+ output test_file.txt
+ echo This
+ echo is
+ echo a
+ echo test
+ echo file
+ output stdout
+ scan test_file.txt fscan
+ if ("$fscan" != "This ")
+  $PASS = 0
+  echo "Default not working!"
+ end
+ scan test_file.txt fscan 4
+ if ("$fscan" != "test ")
+  $PASS = 0
+  echo "Scan failure!"
+ end
+ if ($PASS)
+  exec rm test_file.txt
+ end
+end
+
+# Memory test for scan (default)
+macro memtest1
+
+ file test_file.txt fchk
+ if ($fchk)
+  exec rm test_file.txt
+ end
+ output test_file.txt
+ echo This
+ echo is
+ echo a
+ echo test
+ echo file
+ output stdout
+
+ local i
+
+ list word -x "ps -p $PID -o rss"
+ $startmem = $word:1
+
+ for i 0 10000
+  scan test_file.txt fscan
+ end    
+  
+ list word -x "ps -p $PID -o rss"
+ $endmem = $word:1
+
+ $PASS = 1
+
+ if ($endmem - $startmem > 10)
+   $PASS = 0
+   echo "growth: {$endmem-$startmem}"
+   echo "kB/loop: {($endmem-$startmem)/10000}"
+ end
+
+ if ($PASS)
+  exec rm test_file.txt
+ end
+
+end
+
+
+# Memory test for scan (specified)
+macro memtest2
+
+ file test_file.txt fchk
+ if ($fchk)
+  exec rm test_file.txt
+ end
+ output test_file.txt
+ echo This
+ echo is
+ echo a
+ echo test
+ echo file
+ output stdout
+
+ local i
+
+ list word -x "ps -p $PID -o rss"
+ $startmem = $word:1
+
+ for i 0 10000
+  scan test_file.txt fscan 5
+ end    
+  
+ list word -x "ps -p $PID -o rss"
+ $endmem = $word:1
+
+ $PASS = 1
+
+ if ($endmem - $startmem > 10)
+   $PASS = 0
+   echo "growth: {$endmem-$startmem}"
+   echo "kB/loop: {($endmem-$startmem)/10000}"
+ end
+
+ if ($PASS)
+  exec rm test_file.txt
+ end
+
+end
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/test/shell.sh
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/test/shell.sh	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/test/shell.sh	(revision 11389)
@@ -0,0 +1,35 @@
+
+list tests
+ test1
+ test2
+end
+
+# test that a shell function works at all
+macro test1
+ $PASS = 1
+ exec touch foo.test
+ file foo.test exists
+ if ($exists != 1)
+   $PASS = 0
+ end
+ exec rm -f foo.test
+ file foo.test exists
+ if ($exists != 0)
+   $PASS = 0
+ end
+end
+
+# test that the shell status is returned
+macro test2
+ $PASS = 1
+ exec touch foo.test
+ exec ls foo.test >& /dev/null
+ if ($STATUS != 1)
+   $PASS = 0
+ end
+ exec rm -f foo.test
+ exec ls foo.test >& /dev/null
+ if ($STATUS != 0)
+   $PASS = 0
+ end
+end
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/test/sleep.sh
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/test/sleep.sh	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/test/sleep.sh	(revision 11389)
@@ -0,0 +1,25 @@
+list tests
+ test1
+end
+
+# Does sleep work?
+macro test1
+ $PASS = 1
+
+ list tstart -x "date +%S"
+
+ sleep 10
+
+ list tend -x "date +%S"
+
+ if ($tstart:0 >= 50)
+  $tend:0 = $tend:0 + 60
+ end
+
+ $diff = abs (10 - abs($tstart:0 - $tend:0))
+
+ if ($diff > 1.1)
+  $PASS = 0
+ end
+
+end
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/test/sprintf.sh
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/test/sprintf.sh	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/test/sprintf.sh	(revision 11389)
@@ -0,0 +1,43 @@
+list tests
+ test1
+ memtest1
+end
+
+# Does sprintf work?
+macro test1
+ $PASS = 1
+
+ local test_var
+
+ sprint test_var "%7s %5.2f %9.3e" float 34.5 12630000
+
+ if ("$test_var" != "  float 34.50 1.263e+07")
+  $PASS = 0
+ end
+
+end
+
+# Memory test
+macro memtest1
+
+ local i
+
+ list word -x "ps -p $PID -o rss"
+ $startmem = $word:1
+
+ for i 0 10000
+  sprint test_var "%7s %5.2f %9.3e" float 34.5 12630000
+ end    
+  
+ list word -x "ps -p $PID -o rss"
+ $endmem = $word:1
+
+ $PASS = 1
+
+ if ($endmem - $startmem > 10)
+   $PASS = 0
+   echo "growth: {$endmem-$startmem}"
+   echo "kB/loop: {($endmem-$startmem)/10000}"
+ end
+
+end
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/test/strlen.sh
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/test/strlen.sh	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/test/strlen.sh	(revision 11389)
@@ -0,0 +1,47 @@
+list tests
+ test1
+ memtest1
+end
+
+# Does strlen work?
+macro test1
+ 
+ $PASS = 1
+
+ $tstr = "Test string"
+
+ strlen $tstr len
+
+ if ($len != 11)
+  $PASS = 0
+  echo "Incorrect length: $len"
+ end
+
+end
+
+# Memory Test
+macro memtest1
+
+ local i
+
+ $tstr = "Test string"
+
+ list word -x "ps -p $PID -o rss"
+ $startmem = $word:1
+
+ for i 0 10000
+  strlen $tstr len
+ end    
+  
+ list word -x "ps -p $PID -o rss"
+ $endmem = $word:1
+
+ $PASS = 1
+
+ if ($endmem - $startmem > 10)
+   $PASS = 0
+   echo "growth: {$endmem-$startmem}"
+   echo "kB/loop: {($endmem-$startmem)/10000}"
+ end
+
+end
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/test/test.dat
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/test/test.dat	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/test/test.dat	(revision 11389)
@@ -0,0 +1,1 @@
+test     foobar
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/test/variable.sh
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/test/variable.sh	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/test/variable.sh	(revision 11389)
@@ -0,0 +1,504 @@
+
+list tests
+ test1
+ test2
+ test3
+ test4
+ test5
+ test6
+ test7
+ test8
+ test9
+ test10
+ test11
+ test12
+ test13
+ test14
+ testmem1
+ testmem2
+ testmem3
+ testmem4
+ testmem5
+ testmem6
+ testmem7
+ testmem8
+ testmem9
+ testmem10
+end
+
+# do we set variables correctly?
+macro test1
+
+ local i
+
+ $i = 99
+  
+ if ($i == 99)
+   $PASS = 1
+ else
+   $PASS = 0
+ end
+
+end
+
+# do math expressions assign the correct value (test2 -> test8)
+macro test2
+
+  local i
+
+  $i = 99 - 98
+  
+ if ($i == 1)
+   $PASS = 1
+ else
+   $PASS = 0
+   echo "i : $i"
+ end
+
+end
+
+macro test3
+
+  local i
+
+  $i = 2*3
+  
+ if ($i == 6)
+   $PASS = 1
+ else
+   $PASS = 0
+   echo "i: $i"
+ end
+
+end
+
+macro test4
+
+  local i
+
+  $i = 2^3
+
+ if ($i == 8)
+   $PASS = 1
+ else
+   $PASS = 0
+   echo "i: $i"
+ end
+
+end
+
+macro test5
+
+  local i
+
+  $i = 2+3
+
+ if ($i == 5)
+   $PASS = 1
+ else
+   $PASS = 0
+   echo "i: $i"
+ end
+
+end
+
+macro test6
+
+  local i
+
+  $i = 6/3
+
+ if ($i == 2)
+   $PASS = 1
+ else
+   $PASS = 0
+   echo "i: $i"
+ end
+
+end
+
+# testing operation priority
+macro test7
+
+  local i j
+
+  $i = 2 - 3*2
+  $j = 10/2*5+5
+
+ if (($i == -4) && ($j == 30))
+   $PASS = 1
+ else
+   $PASS = 0
+   echo "i: $i\ j: $j"
+ end
+
+end
+
+# testing math on negative numbers
+macro test8
+
+  local i
+
+  $i = -2 - -3
+
+ if ($i == 1)
+   $PASS = 1
+ else
+   $PASS = 0
+   echo "i: $i"
+ end
+
+end
+
+# testing the existance of variables
+macro test9
+
+  local i
+
+  $i = 0
+
+ if ($?i == 1)
+   $PASS = 1
+ else
+   $PASS = 0
+   echo "i: $i"
+ end
+end
+
+# test increment
+macro test10
+
+  local i N
+
+  $N = 0
+  for i 0 100
+    $N ++
+  end
+
+  if ($N == 100)
+   $PASS = 1
+  else
+   $PASS = 0
+   echo "N: $N"
+ end
+end
+
+# test decrement
+macro test11
+
+  local i N
+
+  $N = 100
+  for i 0 100
+    $N --
+  end
+
+  if ($N == 0)
+   $PASS = 1
+  else
+   $PASS = 0
+   echo "N: $N"
+ end
+end
+
+# test command assign
+macro test12
+
+  local i N
+
+  $N = `ls -dF /etc`
+
+  if ("$N" == "/etc/")
+   $PASS = 1
+  else
+   $PASS = 0
+   echo "N: $N"
+ end
+end
+
+# test vector assign
+macro test13
+
+  local i N
+
+  create v1 0 100
+  v1[5] = 10
+  set v2 = v1 + 20
+
+  if (v2[5] == 30)
+   $PASS = 1
+  else
+   $PASS = 0
+   echo "v1\[5\]: v1[5]"
+   echo "v2\[5\]: v2[5]"
+ end
+end
+
+# test local variables
+macro test14
+
+ $PASS = 1
+
+ if (($?i == 1) || ($?N == 1))
+  $PASS = 0
+ end
+end
+
+# check memleaks (set global)
+macro testmem1
+
+ local i
+
+ list word -x "ps -p $PID -o rss"
+ $startmem = $word:1
+
+ for i 0 10000
+   $Nvar = 10
+ end    
+  
+ list word -x "ps -p $PID -o rss"
+ $endmem = $word:1
+
+ if ({$endmem - $startmem} < 10)
+   $PASS = 1
+ else
+   $PASS = 0
+   echo "growth: {$endmem-$startmem}"
+   echo "kB/loop: {($endmem-$startmem)/10000}"
+ end
+end
+
+# check memleaks (set string)
+macro testmem2
+
+ local i
+
+ list word -x "ps -p $PID -o rss"
+ $startmem = $word:1
+
+ output /dev/null
+ for i 0 10000
+   $Nvar = test line
+ end    
+ output stdout
+  
+ list word -x "ps -p $PID -o rss"
+ $endmem = $word:1
+
+ if ({$endmem - $startmem} < 10)
+   $PASS = 1
+ else
+   $PASS = 0
+   echo "growth: {$endmem-$startmem}"
+   echo "kB/loop: {($endmem-$startmem)/10000}"
+ end
+end
+
+# check memleaks (set double)
+macro testmem3
+
+ local i
+
+ list word -x "ps -p $PID -o rss"
+ $startmem = $word:1
+
+ for i 0 10000
+   $Nvar = 5.212
+ end    
+  
+ list word -x "ps -p $PID -o rss"
+ $endmem = $word:1
+
+ if ({$endmem - $startmem} < 10)
+   $PASS = 1
+ else
+   $PASS = 0
+   echo "growth: {$endmem-$startmem}"
+   echo "kB/loop: {($endmem-$startmem)/10000}"
+ end
+end
+
+# check memleaks (set local)
+macro testmem4
+
+ local i N
+
+ list word -x "ps -p $PID -o rss"
+ $startmem = $word:1
+
+ for i 0 10000
+   $N = 10
+ end    
+  
+ list word -x "ps -p $PID -o rss"
+ $endmem = $word:1
+
+ if ({$endmem - $startmem} < 10)
+   $PASS = 1
+ else
+   $PASS = 0
+   echo "growth: {$endmem-$startmem}"
+   echo "kB/loop: {($endmem-$startmem)/10000}"
+ end
+end
+
+# check memleaks (existence)
+macro testmem5
+
+ local i N
+
+ list word -x "ps -p $PID -o rss"
+ $startmem = $word:1
+
+ output /dev/null
+ for i 0 10000
+   echo $?N
+ end    
+ output stdout
+  
+ list word -x "ps -p $PID -o rss"
+ $endmem = $word:1
+
+ if ({$endmem - $startmem} < 10)
+   $PASS = 1
+ else
+   $PASS = 0
+   echo "growth: {$endmem-$startmem}"
+   echo "kB/loop: {($endmem-$startmem)/10000}"
+ end
+end
+
+# check memleaks (get variable)
+macro testmem6
+
+ local i
+
+ list word -x "ps -p $PID -o rss"
+ $startmem = $word:1
+
+ $Nvar = 5
+ output /dev/null
+ for i 0 10000
+   echo $Nvar
+ end    
+ output stdout
+  
+ list word -x "ps -p $PID -o rss"
+ $endmem = $word:1
+
+ if ({$endmem - $startmem} < 10)
+   $PASS = 1
+ else
+   $PASS = 0
+   echo "growth: {$endmem-$startmem}"
+   echo "kB/loop: {($endmem-$startmem)/10000}"
+ end
+end
+
+# check memleaks (increment)
+macro testmem7
+
+ local i
+
+ list word -x "ps -p $PID -o rss"
+ $startmem = $word:1
+
+ $Nvar = 0
+ output /dev/null
+ for i 0 10000
+   $Nvar ++
+ end    
+ output stdout
+  
+ list word -x "ps -p $PID -o rss"
+ $endmem = $word:1
+
+ if ({$endmem - $startmem} < 10)
+   $PASS = 1
+ else
+   $PASS = 0
+   echo "growth: {$endmem-$startmem}"
+   echo "kB/loop: {($endmem-$startmem)/10000}"
+ end
+end
+
+# check memleaks (decrement)
+macro testmem8
+
+ local i
+
+ list word -x "ps -p $PID -o rss"
+ $startmem = $word:1
+
+ $Nvar = 10000
+ output /dev/null
+ for i 0 10000
+   $Nvar --
+ end    
+ output stdout
+  
+ list word -x "ps -p $PID -o rss"
+ $endmem = $word:1
+
+ if ({$endmem - $startmem} < 10)
+   $PASS = 1
+ else
+   $PASS = 0
+   echo "growth: {$endmem-$startmem}"
+   echo "kB/loop: {($endmem-$startmem)/10000}"
+ end
+end
+
+# check memleaks (command)
+macro testmem9
+
+ local i
+
+ list word -x "ps -p $PID -o rss"
+ $startmem = $word:1
+
+ output /dev/null
+ for i 0 100
+   $Nvar = `ls -d /etc`
+ end    
+ output stdout
+  
+ list word -x "ps -p $PID -o rss"
+ $endmem = $word:1
+
+ if ({$endmem - $startmem} < 10)
+   $PASS = 1
+ else
+   $PASS = 0
+   echo "growth: {$endmem-$startmem}"
+   echo "kB/loop: {($endmem-$startmem)/100}"
+ end
+end
+
+# check memleaks (vector assign)
+macro testmem10
+
+ local i
+
+ create v1 0 100
+
+ list word -x "ps -p $PID -o rss"
+ $startmem = $word:1
+
+ output /dev/null
+ for i 0 10000
+   v1[5] = $i
+ end    
+ output stdout
+  
+ list word -x "ps -p $PID -o rss"
+ $endmem = $word:1
+
+ if ({$endmem - $startmem} < 10)
+   $PASS = 1
+ else
+   $PASS = 0
+   echo "growth: {$endmem-$startmem}"
+   echo "kB/loop: {($endmem-$startmem)/10000}"
+ end
+end
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/test/while.sh
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/test/while.sh	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/test/while.sh	(revision 11389)
@@ -0,0 +1,18 @@
+list tests
+ test1
+end
+
+# Does while work?
+macro test1
+ $PASS = 1
+ local i
+ $i = 0
+ while ($i <= 10)
+  if ($i == 11)
+   $PASS = 0
+   echo "While loop failure!"
+   break
+  end
+  $i++
+ end
+end
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/usleep.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/usleep.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/usleep.c	(revision 11389)
@@ -0,0 +1,15 @@
+# include "basic.h"
+
+int exec_usleep (int argc, char **argv) {
+
+  int i;
+
+  if (argc < 2) {
+    gprint (GP_ERR, "usage: usleep N\n");
+    return (FALSE);
+  }
+
+  i = atof (argv[1]);
+  usleep (i);
+  return (TRUE);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/wait.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/wait.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/wait.c	(revision 11389)
@@ -0,0 +1,14 @@
+# include "basic.h"
+
+int wait_func (int argc, char **argv) {
+
+  char buff[1024];
+  int i;
+
+  for (i = 1; i < argc; i++) {
+    gprint (GP_ERR, "%s ", argv[i]);
+  }
+  gprint (GP_ERR, "\n");
+  scan_line (stdin, buff);
+  return (TRUE);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/which.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/which.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.basic/which.c	(revision 11389)
@@ -0,0 +1,18 @@
+# include "basic.h"
+
+int which (int argc, char **argv) {
+
+  Command *cmd;
+ 
+  if (argc != 2) {
+    gprint (GP_ERR, "USAGE: which <filename>\n");
+    return (FALSE);
+  }
+
+  cmd = MatchCommand (argv[1], TRUE, TRUE);
+  if (cmd == NULL) return (FALSE);
+
+  gprint (GP_ERR, "%-25s -- %s\n", cmd[0].name, cmd[0].help);
+  return (TRUE);
+
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/Makefile
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/Makefile	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/Makefile	(revision 11389)
@@ -0,0 +1,142 @@
+include ../../../Configure
+
+HOME    =       $(ROOT)/src/opihi
+SRC     =       $(HOME)/cmd.data
+BIN     =       $(HOME)/bin
+LIB     =       $(HOME)/lib
+INC     =       $(HOME)/include
+DATA    =       $(DESTDATA)/mana
+
+# data user commands ########################
+srcs = \
+$(SRC)/init.$(ARCH).o          \
+$(SRC)/accum.$(ARCH).o		\
+$(SRC)/applyfit2d.$(ARCH).o	\
+$(SRC)/applyfit.$(ARCH).o	\
+$(SRC)/box.$(ARCH).o		\
+$(SRC)/book.$(ARCH).o		\
+$(SRC)/book_commands.$(ARCH).o	\
+$(SRC)/center.$(ARCH).o	\
+$(SRC)/clear.$(ARCH).o		\
+$(SRC)/clip.$(ARCH).o		\
+$(SRC)/close.$(ARCH).o		\
+$(SRC)/concat.$(ARCH).o	\
+$(SRC)/contour.$(ARCH).o	\
+$(SRC)/create.$(ARCH).o	\
+$(SRC)/cumulative.$(ARCH).o	\
+$(SRC)/cursor.$(ARCH).o	\
+$(SRC)/cut.$(ARCH).o		\
+$(SRC)/delete.$(ARCH).o	\
+$(SRC)/device.$(ARCH).o	\
+$(SRC)/dimendown.$(ARCH).o	\
+$(SRC)/dimenup.$(ARCH).o	\
+$(SRC)/erase.$(ARCH).o		\
+$(SRC)/extract.$(ARCH).o	\
+$(SRC)/fft1d.$(ARCH).o		\
+$(SRC)/fft2d.$(ARCH).o		\
+$(SRC)/fit2d.$(ARCH).o		\
+$(SRC)/fit.$(ARCH).o		\
+$(SRC)/gaussj.$(ARCH).o	\
+$(SRC)/gaussdeviate.$(ARCH).o	\
+$(SRC)/grid.$(ARCH).o		\
+$(SRC)/gridify.$(ARCH).o       \
+$(SRC)/ungridify.$(ARCH).o     \
+$(SRC)/histogram.$(ARCH).o	\
+$(SRC)/imcut.$(ARCH).o	 	\
+$(SRC)/imhist.$(ARCH).o	\
+$(SRC)/imsmooth.$(ARCH).o	\
+$(SRC)/integrate.$(ARCH).o	\
+$(SRC)/interpolate.$(ARCH).o	\
+$(SRC)/jpeg.$(ARCH).o		\
+$(SRC)/kern.$(ARCH).o		\
+$(SRC)/keyword.$(ARCH).o	\
+$(SRC)/labels.$(ARCH).o	\
+$(SRC)/limits.$(ARCH).o	\
+$(SRC)/line.$(ARCH).o		\
+$(SRC)/list_buffers.$(ARCH).o	\
+$(SRC)/list_header.$(ARCH).o	\
+$(SRC)/list_vectors.$(ARCH).o	\
+$(SRC)/load.$(ARCH).o		\
+$(SRC)/lookup.$(ARCH).o	\
+$(SRC)/mkrgb.$(ARCH).o	\
+$(SRC)/mcreate.$(ARCH).o	\
+$(SRC)/medacc.$(ARCH).o	\
+$(SRC)/mget.$(ARCH).o		\
+$(SRC)/minterpolate.$(ARCH).o	\
+$(SRC)/mset.$(ARCH).o		\
+$(SRC)/peak.$(ARCH).o		\
+$(SRC)/periodogram.$(ARCH).o	\
+$(SRC)/plot.$(ARCH).o		\
+$(SRC)/dot.$(ARCH).o		\
+$(SRC)/point.$(ARCH).o		\
+$(SRC)/ps.$(ARCH).o		\
+$(SRC)/queuedelete.$(ARCH).o	\
+$(SRC)/queuedrop.$(ARCH).o	\
+$(SRC)/queuelist.$(ARCH).o	\
+$(SRC)/queueload.$(ARCH).o	\
+$(SRC)/queuesize.$(ARCH).o	\
+$(SRC)/queuepush.$(ARCH).o	\
+$(SRC)/queuepop.$(ARCH).o	\
+$(SRC)/queueprint.$(ARCH).o	\
+$(SRC)/queueinit.$(ARCH).o	\
+$(SRC)/radial.$(ARCH).o	\
+$(SRC)/rd.$(ARCH).o		\
+$(SRC)/rdseg.$(ARCH).o		\
+$(SRC)/read_vectors.$(ARCH).o	\
+$(SRC)/rebin.$(ARCH).o		\
+$(SRC)/resize.$(ARCH).o	\
+$(SRC)/roll.$(ARCH).o		\
+$(SRC)/rotate.$(ARCH).o	\
+$(SRC)/save.$(ARCH).o		\
+$(SRC)/section.$(ARCH).o	\
+$(SRC)/select.$(ARCH).o	\
+$(SRC)/set.$(ARCH).o		\
+$(SRC)/shift.$(ARCH).o		\
+$(SRC)/sort.$(ARCH).o		\
+$(SRC)/spline_apply.$(ARCH).o	\
+$(SRC)/spline_construct.$(ARCH).o \
+$(SRC)/stats.$(ARCH).o		   \
+$(SRC)/style.$(ARCH).o		   \
+$(SRC)/subraster.$(ARCH).o	   \
+$(SRC)/subset.$(ARCH).o	   \
+$(SRC)/svd.$(ARCH).o		   \
+$(SRC)/swapbytes.$(ARCH).o	   \
+$(SRC)/textline.$(ARCH).o	   \
+$(SRC)/tv.$(ARCH).o		   \
+$(SRC)/tvcontour.$(ARCH).o	   \
+$(SRC)/tvgrid.$(ARCH).o	   \
+$(SRC)/uniq.$(ARCH).o		   \
+$(SRC)/unsign.$(ARCH).o	   \
+$(SRC)/vbin.$(ARCH).o		   \
+$(SRC)/vclip.$(ARCH).o		   \
+$(SRC)/vgauss.$(ARCH).o           \
+$(SRC)/vmaxwell.$(ARCH).o           \
+$(SRC)/vgrid.$(ARCH).o		   \
+$(SRC)/vload.$(ARCH).o		   \
+$(SRC)/vpop.$(ARCH).o		   \
+$(SRC)/vroll.$(ARCH).o		   \
+$(SRC)/vsmooth.$(ARCH).o	\
+$(SRC)/vstat.$(ARCH).o		   \
+$(SRC)/wd.$(ARCH).o		   \
+$(SRC)/write_vectors.$(ARCH).o	   \
+$(SRC)/zap.$(ARCH).o		   \
+$(SRC)/zplot.$(ARCH).o
+
+# dependancy rules for include files ########################
+incs = \
+$(INC)/opihi.h \
+$(INC)/external.h \
+$(INC)/shell.h \
+$(INC)/dvomath.h \
+$(INC)/convert.h \
+$(INC)/display.h 
+
+libdatacmd: $(DESTLIB)/libdatacmd.a 
+$(DESTLIB)/libdatacmd.a: $(LIB)/libdatacmd.$(ARCH).a
+$(LIB)/libdatacmd.$(ARCH).a: $(srcs)
+$(srcs): $(incs)
+
+uninstall:
+	rm -f $(DESTLIB)/libdatacmd.a
+
+include ../Makefile.Common
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/accum.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/accum.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/accum.c	(revision 11389)
@@ -0,0 +1,74 @@
+# include "data.h"
+
+int accum (int argc, char **argv) {
+  
+  int i, Nbins, bin, N, Normalize;
+  float start, end, delta;
+  float *V, *K, *O, *NV;
+  Vector *val, *key, *out;
+
+  NV = NULL;
+  Normalize = FALSE;
+  if ((N = get_argument (argc, argv, "-norm"))) {
+    remove_argument (N, &argc, argv);
+    Normalize = TRUE;
+  }
+
+  if ((argc != 6) && (argc != 7)) {
+    gprint (GP_ERR, "USAGE: accum <value> <vector> <key> start end [delta]\n");
+    gprint (GP_ERR, "  sum <value> in bins corresponding to the value of <key>\n");
+    return (FALSE);
+  }
+
+  if ((val = SelectVector (argv[1], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((key = SelectVector (argv[3], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if (val[0].Nelements != key[0].Nelements) {
+    gprint (GP_ERR, "key and value don't match\n");
+    return (FALSE);
+  }
+  if ((out = SelectVector (argv[2], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+
+  start = atof (argv[4]);
+  end   = atof (argv[5]);
+  if (argc == 7) 
+    delta = atof (argv[6]);
+  else 
+    delta = 1;
+  if ((start == end) || (delta == 0)) {
+    gprint (GP_ERR, "error in value: %f to %f, %f\n", start, end, delta);
+    return (FALSE);
+  }
+  delta = fabs (delta);
+  if (end - start < 0) {
+    delta = -1.0 * delta;
+  }
+  Nbins = (end - start) / delta;
+
+  out[0].Nelements = Nbins;
+  REALLOCATE (out[0].elements, float, out[0].Nelements);
+  bzero (out[0].elements, sizeof(float)*out[0].Nelements);
+  if (Normalize) {
+    ALLOCATE (NV, float, Nbins);
+    bzero (NV, sizeof(float)*Nbins);
+  }
+
+  V = val[0].elements;
+  K = key[0].elements;
+  O = out[0].elements;
+
+  for (i = 0; i < val[0].Nelements; i++, V++, K++) {
+    bin = MIN (MAX (0, (*K - start) / delta), Nbins - 1);
+    O[bin] += *V;
+    if (Normalize) NV[bin] ++;
+  }      
+
+  if (Normalize) {
+    for (i = 0; i < Nbins; i++) {
+      O[i] /= (float) NV[i];
+    }
+    free (NV);
+  }
+
+  return (TRUE);
+}
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/applyfit.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/applyfit.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/applyfit.c	(revision 11389)
@@ -0,0 +1,58 @@
+# include "data.h"
+
+char *get_variable (char *);
+
+int applyfit (int argc, char **argv) {
+  
+  int i, j, order;
+  char *c, name[64];
+  double *C, X;
+  float *x, *y;
+  Vector *xvec, *yvec;
+
+  if (argc != 3) {
+    gprint (GP_ERR, "USAGE: applyfit x y\n");
+    return (FALSE);
+  }
+
+  c = get_variable ("Cn");
+  if (c == (char *) NULL) {
+    gprint (GP_ERR, "no fit available\n");
+    return (FALSE);
+  }
+  order = atof (c);
+
+  if ((xvec = SelectVector (argv[1], OLDVECTOR, TRUE)) == NULL) return (FALSE);    
+  if ((yvec = SelectVector (argv[2], ANYVECTOR, TRUE)) == NULL) return (FALSE);    
+
+  ALLOCATE (C, double, order+1);
+  for (i = 0; i < order + 1; i++) {
+    sprintf (name, "C%d", i);
+    c = get_variable (name);
+    if (c == (char *) NULL) {
+      gprint (GP_ERR, "missing fit term %d\n", i);
+      return (FALSE);
+    }
+    C[i] = atof (c);
+  }
+  yvec[0].Nelements = xvec[0].Nelements;
+  REALLOCATE (yvec[0].elements, float, yvec[0].Nelements);
+  bzero (yvec[0].elements, sizeof(float)*yvec[0].Nelements);
+  x = xvec[0].elements;
+  y = yvec[0].elements;
+
+  for (j = 0; j < xvec[0].Nelements; j++, x++, y++) {
+    X = 1;
+    for (i = 0; i < order + 1; i++) {
+      *y += C[i]*X;
+      X = X * (*x);
+    }
+  }
+
+  return (TRUE);
+
+}
+
+
+
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/applyfit2d.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/applyfit2d.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/applyfit2d.c	(revision 11389)
@@ -0,0 +1,68 @@
+# include "data.h"
+
+char *get_variable (char *);
+
+int applyfit2d (int argc, char **argv) {
+  
+  int i, j, n, order;
+  char *c, name[64];
+  double **C, X, Y;
+  float *x, *y, *z;
+  Vector *xvec, *yvec, *zvec;
+
+  if (argc != 4) {
+    gprint (GP_ERR, "USAGE: applyfit x y z\n");
+    return (FALSE);
+  }
+
+  c = get_variable ("Cnn");
+  if (c == (char *) NULL) {
+    gprint (GP_ERR, "no fit available\n");
+    return (FALSE);
+  }
+  order = atof (c);
+
+  if ((xvec = SelectVector (argv[1], OLDVECTOR, TRUE)) == NULL) return (FALSE);    
+  if ((yvec = SelectVector (argv[2], OLDVECTOR, TRUE)) == NULL) return (FALSE);    
+  if ((zvec = SelectVector (argv[3], ANYVECTOR, TRUE)) == NULL) return (FALSE);    
+
+  ALLOCATE (C, double *, order+1);
+  for (i = 0; i < order + 1; i++) {
+    ALLOCATE (C[i], double, order+1);
+    for (j = 0; j < order + 1 - i; j++) {
+      sprintf (name, "CX%dY%d", i, j);
+      c = get_variable (name);
+      if (c == (char *) NULL) {
+	gprint (GP_ERR, "missing fit term %d,%d\n", i, j);
+	return (FALSE);
+      }
+      C[i][j] = atof (c);
+    }
+  }
+
+  zvec[0].Nelements = xvec[0].Nelements;
+  REALLOCATE (zvec[0].elements, float, zvec[0].Nelements);
+  bzero (zvec[0].elements, sizeof(float)*zvec[0].Nelements);
+  x = xvec[0].elements;
+  y = yvec[0].elements;
+  z = zvec[0].elements;
+
+  for (n = 0; n < xvec[0].Nelements; n++, x++, y++, z++) {
+    Y = X = 1;
+    for (j = 0; j < order + 1; j++) {
+      X = Y;
+      for (i = 0; i < order + 1 - j; i++) {
+	*z += C[i][j]*X;
+	X = X * (*x);
+      }
+      Y = Y * (*y);
+    }
+  }
+
+  return (TRUE);
+
+}
+
+
+
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/book.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/book.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/book.c	(revision 11389)
@@ -0,0 +1,80 @@
+# include "data.h"
+
+int book_list (int argc, char **argv);
+int book_init (int argc, char **argv);
+int book_create (int argc, char **argv);
+int book_delete (int argc, char **argv);
+int book_getbook (int argc, char **argv);
+int book_listbook (int argc, char **argv);
+int book_npages (int argc, char **argv);
+int book_newpage (int argc, char **argv);
+int book_getpage (int argc, char **argv);
+int book_delpage (int argc, char **argv);
+int book_listpage (int argc, char **argv);
+int book_setword (int argc, char **argv);
+int book_getword (int argc, char **argv);
+
+static Command book_commands[] = {
+  {"list",     book_list,     "list books"},
+  {"init",     book_init,     "initialize a book"},
+  {"create",   book_create,   "create a book"},
+  {"delete",   book_delete,   "delete a book"},
+  {"getbook",  book_getbook,  "get book name by location"},
+  {"listbook", book_listbook, "list pages in a book"},
+  {"npages",   book_npages,   "return number of pages in a book"},
+  {"newpage",  book_newpage,  "create a new page in a book"},
+  {"getpage",  book_getpage,  "get page name by location"},
+  {"delpage",  book_delpage,  "delete a page in a book"},
+  {"listpage", book_listpage, "list a page in a book"},
+  {"setword",  book_setword,  "set the value of a word in a page"},
+  {"getword",  book_getword,  "set the value of a word from a page"},
+};
+
+int book_command (int argc, char **argv) {
+
+  int i, N, status;
+
+  if (argc < 2) {
+    gprint (GP_ERR, "USAGE: book (command)\n");
+    gprint (GP_ERR, "    book list             			: list books\n");
+    gprint (GP_ERR, "    book init     (book)   		: removes all pages from book\n");
+    gprint (GP_ERR, "    book create   (book)   		: create a book\n");
+    gprint (GP_ERR, "    book delete   (book)                   : delete a book\n");
+    gprint (GP_ERR, "    book getbook  (where)  		: get book name\n");
+    gprint (GP_ERR, "    book listbook (book)    		: list a book\n");
+    gprint (GP_ERR, "    book npages   (book)   		: return number of pages in a book\n");
+    gprint (GP_ERR, "    book newpage  (book) (page)  		: create a new page in a book\n");
+    gprint (GP_ERR, "    book getpage  (book) (where)  		: get page name in a book\n");
+    gprint (GP_ERR, "    book delpage  (book) (page)  		: delete a page in a book\n");
+    gprint (GP_ERR, "    book listpage (book) (page)  		: list a page in a book\n");
+    gprint (GP_ERR, "    book setword  (book) (page) (word) (value)  : set the value of a word in a page\n");
+    gprint (GP_ERR, "    book getword  (book) (page) (word) [-var var] : set the value of a word from a page\n");
+    return (FALSE);
+  }
+
+  N = sizeof (book_commands) / sizeof (Command);
+
+  /* find the book sub-command which matches */
+  for (i = 0; i < N; i++) {
+    if (!strcmp (book_commands[i].name, argv[1])) {
+      status = (*book_commands[i].func) (argc - 1, argv + 1);
+      return (status);
+    }
+  }
+
+  gprint (GP_ERR, "unknown book command %s\n", argv[1]);
+  return (FALSE);
+}
+
+/* book is called with the command "book".  
+   the command line word "book" is meant to be followed the one of several 
+   possible options:
+   
+   book create
+   book delete
+   book list
+   book edit
+   book read
+   book write
+
+*/
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/book_commands.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/book_commands.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/book_commands.c	(revision 11389)
@@ -0,0 +1,400 @@
+# include "data.h"
+
+int book_list (int argc, char **argv) {
+  if (argc != 1) {
+    gprint (GP_ERR, "USAGE: book list\n");
+    return FALSE;
+  }
+
+  ListBooks();
+}
+
+int book_create (int argc, char **argv) {
+  if (argc != 2) {
+    gprint (GP_ERR, "USAGE: book create (book)\n");
+    return FALSE;
+  }
+
+  CreateBook (argv[1]);
+  return TRUE;
+}
+
+int book_delete (int argc, char **argv) {
+
+  int status;
+  Book *book;
+
+  if (argc != 2) {
+    gprint (GP_ERR, "USAGE: book delete (book)\n");
+    return FALSE;
+  }
+
+  book = FindBook (argv[1]);
+  if (book == NULL) {
+    gprint (GP_ERR, "book %s not found\n", argv[1]);
+    return FALSE;
+  }
+
+  status = DeleteBook (book);
+  if (!status) abort ();
+  return TRUE;
+}
+
+int book_init (int argc, char **argv) {
+
+  int status;
+  Book *book;
+
+  if (argc != 2) {
+    gprint (GP_ERR, "USAGE: book init (book)\n");
+    return FALSE;
+  }
+
+  book = FindBook (argv[1]);
+  if (book != NULL) {
+      status = DeleteBook (book);
+      if (!status) abort ();
+  }
+
+  CreateBook (argv[1]);
+  return TRUE;
+}
+
+int book_listbook (int argc, char **argv) {
+
+  int status;
+  Book *book;
+
+  if (argc != 2) {
+    gprint (GP_ERR, "USAGE: book listbook (book)\n");
+    return FALSE;
+  }
+
+  book = FindBook (argv[1]);
+  if (book == NULL) {
+    gprint (GP_ERR, "book %s not found\n", argv[1]);
+    return FALSE;
+  }
+
+  ListPages (book);
+  return TRUE;
+}
+
+int book_npages (int argc, char **argv) {
+
+  int N, status;
+  Book *book;
+  char *varName;
+
+  varName = NULL;
+  if ((N = get_argument (argc, argv, "-var"))) {
+    remove_argument (N, &argc, argv);
+    varName = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 2) {
+    gprint (GP_ERR, "USAGE: book npages (book)\n");
+    FREE (varName);
+    return FALSE;
+  }
+
+  book = FindBook (argv[1]);
+  if (book == NULL) {
+    gprint (GP_ERR, "book %s not found\n", argv[1]);
+    FREE (varName);
+    return FALSE;
+  }
+
+  if (varName) {
+    set_int_variable (varName, book[0].Npages);
+  } else {
+    gprint (GP_ERR, "%d pages\n", book[0].Npages);
+  }
+  FREE (varName);
+  return TRUE;
+}
+
+int book_getbook (int argc, char **argv) {
+
+  int where, N;
+  char *varName;
+  Book *book;
+
+  varName = NULL;
+  if ((N = get_argument (argc, argv, "-var"))) {
+    remove_argument (N, &argc, argv);
+    varName = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 2) {
+    gprint (GP_ERR, "USAGE: book getbook (where) [-var var]\n");
+    FREE (varName);
+    return FALSE;
+  }
+
+  where = atoi (argv[1]);
+  book = GetBook (where);
+  if (book == NULL) {
+    gprint (GP_ERR, "book %s not found\n", argv[1]);
+    FREE (varName);
+    return FALSE;
+  }
+
+  if (varName) {
+    set_str_variable (varName, book[0].name);
+  } else {
+    gprint (GP_ERR, "%s\n", book[0].name);
+  }
+  FREE (varName);
+  return TRUE;
+}
+
+int book_newpage (int argc, char **argv) {
+
+  Book *book;
+
+  if (argc != 3) {
+    gprint (GP_ERR, "USAGE: book newpage (book) (page)\n");
+    return FALSE;
+  }
+
+  book = FindBook (argv[1]);
+  if (book == NULL) {
+    gprint (GP_ERR, "book %s not found\n", argv[1]);
+    return FALSE;
+  }
+  
+  CreatePage (book, argv[2]);
+  return TRUE;
+}
+
+int book_delpage (int argc, char **argv) {
+
+  int i, N;
+  Page *page;
+  Book *book;
+  char *Key, *Value, *value;
+
+  Key = NULL;
+  Value = NULL;
+  if ((N = get_argument (argc, argv, "-key"))) {
+    remove_argument (N, &argc, argv);
+    Key = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+    Value = strcreate (argv[N]);
+  }
+
+  if ((argc != 3) && (argc != 2)) {
+    gprint (GP_ERR, "USAGE: book delpage (book) (page)\n");
+    gprint (GP_ERR, "USAGE: book delpage (book) -key name value\n");
+    FREE (Key);
+    FREE (Value);
+    return FALSE;
+  }
+
+  book = FindBook (argv[1]);
+  if (book == NULL) {
+    gprint (GP_ERR, "book %s not found\n", argv[1]);
+    FREE (Key);
+    FREE (Value);
+    return FALSE;
+  }
+  
+  if (Key) {
+    /* delete by matching key */
+    for (i = 0; i < book[0].Npages; i++) {
+      value = BookGetWord (book[0].pages[i], Key);
+      if (value == NULL) continue;
+      if (!strcmp(value, Value)) {
+	DeletePage (book, book[0].pages[i]);
+	i--; /* if we delete this page, don't advance the counter */
+      }
+    }
+    FREE (Key);
+    FREE (Value);
+    return TRUE;
+  }
+
+  page = FindPage (book, argv[2]);
+  if (page == NULL) {
+    gprint (GP_ERR, "page %s in book %s not found\n", argv[2], argv[1]);
+    FREE (Key);
+    FREE (Value);
+    return FALSE;
+  }
+
+  DeletePage (book, page);
+  FREE (Key);
+  FREE (Value);
+  return TRUE;
+}
+
+int book_listpage (int argc, char **argv) {
+
+  Page *page;
+  Book *book;
+
+  if (argc != 3) {
+    gprint (GP_ERR, "USAGE: book listpage (book) (page)\n");
+    return FALSE;
+  }
+
+  book = FindBook (argv[1]);
+  if (book == NULL) {
+    gprint (GP_ERR, "book %s not found\n", argv[1]);
+    return FALSE;
+  }
+  
+  page = FindPage (book, argv[2]);
+  if (page == NULL) {
+    gprint (GP_ERR, "page %s in book %s not found\n", argv[2], argv[1]);
+    return FALSE;
+  }
+
+  ListWords (page);
+  return TRUE;
+}
+
+int book_getpage (int argc, char **argv) {
+
+  int where, N;
+  char *pageName, *varName, *keyName, *keyValue;
+  Book *book;
+  Page *page;
+
+  varName = NULL;
+  if ((N = get_argument (argc, argv, "-var"))) {
+    remove_argument (N, &argc, argv);
+    varName = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  keyValue = keyName = NULL;
+  if ((N = get_argument (argc, argv, "-key"))) {
+    remove_argument (N, &argc, argv);
+    keyName = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+    keyValue = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 3) {
+    gprint (GP_ERR, "USAGE: book getpage (book) (where) [-var var] [-key key value]\n");
+    FREE (varName);
+    FREE (keyName);
+    FREE (keyValue);
+    return FALSE;
+  }
+
+  where = atoi (argv[2]);
+
+  book = FindBook (argv[1]);
+  if (book == NULL) {
+    gprint (GP_ERR, "book %s not found\n", argv[1]);
+    FREE (varName);
+    FREE (keyName);
+    FREE (keyValue);
+    return FALSE;
+  }
+
+  if (keyName == NULL) {
+    page = GetPage (book, where);
+  } else {
+    page = GetPageRestricted (book, where, keyName, keyValue);
+  }
+  if (page == NULL) {
+    pageName = strcreate ("NULL");
+  } else {
+    pageName = strcreate (page[0].name);
+  }
+
+  if (varName) {
+    set_str_variable (varName, pageName);
+  } else {
+    gprint (GP_ERR, "%s\n", pageName);
+  }
+  FREE (pageName);
+  FREE (varName);
+  FREE (keyName);
+  FREE (keyValue);
+  return TRUE;
+}
+
+int book_setword (int argc, char **argv) {
+
+  Page *page;
+  Book *book;
+
+  if (argc != 5) {
+    gprint (GP_ERR, "USAGE: book setword (book) (page) (word) (value)\n");
+    return FALSE;
+  }
+
+  book = FindBook (argv[1]);
+  if (book == NULL) {
+    gprint (GP_ERR, "book %s not found\n", argv[1]);
+    return FALSE;
+  }
+  
+  page = FindPage (book, argv[2]);
+  if (page == NULL) {
+    gprint (GP_ERR, "page %s in book %s not found\n", argv[2], argv[1]);
+    return FALSE;
+  }
+
+  BookSetWord (page, argv[3], argv[4]);
+  return TRUE;
+}
+
+int book_getword (int argc, char **argv) {
+
+  int N;
+  Page *page;
+  Book *book;
+  char *value, *varName;
+
+  varName = NULL;
+  if ((N = get_argument (argc, argv, "-var"))) {
+    remove_argument (N, &argc, argv);
+    varName = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 4) {
+    gprint (GP_ERR, "USAGE: book newword (book) (page) (word)\n");
+    FREE (varName);
+    return FALSE;
+  }
+
+  book = FindBook (argv[1]);
+  if (book == NULL) {
+    gprint (GP_ERR, "book %s not found\n", argv[1]);
+    FREE (varName);
+    return FALSE;
+  }
+  
+  page = FindPage (book, argv[2]);
+  if (page == NULL) {
+    gprint (GP_ERR, "page %s in book %s not found\n", argv[2], argv[1]);
+    FREE (varName);
+    return FALSE;
+  }
+
+  value = BookGetWord (page, argv[3]);
+  if (value == NULL) {
+    gprint (GP_ERR, "value %s on page %s in book %s not found\n", argv[3], argv[2], argv[1]);
+    FREE (varName);
+    return FALSE;
+  }
+
+  if (varName) {
+    set_str_variable (varName, value);
+  } else {
+    gprint (GP_ERR, "%s\n", value);
+  }
+    
+  FREE (varName);
+  return TRUE;
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/box.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/box.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/box.c	(revision 11389)
@@ -0,0 +1,89 @@
+# include "data.h"
+
+int box (int argc, char **argv) {
+  
+  int i, N, Ngraph, Xgraph;
+  Graphdata graphmode;
+  
+  Ngraph = -1;
+  if ((N = get_argument (argc, argv, "-n"))) {
+    remove_argument (N, &argc, argv);
+    Ngraph = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if (!GetGraph (&graphmode, &Xgraph, &Ngraph)) return (FALSE);
+
+  strcpy (graphmode.ticks, "2222");
+  if ((N = get_argument (argc, argv, "-ticks"))) {
+    remove_argument (N, &argc, argv);
+    strcpy (graphmode.ticks, argv[N]);
+    remove_argument (N, &argc, argv);
+    if (strlen (graphmode.ticks) != 4) { goto usage; }
+    for (i = 0; i < strlen (graphmode.ticks); i++) {
+      if ((graphmode.ticks[i] != '0') && (graphmode.ticks[i] != '1') && (graphmode.ticks[i] != '2')) { goto usage; }
+    }
+  }
+  
+  strcpy (graphmode.labels, "2222");
+  if ((N = get_argument (argc, argv, "-labels"))) {
+    remove_argument (N, &argc, argv);
+    strcpy (graphmode.labels, argv[N]);
+    remove_argument (N, &argc, argv);
+    if (strlen (graphmode.labels) != 4) { goto usage; }
+    for (i = 0; i < strlen (graphmode.labels); i++) {
+      if ((graphmode.labels[i] != '0') && (graphmode.labels[i] != '1') && (graphmode.labels[i] != '2')) { goto usage; }
+    }
+  }
+
+  strcpy (graphmode.axis, "2222");
+  if ((N = get_argument (argc, argv, "-axis"))) {
+    remove_argument (N, &argc, argv);
+    strcpy (graphmode.axis, argv[N]);
+    remove_argument (N, &argc, argv);
+    if (strlen (graphmode.axis) != 4) { goto usage; }
+    for (i = 0; i < strlen (graphmode.axis); i++) {
+      if ((graphmode.axis[i] != '0') && (graphmode.axis[i] != '1') && (graphmode.axis[i] != '2')) { goto usage; }
+    }
+  }
+
+  if (argc != 1) goto usage;
+
+  KapaBox (Xgraph, &graphmode);
+  return (TRUE);
+      
+ usage:
+  gprint (GP_ERR, "USAGE: box [-ticks NNNN] [-axis NNNN] [-labels NNNN]\n");
+  return (FALSE);
+}
+
+
+/* box has:
+   axis
+   labels
+   ticks
+
+   assign like this:   
+   -axis 0000
+   -labels 0000
+   -ticks 0000
+
+   default:
+   -axis 1111
+   -labels 1100
+   -ticks 1111
+
+   messages to kapa:
+
+   DBOX
+   (xmin) (xmax) (ymin) (ymax)
+   AAAA LLLL TTTT
+
+   A = axis
+   L = label
+   T = ticks
+   
+   0 = off
+   1 = on
+   2 = default / maintain
+
+*/
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/center.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/center.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/center.c	(revision 11389)
@@ -0,0 +1,29 @@
+# include "data.h"
+
+int center (int argc, char **argv) {
+  
+  double x, y;
+  int zoom;
+  int Ximage, Nimage, N;
+  
+  Nimage = -1;
+  if ((N = get_argument (argc, argv, "-n"))) {
+    remove_argument (N, &argc, argv);
+    Nimage = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if (!GetImage (&Ximage, &Nimage)) return (FALSE);
+
+  if ((argc != 3) && (argc != 4)) {
+    gprint (GP_ERR, "USAGE: center x y [zoom]\n");
+    return (FALSE);
+  }
+
+  x = atof (argv[1]);
+  y = atof (argv[2]);
+  zoom = 0;
+  if (argc == 4) zoom = atof (argv[3]);
+
+  KiiCenter (Ximage, x, y, zoom);
+  return (TRUE);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/clear.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/clear.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/clear.c	(revision 11389)
@@ -0,0 +1,29 @@
+# include "data.h"
+
+int clear (int argc, char **argv) {
+  
+  int N, ClearSection;
+  int Ngraph, Xgraph;
+
+  Ngraph = -1;
+  if ((N = get_argument (argc, argv, "-n"))) {
+    remove_argument (N, &argc, argv);
+    Ngraph = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if (!GetGraph (NULL, &Xgraph, &Ngraph)) return (FALSE);
+
+  ClearSection = FALSE;
+  if ((N = get_argument (argc, argv, "-s"))) {
+    remove_argument (N, &argc, argv);
+    ClearSection = TRUE;
+  }
+
+  if (argc != 1) {
+    gprint (GP_ERR, "USAGE: clear [-n Xgraph]\n");
+    return (FALSE);
+  }
+
+  KapaClear (Xgraph, ClearSection);
+  return (TRUE);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/clip.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/clip.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/clip.c	(revision 11389)
@@ -0,0 +1,73 @@
+# include "data.h"
+
+int clip (int argc, char **argv) {
+
+  int i, Npix, DO_NAN, DO_INF, N;
+  double min, Vmin, max, Vmax, nan_val, inf_val;
+  float *in;
+  Buffer *buf;
+
+  inf_val = nan_val = min = Vmin = max = Vmax = 0;
+
+  DO_NAN = FALSE;
+  if ((N = get_argument (argc, argv, "-nan"))) {
+    remove_argument (N, &argc, argv);
+    nan_val  = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+    DO_NAN = TRUE;
+  }
+
+  DO_INF = FALSE;
+  if ((N = get_argument (argc, argv, "-inf"))) {
+    remove_argument (N, &argc, argv);
+    inf_val  = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+    DO_INF = TRUE;
+  }
+
+  if ((argc != 6) && (!(DO_INF || DO_NAN))) {
+    gprint (GP_ERR, "USAGE: clip (buffer) [min Vmin max Vmax] [-inf val] [-nan val]\n");
+    return (FALSE);
+  }
+
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+
+  if (argc == 6) {
+    min = atof (argv[2]);
+    Vmin = atof (argv[3]);
+    max = atof (argv[4]);
+    Vmax = atof (argv[5]);
+  }
+
+  Npix = buf[0].matrix.Naxis[0]*buf[0].matrix.Naxis[1];
+  in = (float *) buf[0].matrix.buffer;
+
+  if (argc == 6) {
+    for (i = 0; i < Npix; i++, in++) {
+      if (*in < min) 
+	*in = Vmin;
+      if (*in > max)
+	*in = Vmax;
+    }
+  }
+  in = (float *) buf[0].matrix.buffer;
+  if (DO_NAN) {
+    for (i = 0; i < Npix; i++, in++) {
+      if (isnan (*in)) {
+	*in = nan_val;
+      }
+    }
+  }
+  in = (float *) buf[0].matrix.buffer;
+  if (DO_INF) {
+    for (i = 0; i < Npix; i++, in++) {
+      if (!finite (*in)) {
+	*in = inf_val;
+      }
+    }
+  }
+  return (TRUE);
+
+}
+
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/close.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/close.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/close.c	(revision 11389)
@@ -0,0 +1,33 @@
+# include "data.h"
+
+int close_device (int argc, char **argv) {
+
+  int N, Source, Nsource, IsImage;
+  /* close current graphics device */
+
+  Nsource = -1;
+  if ((N = get_argument (argc, argv, "-n"))) {
+    remove_argument (N, &argc, argv);
+    Nsource = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "-g"))) {
+    remove_argument (N, &argc, argv);
+    SetImageDevice (FALSE);
+  }  
+  if ((N = get_argument (argc, argv, "-i"))) {
+    remove_argument (N, &argc, argv);
+    SetImageDevice (TRUE);
+  }  
+
+  IsImage = GetCurrentDevice ();
+  if (IsImage) {
+    if (!GetImage (&Source, &Nsource)) return (FALSE);
+    close_image (Nsource); 
+  } else {
+    if (!GetGraph (NULL, &Source, &Nsource)) return (FALSE);
+    close_graph (Nsource); 
+  }
+
+  return (TRUE);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/concat.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/concat.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/concat.c	(revision 11389)
@@ -0,0 +1,36 @@
+# include "data.h"
+
+int concat (int argc, char **argv) {
+
+  int  i, j, Nin;
+  double value;
+  Vector *ivec, *ovec;
+
+  /** check basic syntax **/
+  if (argc != 3) {
+    gprint (GP_ERR, "SYNTAX: concat (vector/value) vector\n");
+    gprint (GP_ERR, "  concatanate (vector/value) to vector\n");
+    return (FALSE);
+  }
+
+  if ((ovec = SelectVector (argv[2], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+
+  if (SelectScalar (argv[1], &value)) {
+    Nin = ovec[0].Nelements;
+    ovec[0].Nelements++;
+    REALLOCATE (ovec[0].elements, float, ovec[0].Nelements);
+    ovec[0].elements[Nin] = value;
+    return (TRUE);
+  } 
+  
+  if ((ivec = SelectVector (argv[1], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  
+  REALLOCATE (ovec[0].elements, float, ovec[0].Nelements + ivec[0].Nelements);
+  for (j = ovec[0].Nelements, i = 0; i < ivec[0].Nelements; i++, j++) {
+    ovec[0].elements[j] = ivec[0].elements[i];
+  }
+  ovec[0].Nelements += ivec[0].Nelements;
+  
+  return (TRUE);
+    
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/contour.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/contour.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/contour.c	(revision 11389)
@@ -0,0 +1,262 @@
+# include "data.h"
+# define LL { \
+ dx =  d00 / (*v01 - *v00); \
+ dy = -d00 / (*v10 - *v00); \
+ x = i - 0.5; \
+ y = j - dy - 0.5; }
+
+# define UL { \
+ tmp = d00 / (*v10 - *v00); \
+ dy = 1 - tmp; \
+ dx =  d10 / (*v11 - *v10); \
+ x = i - 0.5; \
+ y = j + tmp - 0.5; }
+      
+# define LR { \
+ tmp = d00 / (*v01 - *v00); \
+ dx = 1 - tmp; \
+ dy = d01 / (*v11 - *v01); \
+ x = i + tmp - 0.5; \
+ y = j - 0.5; }
+
+# define UR { \
+ tmp = d10 / (*v11 - *v10); \
+ dx = 1 - tmp; \
+ dy = -d11 / (*v01 - *v11); \
+ x = i + tmp - 0.5; \
+ y = j + 1 - 0.5; }
+      
+# define HZ { \
+ tmp = d00 / (*v10 - *v00); \
+ dy = d01 / (*v11 - *v01) - tmp; \
+ dx = 1; \
+ x = i - 0.5; \
+ y = j + tmp - 0.5; }
+
+# define VT { \
+ tmp = d00 / (*v01 - *v00); \
+ dx = d10 / (*v11 - *v10) - tmp; \
+ x = i + tmp - 0.5; \
+ dy = 1; \
+ y = j - 0.5; }
+
+Vector *xv, *yv;
+int N, NVEC;
+
+void DUMP (float x, float y, float dx, float dy) {
+  
+  xv[0].elements[N]   = x;
+  xv[0].elements[N+1] = x+dx;
+  
+  yv[0].elements[N]   = y;
+  yv[0].elements[N+1] = y+dy;
+  
+  N+=2;
+
+  if (N >= NVEC - 2) {
+    NVEC += 100;
+    REALLOCATE (xv[0].elements, float, NVEC);
+    REALLOCATE (yv[0].elements, float, NVEC);
+  }
+}
+
+int contour (int argc, char **argv) {
+
+  int i, j, Nx, Ny;
+  float level, d00, d01, d10, d11, tmp;
+  float x, y, dx, dy;
+  float *v00, *v01, *v10, *v11;
+  float *matrix;
+  Buffer *buf;
+  
+  if (argc != 5) {
+    gprint (GP_ERR, "USAGE: contour <buffer> X Y level\n");
+    return (FALSE);
+  }
+
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  if ((xv = SelectVector (argv[2], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((yv = SelectVector (argv[3], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+
+  level = atof (argv[4]);
+  matrix = (float *)(buf[0].matrix.buffer);
+  Nx = buf[0].matrix.Naxis[0];
+  Ny = buf[0].matrix.Naxis[1];
+
+  v00 = matrix;
+  v01 = matrix + 1;
+  v10 = matrix + Nx;
+  v11 = matrix + Nx + 1;
+  d01 = (level - *v00);
+  d11 = (level - *v10);
+
+  N = 0;
+  NVEC = 100;
+  REALLOCATE (xv[0].elements, float, NVEC);
+  REALLOCATE (yv[0].elements, float, NVEC);
+
+  for (j = 1; j < Ny; j++) {
+    if (!(j%10)) gprint (GP_ERR, ".");
+    for (i = 1; i < Nx; i++, v00++, v01++, v10++, v11++) {
+
+      d00 = d01;
+      d10 = d11;
+      d01 = (level - *v01);
+      d11 = (level - *v11);
+
+      if (((d00 > 0) && (d01 > 0) && (d10 > 0) && (d11 > 0)) ||
+	  ((d00 < 0) && (d01 < 0) && (d10 < 0) && (d11 < 0)))
+	continue;
+
+      if ((d00 > 0) && (d10 <= 0)) { 
+	if ((d01 <= 0) && (d11 <= 0)) { /* \  */
+	  LL;
+	  DUMP (x,y,dx,dy);
+	  continue;
+	}
+	if ((d01 > 0) && (d11 <= 0)) { /* -  */
+	  HZ;
+	  DUMP (x,y,dx,dy);
+	  continue;
+	}
+	if ((d01 > 0) && (d11 > 0)) { /* /  */
+	  UL;
+	  DUMP (x,y,dx,dy);
+	  continue;
+	}
+	if ((d01 <= 0) && (d11 > 0)) { /* \\  */
+	  LL;
+	  DUMP (x,y,dx,dy);
+	  UR;
+	  DUMP (x,y,dx,dy);
+	  continue;
+	}
+      }
+
+      if ((d00 <= 0) && (d10 > 0)) {
+	if ((d01 > 0) && (d11 > 0)) { /* \  */
+	  LL;
+	  DUMP (x,y,dx,dy);
+	  continue;
+	}
+	if ((d01 <= 0) && (d11 > 0)) { /* -  */
+	  HZ;
+	  DUMP (x,y,dx,dy);
+	  continue;
+	}
+	if ((d01 <= 0) && (d11 <= 0)) { /* /  */
+	  UL;
+	  DUMP (x,y,dx,dy);
+	  continue;
+	}
+	if ((d01 > 0) && (d11 <= 0)) { /* //  */
+	  UL;
+	  DUMP (x,y,dx,dy);
+	  LR;
+	  DUMP (x,y,dx,dy);
+	  continue;
+	}
+      }
+      
+
+      if ((d00 <= 0) && (d10 <= 0)) { 
+	if ((d01 > 0) && (d11 <= 0)) {
+	  LR;
+	  DUMP (x,y,dx,dy);
+	  continue;
+	}
+	if ((d01 <= 0) && (d11 > 0)) {
+	  UR;
+	  DUMP (x,y,dx,dy);
+	  continue;
+	}
+	if ((d01 > 0) && (d11 > 0)) {
+	  VT;
+	  DUMP (x,y,dx,dy);
+	  continue;
+	}
+      }
+
+      if ((d00 > 0) && (d10 > 0)) { 
+	if ((d01 <= 0) && (d11 > 0)) {
+	  LR;
+	  DUMP (x,y,dx,dy);
+	  continue;
+	}
+	if ((d01 > 0) && (d11 <= 0)) {
+	  UR;
+	  DUMP (x,y,dx,dy);
+	  continue;
+	}
+	if ((d01 <= 0) && (d11 <= 0)) {
+	  VT;
+	  DUMP (x,y,dx,dy);
+	  continue;
+	}
+      }
+
+    }
+    /* skip left-hand edge */
+    v00++; v01++; v10++; v11++;
+    d01 = (level - *v00);
+    d11 = (level - *v10);
+  }
+
+  /****** bottom line *******/
+  v00 = matrix;  
+  v01 = matrix + 1;  
+  y = 0;
+  dx = 0;
+  dy = -0.5;
+  for (i = 1; i < Nx; i++, v00++, v01++) { /* do the edges */
+    if (((*v00 > level) && (*v01 <= level)) || ((*v00 <= level) && (*v01 > level))) {
+      x = i + (level - *v01)/(*v01 - *v00);
+      DUMP (x,y,dx,dy);
+    }
+  }
+
+  /********** top line *******/
+  v00 = matrix + Nx*(Ny - 1);  
+  v01 = v00 + 1;
+  y = Ny - 1;
+  dx = 0;
+  dy = 0.5;
+  for (i = 1; i < Nx; i++, v00++, v01++) { /* do the edges */
+    if (((*v00 > level) && (*v01 <= level)) || ((*v00 <= level) && (*v01 > level))) {
+      x = i + (level - *v01)/(*v01 - *v00);
+      DUMP (x,y,dx,dy);
+    }
+  }
+
+  /******** left line *********/
+  v00 = matrix; 
+  v01 = matrix + Nx;
+  x = 0;
+  dx = -0.5;
+  dy = 0;
+  for (j = 1; j < Ny; j++, v00+=Nx, v01+=Nx) { /* do the edges */
+    if (((*v00 > level) && (*v01 <= level)) || ((*v00 <= level) && (*v01 > level))) {
+      y = j + (level - *v01)/(*v01 - *v00);
+      DUMP (x,y,dx,dy);
+    }
+  }
+
+  /******** right line *********/
+  v00 = matrix + Nx - 1; 
+  v01 = v00 + Nx;
+  x = Nx - 1;
+  dx = 0.5;
+  dy = 0;
+  for (j = 1; j < Ny; j++, v00+=Nx, v01+=Nx) { /* do the edges */
+    if (((*v00 > level) && (*v01 <= level)) || ((*v00 <= level) && (*v01 > level))) {
+      y = j + (level - *v01)/(*v01 - *v00);
+      DUMP (x,y,dx,dy);
+    }
+  }
+  
+/* free anything? */
+
+  xv[0].Nelements = N;
+  yv[0].Nelements = N;
+  return (TRUE);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/create.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/create.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/create.c	(revision 11389)
@@ -0,0 +1,37 @@
+# include "data.h"
+
+int create (int argc, char **argv) {
+  
+  int i, N;
+  float start, end, delta;
+  Vector *vec;
+  
+  if ((argc != 5) && (argc != 4)) {
+    gprint (GP_ERR, "USAGE: create vector start end [delta]\n");
+    return (FALSE);
+  }
+
+  if ((vec = SelectVector (argv[1], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+
+  start = atof (argv[2]);
+  end   = atof (argv[3]);
+  delta = 1;
+  if (argc == 5) delta = atof (argv[4]);
+  if ((start == end) || (delta == 0)) {
+    gprint (GP_ERR, "error in value: %f to %f, %f\n", start, end, delta);
+    return (FALSE);
+  }
+  delta = fabs (delta);
+  if (end - start < 0) {
+    delta = -1.0 * delta;
+  }
+
+  vec[0].Nelements = (end - start) / delta;
+  REALLOCATE (vec[0].elements, float, vec[0].Nelements);
+
+  for (i = 0; i < vec[0].Nelements; i++) {
+    vec[0].elements[i] = start + i*delta;
+  }
+
+  return (TRUE);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/cumulative.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/cumulative.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/cumulative.c	(revision 11389)
@@ -0,0 +1,28 @@
+# include "data.h"
+
+int cumulative (int argc, char **argv) {
+  
+  int i;
+  float *Vi, *Vo;
+  Vector *ivec, *ovec;
+
+  if (argc != 3) {
+    gprint (GP_ERR, "USAGE: cumulative invec outvec\n");
+    return (FALSE);
+  }
+
+  if ((ivec = SelectVector (argv[1], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((ovec = SelectVector (argv[2], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+  ovec[0].Nelements = ivec[0].Nelements;
+    
+  REALLOCATE (ovec[0].elements, float, ovec[0].Nelements);
+  bzero (ovec[0].elements, sizeof(float)*ovec[0].Nelements);
+
+  Vi = ivec[0].elements;
+  Vo = ovec[0].elements;
+  *Vo = *Vi;
+  for (i = 1; i < ivec[0].Nelements; i++, Vi++, Vo++) {
+    *Vo = Vo[-1] + *Vi;
+  }      
+  return (TRUE);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/cursor.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/cursor.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/cursor.c	(revision 11389)
@@ -0,0 +1,77 @@
+# include "data.h"
+
+int cursor (int argc, char **argv) {
+
+  char string[20], key[20];
+  int i, N, Nsource, Source, IsImage;
+  double X, Y, R, D, Z;
+  void *oldsignal;
+  Graphdata graphmode;
+  Buffer *buf;
+
+  Nsource = -1;
+  if ((N = get_argument (argc, argv, "-n"))) {
+    remove_argument (N, &argc, argv);
+    Nsource = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "-g"))) {
+    remove_argument (N, &argc, argv);
+    SetImageDevice (FALSE);
+  }  
+  if ((N = get_argument (argc, argv, "-i"))) {
+    remove_argument (N, &argc, argv);
+    SetImageDevice (TRUE);
+  }  
+  IsImage = GetCurrentDevice ();
+  if (IsImage) {
+    if (!GetImage (&Source, &Nsource)) return (FALSE);
+  } else {
+    if (!GetGraph (&graphmode, &Source, &Nsource)) return (FALSE);
+  }
+
+  N = 0;
+  if (argc == 2) N = atof (argv[1]);
+
+  if ((argc != 1) && (argc != 2)) {
+    gprint (GP_ERR, "USAGE: cursor [Npts] [-n window] [-g | -i]\n");
+    return (FALSE);
+  }
+  
+  buf = NULL;
+  if (IsImage) buf = SelectBuffer (GetImageName(), OLDBUFFER, FALSE);
+  
+  KiiCursorOn (Source);
+  
+  oldsignal = signal (SIGINT, handle_interrupt);
+  interrupt = FALSE;
+  Z = -1.0;
+  for (i = 0; ((i < N) || (N == 0)) && !interrupt; i++) {
+    KiiCursorRead (Source, &X, &Y, key);
+
+    sprintf (string, "X%s", key);
+    set_variable (string, X);
+    sprintf (string, "Y%s", key);
+    set_variable (string, Y);
+    set_str_variable ("KEY", key);
+    
+    if (IsImage) {
+      if (buf != NULL) { 
+	Z = gfits_get_matrix_value (&buf[0].matrix, (int) X, (int) Y);
+      }
+      gprint (GP_LOG, "%s %f %f  %f\n", key, X, Y, Z);
+    } else {
+      XY_to_RD (&R, &D, X, Y, &graphmode.coords);
+      sprintf (string, "R%s", key);
+      set_variable (string, R);
+      sprintf (string, "D%s", key);
+      set_variable (string, D);
+      gprint (GP_LOG, "%s %f %f\n", key, X, Y);
+    }
+    if (!strcasecmp (key, "Q")) break;
+  }
+
+  signal (SIGINT, oldsignal);
+  KiiCursorOff (Source);
+  return (TRUE);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/cut.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/cut.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/cut.c	(revision 11389)
@@ -0,0 +1,120 @@
+# include "data.h"
+
+enum {SUM, MEAN, MEDIAN};
+
+int cut (int argc, char **argv) {
+  
+  int i, j, N, Nx, Ny, Mode;
+  float *Vin, *Vbuf, value;
+  int sx, sy, nx, ny;
+  Vector *xvec, *yvec;
+  Buffer *buf;
+
+  Mode = SUM;
+  if ((N = get_argument (argc, argv, "-median"))) {
+    remove_argument (N, &argc, argv);
+    Mode = MEDIAN;
+  }
+  if ((N = get_argument (argc, argv, "-mean"))) {
+    remove_argument (N, &argc, argv);
+    Mode = MEAN;
+  }
+
+  if (argc != 9) {
+    gprint (GP_ERR, "USAGE: cut <buffer> <X vector> <Y vector> <X|Y> sx sy nx ny\n");
+    return (FALSE);
+  }
+
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+ 
+  sx = atof (argv[5]);
+  sy = atof (argv[6]);
+  nx = atof (argv[7]);
+  ny = atof (argv[8]);
+
+  Nx = buf[0].matrix.Naxis[0];
+  Ny = buf[0].matrix.Naxis[1];
+
+  if ((sx < 0) || (sy < 0) || (sx+nx > Nx) || (sy+ny > Ny)) {
+    gprint (GP_ERR, "region out of range\n");
+    return (FALSE);
+  }
+
+  if ((xvec = SelectVector (argv[2], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((yvec = SelectVector (argv[3], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+
+  switch (argv[4][0]) {
+  case 'x':
+  case 'X':
+    /* create output vectors */
+    xvec[0].Nelements = yvec[0].Nelements = nx;
+    REALLOCATE (xvec[0].elements, float, MAX (nx, 1));
+    REALLOCATE (yvec[0].elements, float, MAX (nx, 1));
+    bzero (yvec[0].elements, nx*sizeof(float));
+    for (i = 0; i < nx; i++) {
+      xvec[0].elements[i] = i + sx; 
+    }
+    ALLOCATE (Vbuf, float, MAX (ny, 1));
+
+    for (i = 0; i < nx; i++) {
+      /* accumulate values */
+      Vin = (float *)(buf[0].matrix.buffer) + sy*Nx + sx + i; 
+      for (j = 0; j < ny; j++, Vin += Nx) {
+	Vbuf[j] = *Vin;
+      }
+      /* apply stat of choice */
+      if (Mode == MEDIAN) {
+	fsort (Vbuf, ny);
+	value = Vbuf[(int)(0.5*ny)];
+      } else {
+	value = 0;
+	for (j = 0; j < ny; j++) {
+	  value += Vbuf[j];
+	}
+	if (Mode == MEAN) { value /= ny; }
+      }
+      yvec[0].elements[i] = value;
+    }
+    break;
+    
+  case 'y':
+  case 'Y':
+    xvec[0].Nelements = yvec[0].Nelements = ny;
+    REALLOCATE (xvec[0].elements, float, ny);
+    REALLOCATE (yvec[0].elements, float, ny);
+    bzero (yvec[0].elements, ny*sizeof(float));
+    for (i = 0; i < ny; i++) {
+      xvec[0].elements[i] = i + sy; 
+    }
+    ALLOCATE (Vbuf, float, MAX (nx, 1));
+
+    for (i = 0; i < ny; i++) {
+      /* accumulate values */
+      Vin = (float *)(buf[0].matrix.buffer) + (sy + i)*Nx + sx; 
+      for (j = 0; j < nx; j++, Vin ++) {
+	Vbuf[j] = *Vin;
+      }
+      /* apply stat of choice */
+      if (Mode == MEDIAN) {
+	fsort (Vbuf, nx);
+	value = Vbuf[(int)(0.5*nx)];
+      } else {
+	value = 0;
+	for (j = 0; j < nx; j++) {
+	  value += Vbuf[j];
+	}
+	if (Mode == MEAN) { value /= nx; }
+      }
+      yvec[0].elements[i] = value;
+    }
+    break;
+
+  default:
+    gprint (GP_ERR, "<dir> can be X or Y\n");
+    return (FALSE);
+    break;
+  }
+
+  return (TRUE);
+}
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/delete.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/delete.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/delete.c	(revision 11389)
@@ -0,0 +1,31 @@
+# include "data.h"
+
+int delete (int argc, char **argv) {
+  
+  int i, N, Quiet;
+
+  Quiet = FALSE;
+  if ((N = get_argument (argc, argv, "-q"))) {
+    Quiet = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "-quiet"))) {
+    Quiet = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc < 2) {
+    gprint (GP_ERR, "USAGE: delete <obiect> [<object> ..]\n");
+    return (FALSE);
+  }
+
+  for (i = 1; i < argc; i++) {
+    if (DeleteNamedBuffer (argv[i])) continue; 
+    if (DeleteNamedVector (argv[i])) continue;
+    if (DeleteNamedScalar (argv[i])) continue; 
+    if (!Quiet) gprint (GP_ERR, "can't find object %s\n", argv[i]);
+  }
+
+  return (TRUE);
+}
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/device.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/device.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/device.c	(revision 11389)
@@ -0,0 +1,33 @@
+# include "data.h"
+
+int device (int argc, char **argv) {
+
+  int N, Source, Nsource, IsImage;
+  /* set / get current graphics device */
+
+  Nsource = -1;
+  if ((N = get_argument (argc, argv, "-n"))) {
+    remove_argument (N, &argc, argv);
+    Nsource = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "-g"))) {
+    remove_argument (N, &argc, argv);
+    SetImageDevice (FALSE);
+  }  
+  if ((N = get_argument (argc, argv, "-i"))) {
+    remove_argument (N, &argc, argv);
+    SetImageDevice (TRUE);
+  }  
+
+  IsImage = GetCurrentDevice ();
+  if (IsImage) {
+    if (!GetImage (&Source, &Nsource)) return (FALSE);
+    gprint (GP_ERR, "kii %d\n", Nsource); 
+  } else {
+    if (!GetGraph (NULL, &Source, &Nsource)) return (FALSE);
+    gprint (GP_ERR, "kapa %d\n", Nsource); 
+  }
+
+  return (TRUE);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/dimendown.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/dimendown.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/dimendown.c	(revision 11389)
@@ -0,0 +1,64 @@
+# include "data.h"
+
+enum {VALUE, XCOORD, YCOORD};
+
+int dimendown (int argc, char **argv) {
+  
+  int i, Nx, Ny, Npix, N, mode;
+  float *in, *out;
+  Vector *vec;
+  Buffer *buf;
+
+  mode = VALUE;
+  if ((N = get_argument (argc, argv, "-x"))) {
+    remove_argument (N, &argc, argv);
+    mode = XCOORD;
+  }
+  if ((N = get_argument (argc, argv, "-y"))) {
+    remove_argument (N, &argc, argv);
+    mode = YCOORD;
+  }
+
+  if (argc != 3) goto usage;
+
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  if ((vec = SelectVector (argv[2], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+
+  Nx = buf[0].matrix.Naxis[0];
+  Ny = buf[0].matrix.Naxis[1];
+  Npix = Nx * Ny;
+
+  vec[0].Nelements = Npix;
+  REALLOCATE (vec[0].elements, float, Npix);
+
+  in = (float *) buf[0].matrix.buffer;
+  out = vec[0].elements;
+
+  switch (mode) {
+    case VALUE:
+      for (i = 0; i < Npix; i++, in++, out++) {
+	*out = *in;
+      }
+      break;
+
+    case XCOORD:
+      for (i = 0; i < Npix; i++, out++) {
+	*out = i % Nx;
+      }
+      break;
+
+    case YCOORD:
+      for (i = 0; i < Npix; i++, out++) {
+	*out = i / Nx;
+      }
+      break;
+  }
+      
+  return (TRUE);
+
+ usage:
+    gprint (GP_ERR, "USAGE: dimendown <buffer> <vector>\n");
+    gprint (GP_ERR, "  -x : fill vector with buffer x-coords\n");
+    gprint (GP_ERR, "  -y : fill vector with buffer y-coords\n");
+    return (FALSE);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/dimenup.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/dimenup.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/dimenup.c	(revision 11389)
@@ -0,0 +1,39 @@
+# include "data.h"
+
+int dimenup (int argc, char **argv) {
+  
+  int i, Nx, Ny, Npix;
+  float *in, *out;
+  Vector *vec;
+  Buffer *buf;
+
+  if (argc != 5) {
+    gprint (GP_ERR, "USAGE: dimenup <vector> <buffer> Nx Ny\n");
+    return (FALSE);
+  }
+
+  if ((vec = SelectVector (argv[1], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((buf = SelectBuffer (argv[2], ANYBUFFER, TRUE)) == NULL) return (FALSE);
+
+  Npix = vec[0].Nelements;
+  Nx = atof (argv[3]);
+  Ny = atof (argv[4]);
+  if (Npix != Nx * Ny) {
+    gprint (GP_ERR, "dimensions don't match\n");
+    return (FALSE);
+  }
+
+  gfits_free_matrix (&buf[0].matrix);
+  gfits_free_header (&buf[0].header);
+  CreateBuffer (buf, Nx, Ny, -32, 0.0, 1.0);
+
+  out = (float *) buf[0].matrix.buffer;
+  in = vec[0].elements;
+
+  for (i = 0; i < Npix; i++, in++, out++) {
+    *out = *in;
+  }
+
+  return (TRUE);
+}
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/dot.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/dot.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/dot.c	(revision 11389)
@@ -0,0 +1,30 @@
+# include "data.h"
+
+int dot (int argc, char **argv) {
+  
+  Graphdata graphmode;
+  float x, y;
+
+  if (!style_args (&graphmode, &argc, argv, -1)) return FALSE;
+
+  if (argc != 3) {
+    gprint (GP_ERR, "USAGE: plot <x> <y>\n");
+    return (FALSE);
+  }
+  x = atof(argv[1]);
+  y = atof(argv[2]);
+
+  /* set plotting options (these are sticky) */
+  SetGraph (graphmode);
+
+  /* set point style and errorbar mode (these are NOT sticky) */
+  graphmode.style = 2;
+  graphmode.etype = 0;
+
+  if (!PrepPlotting (1, &graphmode)) return (FALSE);
+  
+  PlotVector (1, &x);
+  PlotVector (1, &y);
+  
+  return (TRUE);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/erase.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/erase.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/erase.c	(revision 11389)
@@ -0,0 +1,37 @@
+# include "data.h"
+
+int erase (int argc, char **argv) {
+  
+  int i, N;
+  int Ximage, Nimage;
+  
+  Nimage = -1;
+  if ((N = get_argument (argc, argv, "-n"))) {
+    remove_argument (N, &argc, argv);
+    Nimage = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if (!GetImage (&Ximage, &Nimage)) return (FALSE);
+
+  if (argc < 2) {
+    gprint (GP_ERR, "USAGE: erase (overlay) [overlay, overlay, ..] \n");
+    gprint (GP_ERR, " (overlay) may be: red (0), green (1), blue (2), yellow (3) or all\n");
+    return (FALSE);
+  }
+
+  for (i = 1; i < argc; i++) {
+    if (!(strcasecmp (argv[i], "all"))) {
+      KiiEraseOverlay (Ximage, "red");
+      KiiEraseOverlay (Ximage, "green");
+      KiiEraseOverlay (Ximage, "blue");
+      KiiEraseOverlay (Ximage, "yellow");
+      continue;
+    }
+    if (!KiiSelectOverlay (argv[i], &N)) {
+      gprint (GP_ERR, "%s is not a valid overlay\n", argv[i]);
+      return (FALSE);
+    }
+    KiiEraseOverlay (Ximage, argv[i]);
+  }
+  return (TRUE);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/extract.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/extract.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/extract.c	(revision 11389)
@@ -0,0 +1,92 @@
+# include "data.h"
+
+int extract (int argc, char **argv) {
+  
+  int i, j;
+  float *Vin, *Vout;
+  int sx, sy, nx, ny, NX, NY;
+  int Sx, Sy, Nx, Ny;
+  Buffer *in, *out;
+
+  if (argc != 11) {
+    gprint (GP_ERR, "USAGE: extract <from> <to> sx sy nx ny Sx Sy Nx Ny\n");
+    return (FALSE);
+  }
+
+  if ((in = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  NX = in[0].matrix.Naxis[0];
+  NY = in[0].matrix.Naxis[1];
+
+  sx = atof (argv[3]);
+  sy = atof (argv[4]);
+  nx = atof (argv[5]);
+  ny = atof (argv[6]);
+
+  Sx = atof (argv[7]);
+  Sy = atof (argv[8]);
+  Nx = atof (argv[9]);
+  Ny = atof (argv[10]);
+
+  if ((Sy + ny > Ny) || (Sx + nx > Nx)) {
+    gprint (GP_ERR, "mismatch between source and dest regions\n");
+    gprint (GP_ERR, "%d + %d > %d or %d + %d > %d\n", Sy, ny, Ny, Sx, nx, Nx);
+    return (FALSE);
+  }
+
+  /* region is not on first image */
+  if ((sx + nx < 0) || (sy + ny < 0) || 
+      (sx > in[0].matrix.Naxis[0]) || 
+      (sy > in[0].matrix.Naxis[1])) {
+    gprint (GP_ERR, "region outside of source image\n");
+    return (FALSE);
+  }
+
+  if ((Sx + nx > Nx) || (Sy + ny > Ny)) {
+    gprint (GP_ERR, "source region larger than dest region\n");
+    return (FALSE);
+  }
+  if ((Sx < 0) || (Sy < 0)) {
+    gprint (GP_ERR, "dest region out of range\n");
+    return (FALSE);
+  }
+
+  if ((out = SelectBuffer (argv[2], OLDBUFFER, FALSE)) == NULL) {
+    if ((out = SelectBuffer (argv[2], ANYBUFFER, TRUE)) == NULL) return (FALSE);
+    gfits_free_matrix (&out[0].matrix);
+    gfits_free_header (&out[0].header);
+
+    out[0].bitpix = in[0].bitpix;
+    out[0].unsign = in[0].unsign;
+    out[0].bscale = in[0].bscale;
+    out[0].bzero  = in[0].bzero;
+    gfits_copy_header (&in[0].header, &out[0].header);
+    gfits_modify (&out[0].header, "NAXIS1", "%d", 1, Nx);
+    gfits_modify (&out[0].header, "NAXIS2", "%d", 1, Ny);
+    out[0].header.Naxis[0] = Nx;
+    out[0].header.Naxis[1] = Ny;
+    gfits_create_matrix (&out[0].header, &out[0].matrix);
+  } else {
+    if ((out[0].header.Naxis[1] != Ny) || (out[0].header.Naxis[0] != Nx)) {
+      gprint (GP_ERR, "matrix sizes mis-matched\n");
+      gprint (GP_ERR, "%d x %d  vs  %d x %d\n", Nx, Ny, 
+	       out[0].header.Naxis[0], out[0].header.Naxis[1]);
+      return (FALSE);
+    }
+  }
+
+  for (j = 0; j < ny; j++) {
+    if (j + sy < 0) continue;
+    if (j + sy >= NY) continue;
+    Vin = (float *)(in[0].matrix.buffer) + (j + sy)*in[0].matrix.Naxis[0] + sx;  
+    Vout = (float *)(out[0].matrix.buffer) + (j + Sy)*out[0].matrix.Naxis[0] + Sx;   
+    for (i = 0; i < nx; i++, Vin++, Vout++) {
+      if (i + sx < 0) continue;
+      if (i + sx >= NX) continue;
+      *Vout = *Vin;
+    }
+  }
+
+  return (TRUE);
+
+}
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/fft1d.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/fft1d.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/fft1d.c	(revision 11389)
@@ -0,0 +1,70 @@
+# include "data.h"
+
+int fft1d (int argc, char **argv) {
+  
+  int i, Npix, ZeroImaginary;
+  float *t1, *t2, *temp;
+  Vector *Ire, *Iim, *Ore, *Oim;
+
+  if ((argc != 6) || (strcmp (argv[3], "to"))) {
+    gprint (GP_ERR, "USAGE: fft1d (real) (imag) to (real) (imag)\n");
+    return (FALSE);
+  }
+
+  Iim = NULL;
+  ZeroImaginary = TRUE;
+  if (strcmp (argv[2], "0")) {
+    ZeroImaginary = FALSE;
+    if ((Iim = SelectVector (argv[2], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  }    
+  if ((Ire = SelectVector (argv[1], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((Ore = SelectVector (argv[4], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((Oim = SelectVector (argv[5], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+
+  Npix = Ire[0].Nelements;
+  if (!ZeroImaginary && (Npix != Iim[0].Nelements)) {
+    gprint (GP_ERR, "vector mismatch in size\n");
+    return (FALSE);
+  }
+
+  if (!IsBinary (Npix)) {
+    gprint (GP_ERR, "Npix is not a binary number!\n");
+    return (FALSE);
+  }
+  
+  ALLOCATE (temp, float, 2*Npix);
+  if (ZeroImaginary) {
+    t1 = Ire[0].elements;
+    for (i = 0; i < Npix; i++, t1++) {
+      temp[2*i  ] = *t1;
+      temp[2*i+1] = 0;
+    }
+  } else {
+    t1 = Ire[0].elements;
+    t2 = Iim[0].elements;
+    for (i = 0; i < Npix; i++, t1++, t2++) {
+      temp[2*i  ] = *t1;
+      temp[2*i+1] = *t2;
+    }
+  }    
+    
+  fft (temp, Npix, 1); 
+
+  Ore[0].Nelements = Npix;
+  Oim[0].Nelements = Npix;
+  REALLOCATE (Ore[0].elements, float, Npix);
+  REALLOCATE (Oim[0].elements, float, Npix);
+ 
+  t1 = Ore[0].elements;
+  t2 = Oim[0].elements;
+  for (i = 0; i < Npix; i++, t1++, t2++) {
+    *t1 = temp[2*i  ] / Npix;
+    *t2 = temp[2*i+1] / Npix;
+  }    
+  
+  free (temp);
+  
+  return (TRUE);
+}
+
+  
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/fft2d.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/fft2d.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/fft2d.c	(revision 11389)
@@ -0,0 +1,113 @@
+# include "data.h"
+
+int fft2d (int argc, char **argv) {
+  
+  int i, N, Nx, Ny, Naxis[2];
+  int Npix, ZeroImaginary, isign;
+  float *t1, *t2, *out, *temp;
+  Buffer *Ire, *Iim, *Ore, *Oim;;
+
+  isign = 1;
+  if ((N = get_argument (argc, argv, "-inverse"))) {
+    remove_argument (N, &argc, argv);
+    isign = -1;
+  }
+
+  if ((argc != 6) || (strcmp (argv[3], "to"))) {
+    gprint (GP_ERR, "USAGE: fft2d (real) (imag) to (real) (imag)\n");
+    return (FALSE);
+  }
+
+  /* select input / output buffers */
+  Iim = NULL;
+  ZeroImaginary = TRUE; /* Input(imaginary) may be 0, in which case we create a 0 filled image */
+  if (!strcmp (argv[2], "0")) { 
+  } else {
+    ZeroImaginary = FALSE;
+    if ((Iim = SelectBuffer (argv[2], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  }    
+  if ((Ire = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  if ((Ore = SelectBuffer (argv[4], ANYBUFFER, TRUE)) == NULL) return (FALSE);
+  if ((Oim = SelectBuffer (argv[5], ANYBUFFER, TRUE)) == NULL) return (FALSE);
+
+  /* free up output space */
+  gfits_free_matrix (&Ore[0].matrix);
+  gfits_free_header (&Ore[0].header);
+  gfits_free_matrix (&Oim[0].matrix);
+  gfits_free_header (&Oim[0].header);
+
+  /* get image dimensions, check value */
+  Npix = Ire[0].header.Naxis[0]*Ire[0].header.Naxis[1];
+  Nx = Ire[0].header.Naxis[0];
+  Ny = Ire[0].header.Naxis[1];
+  Naxis[0] = Ny; Naxis[1] = Nx;
+  if (!IsBinary (Npix)) {
+    gprint (GP_ERR, "dimensions are not binary!\n");
+    return (FALSE);
+  }
+  
+  /* create working space */
+  t1 = (float *) Ire[0].matrix.buffer;
+  ALLOCATE (temp, float, 2*Npix);
+  out = temp;
+
+  /* copy input to working space */
+  if (ZeroImaginary) {
+    for (i = 0; i < Npix; i++, t1++) {
+      *out = *t1;
+      out++;
+      *out = 0;
+      out++;
+    }
+  } else {
+    t2 = (float *) Iim[0].matrix.buffer;
+    for (i = 0; i < Npix; i++, t1++, t2++) {
+      *out = *t1;
+      out++;
+      *out = *t2;
+      out++;
+    }
+  } 
+    
+  /* run the fft */
+  fftN (temp, Naxis, 2, isign);
+
+  /* fix up output headers (real) */
+  gfits_copy_header (&Ire[0].header, &Ore[0].header);
+  gfits_modify (&Ore[0].header, "NAXIS1", "%d", 1, Nx);
+  gfits_modify (&Ore[0].header, "NAXIS2", "%d", 1, Ny);
+  Ore[0].header.Naxis[0] = Nx;
+  Ore[0].header.Naxis[1] = Ny;
+  Ore[0].bitpix = Ire[0].bitpix;
+  Ore[0].unsign = Ire[0].unsign;
+  Ore[0].bscale = Ire[0].bscale;
+  Ore[0].bzero  = Ire[0].bzero;
+  gfits_create_matrix (&Ore[0].header, &Ore[0].matrix);
+
+  /* fix up output headers (imaginary) */
+  gfits_copy_header (&Ire[0].header, &Oim[0].header);
+  gfits_modify (&Oim[0].header, "NAXIS1", "%d", 1, Nx);
+  gfits_modify (&Oim[0].header, "NAXIS2", "%d", 1, Ny);
+  Oim[0].header.Naxis[0] = Nx;
+  Oim[0].header.Naxis[1] = Ny;
+  Oim[0].bitpix = Ire[0].bitpix;
+  Oim[0].unsign = Ire[0].unsign;
+  Oim[0].bscale = Ire[0].bscale;
+  Oim[0].bzero  = Ire[0].bzero;
+  gfits_create_matrix (&Oim[0].header, &Oim[0].matrix);
+
+  /* move data from working space to output buffers */
+  out = temp;
+  t1 = (float *) Ore[0].matrix.buffer;
+  t2 = (float *) Oim[0].matrix.buffer;
+  for (i = 0; i < Npix; i++, t1++, t2++) {
+    *t1 = *out / Npix;
+    out ++;
+    *t2 = *out / Npix;
+    out ++;
+  }    
+
+  free (temp);
+
+  return (TRUE);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/fit.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/fit.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/fit.c	(revision 11389)
@@ -0,0 +1,227 @@
+# include "data.h"
+
+int fit (int argc, char **argv) {
+  
+  double **c, **b, *s, X, Y, dY, dY2;
+  double ClipNSigma, mean, sigma, maxsigma;
+  int i, j, nterm, mterm, order, Npt, Nmask;
+  int N, Weight, Quiet, ClipNiter;
+  Vector *xvec, *yvec, *dyvec;
+  float *x, *y, *dy, *yf, *yfit;
+  char name[64], *mask;
+
+  Quiet = FALSE;
+  if ((N = get_argument (argc, argv, "-q"))) {
+    Quiet = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "-quiet"))) {
+    Quiet = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  ClipNSigma = 0;
+  ClipNiter  = 1;
+  if ((N = get_argument (argc, argv, "-clip"))) {
+    remove_argument (N, &argc, argv);
+    ClipNSigma = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+    ClipNiter  = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  dy = NULL;
+  dyvec = NULL;
+  Weight = FALSE;
+  if ((N = get_argument (argc, argv, "-dy"))) {
+    remove_argument (N, &argc, argv);
+    if ((dyvec = SelectVector (argv[N], OLDVECTOR, TRUE)) == NULL) return (FALSE);    
+    remove_argument (N, &argc, argv);
+    Weight = TRUE;
+  }
+
+  if (argc != 4) {
+    gprint (GP_ERR, "USAGE: fit x y order [-dy wt] [-quiet/-q] [-clip Nsigma Niter]\n");
+    return (FALSE);
+  }
+
+  if ((xvec = SelectVector (argv[1], OLDVECTOR, TRUE)) == NULL) return (FALSE);    
+  if ((yvec = SelectVector (argv[2], OLDVECTOR, TRUE)) == NULL) return (FALSE);    
+
+  if (xvec[0].Nelements != yvec[0].Nelements) {
+    gprint (GP_ERR, "vectors must have same length\n");
+    return (FALSE);
+  }
+  if (Weight && xvec[0].Nelements != dyvec[0].Nelements) {
+    gprint (GP_ERR, "vectors must have same length\n");
+    return (FALSE);
+  }
+  
+  /* nterm is number of polynomial terms, starting at x^0 */
+  order = atof (argv[3]);
+  nterm = order + 1;
+  mterm = 2*nterm;
+
+  ALLOCATE (yfit, float, xvec[0].Nelements);
+  ALLOCATE (mask, char, xvec[0].Nelements);
+  memset (mask, 0, xvec[0].Nelements);
+
+  ALLOCATE (s, double, mterm);
+  ALLOCATE (b, double *, nterm);
+  ALLOCATE (c, double *, nterm);
+  for (i = 0; i < nterm; i++) {
+    ALLOCATE (c[i], double, nterm);
+    ALLOCATE (b[i], double, 1);
+  }
+
+  Nmask = 0;
+  sigma = 0.0;
+
+  for (N = 0; N < ClipNiter; N++) {
+
+    /* init registers for current pass */
+    memset (s, 0, mterm*sizeof(double));
+    for (i = 0; i < nterm; i++) {
+      memset (c[i], 0, nterm*sizeof(double));
+      memset (b[i], 0, sizeof(double));
+    }
+
+    /* perform linear fit */
+    x = xvec[0].elements;
+    y = yvec[0].elements;
+    if (Weight) dy = dyvec[0].elements;
+
+    for (i = 0; i < xvec[0].Nelements; i++, x++, y++) {
+      if (mask[i]) continue;
+      if (!(finite(*x) && finite(*y))) continue;
+      dY = 1.0;
+      if (Weight) { 
+	dY = 1.0 / SQ(*dy);
+	dy ++;
+      }
+      X = 1*dY;
+      Y = *y*dY;
+      for (j = 0; j < nterm; j++) {
+	s[j] += X;
+	b[j][0] += Y;
+	X = X * (*x);
+	Y = Y * (*x);
+      }
+      for (j = nterm; j < mterm; j++) {
+	s[j] += X;
+	X = X * (*x);
+      }
+    }
+    for (i = 0; i < nterm; i++) {
+      for (j = 0; j < nterm; j++) {
+	c[i][j] = s[i + j];
+      }
+    }
+    if (!dgaussj (c, nterm, b, 1)) goto escape;
+
+    /* generate fitted values */
+    x = xvec[0].elements;
+    yf = yfit;
+    for (i = 0; i < xvec[0].Nelements; i++, x++, yf++) {
+      if (!finite(*x)) continue;
+      *yf = 0;
+      X = 1;
+      for (j = 0; j < order + 1; j++) {
+	*yf += b[j][0]*X;
+	X = X * (*x);
+      }
+    }
+
+    /* measure fit residual scatter */
+    x  = xvec[0].elements;
+    y  = yvec[0].elements;
+    yf = yfit;
+    dY = dY2 = 0;
+    for (i = Npt = 0; i < xvec[0].Nelements; i++, x++, y++, yf++) {
+      if (mask[i]) continue;
+      if (!finite(*x)) continue;
+      dY  += (*y - *yf);
+      dY2 += SQ(*y - *yf);
+      Npt ++;
+    }
+    mean  = dY / Npt;
+    sigma = sqrt (fabs(dY2/Npt - SQ(mean)));
+    maxsigma = ClipNSigma * sigma;
+
+    /* mask outlier points */
+    x  = xvec[0].elements;
+    y  = yvec[0].elements;
+    yf = yfit;
+    Nmask = 0;
+    for (i = 0; ClipNSigma && (i < xvec[0].Nelements); i++, x++, y++, yf++) {
+      dY = (*y - *yf);
+      if (fabs(dY) > maxsigma) {
+	mask[i] = TRUE;
+	Nmask ++;
+      } else {
+	mask[i] = FALSE;
+      }	
+    }
+  }
+      
+  /* print & save basic fit parameters */
+  if (!Quiet) gprint (GP_ERR, "y = ");
+  for (i = 0; i < nterm; i++) {
+    sprintf (name, "C%d", i);
+    set_variable (name, b[i][0]);
+    if (!Quiet) gprint (GP_ERR, "%f x^%d ", b[i][0], i);
+  }
+  sprintf (name, "Cn");
+  set_variable (name, (double) order);
+  
+  /* print & save basic fit parameters */
+  if (!Quiet) gprint (GP_ERR, "\n");
+  if (!Quiet) gprint (GP_ERR, "    ");
+  for (i = 0; i < nterm; i++) {
+    sprintf (name, "dC%d", i);
+    set_variable (name, sqrt(c[i][i]));
+    if (!Quiet) gprint (GP_ERR, "%f     ", sqrt(c[i][i]));
+  }
+  if (!Quiet) gprint (GP_ERR, "\n");
+
+  set_variable ("dC", sigma);
+  set_variable ("Cnv", (xvec[0].Nelements - Nmask));
+
+  /* save mask and yfit for testing? */
+  if (1) { 
+    Vector *fvec, *mvec;
+    if ((fvec = SelectVector ("yfit", ANYVECTOR, TRUE)) == NULL) return (FALSE);    
+    if ((mvec = SelectVector ("mask", ANYVECTOR, TRUE)) == NULL) return (FALSE);    
+    free (fvec[0].elements);
+    fvec[0].elements = yfit;
+    fvec[0].Nelements = xvec[0].Nelements;
+    mvec[0].Nelements = xvec[0].Nelements;
+
+    REALLOCATE (mvec[0].elements, float, xvec[0].Nelements);
+    for (i = 0; i < xvec[0].Nelements; i++) {
+      mvec[0].elements[i] = mask[i];
+    }
+  } else {
+    free (yfit);
+  }
+  free (mask);
+
+  for (i = 0; i < nterm; i++) {
+    free (b[i]);
+    free (c[i]);
+  }
+  free (b);
+  free (c);
+  free (s);
+  return (TRUE);
+
+escape:
+  for (i = 0; i < nterm; i++) {
+    free (b[i]);
+    free (c[i]);
+  }
+  free (b);
+  free (c);
+  free (s);
+  return (FALSE);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/fit2d.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/fit2d.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/fit2d.c	(revision 11389)
@@ -0,0 +1,265 @@
+# include "data.h"
+
+int fit2d (int argc, char **argv) {
+  
+  double **c, **b, **s, X, Y, dZ, dZ2;
+  double ClipNSigma, mean, sigma, maxsigma;
+  int k, K, i, j, n, Npt, Nmask, nx, ny, nterm, mterm, wterm, order;
+  int N, Weight, Quiet, ClipNiter, VERBOSE;
+  float *x, *y, *z, *dz, *zfit, *zf; 
+  char name[64], *mask;
+  Vector *xvec, *yvec, *zvec, *dzvec;
+
+  VERBOSE = FALSE;
+  if ((N = get_argument (argc, argv, "-v"))) {
+    VERBOSE = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  Quiet = FALSE;
+  if ((N = get_argument (argc, argv, "-q"))) {
+    Quiet = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "-quiet"))) {
+    Quiet = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  ClipNSigma = 0;
+  ClipNiter  = 1;
+  if ((N = get_argument (argc, argv, "-clip"))) {
+    remove_argument (N, &argc, argv);
+    ClipNSigma = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+    ClipNiter  = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  dz = NULL;
+  dzvec = NULL;
+  Weight = FALSE;
+  if ((N = get_argument (argc, argv, "-dz"))) {
+    remove_argument (N, &argc, argv);
+    if ((dzvec = SelectVector (argv[N], OLDVECTOR, TRUE)) == NULL) return (FALSE);    
+    remove_argument (N, &argc, argv);
+    Weight = TRUE;
+  }
+
+  if (argc != 5) {
+    gprint (GP_ERR, "USAGE: fit x y z order [-dz wt]\n");
+    return (FALSE);
+  }
+
+  if ((xvec = SelectVector (argv[1], OLDVECTOR, TRUE)) == NULL) return (FALSE);    
+  if ((yvec = SelectVector (argv[2], OLDVECTOR, TRUE)) == NULL) return (FALSE);    
+  if ((zvec = SelectVector (argv[3], OLDVECTOR, TRUE)) == NULL) return (FALSE);    
+
+  if (xvec[0].Nelements != yvec[0].Nelements) {
+    gprint (GP_ERR, "vectors must have same length\n");
+    return (FALSE);
+  }
+  if (xvec[0].Nelements != zvec[0].Nelements) {
+    gprint (GP_ERR, "vectors must have same length\n");
+    return (FALSE);
+  }
+  if (Weight && xvec[0].Nelements != dzvec[0].Nelements) {
+    gprint (GP_ERR, "vectors must have same length\n");
+    return (FALSE);
+  }
+  
+  order = atof (argv[4]);
+  nterm = order + 1;
+  wterm = nterm*(nterm + 1)/2;
+  mterm = 2*order + 1;
+
+  ALLOCATE (zfit, float, xvec[0].Nelements);
+  ALLOCATE (mask, char, xvec[0].Nelements);
+  memset (mask, 0, xvec[0].Nelements);
+
+  /* allocate the summation matrices */
+  ALLOCATE (s, double *, mterm);
+  ALLOCATE (b, double *, wterm);
+  ALLOCATE (c, double *, wterm);
+  for (i = 0; i < wterm; i++) {
+    ALLOCATE (c[i], double, wterm);
+    ALLOCATE (b[i], double, 1);
+  }
+  for (i = 0; i < mterm; i++) {
+    ALLOCATE (s[i], double, mterm);
+  }
+
+  for (N = 0; N < ClipNiter; N++) {
+
+    /* init registers for current pass */
+    // XXX this was incorrectly using nterm (missing 1 row)
+    for (i = 0; i < wterm; i++) {
+      memset (c[i], 0, wterm*sizeof(double));
+      memset (b[i], 0, sizeof(double));
+    }
+    for (i = 0; i < mterm; i++) {
+      memset (s[i], 0, mterm*sizeof(double));
+    }
+
+    x = xvec[0].elements;
+    y = yvec[0].elements;
+    z = zvec[0].elements;
+    if (Weight) dz = dzvec[0].elements;
+
+    /* add up the x,y values */
+    for (i = 0; i < xvec[0].Nelements; i++, x++, y++) {
+      if (mask[i]) continue;
+      if (!finite(*x) || !finite(*y)) continue;
+      dZ = 1.0;
+      if (Weight) { 
+	dZ = 1.0 / SQ(*dz);
+	dz ++;
+      }
+      Y = X = 1*dZ;
+      for (ny = 0; ny < mterm; ny++) {
+	X = Y;
+	for (nx = 0; nx < mterm - ny; nx++) {
+	  s[nx][ny] += X;
+	  X = X * (*x);
+	}
+	Y = Y * (*y);
+      }
+    }
+
+    /* add up the z values */
+    x = xvec[0].elements;
+    y = yvec[0].elements;
+    z = zvec[0].elements;
+    for (i = 0; i < xvec[0].Nelements; i++, x++, y++, z++) {
+      if (mask[i]) continue;
+      if (!finite(*x) || !finite(*y)) continue;
+      dZ = 1.0;
+      if (Weight) { 
+	dZ = 1.0 / SQ(*dz);
+	dz ++;
+      }
+      Y = X = *z*dZ;
+      for (j = 0, ny = 0; ny < nterm; ny++) {
+	X = Y;
+	for (nx = 0; nx < nterm - ny; nx++, j++) {
+	  b[j][0] += X;
+	  X = X * (*x);
+	}
+	Y = Y * (*y);
+      }
+    }
+
+    /* re-sort mterm x mterm matrix to wterm matrix */
+    for (k = j = 0; j < nterm; j++) {
+      for (i = 0; i < nterm - j; i++, k++) {
+	for (K = ny = 0; ny < nterm; ny++) {
+	  for (nx = 0; nx < nterm - ny; nx++, K++) {
+	    c[K][k] = s[nx+i][ny+j];
+	  }
+	}
+      }
+    }
+
+    dgaussj (c, wterm, b, 1);
+
+    /** test print **/
+    if (VERBOSE) {
+      for (i = ny = 0; ny < nterm; ny++) {
+	for (nx = 0; nx < nterm - ny; nx++, i++) {
+	  gprint (GP_ERR, "x^%d y^%d: %g\n", nx, ny, b[i][0]);
+	}
+      }
+    }
+
+    /* the b[][0] terms are in the following order:
+       y^0 x^0, y^0 x^1, ... y^0 x^N
+       y^1 x^0, y^1 x^1, ... y^1 x^N
+       ...
+       y^N x^0, y^N x^1, ... y^N x^N
+    */
+    /* generate fitted values */
+    x = xvec[0].elements;
+    y = yvec[0].elements;
+    zf = zfit;
+    for (n = 0; n < xvec[0].Nelements; n++, x++, y++, zf++) {
+      if (!finite(*x) || !finite(*y)) continue;
+      *zf = 0;
+      Y = X = 1;
+      for (i = ny = 0; ny < nterm; ny++) {
+	Y = X;
+	for (nx = 0; nx < nterm - ny; nx++, i++) {
+	  *zf += b[i][0]*Y;
+	  Y = Y * (*y);
+	}
+	X = X * (*x);
+      }
+    }
+
+    /* measure fit residual scatter */
+    x  = xvec[0].elements;
+    y  = yvec[0].elements;
+    z  = zvec[0].elements;
+    zf = zfit;
+    dZ = dZ2 = 0;
+    for (i = Npt = 0; i < xvec[0].Nelements; i++, x++, y++, z++, zf++) {
+      if (mask[i]) continue;
+      if (!finite(*x) || !finite(*y)) continue;
+      dZ  += (*z - *zf);
+      dZ2 += SQ(*z - *zf);
+      Npt ++;
+    }
+    mean  = dZ / Npt;
+    sigma = sqrt (fabs(dZ2/Npt - SQ(mean)));
+    maxsigma = ClipNSigma * sigma;
+
+    if (VERBOSE) gprint (GP_ERR, "mean: %g, sigma: %g, maxsigma: %g\n", mean, sigma, maxsigma);
+
+    /* mask outlier points */
+    x  = xvec[0].elements;
+    y  = yvec[0].elements;
+    z  = zvec[0].elements;
+    zf = zfit;
+    Nmask = 0;
+    for (i = 0; ClipNSigma && (i < xvec[0].Nelements); i++, x++, y++, z++, zf++) {
+      dZ = (*z - *zf);
+      if (fabs(dZ) > maxsigma) {
+	mask[i] = TRUE;
+	Nmask ++;
+      } else {
+	mask[i] = FALSE;
+      }	
+    }
+    if (VERBOSE) gprint (GP_ERR, "pass: %d, Nmask: %d\n", N, Nmask);
+  }
+
+  if (!Quiet) gprint (GP_ERR, "z = ");
+  for (N = ny = 0; ny < nterm; ny++) {
+    for (nx = 0; nx < nterm - ny; nx++, N++) {
+      sprintf (name, "CX%dY%d", nx, ny);
+      set_variable (name, b[N][0]);
+      if (!Quiet) gprint (GP_ERR, "%f x^%d y^%d  ", b[N][0], nx, ny);
+    }
+  }
+  sprintf (name, "Cnn");
+  set_variable (name, (double) order);
+  
+  if (!Quiet) gprint (GP_ERR, "\n");
+
+  /* free internal data */
+  free (zfit);
+  free (mask);
+
+  for (i = 0; i < wterm; i++) {
+    free (c[i]);
+    free (b[i]);
+  }
+  free (b);
+  free (c);
+
+  for (i = 0; i < mterm; i++) {
+    free (s[i]);
+  }
+  free (s);
+
+  return (TRUE);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/gaussdeviate.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/gaussdeviate.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/gaussdeviate.c	(revision 11389)
@@ -0,0 +1,61 @@
+# include "data.h"
+
+int gaussdeviate (int argc, char **argv) {
+  
+  int i, Npts;
+  double mean, sigma;
+  Vector *vec;
+
+  if (argc != 5) goto usage;
+
+  if ((vec = SelectVector (argv[1], ANYVECTOR, TRUE)) == NULL) return (FALSE);    
+
+  Npts = atoi (argv[2]);
+  mean = atof (argv[3]);
+  sigma = atof (argv[4]);
+
+  vec[0].Nelements = Npts;
+  REALLOCATE (vec[0].elements, float, Npts);
+
+  gauss_init (2048);
+  for (i = 0; i < Npts; i++) {
+    vec[0].elements[i] = rnd_gauss (mean, sigma);
+  }
+  return (TRUE);
+
+ usage:
+  gprint (GP_ERR, "USAGE: gaussdeviate (vector) Npts mean sigma\n");
+  return (FALSE);
+    
+}
+
+double int_gauss (int i);
+
+int gaussintegral (int argc, char **argv) {
+  
+  int i, Npts;
+  double mean, sigma;
+  Vector *vec;
+
+  if (argc != 5) goto usage;
+
+  if ((vec = SelectVector (argv[1], ANYVECTOR, TRUE)) == NULL) return (FALSE);    
+
+  Npts = atoi (argv[2]);
+  mean = atof (argv[3]);
+  sigma = atof (argv[4]);
+
+  vec[0].Nelements = Npts;
+  REALLOCATE (vec[0].elements, float, Npts);
+
+  gauss_init (Npts);
+  for (i = 0; i < Npts; i++) {
+    vec[0].elements[i] = int_gauss (i);
+  }
+  return (TRUE);
+
+ usage:
+  gprint (GP_ERR, "USAGE: gaussintegral Npts mean sigma\n");
+  return (FALSE);
+    
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/gaussj.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/gaussj.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/gaussj.c	(revision 11389)
@@ -0,0 +1,58 @@
+# include "data.h"
+
+int gaussjordan (int argc, char **argv) {
+  
+  float *m, *v;
+  double **a, **b;
+  int i, j, N;
+  Vector *B;
+  Buffer *A;
+
+  if (argc != 3) goto usage;
+
+  if ((A = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);    
+  if ((B = SelectVector (argv[2], OLDVECTOR, TRUE)) == NULL) return (FALSE);    
+
+  N = B[0].Nelements;
+  if (A[0].matrix.Naxis[0] != N) goto usage;
+  if (A[0].matrix.Naxis[1] != N) goto usage;
+  
+  ALLOCATE (a, double *, N);
+  ALLOCATE (b, double *, N);
+  for (i = 0; i < N; i++) {
+    ALLOCATE (a[i], double, N);
+    ALLOCATE (b[i], double, 1);
+  }
+
+  m = (float *) A[0].matrix.buffer;
+  v = B[0].elements;
+  for (i = 0; i < N; i++) {
+    for (j = 0; j < N; j++) {
+      a[i][j] = m[i+j*N];
+    }
+    b[i][0] = v[i]; 
+  }
+  dgaussj (a, N, b, 1);
+
+  for (i = 0; i < N; i++) {
+    for (j = 0; j < N; j++) {
+       m[i+j*N] = a[i][j];
+    }
+    v[i] = b[i][0]; 
+  }
+
+  for (i = 0; i < N; i++) {
+    free (a[i]);
+    free (b[i]);
+  }
+  free (a);
+  free (b);
+  return (TRUE);
+
+ usage:
+  gprint (GP_ERR, "USAGE: gaussj A B\n");
+  gprint (GP_ERR, "  solves Ax = B, returns 1/A in A and x in B\n");
+  gprint (GP_ERR, "  A must be square, B same dimensions\n");
+  return (FALSE);
+    
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/grid.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/grid.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/grid.c	(revision 11389)
@@ -0,0 +1,212 @@
+# include "data.h"
+
+int grid (int argc, char **argv) {
+  
+  int j, N, MinorTick, MajorTick;
+  Vector Xvec, Yvec;
+  double range, lrange, factor, mantis, fmantis, power, major, minor, first, next;
+  Graphdata graphmode;
+  int Ngraph;
+
+  Ngraph = -1;
+  if ((N = get_argument (argc, argv, "-n"))) {
+    remove_argument (N, &argc, argv);
+    Ngraph = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if (!GetGraph (&graphmode, NULL, &Ngraph)) return (FALSE);
+
+  MajorTick = TRUE;
+  MinorTick = FALSE;
+  if ((N = get_argument (argc, argv, "-all"))) {
+    remove_argument (N, &argc, argv);
+    MinorTick = TRUE;
+  }
+
+  if (argc > 1) {
+    gprint (GP_ERR, "USAGE: grid [-n graph]\n");
+    return (FALSE);
+  }
+
+  N = 0;
+  Xvec.Nelements = 200;
+  Yvec.Nelements = 200;
+  ALLOCATE (Xvec.elements, float, Xvec.Nelements);
+  ALLOCATE (Yvec.elements, float, Yvec.Nelements);
+
+  major = minor = 1;
+  range = graphmode.xmax - graphmode.xmin;
+  lrange = log10(MAX(fabs(range), 1e-30));
+  factor = (int) (lrange);
+  if (lrange < 0) { factor -= 1; }
+  mantis = lrange - factor;
+  power = pow(10.0, factor);
+  fmantis = pow(10.0, mantis);
+  if ((fmantis >= 1.0) && (fmantis <=  2.0)) {
+    major = 0.5 * power;
+    minor = 0.1 * power;
+  }
+  if ((fmantis > 2.0) && (fmantis <=  4.0)) {
+    major = 1.0 * power;
+    minor = 0.2 * power;
+  }
+  if ((fmantis > 4.0) && (fmantis <=  6.0)) {
+    major = 1.0 * power;
+    minor = 0.5 * power;
+  }
+  if ((fmantis > 6.0) && (fmantis <=  10.0)) {
+    major = 2.0 * power;
+    minor = 0.5 * power;
+  }
+  if (graphmode.xmin > 0)
+    first = minor + minor*((int)(graphmode.xmin/minor));
+  else 
+    first = -minor + minor*((int)(graphmode.xmin/minor));
+  if (minor*((int)(graphmode.xmin/minor)) == graphmode.xmin) {
+    first = graphmode.xmin;
+  }
+  
+  for (j = 0, next = first; next <= graphmode.xmax; j++) {
+    if ((fabs((int)(next/major) - (next/major)) < 0.5*(minor/major)) || (fabs ((int)((next + 0.5*minor)/major) - (next/major)) < 0.5*(minor/major))) {
+      if (MajorTick) {
+	/* major tick */
+	Xvec.elements[N] = next;
+	Yvec.elements[N] = graphmode.ymin;
+	N++;
+	if (N == Xvec.Nelements) {
+	  Xvec.Nelements += 200;
+	  Yvec.Nelements += 200;
+	  REALLOCATE (Xvec.elements, float, Xvec.Nelements);
+	  REALLOCATE (Yvec.elements, float, Yvec.Nelements);
+	}
+	Xvec.elements[N] = next;
+	Yvec.elements[N] = graphmode.ymax;
+	N++;
+	if (N == Xvec.Nelements) {
+	  Xvec.Nelements += 200;
+	  Yvec.Nelements += 200;
+	  REALLOCATE (Xvec.elements, float, Xvec.Nelements);
+	  REALLOCATE (Yvec.elements, float, Yvec.Nelements);
+	}
+      }
+    } else {
+      if (MinorTick) {
+	/* minor tick */
+	Xvec.elements[N] = next;
+	Yvec.elements[N] = graphmode.ymin;
+	N++;
+	if (N == Xvec.Nelements) {
+	  Xvec.Nelements += 200;
+	  Yvec.Nelements += 200;
+	  REALLOCATE (Xvec.elements, float, Xvec.Nelements);
+	  REALLOCATE (Yvec.elements, float, Yvec.Nelements);
+	}
+	Xvec.elements[N] = next;
+	Yvec.elements[N] = graphmode.ymax;
+	N++;
+	if (N == Xvec.Nelements) {
+	  Xvec.Nelements += 200;
+	  Yvec.Nelements += 200;
+	  REALLOCATE (Xvec.elements, float, Xvec.Nelements);
+	  REALLOCATE (Yvec.elements, float, Yvec.Nelements);
+	}
+      }
+    }
+    next += minor;
+  }
+
+  range = graphmode.ymax - graphmode.ymin;
+  lrange = log10(MAX(fabs(range), 1e-30));
+  factor = (int) (lrange);
+  if (lrange < 0) { factor -= 1; }
+  mantis = lrange - factor;
+  power = pow(10.0, factor);
+  fmantis = pow(10.0, mantis);
+  if ((fmantis >= 1.0) && (fmantis <=  2.0)) {
+    major = 0.5 * power;
+    minor = 0.1 * power;
+  }
+  if ((fmantis > 2.0) && (fmantis <=  4.0)) {
+    major = 1.0 * power;
+    minor = 0.2 * power;
+  }
+  if ((fmantis > 4.0) && (fmantis <=  6.0)) {
+    major = 1.0 * power;
+    minor = 0.5 * power;
+  }
+  if ((fmantis > 6.0) && (fmantis <=  10.0)) {
+    major = 2.0 * power;
+    minor = 0.5 * power;
+  }
+  if (graphmode.ymin > 0)
+    first = minor + minor*((int)(graphmode.ymin/minor));
+  else 
+    first = -minor + minor*((int)(graphmode.ymin/minor));
+  if (minor*((int)(graphmode.ymin/minor)) == graphmode.ymin) {
+    first = graphmode.ymin;
+  }
+  
+  for (j = 0, next = first; next <= graphmode.ymax; j++) {
+    if ((fabs((int)(next/major) - (next/major)) < 0.5*(minor/major)) || (fabs ((int)((next + 0.5*minor)/major) - (next/major)) < 0.5*(minor/major))) {
+      if (MajorTick) {
+	/* major tick */
+	Xvec.elements[N] = graphmode.xmin;
+	Yvec.elements[N] = next;
+	N++;
+	if (N == Xvec.Nelements) {
+	  Xvec.Nelements += 200;
+	  Yvec.Nelements += 200;
+	  REALLOCATE (Xvec.elements, float, Xvec.Nelements);
+	  REALLOCATE (Yvec.elements, float, Yvec.Nelements);
+	}
+	Xvec.elements[N] = graphmode.xmax;
+	Yvec.elements[N] = next;
+	N++;
+	if (N == Xvec.Nelements) {
+	  Xvec.Nelements += 200;
+	  Yvec.Nelements += 200;
+	  REALLOCATE (Xvec.elements, float, Xvec.Nelements);
+	  REALLOCATE (Yvec.elements, float, Yvec.Nelements);
+	}
+      }
+    } else {
+      if (MinorTick) {
+	/* minor tick */
+	Xvec.elements[N] = graphmode.xmin;
+	Yvec.elements[N] = next;
+	N++;
+	if (N == Xvec.Nelements) {
+	  Xvec.Nelements += 200;
+	  Yvec.Nelements += 200;
+	  REALLOCATE (Xvec.elements, float, Xvec.Nelements);
+	  REALLOCATE (Yvec.elements, float, Yvec.Nelements);
+	}
+	Xvec.elements[N] = graphmode.xmax;
+	Yvec.elements[N] = next;
+	N++;
+	if (N == Xvec.Nelements) {
+	  Xvec.Nelements += 200;
+	  Yvec.Nelements += 200;
+	  REALLOCATE (Xvec.elements, float, Xvec.Nelements);
+	  REALLOCATE (Yvec.elements, float, Yvec.Nelements);
+	}
+      }
+    }
+    next += minor;
+  }
+
+  Xvec.Nelements = Yvec.Nelements = N;
+  graphmode.style = 2; /* points */
+  graphmode.ptype = 100; /* connect a pair */
+  graphmode.etype = 0;
+  PrepPlotting (N, &graphmode);
+  PlotVector (N, Xvec.elements);
+  PlotVector (N, Yvec.elements);
+
+  free (Xvec.elements);
+  free (Yvec.elements);
+
+  return (TRUE);
+
+}
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/gridify.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/gridify.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/gridify.c	(revision 11389)
@@ -0,0 +1,82 @@
+# include "data.h"
+
+int gridify (int argc, char **argv) {
+
+  int i, Nx, Ny, Xb, Yb, Normalize, N;
+  float Xmin, Xmax, dX, Ymin, Ymax, dY;
+  float *buf, *val, *x, *y, *z;
+  int *Nval;
+  Buffer *bf;
+  Vector *vx, *vy, *vz;
+
+  Normalize = TRUE;
+  if ((N = get_argument (argc, argv, "-raw"))) {
+    remove_argument (N, &argc, argv);
+    Normalize = FALSE;
+  }
+
+  if (argc != 11) {
+    gprint (GP_ERR, "USAGE: gridify x y z buffer Xmin Xmax dX Ymin Ymax dY\n");
+    return (FALSE);
+  }
+  
+  if ((vx = SelectVector (argv[1], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((vy = SelectVector (argv[2], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((vz = SelectVector (argv[3], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((bf = SelectBuffer (argv[4], ANYBUFFER, TRUE)) == NULL) return (FALSE);
+
+  if (vx[0].Nelements != vy[0].Nelements) return (FALSE);
+  if (vx[0].Nelements != vz[0].Nelements) return (FALSE);
+
+  Xmin = atof (argv[5]);
+  Xmax = atof (argv[6]);
+  dX   = atof (argv[7]);
+
+  Ymin = atof (argv[8]);
+  Ymax = atof (argv[9]);
+  dY   = atof (argv[10]);
+
+  Nx = (Xmax - Xmin) / dX + 1;
+  Ny = (Ymax - Ymin) / dY + 1;
+  
+  gfits_free_matrix (&bf[0].matrix);
+  gfits_free_header (&bf[0].header);
+  CreateBuffer (bf, Nx, Ny, -32, 0.0, 1.0);
+  strcpy (bf[0].file, "(empty)");
+
+  ALLOCATE (val, float, Nx*Ny);
+  bzero (val, Nx*Ny*sizeof(float));
+  ALLOCATE (Nval, int, Nx*Ny);
+  bzero (Nval, Nx*Ny*sizeof(int));
+
+  x = vx[0].elements;
+  y = vy[0].elements;
+  z = vz[0].elements;
+  for (i = 0; i < vx[0].Nelements; i++, x++, y++, z++) {
+    Xb = (*x - Xmin) / dX;
+    Yb = (*y - Ymin) / dY;
+    if (Xb >= Nx) continue;
+    if (Yb >= Ny) continue;
+    val[Xb + Yb*Nx] += *z;
+    Nval[Xb + Yb*Nx]++;
+  }
+
+  buf = (float *) bf[0].matrix.buffer;
+  for (i = 0; i < Nx*Ny; i++) {
+    if (Normalize) {
+      if (Nval[i] == 0) {
+	buf[i] = 0;
+	continue;
+      }
+      buf[i] = val[i] / Nval[i];
+    } else {
+      buf[i] = val[i];
+    }
+  }
+
+  free (val);
+  free (Nval);
+
+  return (TRUE);
+
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/Graphics
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/Graphics	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/Graphics	(revision 11389)
@@ -0,0 +1,20 @@
+
+  Kapa, the graphics window.
+
+  Kapa is the program which Status uses to display plots on an X
+terminal.  There are actually 5 graphics windows available to Status,
+though several functions write to specific windows by default.  All
+plots of sky coordinates are displayed on window 0, while 
+functions which plot other types of data use window 1.  Most functions
+have an option -n which allows the user to specify which Kapa window.
+If it is not specified, the last window used will receive the action.
+
+  Below are the available Resources.  
+
+  kii*Foreground:			white
+  kii*Background:			maroon
+  kii*geometry:				540x540+10+10
+
+  See Also: box, clear, limits, plot
+
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/Kii
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/Kii	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/Kii	(revision 11389)
@@ -0,0 +1,57 @@
+
+
+  Kii (= "picture" in Hawaiian) is the program which Mana uses to
+display images on an X terminal.  The window consists of a main region
+where the image is displayed, a small "zoom box" where a magnified
+view of the region around the cursor is shown, a colorbar showing the
+current color map across the top of the window, a status box where the
+coordinates and pixel values are displayed, and several buttons.
+Clicking with the mounse in the different regions produces different
+effects.
+
+  Image Window:  Clicking with the left mouse button (mouse-1)
+recenters the image at the specified location.  Clicking with the
+right button (mouse-3) also recenters, but increases the zoom factor
+by one.  Clicking with the middle button centers and decreases the
+zoom factor.  
+
+  Colorbar: Clicking and draging with the left button (mouse-1) alters
+the color mapping.  Moving left-to-right slides the center of the
+color scale with the mouse.  Moving up-and-down squeezes or expands
+the color scale.  The middle button resets the color mapping.
+Clicking and dragging side-to-side with the right button expands or
+squeezes the color mapping.  **Note: the dynamic colormap cannot be
+used with a 24 or 32 bit visual.  The standard Linux XFree86 server
+does not support 8 bit visuals in 24 or 32 bit/pixel mode.  In this
+case, the Kii window must resort to a static colormap with the
+colorbar disabled.  In Linux, it is possible to run startx with the
+following command-line options to force the 8 bit/pixel mode:
+# startx -- -bpp 8 
+This assumes that you have an 8bpp Display mode set in the XF86Config
+file.  If not, you can just duplicate the 24 or 32 bpp Display modes
+which will enable this option.
+
+  Buttons:
+    PS: this button creates a PostScript version of the image.
+    Grey: this button makes the colormap a greyscale.
+    Rainbow: this button makes the colormap a rainbow.
+    Puns: this button make the colormap a blue and yellow mapping.
+    Recenter: this button recenters the image and resets the zoom.
+
+  Kii also recognizes several X Resource values:
+
+  Below are the available Resources (with Gene's default values).  Unlike
+most standard X programs, the geometry resource specifies the size of
+the Image Window, not the borders of the entire window.  Valid values
+for the colormap are: greyscale, grayscale (photonegative), -greyscale,
+-grayscale (photopositive), Puns, GoBears (buff 'n blue colormap),
+Rainbow (a rainbow map).  
+
+  kii*Foreground:			white
+  kii*Background:			maroon
+  kii*Colormap:				greyscale
+  kii*geometry:				540x540+10+10
+  
+
+  See Also: tv, cursor
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/Math
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/Math	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/Math	(revision 11389)
@@ -0,0 +1,58 @@
+
+  Opihi shell math operations:
+
+  Mana will evaluate scalar (1D) arithmetic expresions in two
+situations.  To set a variable equal to a math operation, use the
+syntax is:
+
+  $foo = expression
+
+where "expression" is an arithmetic expression on numbers and
+variables, including a variety of functions (see below).  After
+performing the arithmetic and setting the variable to the resulting
+value, mana returns the prompts without performing any further
+command.  Mana will also evaluate any arithmetic expression enclosed
+in curly brackets before attempting to perform the given command.  For
+example, if the variables $MEAN and $SIGMA contain the mean and
+standard deviation of an image, it would be possible to display the
+image with a zero and range based on $MEAN and $SIGMA like this:
+
+  tv image {$MEAN - 1.5*$SIGMA} {5*$SIGMA}
+
+
+The two expressions in curly brackets are evaluated and the resulting
+numbers passed as arguments to the "tv" command.
+
+  See Also:  Variables, tv
+
+
+list of valid math operations:
+
+  binary operators:
+  * (times)
+  / (divided by)
+  + (plus)
+  - (minus)
+  ^ (to the power of: 2^3 = 8)
+
+  unary operators:
+  exp (e to the power of)
+  ten (10 to the power of)
+  ln  (natural logarithm)
+  log (log base 10)
+
+  angles in radians:
+  sin (sine)
+  cos (cosine)
+  tan (tangent)
+  asin (arcsin)
+  acos (arccos)
+  atan (arctan)
+
+  angles in degrees:
+  dsin (sine)
+  dcos (cosine)
+  dtan (tangent)
+  dasin (arcsin)
+  dacos (arccos)
+  datan (arctan)
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/applyfit
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/applyfit	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/applyfit	(revision 11389)
@@ -0,0 +1,10 @@
+
+  applyfit x y
+
+  apply the results of a polynomial fit (stored in variables 
+  $C0, $C1, etc, with $Cn representing the order of the fit).
+  The second vector will contain the function value at the 
+  corresponding x coordinates of the first vector.
+
+  See also: fit
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/box
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/box	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/box	(revision 11389)
@@ -0,0 +1,11 @@
+
+  box [-n Nwindow]
+
+  draw a coordinate box on the current kapa window, or on the window
+specified by -n (0 - 4).
+
+  See also: Kapa
+
+
+
+  
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/buffers
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/buffers	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/buffers	(revision 11389)
@@ -0,0 +1,9 @@
+
+  buffers
+
+  buffers gives information about the currently allocated buffers.  
+A * next to the filename means the data has been altered from the
+originally read in image.
+
+  See also: memory
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/center
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/center	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/center	(revision 11389)
@@ -0,0 +1,10 @@
+
+  center (xpix) (ypix) [magnification]
+
+  "center" centers the Kii window at the specified pixel coordinates.
+Specifying a magnification will change the image scale to the
+specified magnification.  If you do not specify a magnification
+(default), the image scale will remain the same.
+
+  See also: Kii, tv
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/clear
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/clear	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/clear	(revision 11389)
@@ -0,0 +1,5 @@
+
+   clear
+
+   clear the Kapa window
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/clip
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/clip	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/clip	(revision 11389)
@@ -0,0 +1,8 @@
+
+  clip (buffer) [min Vmin max Vmax] [-inf val] [-nan val]
+
+  clip values in an image.  A min/max clip can be applied, 
+  in which case all values above max are set to Vmax and all
+  below min are set to Vmin.  -nan and -inf flags will set all 
+  instances of NaN or any non-finite values to the given value.
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/concat
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/concat	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/concat	(revision 11389)
@@ -0,0 +1,8 @@
+
+   concat v1 v2
+
+   concatenates the values of vector v2 to the end of vector
+   v1, increasing the length of v1.
+
+   See also: subset, set
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/contour
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/contour	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/contour	(revision 11389)
@@ -0,0 +1,13 @@
+
+  contour <buffer> (overlay) level [Npix]
+
+  "contour" makes a contour plot from the given <buffer> at the
+specified level.  If Npix is specified, the image is rebinned by a
+factor of Npix in each direction.  The contour is drawn as a series of
+lines on the specified overlay.  The new lines are added to any
+existing shapes.  (Use "erase" first to erase all objects if desired).
+
+Valid overlays may be: 0, red, 1, green, 2, blue, 3, yellow.
+
+  See also: load, save, erase
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/create
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/create	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/create	(revision 11389)
@@ -0,0 +1,7 @@
+
+   create vector start end [delta]
+
+   create a vector of uniformly spaced values, starting at
+   start and going to end.  By default the spacing is 1, but
+   may be chosen with the delta option.
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/cursor
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/cursor	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/cursor	(revision 11389)
@@ -0,0 +1,13 @@
+
+  cursor
+
+  place cursor coordinates (and values ??) into Mana variables.  to do
+this, type cursor, then place the cursor on the desired spot in the
+Ki'i window and type a digit (0 - 9).  The coordinates of the cursor
+are then placed in the variables $Xn and $Yn (where n is the digit you
+typed).  To exit the cursor mode, type "q" (or "Q") in the Ki'i
+window.  
+
+  See Also: Kii, tv, center
+
+ 
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/cut
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/cut	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/cut	(revision 11389)
@@ -0,0 +1,9 @@
+
+   cut buffer <X vector> <Y vector> <X|Y> sx sy nx ny
+
+   take a cut from an image and place it in a pair of vectors.
+   the <X vector> gets the pixel coordinate in the given direction,
+   the <Y vector> gets the pixel values.  <X|Y> specifies the 
+   direction of the cut.  the region sx, sy, nx, ny specifies the
+   region for the cut, with summation in the cross-direction.
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/datafile
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/datafile	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/datafile	(revision 11389)
@@ -0,0 +1,6 @@
+
+   datafile (filename)
+
+   define a data file for subsequent vector reads.
+
+   See also: read
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/delete
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/delete	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/delete	(revision 11389)
@@ -0,0 +1,5 @@
+
+  delete <buffer>
+
+  delete the named buffer.  Warning: no second chances are given!
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/erase
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/erase	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/erase	(revision 11389)
@@ -0,0 +1,8 @@
+
+  erase (overlay)
+
+  "erase" erases all objects on the specified overlay.  
+  Valid overlays may be: all, red, green, blue, yellow.
+
+  See also: load, save, contour
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/extract
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/extract	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/extract	(revision 11389)
@@ -0,0 +1,12 @@
+
+  extract <from> <to> sx sy nx ny sx sy nx ny
+
+  extract takes a portion of an image (buffer <from>) and creates a
+new image (buffer <to>).  The source region is defined by the first
+set of (sx sy nx ny), the resulting image and the location of the
+extracted image are defined by the second (sx sy nx ny).  This allows
+a portion of an image to be overlayed at a particular location in a
+larger image.
+
+  See also: Kii, tv
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/fit
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/fit	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/fit	(revision 11389)
@@ -0,0 +1,9 @@
+
+   fit x y order [-dy wt]
+
+   perform a lease-square polynomial fit to the data defined 
+   by vectors x and y.  the coefficients are placed in the variables
+   $C0, $C1, ..., and the order is placed in $Cn.
+
+   See also: applyfit
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/grid
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/grid	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/grid	(revision 11389)
@@ -0,0 +1,6 @@
+
+   grid (overlay) (buffer)
+
+   draw a coordinate grid for the given buffer in the 
+   given overlay in Kii.
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/header
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/header	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/header	(revision 11389)
@@ -0,0 +1,8 @@
+
+   header (buffer)
+
+   print the header information for the given buffer.  The header
+   information is Meta-information associated with an image.  It is
+   well-defined for the FITS images, but may not exist for some of the
+   other possible data types.  
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/histogram
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/histogram	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/histogram	(revision 11389)
@@ -0,0 +1,8 @@
+
+   histogram <buffer> <x> <y> [-region sx sy nx ny] [-range min max]
+
+   calculate a histogram of the image pixel values in the given
+   buffer, optionally constrained to the given region, with optional
+   max and min values.  the results are placed in the vectors x and y,
+   which contain the pixel values and the number of occurences.
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/kern
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/kern	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/kern	(revision 11389)
@@ -0,0 +1,4 @@
+
+   kern buffer (kernel file or -)
+
+   apply a 3x3 kernel to the image.  
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/keyword
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/keyword	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/keyword	(revision 11389)
@@ -0,0 +1,11 @@
+
+  keyword <buffer> (KEYWORD) [variable] [-w value]
+
+  "keyword" extracts the specified keyword from the header of the
+   specified buffer.  If a third word is listed, the value of the
+   keyword is stored in a variable with the given name.  If the -w
+   option is given, the value is written to the header keyword.
+
+   The header Meta-data is well-defined for FITS, but not necessarily
+   for other data types.
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/labels
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/labels	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/labels	(revision 11389)
@@ -0,0 +1,23 @@
+
+   labels 
+
+   write a label on the Kapa window.  there are many options:
+
+   -fn font size -- define the font (may be times, helvetica, courier)
+
+   -x "a long line" -- label on the bottom x-axis
+
+   +x "a long line" -- label on the top x-axis
+
+   -y "a long line" -- label on the left y-axis
+
+   +y "a long line" -- label on the right y-axis
+
+   -ul "a long line" -- label on the upper left of plot
+
+   -ll "a long line" -- label on the lower left of plot
+
+   -ur "a long line" -- label on the upper right of plot
+
+   -lr "a long line" -- label on the lower right of plot
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/limits
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/limits	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/limits	(revision 11389)
@@ -0,0 +1,12 @@
+
+   limits min max min max
+   limits x y
+   limits x min max
+   limits min max y
+   
+   set Kapa plot limits.  The x and y axis limits may be explicitly
+   set (first example), or they may be assigned based on the range of
+   values in a pair of vectors (second examples), or one range may be
+   explicit and the other range assigned from a vector.
+
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/load
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/load	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/load	(revision 11389)
@@ -0,0 +1,20 @@
+
+   load (overlay) (filename)
+
+  "load" reads a file with objects in SAOimage style into the
+  specified overlay.  If the specified overlay is already used, the
+  new objects are added to the old.  If you do not want this, use
+  "erase" to erase all objects in the overlay first.  Valid overlays
+  may be: 0, red, 1, green, 2, blue, 3, yellow.
+
+Examples of SAOimage style objects:
+BOX   300  200  100 50  : draws a box centered at pixel 300,200 that
+			  is 100 pixels wide, and 50 pixels high
+
+CIRCLE 500 400 200 : draws a circle centered at pixel 500,400 with a
+                     radius of 200 pixels
+
+LINE 100 100 200 200 : draws a line from (100,100) with length (200,200)
+
+  See also: save, erase, contour
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/plot
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/plot	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/plot	(revision 11389)
@@ -0,0 +1,13 @@
+
+   plot <x> <y> [-dx dx] [-dy dy] [+dx dx] [+dy dy]
+
+   plot a pair of vectors.  the options allow for errorbars.  If only
+   one of -dy or +dy is given, the given vector is used for the
+   errorbar.  If both are given, -dy defines the lower errorbar, while
+   +dy defines the upper errorbar.  This allows for assymetric errors
+   in a trivial fashion.  The same applies to the -dx, +dx values.  
+
+   The vectors are plotted with the current plot style.  See style for
+   all of the options.
+
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/ps
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/ps	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/ps	(revision 11389)
@@ -0,0 +1,16 @@
+
+   ps [-name file.ps] [-g | -i] [-n device] [-raw] [-noscale] [-newpage]
+
+   create a PostScript file from the current graphics window (Kii or
+   Kapa).  The target graphics window may be selected with the -g or
+   -i options (to choose between Kii or Kapa) in combination the -n
+   option (to specify which instance).
+
+   With no additional arguments, Kii produces an encapsulated
+   postscript file called Ximage.ps, while Kapa produces a file called
+   Xgraph.ps.  The output name may be set with the -name (file.ps)
+   option. 
+
+   By default, the output is scaled to fit on a letter page 
+
+   
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/rd
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/rd	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/rd	(revision 11389)
@@ -0,0 +1,10 @@
+
+  rd (buffer) (filename)
+
+  "rd" reads a file into the specified buffer, creating the buffer if
+  none exists.  A buffer name may consist of any letters, numbers, and
+  some limited other characters.  However, the name may not start with
+  a digit.
+
+  See also: wd, tv
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/read
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/read	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/read	(revision 11389)
@@ -0,0 +1,10 @@
+
+   read vect col [vect col, ...]
+
+   read vector values from a file.  An arbitrary number of vectors can
+   be specified, and the (whitespace-separated) field number given for
+   each vector.  Data is read from the file defined by "datafile".
+
+   See also: datafile
+
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/rebin
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/rebin	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/rebin	(revision 11389)
@@ -0,0 +1,9 @@
+
+  rebin <from> <to> scale
+
+  "rebin" rebins the specified buffer by the given scale factor and
+  places the result in the <to> buffer.  Negative integer values imply
+  expansion, positive numbers imply compression.
+
+  See also: extract
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/resize
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/resize	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/resize	(revision 11389)
@@ -0,0 +1,6 @@
+
+   resize Nx Ny
+
+   change the size of the Kii window to have image dimensions Nx x
+   Ny.  
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/rotate
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/rotate	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/rotate	(revision 11389)
@@ -0,0 +1,10 @@
+
+   rotate (buffer) (angle) [-center x y]
+
+   rotate the buffer by the given angle.  The angle may also be one of
+   the following special words:
+
+   -flipx - flip in the x direction
+   -flipy - flip in the y direction
+
+   if the optional center is given the rotation is about this position.
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/save
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/save	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/save	(revision 11389)
@@ -0,0 +1,16 @@
+  save (overlay) (filename)
+
+  "save" stores the objects from the specified overlay into the named
+file.  Valid overlays may be: 0, red, 1, green, 2, blue, 3, yellow.
+
+Examples of SAOimage style objects:
+BOX   300  200  100 50  : draws a box centered at pixel 300,200 that
+			  is 100 pixels wide, and 50 pixels high
+
+CIRCLE 500 400 200 : draws a circle centered at pixel 500,400 with a
+                     radius of 200 pixels
+
+LINE 100 100 200 200 : draws a line from (100,100) with length (200,200)
+
+  See also: load, erase, contour
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/set
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/set	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/set	(revision 11389)
@@ -0,0 +1,41 @@
+
+  set (buffer) = expression..
+
+  perform math operations on images.  there are several allowed
+  operators.  the standard math functions are + - * /.  Exponentiation
+  is performed with ^ (set c = a ^ b).  There are several "logic"
+  operators which need some explanation.
+
+  set c = a < b  -- c is 1 if a < b, 0 otherwise
+  set c = a > b  -- c is 1 if a > b, 0 otherwise
+  set c = m1 & m1 - c is 1 if m1 AND m2 true (non-zero is true)
+  set c = m1 | m1 - c is 1 if m1 OR m2 true (non-zero is true)
+  set c = a << b -- c is the minimum of a and b
+  set c = a >> b -- c is maximum of a and b
+
+  complex operations may be performed:
+
+  set c = a*(a < b) + c*((a < c) | (c < d))
+
+  unary operators also exist:
+
+  exp(a) - e to the power of a
+  ten(a) - 10 to the power of a
+  ln(a) - log base e of a
+  log(a) - log base 10 of a
+  sqrt(a) - square root of a
+  sin(a) - sin of a
+  cos(a) - sin of a
+  tan(a) - sin of a
+  not(a) - logical inverse of a
+  abs(a) - absolute value of a
+  int(a) - integer value of a
+
+  Examples:
+  
+  set a = b + 10  (add 10 to every pixel in b and put the answer in a)
+  set a = a / b   (divide every pixel in a by the corresponding pixel
+                     b and put the answer in a)
+  set b = 10 / a  (divide 10 by every pixel in a and put the answer
+                     in b)
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/shift
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/shift	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/shift	(revision 11389)
@@ -0,0 +1,6 @@
+
+   shift buffer dx dy
+
+   shift image by dx,dy pixels (may be fractional values).
+
+   
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/stats
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/stats	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/stats	(revision 11389)
@@ -0,0 +1,10 @@
+
+  stats (buffer) (x) (y) (nx) (ny)
+
+  report the statistics on a portion of an image.  (x) and (y) specify
+the starting corner of the region, (nx) and (ny) specify the width and
+height of the region.  stats reports the mean, sigma, and number of
+pixels in the region.
+
+  See Also: ??
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/style
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/style	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/style	(revision 11389)
@@ -0,0 +1,36 @@
+
+   style -- many options
+
+   define or check the Kapa plotting style.  without any command-line arguments,
+   style prints the current style.  
+
+   option definitions:
+
+   -n	window number (0-4), can also be used to change active window.
+   -pt	point style: 
+		0 = filled box
+		1 = open box
+		2 = +
+		3 = X
+		4 = filled triangle
+		5 = blank
+		6 = open triangle 
+		7 = open circle
+		100 = connect pair of points
+   -x	plotting method:
+		0 = connect
+		1 = histogram
+		2 = points
+   -lt	line type:
+		0 = solid
+		1 = dashed
+		2 = dotted??
+   -lw	line weight (0-10)
+   -sz	point size
+   -c   color:
+	black, white, red, orange, 
+	yellow, green, blue, indigo, violet
+   -eb  errorbar with no top
+   +eb  errorbar with top
+
+   See also: plot, box
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/subset
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/subset	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/subset	(revision 11389)
@@ -0,0 +1,12 @@
+
+   subset vec = vec if (logic expression)
+
+   reduce the length of a vector based on logical expression.  The
+   logic expression is some function of vectors of equal length to the
+   main vector.
+
+   for example, we have vectors x and y of the same length:
+   
+   subset X = x if ((y > 100) | (x < 10))
+
+    
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/textline
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/textline	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/textline	(revision 11389)
@@ -0,0 +1,7 @@
+
+   textline x y (line) [-fn (font) size] [-rot angle]
+
+   write the string at the given coordinates and rotation,
+   in the given font.
+
+   (enclose long strings with spaces in quotes)
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/tv
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/tv	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/tv	(revision 11389)
@@ -0,0 +1,13 @@
+
+  tv [-log] (buffer) [zero range]
+
+  display an image in the Ki'i window (X display program).  zero and
+  range specify the data values corresponding to the color mapping.
+  If they are not specified, the old values are used (default is 0,
+  1024).
+
+  If -log is specified the color mapping scale will be logarithmic.  
+
+
+  See Also: Kii, rd, cursor
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/unsign
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/unsign	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/unsign	(revision 11389)
@@ -0,0 +1,20 @@
+  unsign
+
+  "unsign" toggles the status of the UNSIGN mode.  Warning: This is a
+non-FITS standard implementation.  The FITS standard does not allow
+for unsigned integer data values, but many sites write CCD images with
+16 bit UNSIGNED data.  Mana looks for a FITS keyword "UNSIGN" to
+determine if an image which is read in has signed or unsigned
+integers.  However, since this is a non-standard concept, many sites
+do not use the UNSIGN flag, yet still write unsigned data.  If the
+user knows the data in the file is unsigned (ie, the user must have
+apriori knowledge -- a FITS no-no!), then the user should set the
+UNSIGN mode to true.  In the event that the UNSIGN mode is set, if a
+FITS file is encountered which contains integers, but which does not
+contain the UNSIGN keyword, Mana will make the default assumption that
+the data is unsigned.  If the SIGNED mode is set, Mana will assume all
+integer FITS files contain signed integers.  
+
+((( should be able to say "unsign <buffer>" to convert the status of a
+buffer to UNSIGN or to toggle the buffer's status, but not yet
+implemented)))
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/vectors
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/vectors	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/vectors	(revision 11389)
@@ -0,0 +1,5 @@
+
+   vectors
+
+   list the currently defined vectors and lengths
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/wd
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/wd	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/wd	(revision 11389)
@@ -0,0 +1,29 @@
+
+  wd (buffer) (filename) [BITPIX]
+
+  wd writes a buffer to the specified file in FITS format.  (You may
+need quotes around the filename if there are any /'s in the path).
+The FITS keyword BITPIX may be specified.  Valid values are 8, 16, 32
+(integer formats) and -32, -64 (floating point formats).  If BITPIX is
+unspecified, the original value of the image is used.  The image is
+converted blindly to the format and written out.  This may mean that
+values are rounded (integers), or wrapped by the range of the number
+of bits.  Also beware of the issue of signed vs unsigned images.
+
+  See Also: rd
+
+bitpix  bzero  bscale  file range     data range
+16      0      1       -32k : 32k     -32k : 32k
+16	32k    1       -32k : 32k        0 : 64k
+16	0      2       -32k : 32k     -64k : 64k
+16	0      0.001   -32k : 32k     -32. : 32.
+32	0      1       -2e9 : 2e9     -2e9 : 2e9
+8	0      1       -128 : 128     -128 : 128
+
+so for example, a file with a data range of -128k to +128k written
+with bitpix 16, bzero 0, bscale 1 will have all data outside -32k :
++32k wrapped back in that range.
+
+note: on write, bzero is subtracted from the data before the data is
+      divided by bscale.
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/zplot
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/zplot	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/help/zplot	(revision 11389)
@@ -0,0 +1,7 @@
+
+   zplot x y z min max
+
+   plot the vector pair x and y as a series of points with size scaled
+   by the values in the vector z, with the smallest point having
+   values <= min and the largest having values >= max.
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/histogram.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/histogram.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/histogram.c	(revision 11389)
@@ -0,0 +1,45 @@
+# include "data.h"
+
+int histogram (int argc, char **argv) {
+  
+  int i, bin, Nbins;
+  float *V, start, end, delta;
+  Vector *xvec, *yvec;
+
+  if ((argc != 6) && (argc != 5)) {
+    gprint (GP_ERR, "USAGE: hist invec outvec start end [delta]\n");
+    return (FALSE);
+  }
+
+  delta = 1;
+  start = atof (argv[3]);
+  end   = atof (argv[4]);
+  if (argc == 6) delta = atof (argv[5]);
+ 
+  if ((start == end) || (delta == 0)) {
+    gprint (GP_ERR, "error in value: %f to %f, %f\n", start, end, delta);
+    return (FALSE);
+  }
+  delta = fabs (delta);
+  if (end - start < 0) {
+    delta = -1.0 * delta;
+  }
+  Nbins = (end - start) / delta;
+  /* number here should match number in create.c */
+
+  if ((xvec = SelectVector (argv[1], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((yvec = SelectVector (argv[2], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+  yvec[0].Nelements = Nbins;
+    
+  REALLOCATE (yvec[0].elements, float, yvec[0].Nelements);
+  bzero (yvec[0].elements, sizeof(float)*yvec[0].Nelements);
+
+  V = xvec[0].elements;
+  for (i = 0; i < xvec[0].Nelements; i++, V++) {
+    bin = MIN (MAX (0, (*V - start) / delta), Nbins - 1);
+    yvec[0].elements[bin] += 1.0;
+  }      
+
+  return (TRUE);
+
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/imcut.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/imcut.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/imcut.c	(revision 11389)
@@ -0,0 +1,66 @@
+# include "data.h"
+
+int imcut (int argc, char **argv) {
+  
+  int i, Nx, Ny, xi, yi, L;
+  double xs, ys, xe, ye, dX, dY;
+  Vector *xvec, *yvec;
+  Buffer *buf;
+  float *V;
+
+  if (argc != 8) {
+    gprint (GP_ERR, "USAGE: cut <buffer> <X vector> <Y vector> xs ys xe ye\n");
+    return (FALSE);
+  }
+
+  if ((buf  = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) goto missed;
+  if ((xvec = SelectVector (argv[2], ANYVECTOR, TRUE)) == NULL) goto usage;
+  if ((yvec = SelectVector (argv[3], ANYVECTOR, TRUE)) == NULL) goto usage;
+ 
+  xs = atof (argv[4]);
+  ys = atof (argv[5]);
+  xe = atof (argv[6]);
+  ye = atof (argv[7]);
+
+  Nx = buf[0].matrix.Naxis[0];
+  Ny = buf[0].matrix.Naxis[1];
+
+  if ((xs < 0) || (xs > Nx)) goto range;
+  if ((ys < 0) || (ys > Ny)) goto range;
+  if ((xe < 0) || (xe > Nx)) goto range;
+  if ((ye < 0) || (ye > Ny)) goto range;
+
+  dX = xe - xs;
+  dY = ye - ys;
+  L = hypot (dX, dY);
+  dX = dX / L;
+  dY = dY / L;
+
+  REALLOCATE (xvec[0].elements, float, MAX (L, 1));
+  REALLOCATE (yvec[0].elements, float, MAX (L, 1));
+  xvec[0].Nelements = L;
+  yvec[0].Nelements = L;
+
+  V = (float *)buf[0].matrix.buffer;
+  for (i = 0; i < L; i++) {
+    xi = xs + i*dX - 0.5;
+    yi = ys + i*dY - 0.5;
+    xvec[0].elements[i] = i;
+    yvec[0].elements[i] = V[xi + Nx*yi];
+  }
+
+  return (TRUE);
+
+ usage: 
+  gprint (GP_ERR, "USAGE: circstats <buffer> x y radius\n");
+  return (FALSE);
+
+ range:
+  gprint (GP_ERR, "ERROR: coordinates out of range\n");
+  return (FALSE);
+
+ missed:
+  gprint (GP_ERR, "ERROR: buffer not found\n");
+  return (FALSE);
+}
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/imhist.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/imhist.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/imhist.c	(revision 11389)
@@ -0,0 +1,97 @@
+# include "data.h"
+
+int imhist (int argc, char **argv) {
+  
+  int i, j, N;
+  int sx, sy, nx, ny, bin;
+  float *V;
+  double max, min, dx;
+  Vector *vec1, *vec2;
+  Buffer *buf;
+
+  min = max = 0.0;
+  if ((N = get_argument (argc, argv, "-range"))) {
+    remove_argument (N, &argc, argv);
+    min = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+    max = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  sx = sy = 0.0;
+  nx = ny = 0.0;
+  if ((N = get_argument (argc, argv, "-region"))) {
+    remove_argument (N, &argc, argv);
+    sx = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+    sy = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+    nx = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+    ny = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 4) {
+    gprint (GP_ERR, "USAGE: histogram <buffer> <x> <y> [-region sx sy nx ny] [-range min max]\n");
+    return (FALSE);
+  }
+
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  
+  /* if either range is set to zero, use the rest of the chip */
+  if (nx == 0)
+    nx = buf[0].matrix.Naxis[0] - sx;
+  if (ny == 0)
+    ny = buf[0].matrix.Naxis[1] - sy;
+
+  if ((sx < 0) || (sy < 0) || 
+      (sx+nx > buf[0].matrix.Naxis[0]) || 
+      (sy+ny > buf[0].matrix.Naxis[1])) {
+    gprint (GP_ERR, "region out of range\n");
+    return (FALSE);
+  }
+
+  if ((vec1 = SelectVector (argv[2], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((vec2 = SelectVector (argv[3], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+
+  /* unfortunately, we must do this in two passes:
+     first pass finds the max and min and defines the bin size
+     second pass counts the pixes in each bin 
+     */
+
+  if ((max == 0) && (min == 0)) {
+    max = min = *((float *)(buf[0].matrix.buffer) + sy*buf[0].matrix.Naxis[0] + sx);
+    gprint (GP_ERR, "sx: %d, sy: %d, first: %f\n", sx, sy, max);
+    for (j = sy; j < sy + ny; j++) {
+      V = (float *)(buf[0].matrix.buffer) + j*buf[0].matrix.Naxis[0] + sx; 
+      for (i = 0; i < nx; i++, V++) {
+	max = MAX (max, *V);
+	min = MIN (min, *V);
+      }
+    }
+  }
+  dx = (max - min) / 1024.0;
+  gprint (GP_ERR, "max %f, min %f, dx %f\n", max, min, dx);
+  
+  vec1[0].Nelements = 1025;
+  vec2[0].Nelements = 1025;
+  REALLOCATE (vec1[0].elements, float, vec1[0].Nelements);
+  bzero (vec1[0].elements, vec1[0].Nelements*sizeof(float));
+  REALLOCATE (vec2[0].elements, float, vec2[0].Nelements);
+  bzero (vec2[0].elements, vec2[0].Nelements*sizeof(float));
+  
+  for (j = sy; j < sy + ny; j++) {
+    V = (float *)(buf[0].matrix.buffer) + j*buf[0].matrix.Naxis[0] + sx; 
+    for (i = 0; i < nx; i++, V++) {
+      bin = MAX (MIN (1024, (*V - min) / dx), 0);
+      vec2[0].elements[bin] += 1.0;
+    }
+  }
+  for (i = 0; i < 1025; i++, V++) {
+    vec1[0].elements[i] = i*dx + min;
+  }
+  
+  return (TRUE);
+}
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/imsmooth.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/imsmooth.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/imsmooth.c	(revision 11389)
@@ -0,0 +1,75 @@
+# include "data.h"
+
+int imsmooth (int argc, char **argv) {
+  
+  int i, j, n, N, Nx, Ny, Ns, Ngauss;
+  float *vi, *vo, *gauss, *gaussnorm;
+  float g, s, sigma, Nsigma;
+  Buffer *in;
+  float *temp;
+
+  Nsigma = 3;
+  if ((N = get_argument (argc, argv, "-Nsigma"))) {
+    remove_argument (N, &argc, argv);
+    Nsigma = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 3) {
+    gprint (GP_ERR, "USAGE: imsmooth (input) sigma\n");
+    return (FALSE);
+  }
+  
+  if ((in  = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  sigma = atof (argv[2]);
+
+  Nx = in[0].matrix.Naxis[0];
+  Ny = in[0].matrix.Naxis[1];
+  ALLOCATE (temp, float, Nx*Ny);
+
+  /* build a 1D gaussian */
+  Ns = (int) (Nsigma*sigma + 0.5);
+  Ngauss = 2*Ns + 1;
+  ALLOCATE (gaussnorm, float, Ngauss);
+  gauss = &gaussnorm[Ns];
+  for (i = -Ns; i < Ns + 1; i++) {
+    gauss[i] = exp ((i*i)/(-2*sigma*sigma));
+  }
+
+  /* smooth in X direction */
+  for (j = 0; j < Ny; j++) {
+    vi = (float *) in[0].matrix.buffer + j*Nx;
+    vo = &temp[j*Nx];
+    for (i = 0; i < Nx; i++) {
+      g = s = 0;
+      for (n = -Ns; n < Ns + 1; n++) {
+	if (i+n < 0) continue;
+	if (i+n >= Nx) continue;
+	s += gauss[n]*vi[i+n];
+	g += gauss[n];
+      }
+      vo[i] = s / g;
+    }
+  }
+
+  /* smooth in Y direction */
+  for (i = 0; i < Nx; i++) {
+    vi = &temp[i];
+    vo = (float *)in[0].matrix.buffer + i;
+    for (j = 0; j < Ny; j++) {
+      g = s = 0;
+      for (n = -Ns; n < Ns + 1; n++) {
+	if (j+n < 0) continue;
+	if (j+n >= Ny) continue;
+	s += gauss[n]*vi[(n+j)*Nx];
+	g += gauss[n];
+      }
+      vo[j*Nx] = s / g;
+    }
+  }
+
+  free (temp);
+  free (gaussnorm);
+  return (TRUE);
+}
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/init.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/init.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/init.c	(revision 11389)
@@ -0,0 +1,245 @@
+# include "data.h"
+
+int accum            PROTO((int, char **));
+int applyfit         PROTO((int, char **));
+int applyfit2d       PROTO((int, char **));
+int box              PROTO((int, char **));
+int book_command     PROTO((int, char **));
+int center           PROTO((int, char **));
+int circstats        PROTO((int, char **));
+int clear            PROTO((int, char **));
+int clip             PROTO((int, char **));
+int close_device     PROTO((int, char **));
+int concat           PROTO((int, char **));
+int contour          PROTO((int, char **));
+int create           PROTO((int, char **));
+int cumulative       PROTO((int, char **));
+int cursor           PROTO((int, char **));
+int cut              PROTO((int, char **));
+int datafile         PROTO((int, char **));
+int delete           PROTO((int, char **));
+int device           PROTO((int, char **));
+int dimendown        PROTO((int, char **));
+int dimenup          PROTO((int, char **));
+int erase            PROTO((int, char **));
+int extract          PROTO((int, char **));
+int fft1d            PROTO((int, char **));
+int fft2d            PROTO((int, char **));
+int fit2d            PROTO((int, char **));
+int fit              PROTO((int, char **));
+int gaussjordan      PROTO((int, char **));
+int gaussdeviate     PROTO((int, char **));
+int gaussintegral    PROTO((int, char **));
+int grid             PROTO((int, char **));
+int gridify          PROTO((int, char **));
+int ungridify        PROTO((int, char **));
+int histogram        PROTO((int, char **));
+int imcut            PROTO((int, char **));
+int imhist           PROTO((int, char **));
+int imsmooth         PROTO((int, char **));
+int integrate        PROTO((int, char **));
+int interpolate      PROTO((int, char **));
+int jpeg             PROTO((int, char **));
+int kern             PROTO((int, char **));
+int keyword          PROTO((int, char **));
+int labels           PROTO((int, char **));
+int limits           PROTO((int, char **));
+int line             PROTO((int, char **));
+int list_buffers     PROTO((int, char **));
+int header           PROTO((int, char **));
+int list_vectors     PROTO((int, char **));
+int load             PROTO((int, char **));
+int lookup           PROTO((int, char **));
+int mkrgb            PROTO((int, char **));
+int mcreate          PROTO((int, char **));
+int medacc           PROTO((int, char **));
+int mget             PROTO((int, char **));
+int minterp          PROTO((int, char **));
+int mset             PROTO((int, char **));
+int peak             PROTO((int, char **));
+int periodogram      PROTO((int, char **));
+int plot             PROTO((int, char **));
+int dot              PROTO((int, char **));
+int point            PROTO((int, char **));
+int ps               PROTO((int, char **));
+int queuelist        PROTO((int, char **));
+int queueload        PROTO((int, char **));
+int queueinit        PROTO((int, char **));
+int queuedelete      PROTO((int, char **));
+int queuedrop        PROTO((int, char **));
+int queuepop         PROTO((int, char **));
+int queueprint       PROTO((int, char **));
+int queuepush        PROTO((int, char **));
+int queuesize        PROTO((int, char **));
+int rd               PROTO((int, char **));
+int rdseg            PROTO((int, char **));
+int read_vectors     PROTO((int, char **));
+int rebin            PROTO((int, char **));
+int resize           PROTO((int, char **));
+int roll             PROTO((int, char **));
+int rotate           PROTO((int, char **));
+int save             PROTO((int, char **));
+int section          PROTO((int, char **));
+int set              PROTO((int, char **));
+int shift            PROTO((int, char **));
+int sort_vectors     PROTO((int, char **));
+int spline_apply     PROTO((int, char **));
+int spline_construct PROTO((int, char **));
+int stats            PROTO((int, char **));
+int style            PROTO((int, char **));
+int subraster        PROTO((int, char **));
+int subset           PROTO((int, char **));
+int svd              PROTO((int, char **));
+int swapbytes        PROTO((int, char **));
+int textline         PROTO((int, char **));
+int tv               PROTO((int, char **));
+int tvcontour        PROTO((int, char **));
+int tvgrid           PROTO((int, char **));
+int uniq             PROTO((int, char **));
+int unsign           PROTO((int, char **));
+int vbin             PROTO((int, char **));
+int vclip            PROTO((int, char **));
+int vect_select      PROTO((int, char **));
+int vgrid            PROTO((int, char **));
+int vgauss           PROTO((int, char **));
+int vmaxwell         PROTO((int, char **));
+int vload            PROTO((int, char **));
+int vstat            PROTO((int, char **));
+int vroll            PROTO((int, char **));
+int vpop             PROTO((int, char **));
+int vsmooth          PROTO((int, char **));
+int wd               PROTO((int, char **));
+int write_vectors    PROTO((int, char **));
+int zap              PROTO((int, char **));
+int zplot            PROTO((int, char **));
+
+static Command cmds[] = {  
+  {"accum",        accum,	     "accumulate vector values in another vector"},
+  {"applyfit",     applyfit,	     "apply fit to new vector"},
+  {"applyfit2d",   applyfit2d,	     "apply 2-d fit to new vector"},
+  {"box",     	   box,		     "draw a box on the plot"},
+  {"book",    	   book_command,     "commands to manipulate book/page/word data"},
+  {"center",       center,	     "center image on coords"},
+  {"circstats",    circstats,	     "circular statistics"},
+  {"clear",   	   clear,	     "erase plot"},
+  {"clip",         clip,	     "clip values in a buffer to be within a range"},
+  {"close",        close_device,     "close the current display device"},
+  {"concat",  	   concat,	     "reduce vector dimension"},
+  {"contour", 	   contour,	     "create contour from image"},
+  {"create",  	   create,	     "create a new vector"},
+  {"cumulative",   cumulative,	     "build a cumulative histogram from a specific histogram"},
+  {"cursor",  	   cursor,	     "get coords from cursor"},
+  {"cut",	   cut,		     "extract a cut across an image"},
+  {"datafile",     datafile,	     "define file to read vectors"},
+  {"delete",  	   delete,	     "delete vectors or matrices"},
+  {"device",  	   device,	     "set / get current graphics device"},
+  {"dimendown",	   dimendown,	     "convert matrix to vector"},
+  {"dimenup",	   dimenup,	     "convert vector to matrix"},
+  {"erase",        erase,	     "erase objects on an overlay"},
+  {"extract",      extract,	     "extract a portion of a buffer into another buffer"},
+  {"fft1d",        fft1d,	     "fft on the pixel-stream in an image"},
+  {"fft2d",        fft2d,	     "fft on an image"},
+  {"fit",     	   fit,		     "fit polynomial to vector pair"},
+  {"fit2d",        fit2d,	     "fit 2-d polynomial to vector triplet"},
+  {"gaussj",  	   gaussjordan,	     "solve Ax = B (N-D)"},
+  {"gaussdev",	   gaussdeviate,     "generate a gaussian deviate vector"},
+  {"gaussint",	   gaussintegral,    "return the integrated gaussian vector"},
+  {"grid",    	   grid,	     "plot cartesian grid"},
+  {"gridify",      gridify,	     "convert vector triplet to buffer"},
+  {"ungridify",    ungridify,        "convert buffer region to vector triplet"},
+  {"header",       header,	     "print buffer header"},
+  {"histogram",    histogram,	     "generate histogram from vector"},
+  {"imcut",        imcut,	     "linear image cut between arbitrary coords"},
+  {"imhist",       imhist,	     "histogram of an image region"},
+  {"imsmooth",     imsmooth,	     "circular gaussian smoothing"},
+  {"integrate",    integrate,	     "integrate a vector"},
+  {"interpolate",  interpolate,	     "interpolate between vector pairs"},
+  {"jpeg",         jpeg,	     "write text line on graph"},
+  {"png",          jpeg,	     "write text line on graph"},
+  {"ppm",          jpeg,	     "write text line on graph"},
+  {"kern",         kern,	     "convolve with 3x3 kernel"},
+  {"keyword",      keyword,	     "extract a FITS keyword from buffer header"},
+  {"labels",  	   labels,	     "define labels for plot"},
+  {"limits",  	   limits,	     "define plot limits"},
+  {"line",         line,	     "plot line"},
+  {"buffers",      list_buffers,     "list the currently allocated buffers"},
+  {"vectors", 	   list_vectors,     "list vectors"},
+  {"load",         load,	     "load an SAOimage style overlay"},
+  {"lookup",       lookup,	     "convert vector via lookup table (vector pair)"},
+  {"mkrgb", 	   mkrgb,	     "convert 3 images to rgb jpeg"},
+  {"mcreate", 	   mcreate,	     "create a matrix"},
+  {"medacc",       medacc,	     "accumulate vector values in another vector"},
+  {"mget",    	   mget,	     "extract a vector from a matrix"},
+  {"minterp",      minterp,	     "interpolate image pixels"},
+  {"mset",    	   mset,	     "insert a vector in a matrix"},
+  {"peak",	   peak,	     "find vector peak in range"},
+  {"periodogram",  periodogram,	     "measure periods in unevenly sampled data"},
+  {"plot",    	   plot,	     "plot a pair of vectors"},
+  {"dot",    	   dot,	             "plot a single point"},
+  {"point",	   point,	     "load overlay with single point"},
+  {"ps",      	   ps,		     "define labels for plot"},
+  {"queuepop", 	   queuepop,	     "pop value from queue to variable"},
+  {"queuedrop",    queuedrop,	     "drop values from queue matching a key"},
+  {"queueprint",   queueprint,	     "print the contents of a queue"},
+  {"queuepush",	   queuepush,	     "push value onto queue"},
+  {"queueinit",	   queueinit,	     "create an empty queue"},
+  {"queuedelete",  queuedelete,	     "delete a queue"},
+  {"queuelist",	   queuelist,	     "list defined queues"},
+  {"queueload",	   queueload,	     "load queue from command"},
+  {"queuesize",    queuesize,	     "show queue size"},
+  {"rd",           rd,		     "load fits image"},
+  {"rdseg",	   rdseg,	     "read a segment of an image from a file"},
+  {"read",         read_vectors,     "read vectors from datafile"},
+  {"rebin",	   rebin,	     "rebin data by factor of N"},
+  {"resize",  	   resize,	     "set graphics/image window size"},
+  {"roll",	   roll,	     "roll image to new start point"},
+  {"rotate",	   rotate,	     "rotate image"},
+  {"save",	   save,	     "save an SAOimage style overlay"},
+  {"section", 	   section,	     "define section of graph"},
+  {"set",     	   set,		     "vector math"},
+  {"shift",	   shift,	     "shift data in an image"},
+  {"sort",    	   sort_vectors,     "sort list of vectors"},
+  {"spline.apply", spline_apply,     "apply spline fit to generate an image"},
+  {"spline.const", spline_construct, "create spline 2nd deriv. terms"},
+  {"stats",   	   stats,	     "give statistics on a portion of a buffer"},
+  {"style",   	   style,	     "set the style for graph plots"},
+  {"subraster",    subraster,	     "subraster of fits image"},
+  {"subset",  	   subset,	     "expand vector dimension"},
+  {"svd",	   svd,		     "singular value decomposition of a matrix"},
+  {"swapbytes",	   swapbytes,        "byte swap thing"},
+  {"textline",     textline,	     "write text line on graph"},
+  {"tv",      	   tv,		     "display an image on the Kii window"},
+  {"tvcontour",	   tvcontour,	     "send contour to overlay"},
+  {"tvgrid",	   tvgrid,	     "wait until return is typed"},
+  {"uniq",    	   uniq,	     "create a uniq vector subset from a vector"},
+  {"unsign",	   unsign,	     "toggle the UNSIGN status"},
+  {"vbin",	   vbin,	     "bin values in a vector to be within a range"},
+  {"vclip",	   vclip,	     "clip values in a vector to be within a range"},
+  {"select",	   vect_select,	     "selective vector assignment"},
+  {"vgauss",       vgauss,	     ""},
+  {"vmaxwell",     vmaxwell,	     ""},
+  {"vgrid",        vgrid,	     ""},
+  {"vload",        vload,	     "load vectors on Kii"},
+  {"vstat",        vstat,	     "get info from imreg database"},
+  {"vsmooth",      vsmooth,	     "gaussian smooth of a vector"},
+  {"vroll",        vroll,	     "roll vector elements"},
+  {"vpop",         vpop, 	     "remove first element"},
+  {"wd",      	   wd,		     "write an image to a file"},
+  {"write",   	   write_vectors,    "write vectors to datafile"},
+  {"zap",     	   zap,		     "delete pixels"},
+  {"zplot",   	   zplot,	     "plot x y with size scaled by z"},
+}; 
+
+void InitData () {
+  
+  int i;
+
+  InitGraph ();
+  InitImage ();
+  InitQueues ();
+
+  for (i = 0; i < sizeof (cmds) / sizeof (Command); i++) {
+    AddCommand (&cmds[i]);
+  }
+
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/integrate.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/integrate.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/integrate.c	(revision 11389)
@@ -0,0 +1,44 @@
+# include "data.h"
+
+int integrate (int argc, char **argv) {
+  
+  int i, N, VERBOSE;
+  float *X, *Y;
+  double start, end, value, range;
+  Vector *vecx, *vecy;
+
+  VERBOSE = FALSE;
+  if ((N = get_argument (argc, argv, "-v"))) {
+    VERBOSE = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 5) {
+    gprint (GP_ERR, "USAGE: integrate <x> <y> start end\n");
+    return (FALSE);
+  }
+
+  if ((vecx = SelectVector (argv[1], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((vecy = SelectVector (argv[2], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+
+  start = atof (argv[3]);
+  end   = atof (argv[4]);
+
+  X = vecx[0].elements;
+  Y = vecy[0].elements;
+
+  value = 0;
+  range = 0;
+  for (i = 0; i < vecx[0].Nelements-1; i++, X++, Y++) {
+    if ((*X >= start) && (*X <= end)) {
+      value += *Y * (X[1] - X[0]);
+      range += (X[1] - X[0]);
+    }
+  }      
+
+  set_variable ("sum", value); 
+  set_variable ("range", range);
+  if (VERBOSE) gprint (GP_LOG, "sum: %f\n", value);
+  return (TRUE);
+}
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/interpolate.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/interpolate.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/interpolate.c	(revision 11389)
@@ -0,0 +1,53 @@
+# include "data.h"
+
+int interpolate (int argc, char **argv) {
+
+  int  i, j;
+  double x0, x1, dx, dy, y0;
+  Vector *xout, *yout, *xin, *yin;
+
+  /** check basic syntax **/
+  if (argc != 5) {
+    gprint (GP_ERR, "USAGE: interpolate Xi Yi Xo Yo\n");
+    gprint (GP_ERR, "  Xi Yi - sorted reference vectors\n");
+    gprint (GP_ERR, "  Xo    - output positions\n");
+    gprint (GP_ERR, "  Yo    - output values\n");
+    return (FALSE);
+  }
+
+  if ((xin  = SelectVector (argv[1],  OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((yin  = SelectVector (argv[2],  OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((xout = SelectVector (argv[3],  OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((yout = SelectVector (argv[4],  ANYVECTOR, TRUE)) == NULL) return (FALSE);
+
+  yout[0].Nelements = xout[0].Nelements;
+  REALLOCATE (yout[0].elements, float, yout[0].Nelements);
+
+  dx = xin[0].elements[1] - xin[0].elements[0];
+  dy = yin[0].elements[1] - yin[0].elements[0];
+  x0 = xin[0].elements[0];
+  y0 = yin[0].elements[0];
+  
+  /* in vectors are sorted, out vectors are not */
+  for (j = 0; j < xin[0].Nelements - 1; j++) {
+    dx = xin[0].elements[j+1] - xin[0].elements[j];
+    dy = yin[0].elements[j+1] - yin[0].elements[j];
+    x0 = xin[0].elements[j];
+    y0 = yin[0].elements[j];
+    x1 = xin[0].elements[j+1];
+    for (i = 0; i < xout[0].Nelements; i++) {
+      if ((xout[0].elements[i] >= x0) && (xout[0].elements[i] < x1)) {
+	yout[0].elements[i] = (dy/dx)*(xout[0].elements[i] - x0) + y0;
+      }
+      if ((j == 0) && (xout[0].elements[i] < x0)) {
+	yout[0].elements[i] = (dy/dx)*(xout[0].elements[i] - x0) + y0;
+      }
+      if ((j == xin[0].Nelements - 2) && (xout[0].elements[i] >= x1)) {
+	yout[0].elements[i] = (dy/dx)*(xout[0].elements[i] - x0) + y0;
+      }
+    }    
+  }
+
+  return (TRUE);
+    
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/jpeg.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/jpeg.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/jpeg.c	(revision 11389)
@@ -0,0 +1,61 @@
+# include "data.h"
+
+int jpeg (int argc, char **argv) {
+
+  char filename[1024];
+  int N, Source, Nsource, IsImage, IsPNG;
+  
+  if ((N = get_argument (argc, argv, "--help"))) {
+    gprint (GP_ERR, "USAGE: jpeg [-name file] [-g | -i] [-n device] [-ppm]\n");
+    return (FALSE);
+  }
+
+  /* image type */
+  IsPNG = TRUE;
+  if ((N = get_argument (argc, argv, "-ppm"))) {
+    remove_argument (N, &argc, argv);
+    IsPNG = FALSE;
+  }
+
+  /* file name */
+  filename[0] = 0;
+  if ((N = get_argument (argc, argv, "-name"))) {
+    remove_argument (N, &argc, argv);
+    strcpy (filename, argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  /* display source */
+  Nsource = -1;
+  if ((N = get_argument (argc, argv, "-n"))) {
+    remove_argument (N, &argc, argv);
+    Nsource = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "-g"))) {
+    remove_argument (N, &argc, argv);
+    SetImageDevice (FALSE);
+  }  
+  if ((N = get_argument (argc, argv, "-i"))) {
+    remove_argument (N, &argc, argv);
+    SetImageDevice (TRUE);
+  }  
+  IsImage = GetCurrentDevice ();
+  if (IsImage) {
+    if (!GetImage (&Source, &Nsource)) return (FALSE);
+    if (!filename[0]) strcpy (filename, "Ximage.jpg");
+    KiiJPEG (Source, filename);
+  } else {
+    if (!GetGraph (NULL, &Source, &Nsource)) return (FALSE);
+    if (!filename[0]) strcpy (filename, "Xgraph.png");
+    if (IsPNG) {
+      KapaPNG (Source, filename);
+    } else {
+      KapaPPM (Source, filename);
+    }
+  }
+  return (TRUE);
+}
+
+/* jpeg converts graph to png or ppm
+   jpeg converts image to jpeg */
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/kern.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/kern.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/kern.c	(revision 11389)
@@ -0,0 +1,123 @@
+# include "data.h"
+
+/** need to allow larger kernels (5x5, 7x7, etc) **/
+int kern (int argc, char **argv) {
+
+  int i, n, m;
+  int NX, NY, status;
+  FILE *f;
+  float *in_buff, *out_buff, *ib, *ob;
+  char line[256], *list;
+  double kernel[3][3], val;
+  Buffer *buf;
+
+  if (argc != 3) {
+    gprint (GP_ERR, "USAGE: kern buffer (file)\n");
+    gprint (GP_ERR, "USAGE: kern buffer (list)\n");
+    gprint (GP_ERR, "USAGE: kern buffer -\n");
+    gprint (GP_ERR, "kernel file contains a 3x3 matrix for convolution\n");
+    return (FALSE);
+  }
+
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+
+  /* open file to read in kernel */
+  if (!strcmp (argv[2], "-")) {
+    for (i = 0; i < 3; i++) {
+      status = scan_line (stdin, line);
+      if (status == EOF) {
+	gprint (GP_ERR, "kernel should be a 3x3 matrix...\n");
+	return (FALSE);
+      }
+      dparse (&kernel[0][i], 1, line);
+      dparse (&kernel[1][i], 2, line);
+      dparse (&kernel[2][i], 3, line);
+    }
+    goto have_kernel;
+  }
+  /* test list */
+  sprintf (line, "%s:n", argv[2]);
+  if ((list = get_variable (line)) == (char *) NULL) {
+    /* file */
+    f = fopen (argv[2], "r");
+    if (f == NULL) {
+      gprint (GP_ERR, "file not found: %s\n", argv[2]);
+      return (FALSE);
+    }
+    for (i = 0; i < 3; i++) {
+      status = scan_line (f, line);
+      if (status == EOF) {
+	gprint (GP_ERR, "kernel should be a 3x3 matrix...\n");
+	fclose (f);
+      }
+      return (FALSE);
+      dparse (&kernel[0][i], 1, line);
+      dparse (&kernel[1][i], 2, line);
+      dparse (&kernel[2][i], 3, line);
+    }
+    fclose (f);
+    goto have_kernel;
+  }
+  if (atoi (list) != 9) {
+    gprint (GP_ERR, "kernel should be a 3x3 matrix...\n");
+    return (FALSE);
+  }
+  free (list);
+  for (i = 0; i < 9; i++) {
+    sprintf (line, "%s:%d", argv[2], i);
+    list = get_variable (line);
+    if (list == (char *) NULL) {
+      gprint (GP_ERR, "kernel should be a 3x3 matrix...\n");
+      return (FALSE);
+    }
+    kernel[(int)(i/3)][i%3] = atof (list);
+    free (list);
+  }
+  goto have_kernel;
+
+ have_kernel:
+  /* normalize kernel */
+  val = 0;
+  for (n = 0; n < 3; n++) {
+    for (m = 0; m < 3; m++) {
+      val += kernel[n][m];
+    }
+  }
+  if (val == 0) {
+    gprint (GP_ERR, "kernel has zero power, not renormalizing...");
+  } else {
+    for (n = 0; n < 3; n++) {
+      for (m = 0; m < 3; m++) {
+	kernel[n][m] /= val;
+      }
+    }
+  }
+
+  gprint (GP_ERR, "working...");
+  
+  /* create output buffer */
+  NX = buf[0].header.Naxis[0];
+  NY = buf[0].header.Naxis[1];
+  in_buff = (float *)buf[0].matrix.buffer;
+  ALLOCATE (buf[0].matrix.buffer, char, sizeof(float)*NX*NY);
+  out_buff = (float *)buf[0].matrix.buffer;
+  
+  /* do the convolution (on all but outer rows) */
+  
+  for (n = 0; n < 3; n++) {
+    for (m = 0; m < 3; m++) {
+      gprint (GP_ERR, "%d", n*3 + m + 1);
+      val = kernel[n][m];
+      ob = out_buff + NX + 1;
+      ib = in_buff + m*NX + n;
+      for (i = 0; i < (NX-2)*(NY-2); i++, ob++, ib++) {
+	*ob += *ib*val;
+      }
+    }
+  }
+  gprint (GP_ERR, "(done)\n");
+
+  free (in_buff);
+  return (TRUE);
+
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/keyword.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/keyword.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/keyword.c	(revision 11389)
@@ -0,0 +1,158 @@
+# include "data.h"
+
+enum {NONE, STRING, FLOAT, INT, BOOLEAN, KEYCOMMENT, COMMENT};
+
+/** WARNING: no error checking on variable validity **/
+int keyword (int argc, char **argv) {
+
+  int ivalue, status, N, ascomment, asfloat, delete, soft, Wmode;
+  char line[80];
+  double value;
+  Buffer *buf;
+
+  asfloat = FALSE;
+  if ((N = get_argument (argc, argv, "-f"))) {
+    remove_argument (N, &argc, argv);
+    asfloat = TRUE;
+  }
+  
+  ascomment = FALSE;
+  if ((N = get_argument (argc, argv, "-c"))) {
+    remove_argument (N, &argc, argv);
+    ascomment = TRUE;
+  }
+  
+  delete = FALSE;
+  if ((N = get_argument (argc, argv, "-d"))) {
+    remove_argument (N, &argc, argv);
+    delete = TRUE;
+  }
+  
+  /* return TRUE for missing keyword if soft */
+  soft = FALSE;
+  if ((N = get_argument (argc, argv, "-soft"))) {
+    remove_argument (N, &argc, argv);
+    soft = TRUE;
+  }
+  
+  /* identify write modes */
+  Wmode = NONE;
+  if ((N = get_argument (argc, argv, "-w"))) {
+    remove_argument (N, &argc, argv);
+    strcpy (line, argv[N]);
+    remove_argument (N, &argc, argv);
+    Wmode = STRING;
+  }
+  if ((N = get_argument (argc, argv, "-wf"))) {
+    remove_argument (N, &argc, argv);
+    strcpy (line, argv[N]);
+    remove_argument (N, &argc, argv);
+    Wmode = FLOAT;
+  }
+  if ((N = get_argument (argc, argv, "-wd"))) {
+    remove_argument (N, &argc, argv);
+    strcpy (line, argv[N]);
+    remove_argument (N, &argc, argv);
+    Wmode = INT;
+  }
+  if ((N = get_argument (argc, argv, "-wc"))) {
+    remove_argument (N, &argc, argv);
+    strcpy (line, argv[N]);
+    remove_argument (N, &argc, argv);
+    Wmode = KEYCOMMENT;
+  }
+  if ((N = get_argument (argc, argv, "-ws"))) {
+    remove_argument (N, &argc, argv);
+    strcpy (line, argv[N]);
+    remove_argument (N, &argc, argv);
+    Wmode = COMMENT;
+  }
+  if ((N = get_argument (argc, argv, "-wb"))) {
+    remove_argument (N, &argc, argv);
+    strcpy (line, argv[N]);
+    remove_argument (N, &argc, argv);
+    Wmode = BOOLEAN;
+  }
+
+  if (!((argc == 3) || (!N && argc == 4))) {
+    gprint (GP_ERR, "USAGE: keyword <buffer> (KEYWORD) [variable] [-d] [-w(mode) value]\n");
+    gprint (GP_ERR, " -w modes: \n");
+    gprint (GP_ERR, "  -w  - string\n");
+    gprint (GP_ERR, "  -wf - float\n");
+    gprint (GP_ERR, "  -wd - int\n");
+    gprint (GP_ERR, "  -wb - boolean\n");
+    gprint (GP_ERR, "  -wc - comment\n");
+    gprint (GP_ERR, "  -ws - full string comment\n");
+    return (FALSE);
+  }
+
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+
+  if (Wmode != NONE) {
+    switch (Wmode) {
+    case STRING:
+      gfits_modify (&buf[0].header, argv[2], "%s", 1, line);
+      return (TRUE);
+    case FLOAT:
+      value = atof(line);
+      gfits_modify (&buf[0].header, argv[2], "%lf", 1, value);
+      return (TRUE);
+    case INT:
+      gfits_modify (&buf[0].header, argv[2], "%d", 1, atoi(line));
+      return (TRUE);
+    case BOOLEAN:
+      if (strcasecmp (line, "T") && strcasecmp (line, "TRUE") && strcasecmp (line, "F") && strcasecmp (line, "FALSE")) {
+	gprint (GP_ERR, "syntax error in boolean value\n");
+	return (FALSE);
+      }
+      ivalue = !strcasecmp (line, "T");
+      gfits_modify (&buf[0].header, argv[2], "%t", 1, ivalue);
+      return (TRUE);
+    case KEYCOMMENT:
+      gfits_modify (&buf[0].header, argv[2], "%C", 1, line);
+      return (TRUE);
+    case COMMENT:
+      gfits_modify (&buf[0].header, argv[2], "%S", 0, line);
+      return (TRUE);
+    }
+  }
+  
+  if (delete) {
+    gfits_delete (&buf[0].header, argv[2], -1);
+    return (TRUE);
+  }
+  
+  /* grab the value in the given format, either a string or a digit */
+  if (asfloat) {
+    status = gfits_scan (&buf[0].header, argv[2], "%lf", 1, &value);
+    if (!status) goto failure;
+    if (argc == 4) 
+      set_variable (argv[3], value);
+    else 
+      gprint (GP_LOG, "%s: %f\n", argv[2], value);
+    return (TRUE);
+  } 
+
+  if (ascomment) {
+    status = gfits_scan (&buf[0].header, argv[2], "%C", 1, line);
+    if (!status) goto failure;
+    if (argc == 4) 
+      set_str_variable (argv[3], line);
+    else 
+      gprint (GP_LOG, "%s: %s\n", argv[2], line);
+    return (TRUE);
+  }    
+
+  /* not-specified */
+  status = gfits_scan (&buf[0].header, argv[2], "%s", 1, line);
+  if (!status) goto failure;
+  if (argc == 4) 
+    set_str_variable (argv[3], line);
+  else 
+    gprint (GP_LOG, "%s: %s\n", argv[2], line);
+  return (TRUE);
+
+ failure: 
+  if (!soft) gprint (GP_ERR, "keyword %s not found\n", argv[2]);
+  return (soft);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/labels.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/labels.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/labels.c	(revision 11389)
@@ -0,0 +1,95 @@
+# include "data.h"
+
+int labels (int argc, char **argv) {
+  
+  char name[64];
+  int N, size, Xgraph;
+
+  if (!GetGraph (NULL, &Xgraph, NULL)) return (FALSE);
+
+  if (get_argument (argc, argv, "-h")) {
+    gprint (GP_ERR, "label options: \n");
+    gprint (GP_ERR, " -x : bottom-center\n");
+    gprint (GP_ERR, " +x : top-center\n");
+    gprint (GP_ERR, " -y : right-side\n");
+    gprint (GP_ERR, " +y : left-side\n\n");
+
+    gprint (GP_ERR, " -ul : upper-left corner\n");
+    gprint (GP_ERR, " -ll : lower-left corner\n");
+    gprint (GP_ERR, " -ur : upper-right corner\n");
+    gprint (GP_ERR, " -lr : lower-right corner\n\n");
+
+    gprint (GP_ERR, " -fn (font) (size) : set font and size\n");
+    gprint (GP_ERR, "   (font) : courier, helvetica, times, symbol\n\n");
+    gprint (GP_ERR, " label special characters:\n");
+    gprint (GP_ERR, " ^ : superscript\n");
+    gprint (GP_ERR, " _ : subscript\n");
+    gprint (GP_ERR, " | : default script \n");
+    gprint (GP_ERR, " &c, &h, &t, &s : set font\n\n");
+    return (FALSE);
+  }
+
+  if ((N = get_argument (argc, argv, "-fn"))) {
+    remove_argument (N, &argc, argv);
+    strcpy (name, argv[N]);
+    remove_argument (N, &argc, argv);
+    size = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+    KapaSetFont (Xgraph, name, size);
+  } 
+
+  if ((N = get_argument (argc, argv, "-x"))) {
+    remove_argument (N, &argc, argv);
+    KapaSendLabel (Xgraph, argv[N], 0);
+    remove_argument (N, &argc, argv);
+  }
+
+  if ((N = get_argument (argc, argv, "-y"))) {
+    remove_argument (N, &argc, argv);
+    KapaSendLabel (Xgraph, argv[N], 1);
+    remove_argument (N, &argc, argv);
+  }
+
+  if ((N = get_argument (argc, argv, "+x"))) {
+    remove_argument (N, &argc, argv);
+    KapaSendLabel (Xgraph, argv[N], 2);
+    remove_argument (N, &argc, argv);
+  }
+
+  if ((N = get_argument (argc, argv, "+y"))) {
+    remove_argument (N, &argc, argv);
+    KapaSendLabel (Xgraph, argv[N], 3);
+    remove_argument (N, &argc, argv);
+  }
+
+  if ((N = get_argument (argc, argv, "-ul"))) {
+    remove_argument (N, &argc, argv);
+    KapaSendLabel (Xgraph, argv[N], 4);
+    remove_argument (N, &argc, argv);
+  }
+
+  if ((N = get_argument (argc, argv, "-ur"))) {
+    remove_argument (N, &argc, argv);
+    KapaSendLabel (Xgraph, argv[N], 5);
+    remove_argument (N, &argc, argv);
+  }
+
+  if ((N = get_argument (argc, argv, "-ll"))) {
+    remove_argument (N, &argc, argv);
+    KapaSendLabel (Xgraph, argv[N], 6);
+    remove_argument (N, &argc, argv);
+  }
+
+  if ((N = get_argument (argc, argv, "-lr"))) {
+    remove_argument (N, &argc, argv);
+    KapaSendLabel (Xgraph, argv[N], 7);
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 1) {
+    gprint (GP_ERR, "USAGE: labels [-x] [-y] [+x] [+y] [-ul] [-ur] [-ll] [-lr]\n");
+    return (FALSE);
+  }
+
+  return (TRUE);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/limits.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/limits.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/limits.c	(revision 11389)
@@ -0,0 +1,75 @@
+# include "data.h"
+
+int limits (int argc, char **argv) {
+
+  int N, APPLY;
+  int Ngraph, Xgraph;
+  Graphdata graphmode;
+  Vector *xvec, *yvec;
+
+  xvec = yvec = NULL;
+
+  APPLY = FALSE;
+  if ((N = get_argument (argc, argv, "-a"))) {
+    remove_argument (N, &argc, argv);
+    APPLY = TRUE;
+  }
+
+  Ngraph = -1;
+  if ((N = get_argument (argc, argv, "-n"))) {
+    remove_argument (N, &argc, argv);
+    Ngraph = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if (!GetGraph (&graphmode, &Xgraph, &Ngraph)) return (FALSE);
+
+  if (argc == 1) {
+    gprint (GP_ERR, "limits: %f %f %f %f [-a] [-n Xgraph]\n",
+	     graphmode.xmin, graphmode.xmax,
+	     graphmode.ymin, graphmode.ymax);
+    goto success;
+  }
+
+  if (argc == 3) { /* expect to see: limits x y */
+    if ((xvec = SelectVector (argv[1], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+    if ((yvec = SelectVector (argv[2], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+    goto success;
+  }
+    
+  if (argc == 4) { /* expect to see: limits x num num or limits num num y */
+    if (ISNUM(argv[1][0]) && ISNUM(argv[2][0])) {
+      if ((yvec = SelectVector (argv[3], OLDVECTOR, FALSE)) == NULL) goto error;
+      graphmode.xmin = atof (argv[1]);
+      graphmode.xmax = atof (argv[2]);
+      goto success;
+    }
+    if (ISNUM(argv[2][0]) && ISNUM(argv[3][0])) {
+      if ((xvec = SelectVector (argv[1], OLDVECTOR, FALSE)) == NULL) goto error;
+      graphmode.ymin = atof (argv[2]);
+      graphmode.ymax = atof (argv[3]);
+      goto success;
+    }
+    goto error;
+  }
+  
+  if (argc == 5) {
+    graphmode.xmin = atof (argv[1]);
+    graphmode.xmax = atof (argv[2]);
+    graphmode.ymin = atof (argv[3]);
+    graphmode.ymax = atof (argv[4]);
+    goto success;
+  }
+
+  gprint (GP_ERR, "USAGE: limits [xrange] [yrange]\n");
+  gprint (GP_ERR, " [range] may be either [min max] or a vector\n");
+  return (FALSE);
+
+ error:
+  gprint (GP_ERR, "error in vectors\n");
+  return (FALSE);
+
+ success:
+  SetLimits (xvec, yvec, &graphmode);
+  if (APPLY) KapaSetLimits (Xgraph, &graphmode);
+  return (TRUE);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/line.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/line.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/line.c	(revision 11389)
@@ -0,0 +1,33 @@
+# include "data.h"
+
+int line (int argc, char **argv) {
+  
+  int N, Npts;
+  Graphdata graphmode;
+  float x[2], y[2];
+
+  if (!style_args (&graphmode, &argc, argv, -1)) return FALSE;
+
+  if (argc != 6) {
+    gprint (GP_ERR, "USAGE: line <x> <y> to <x> <y>\n");
+    return (FALSE);
+  }
+  x[0] = atof(argv[1]);
+  y[0] = atof(argv[2]);
+  x[1] = atof(argv[4]);
+  y[1] = atof(argv[5]);
+
+  SetGraph (graphmode);
+
+  /* set point style and errorbar mode (these are NOT sticky) */
+  graphmode.style = 0;
+  graphmode.etype = 0;
+
+  if (!PrepPlotting (2, &graphmode)) return (FALSE);
+  
+  PlotVector (2, x);
+  PlotVector (2, y);
+  
+  return (TRUE);
+
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/list_buffers.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/list_buffers.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/list_buffers.c	(revision 11389)
@@ -0,0 +1,10 @@
+# include "data.h"
+
+int list_buffers (int argc, char **argv) {
+
+  if (argc == 3) PrintBuffers (TRUE);
+  else PrintBuffers (FALSE);
+
+  return (TRUE);
+
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/list_header.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/list_header.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/list_header.c	(revision 11389)
@@ -0,0 +1,81 @@
+# include "data.h"
+
+int header (int argc, char **argv) {
+  
+  int j, N, nlines, nbytes, Nbytes, LOADHEAD, status, bitpix, unsign;
+  char *p, filename[128];
+  FILE *f;
+  double bscale, bzero;
+  Buffer *buf;
+
+  LOADHEAD = FALSE;
+  if ((N = get_argument (argc, argv, "-w"))) {
+    remove_argument (N, &argc, argv);
+    strcpy (filename, argv[N]);
+    remove_argument (N, &argc, argv);
+    LOADHEAD = TRUE;
+  }
+
+  if (argc != 2) {
+    gprint (GP_ERR, "USAGE: header <buffer> [-w filename]\n");
+    return (FALSE);
+  }
+
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+
+  if (LOADHEAD) {
+    f = fopen (filename, "r");
+    if (f == (FILE *) NULL) {
+      gprint (GP_ERR, "file %s not found\n", filename);
+      return (FALSE);
+    }
+    fclose (f);
+    
+    bitpix = buf[0].header.bitpix;
+    bzero  = buf[0].header.bzero;
+    bscale = buf[0].header.bscale;
+    unsign = buf[0].header.unsign;
+    gfits_free_header (&buf[0].header);
+    
+    strcpy (filename, buf[0].file);
+    strcpy (buf[0].file, "*");
+    strcat (buf[0].file, filename);
+    status = gfits_read_header (argv[2], &buf[0].header);
+    buf[0].header.bitpix = bitpix;     
+    buf[0].header.bzero  = bzero;      
+    buf[0].header.bscale = bscale;     
+    buf[0].header.unsign = unsign;     
+    gfits_modify (&buf[0].header, "BITPIX", "%d",  1, bitpix);
+    gfits_modify (&buf[0].header, "BSCALE", "%lf", 1, bscale);
+    gfits_modify (&buf[0].header, "BZERO",  "%lf", 1, bzero);
+    gfits_modify (&buf[0].header, "UNSIGN", "%t",  1, unsign);
+    
+  } else {
+
+    f = popen ("more", "w");
+    
+    p = gfits_header_field (&buf[0].header, "END", 1);
+    nlines = (p - buf[0].header.buffer) / 80;
+    nbytes = 81*nlines;
+
+    /* duplicate the header, add in the <return> chars, send to more */
+    ALLOCATE (p, char, nbytes);
+    for (j = 0; j < nlines; j++) {
+      memcpy (&p[81*j], &buf[0].header.buffer[80*j], 80);
+      p[81*j+80] = 10;
+    }
+    Nbytes = fwrite (p, sizeof(char), nbytes, f);
+    if (Nbytes != nbytes) {
+      gprint (GP_ERR, "warning: not all printed...\n");
+    }
+    free (p);
+
+    pclose (f);
+
+  }
+
+  return (TRUE);
+
+}
+
+/* XXX this function is not written in the context of the output file/buffer */
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/list_vectors.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/list_vectors.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/list_vectors.c	(revision 11389)
@@ -0,0 +1,8 @@
+# include "data.h"
+
+int list_vectors (int argc, char **argv) {
+
+  ListVectors ();
+  return (TRUE);
+}
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/load.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/load.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/load.c	(revision 11389)
@@ -0,0 +1,142 @@
+# include "data.h"
+
+int load (int argc, char **argv) {
+  
+  int i, N, n, ISCEL;
+  int Ximage, Nimage, Noverlay, NOVERLAY;
+  char *c, type[10], string[128], line[1024];
+  double x, y, dx, dy, x1, y1;
+  double dra, ddec, ra1, dec1, ra, dec;
+  FILE *f;
+  char *buffer;
+  Coords coords;
+  Buffer *buf;
+  KiiOverlay *overlay;
+  
+  Nimage = -1;
+  if ((N = get_argument (argc, argv, "-n"))) {
+    remove_argument (N, &argc, argv);
+    Nimage = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if (!GetImage (&Ximage, &Nimage)) return (FALSE);
+
+  ISCEL = FALSE;
+  if ((N = get_argument (argc, argv, "-c"))) {
+    remove_argument (N, &argc, argv);
+    ISCEL = TRUE;
+  }
+
+  if (argc != 3) {
+    gprint (GP_ERR, "USAGE: load (overlay) <filename>\n [-c] [-n]");
+    gprint (GP_ERR, "  -c: read overlay in celestial coords\n");
+    return (FALSE);
+  }
+  
+  if (!strcmp (argv[2], "-")) {
+    f = stdin;
+  } else {
+    f = fopen (argv[2], "r");
+  }
+  if (f == NULL) {
+    gprint (GP_ERR, "can't find file %s\n", argv[2]);
+    return (FALSE);
+  }
+
+  if (ISCEL) {
+    if ((buf = SelectBuffer (GetImageName(), OLDBUFFER, TRUE)) == NULL) return (FALSE);
+    GetCoords (&coords, &buf[0].header);
+  }
+
+  Noverlay = 0;
+  NOVERLAY = 1000;
+  ALLOCATE (overlay, KiiOverlay, NOVERLAY);
+
+  ALLOCATE (buffer, char, 65536);  /* space for 512 lines of 128 bytes */
+  bzero (buffer, 65536);
+
+  dx = dy = 0;
+  for (n = 0; scan_line (f, line) != EOF;) {
+    c = strchr (line, '#');
+    if (c != (char *) NULL) 
+      *c = 0;  /* force end of line at comment! */
+    while ((c = strchr (line, '(')) != (char *) NULL) 
+      *c = ' ';
+    while ((c = strchr (line, ')')) != (char *) NULL) 
+      *c = ' ';
+    while ((c = strchr (line, ',')) != (char *) NULL) 
+      *c = ' ';
+    /* we could use some syntactial checks here */
+    /* have to get all three for this to be any valid object, if the line is commented out,
+     we should get none, so check that N == 3 before continuing: */
+    N = sscanf (line, "%s %lf %lf %lf %lf", type, &ra, &dec, &dra, &ddec);
+    switch (N) {
+    case 0:
+    case -1:
+      continue;
+    case 1:
+    case 2:
+    case 3:
+      if (strcmp (type, "TEXT")) {
+	gprint (GP_ERR, "syntax error in line:\n   %s\n", line);
+	continue;
+      }
+      sscanf (line, "%s %lf %lf %127s", type, &ra, &dec, string);
+    case 4:
+      ddec = dra;
+    case 5:
+      x = ra;
+      y = dec;
+      dx = dra;
+      dy = ddec;
+      if (ISCEL) {
+	if (!strcmp (type, "LINE")) {
+	  RD_to_XY (&x, &y, ra, dec, &coords);
+	  ra1 = ra + dra;
+	  dec1 = dec + ddec;
+	  RD_to_XY (&x1, &y1, ra1, dec1, &coords);
+	  dy = (y1 - y);
+	  dx = (x1 - x);
+	} else {
+	  RD_to_XY (&x, &y, ra, dec, &coords);
+	  ra1 = ra;
+	  dec1 = dec + ddec;
+	  RD_to_XY (&x1, &y1, ra1, dec1, &coords);
+	  dy = (fabs(x1 - x) + fabs(y1 - y));
+	  ra1 = ra + dra/cos(dec*RAD_DEG);;
+	  dec1 = dec;
+	  RD_to_XY (&x1, &y1, ra1, dec1, &coords);
+	  dx = (fabs(x1 - x) + fabs(y1 - y));
+	}
+      }
+    }
+    overlay[Noverlay].type = KiiOverlayTypeByName (type);
+    if (overlay[Noverlay].type == KII_OVERLAY_TEXT) {
+      overlay[Noverlay].text = strcreate (string);
+    } else {
+      overlay[Noverlay].text = NULL;
+    }
+    overlay[Noverlay].x = x;
+    overlay[Noverlay].y = y;
+    overlay[Noverlay].dx = dx;
+    overlay[Noverlay].dy = dy;
+    Noverlay++;
+    CHECK_REALLOCATE (overlay, KiiOverlay, NOVERLAY, Noverlay, 1000);
+  }
+
+  KiiLoadOverlay (Ximage, overlay, Noverlay, argv[1]);
+
+  for (i = 0; i < Noverlay; i++) {
+    if (overlay[i].text == NULL) continue;
+    free (overlay[i].text);
+  }
+  free (overlay);
+
+  gprint (GP_ERR, "loaded %d objects\n", Noverlay);
+
+  if (f != stdin) {
+    fclose (f);
+  }
+  return (TRUE);
+}
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/lookup.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/lookup.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/lookup.c	(revision 11389)
@@ -0,0 +1,40 @@
+# include "data.h"
+
+int lookup (int argc, char **argv) {
+  
+  int i, j;
+  float *ip, *op, *xp, *yp;
+  Vector *in, *out, *xv, *yv;
+
+  if (argc != 5) {
+    gprint (GP_ERR, "USAGE: lookup (input) (output) (x) (y)\n");
+    return (FALSE);
+  }
+
+  if ((in  = SelectVector (argv[1], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((out = SelectVector (argv[2], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((xv  = SelectVector (argv[3], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((yv  = SelectVector (argv[4], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+
+  if (xv[0].Nelements != yv[0].Nelements) {
+      gprint (GP_ERR, "unmatched lookup table lengths\n");
+      return (FALSE);
+  }
+
+  out[0].Nelements = in[0].Nelements;
+  REALLOCATE (out[0].elements, float, out[0].Nelements);
+
+  ip = in[0].elements;
+  op = out[0].elements;
+
+  for (i = 0; i < in[0].Nelements; i++, ip++, op++) {
+    // re-write this using bisection
+    xp = xv[0].elements;
+    yp = yv[0].elements;
+
+    for (j = 0; (*ip < *xp) && (j < yv[0].Nelements); j++);
+    *op = j;
+  }      
+
+  return (TRUE);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/mcreate.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/mcreate.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/mcreate.c	(revision 11389)
@@ -0,0 +1,22 @@
+# include "data.h"
+
+int mcreate (int argc, char **argv) {
+  
+  int Nx, Ny;
+  Buffer *buf;
+
+  if (argc != 4) {
+    gprint (GP_ERR, "USAGE: mcreate <buffer> Nx Ny\n");
+    return (FALSE);
+  }
+
+  if ((buf = SelectBuffer (argv[1], ANYBUFFER, TRUE)) == NULL) return (FALSE);
+  Nx = atof (argv[2]);
+  Ny = atof (argv[3]);
+
+  /* I should encapsulate this in a create_default_buffer */
+  gfits_free_matrix (&buf[0].matrix);
+  gfits_free_header (&buf[0].header);
+  CreateBuffer (buf, Nx, Ny, -32, 1.0, 0.0);
+  return (TRUE);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/medacc.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/medacc.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/medacc.c	(revision 11389)
@@ -0,0 +1,83 @@
+# include "data.h"
+
+int medacc (int argc, char **argv) {
+  
+  int i, j, Nbins, Nvalues, N, N0, N1;
+  double start, end, delta, k0, k1, fn;
+  float *V, *K, *V1, *K1, *O, *tmpvec, *tmpkey;
+  Vector *val, *key, *out;
+
+  if ((argc != 6) && (argc != 7)) {
+    gprint (GP_ERR, "USAGE: medacc <value> <vector> <key> start end [delta]\n");
+    return (FALSE);
+  }
+
+  if ((val = SelectVector (argv[1], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((key = SelectVector (argv[3], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if (val[0].Nelements != key[0].Nelements) {
+    gprint (GP_ERR, "key and value don't match\n");
+    return (FALSE);
+  }
+  if ((out = SelectVector (argv[2], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+
+  start = atof (argv[4]);
+  end   = atof (argv[5]);
+  if (argc == 7) 
+    delta = atof (argv[6]);
+  else 
+    delta = 1;
+
+  delta = fabs (delta);
+  if (end - start < 0) {
+    delta = -1.0 * delta;
+  }
+  Nbins = 1 + (int)((end - start) / delta);
+
+  out[0].Nelements = Nbins;
+  REALLOCATE (out[0].elements, float, out[0].Nelements);
+  bzero (out[0].elements, sizeof(float)*out[0].Nelements);
+
+  /* copy vec and key to temp vectors */
+  ALLOCATE (tmpvec, float, val[0].Nelements);
+  ALLOCATE (tmpkey, float, val[0].Nelements);
+
+  V = val[0].elements;
+  K = key[0].elements;
+  V1 = tmpvec;
+  K1 = tmpkey;
+  Nvalues = val[0].Nelements;
+  for (i = 0; i < Nvalues; i++, V++, K++, V1++, K1++) {
+    *V1 = *V;
+    *K1 = *K;
+  }      
+
+  /* sort vec and key by key */
+  fsortpair (tmpkey, tmpvec, Nvalues);
+
+  O = out[0].elements;
+  /* find the start and end key for each range */
+  N0 = 0;
+  N1 = 0;
+  for (i = 0; i < Nbins; i++) {
+    k0 = i*delta + start;
+    k1 = (i+1)*delta + start;
+    for (j = N1; (j < Nvalues) && (tmpkey[j] < k0); j++);
+    N0 = j;
+    for (j = N0; (j < Nvalues) && (tmpkey[j] < k1); j++);
+    N1 = j;
+    N = N1 - N0;
+    fsort (&tmpvec[N0], N);
+    fn = O[i] = 0;
+    for (j = N0 + 0.25*N; j < N0 + 0.75*N; j++) {
+      O[i] += tmpvec[j];
+      fn += 1.0;
+    }
+    if (fn > 0) O[i] /= fn;
+  }      
+  
+  free (tmpvec);
+  free (tmpkey);
+
+  return (TRUE);
+}
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/mget.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/mget.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/mget.c	(revision 11389)
@@ -0,0 +1,61 @@
+# include "data.h"
+
+int mget (int argc, char **argv) {
+  
+  int i, Nx, Ny, Npix, xdir, Nset;
+  float *in, *out;
+  Buffer *buf;
+  Vector *vec;
+
+  if (argc != 5) {
+    gprint (GP_ERR, "USAGE: mget <buffer> <vector> <-x/-y> <N>\n");
+    return (FALSE);
+  }
+
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  if ((vec = SelectVector (argv[2], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+
+  if (strcasecmp (argv[3], "-x") && strcasecmp (argv[3], "-y")) {
+    gprint (GP_ERR, "USAGE: mget <buffer> <vector> <-x/-y> <N>\n");
+    return (FALSE);
+  }
+  xdir = TRUE;
+  if (!strcasecmp (argv[3], "-y")) xdir = FALSE;
+
+  Nx = buf[0].matrix.Naxis[0];
+  Ny = buf[0].matrix.Naxis[1];
+  Nset = atof (argv[4]);
+  if (Nset < 0) {
+    gprint (GP_ERR, "selection out of range\n");
+    return (FALSE);
+  }
+
+  if (xdir) {
+    vec[0].Nelements = Npix = Nx;
+    REALLOCATE (vec[0].elements, float, Npix);
+    if (Nset >= Ny) {
+      gprint (GP_ERR, "row out of range\n");
+      return (FALSE);
+    }
+    in  = (float *) buf[0].matrix.buffer + Nx*Nset;
+    out = vec[0].elements;
+    for (i = 0; i < Npix; i++, in++, out++) {
+      *out = *in;
+    }
+    return (TRUE);
+  } else {
+    vec[0].Nelements = Npix = Ny;
+    REALLOCATE (vec[0].elements, float, Npix);
+    if (Nset >= Nx) {
+      gprint (GP_ERR, "column out of range\n");
+      return (FALSE);
+    }
+    in  = (float *) buf[0].matrix.buffer + Nset;
+    out = vec[0].elements;
+    for (i = 0; i < Npix; i++, in+=Nx, out++) {
+      *out = *in;
+    }
+    return (TRUE);
+  }    
+}
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/minterpolate.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/minterpolate.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/minterpolate.c	(revision 11389)
@@ -0,0 +1,159 @@
+# include "data.h"
+
+int minterp (int argc, char **argv) {
+  
+  int i, j, status, nx, ny, Nx, Ny, N, Extrapolate;
+  int ic, jc, dx, dy, Npix;
+  char temp[1024];
+  double scale, scale2, dX, dY;
+  float *V00, *V01, *V10, *V11, *Vout, dV1, dV2, dV3;
+  float *buf, I, J, x, y, xs, xe, ys, ye;
+  Buffer *in, *out;
+
+  /* choose the appropriate graphing window */
+  Extrapolate = FALSE;
+  if ((N = get_argument (argc, argv, "-extrapolate"))) {
+    remove_argument (N, &argc, argv);
+    Extrapolate = TRUE;
+  }
+
+  if (argc != 4) {
+    gprint (GP_ERR, "USAGE: minterpolate <from> <to> scale [-extrapolate]\n");
+    return (FALSE);
+  }
+
+  if ((in  = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  if ((out = SelectBuffer (argv[2], ANYBUFFER, TRUE)) == NULL) return (FALSE);
+
+  gfits_free_matrix (&out[0].matrix);
+  gfits_free_header (&out[0].header);
+
+  scale  = atof (argv[3]);
+  scale2 = scale*scale;
+  Nx = in[0].header.Naxis[0];
+  Ny = in[0].header.Naxis[1];
+  nx = Nx * scale;
+  ny = Ny * scale;
+
+  /* create new matrix */
+  out[0].bitpix = in[0].bitpix;
+  out[0].unsign = in[0].unsign;
+  out[0].bscale = in[0].bscale;
+  out[0].bzero  = in[0].bzero;
+  gfits_copy_header (&in[0].header, &out[0].header);
+
+  gfits_modify (&out[0].header, "NAXIS1", "%d", 1, nx);
+  gfits_modify (&out[0].header, "NAXIS2", "%d", 1, ny);
+  out[0].header.Naxis[0] = nx;
+  out[0].header.Naxis[1] = ny;
+  gfits_create_matrix (&out[0].header, &out[0].matrix);
+
+  /* fix astrometric terms */
+  status =  gfits_scan (&out[0].header, "CDELT1", "%lf", 1, &dX);
+  status &= gfits_scan (&out[0].header, "CDELT2", "%lf", 1, &dY);
+  dX /= scale;
+  dY /= scale;
+  if (status) {
+    gfits_modify (&out[0].header, "CDELT1", "%lf", 1, dX);
+    gfits_modify (&out[0].header, "CDELT2", "%lf", 1, dY);
+  }
+  status =  gfits_scan (&out[0].header, "CRPIX1", "%lf", 1, &dX);
+  status &= gfits_scan (&out[0].header, "CRPIX2", "%lf", 1, &dY);
+  dX *= scale;
+  dY *= scale;
+  if (status) {
+    gfits_modify (&out[0].header, "CRPIX1", "%lf", 1, dX);
+    gfits_modify (&out[0].header, "CRPIX2", "%lf", 1, dY);
+  }
+
+  /* adjust filename */
+  temp[0] = 0;
+  if ((in[0].file[0] != '*') && (in[0].file[0] != '(')) {
+    strcpy (temp, "*");
+  }
+  strcat (temp, in[0].file);
+  strcpy (out[0].file, temp);
+
+  dX = dY = scale;
+
+  buf = (float *)in[0].matrix.buffer;
+  Npix = 0;
+
+  if (Extrapolate) {
+    for (j = 0; j < Ny - 1; j++) {
+      for (i = 0; i < Nx - 1; i++) {
+	V00 = buf + i + j*Nx;
+	V10 = V00 + 1;
+	V01 = V00 + Nx;
+	V11 = V01 + 1;
+	dV1 = (*V11 + *V00 - *V01 - *V10) / scale2;
+	dV2 = (*V01 - *V00) / scale;
+	dV3 = (*V10 - *V00) / scale;
+
+	x = (i + 0.5) * scale;
+	y = (j + 0.5) * scale;
+
+	xs = ys = 0;
+	xe = ye = scale;
+
+	if (i == 0)      { xs = -0.5*scale; }
+	if (i == Nx - 2) { xe =  1.5*scale; }
+
+	if (j == 0)      { ys = -0.5*scale; }
+	if (j == Ny - 2) { ye =  1.5*scale; }
+
+	for (J = ys; J < ye; J += 1.0) {
+	  dx = (x + xs);
+	  dy = (y + J);
+	  Vout = (float *)(out[0].matrix.buffer) + dy*nx + dx;
+	  for (I = xs; I < xe; I += 1.0, Vout++) {
+	    *Vout = dV1 * (I*J) + dV2 * J + dV3 * I + *V00;
+	    Npix ++;
+	  }
+	}
+      }
+    }
+  } else {
+     for (j = -1; j < Ny; j++) {
+      for (i = -1; i < Nx; i++) {
+	ic = MIN (MAX (i, 0), Nx-1);  /* we never actually reach Nx, Ny */
+	jc = MIN (MAX (j, 0), Ny-1);
+	V00 = buf + ic + jc*Nx;
+	V10 = V00 + 1;
+	V01 = V00 + Nx;
+	V11 = V01 + 1;
+
+	if ((i == -1) || (i == Nx - 1)) { V10 = V00; } else { V10 = V00 + 1; }
+	if ((j == -1) || (j == Ny - 1)) { V01 = V00; } else { V01 = V00 + Nx; }
+	if ((i == -1) || (i == Nx - 1)) { V11 = V01; } else { V11 = V01 + 1; }
+
+	dV1 = (*V11 + *V00 - *V01 - *V10) / scale2;
+	dV2 = (*V01 - *V00) / scale;
+	dV3 = (*V10 - *V00) / scale;
+
+	x = (i + 0.5) * scale;
+	y = (j + 0.5) * scale;
+
+	xs = ys = 0;
+	xe = ye = scale;
+
+	if (i == -1)     { xs = 0.5*scale; }
+	if (i == Nx - 1) { xe = 0.5*scale; }
+
+	if (j == -1)     { ys = 0.5*scale; }
+	if (j == Ny - 1) { ye = 0.5*scale; }
+
+	for (J = ys; J < ye; J += 1.0) {
+	  dx = (x + xs);
+	  dy = (y + J);
+	  Vout = (float *)(out[0].matrix.buffer) + dy*nx + dx;
+	  for (I = xs; I < xe; I += 1.0, Vout++) {
+	    *Vout = dV1 * (I*J) + dV2 * J + dV3 * I + *V00;
+	    Npix ++;
+	  }
+	}
+      }
+    }
+  }
+  return (TRUE);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/mkrgb.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/mkrgb.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/mkrgb.c	(revision 11389)
@@ -0,0 +1,78 @@
+# include "data.h"
+# include "jpeglib.h"
+
+int mkrgb (int argc, char **argv) {
+ 
+  int i, j, Nx, Ny;
+  FILE *f;
+  Buffer *red, *green, *blue;
+  float *Vr, *Vg, *Vb;
+
+  struct jpeg_compress_struct cinfo;
+  struct jpeg_error_mgr jerr;
+  JSAMPROW row_pointer[1];	/* pointer to JSAMPLE row[s] */
+  JSAMPLE *image_buffer;	/* Points to data for current line */
+
+  if (argc != 5) {
+    gprint (GP_ERR, "USAGE: mkrgb (red) (green) (blue) (output)\n");
+    return (FALSE);
+  }
+
+  // define the input buffer and examine the shift
+  if ((red    = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  if ((green  = SelectBuffer (argv[2], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  if ((blue   = SelectBuffer (argv[3], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+
+  Nx = red[0].matrix.Naxis[0];
+  Ny = red[0].matrix.Naxis[1];
+  if (Nx != blue[0].matrix.Naxis[0]) return (FALSE);
+  if (Ny != blue[0].matrix.Naxis[1]) return (FALSE);
+  if (Nx != green[0].matrix.Naxis[0]) return (FALSE);
+  if (Ny != green[0].matrix.Naxis[1]) return (FALSE);
+
+  f = fopen (argv[4], "w");
+  if (f == (FILE *) NULL) {
+    fprintf (stderr, "failed to open %s for output\n", argv[4]);
+    return (FALSE);
+  }
+
+  /* set up the error handler , initialize the JPEG compression object. */
+  cinfo.err = jpeg_std_error (&jerr);
+  jpeg_create_compress (&cinfo);
+  jpeg_stdio_dest(&cinfo, f);
+  
+  // set up the basic jpeg output file
+  cinfo.image_width = Nx; 	/* image width and height, in pixels */
+  cinfo.image_height = Ny;
+  cinfo.input_components = 3;		        
+  cinfo.in_color_space = JCS_RGB; 	
+  jpeg_set_defaults (&cinfo);
+  jpeg_set_quality (&cinfo, 75, TRUE       /* limit to baseline-JPEG values */);
+  jpeg_start_compress (&cinfo, TRUE);
+
+  ALLOCATE (image_buffer, JSAMPLE, 3*Nx);
+
+  // ??
+  // && (cinfo.next_scanline < cinfo.image_height)
+
+  Vr = (float *) red[0].matrix.buffer;
+  Vg = (float *) green[0].matrix.buffer;
+  Vb = (float *) blue[0].matrix.buffer;
+
+  for (j = 0; j < Ny; j++) {
+    for (i = 0; i < Nx; i++, Vr++, Vg++, Vb++) {
+      image_buffer[3*i+0] = MAX (0.0, MIN (255.0, *Vr));
+      image_buffer[3*i+1] = MAX (0.0, MIN (255.0, *Vg));
+      image_buffer[3*i+2] = MAX (0.0, MIN (255.0, *Vb));
+    }
+    row_pointer[0] = image_buffer;
+    (void) jpeg_write_scanlines (&cinfo, row_pointer, 1);
+  }
+
+  jpeg_finish_compress (&cinfo);
+  fclose (f);
+
+  jpeg_destroy_compress (&cinfo);
+
+  return (TRUE);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/mset.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/mset.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/mset.c	(revision 11389)
@@ -0,0 +1,66 @@
+# include "data.h"
+
+int mset (int argc, char **argv) {
+  
+  int i, Nx, Ny, Npix, xdir, Nset;
+  float *in, *out;
+  Buffer *buf;
+  Vector *vec;
+
+  if (argc != 5) {
+    gprint (GP_ERR, "USAGE: mset <buffer> <vector> <-x/-y> <N>\n");
+    return (FALSE);
+  }
+
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  if ((vec = SelectVector (argv[2], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+
+  if (strcasecmp (argv[3], "-x") && strcasecmp (argv[3], "-y")) {
+    gprint (GP_ERR, "USAGE: mset <buffer> <vector> <-x/-y> <N>\n");
+    return (FALSE);
+  }
+  xdir = TRUE;
+  if (!strcasecmp (argv[3], "-y")) xdir = FALSE;
+
+  Npix = vec[0].Nelements;
+  Nx = buf[0].matrix.Naxis[0];
+  Ny = buf[0].matrix.Naxis[1];
+  Nset = atof (argv[4]);
+  if (Nset < 0) {
+    gprint (GP_ERR, "selection out of range\n");
+    return (FALSE);
+  }
+
+  if (xdir) {
+    if (Nx != Npix) {
+      gprint (GP_ERR, "dimensions don't match\n");
+      return (FALSE);
+    }
+    if (Nset >= Ny) {
+      gprint (GP_ERR, "row out of range\n");
+      return (FALSE);
+    }
+    out = (float *) buf[0].matrix.buffer + Nx*Nset;
+    in = vec[0].elements;
+    for (i = 0; i < Npix; i++, in++, out++) {
+      *out = *in;
+    }
+    return (TRUE);
+  } else {
+    if (Ny != Npix) {
+      gprint (GP_ERR, "dimensions don't match\n");
+      return (FALSE);
+    }
+    if (Nset >= Nx) {
+      gprint (GP_ERR, "column out of range\n");
+      return (FALSE);
+    }
+    out = (float *) buf[0].matrix.buffer + Nset;
+    in = vec[0].elements;
+    for (i = 0; i < Npix; i++, in++, out+=Nx) {
+      *out = *in;
+    }
+    return (TRUE);
+  }    
+}
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/peak.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/peak.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/peak.c	(revision 11389)
@@ -0,0 +1,55 @@
+# include "data.h"
+
+int peak (int argc, char **argv) {
+  
+  int i, N, imax, QUIET;
+  double start, end, xmax, ymax;
+  float *X, *Y;
+  Vector *vecx, *vecy;
+
+  QUIET = FALSE;
+  if ((N = get_argument (argc, argv, "-q"))) {
+    QUIET = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  if ((argc != 5) && (argc != 3)) {
+    gprint (GP_ERR, "USAGE: peak <x> <y> [start end]\n");
+    return (FALSE);
+  }
+
+  if ((vecx = SelectVector (argv[1], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((vecy = SelectVector (argv[2], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+
+  if (argc == 5) {
+    start = atof (argv[3]);
+    end   = atof (argv[4]);
+  } else {
+    start = vecx[0].elements[0];
+    end   = vecx[0].elements[vecx[0].Nelements - 1];
+  }
+
+  X = vecx[0].elements;
+  Y = vecy[0].elements;
+
+  imax = -1;
+  xmax = *X;
+  ymax = *Y;
+  for (i = 1; i < vecx[0].Nelements-1; i++, X++, Y++) {
+    if ((*X >= start) && (*X <= end)) {
+      if ((imax == -1) || (*Y > ymax)) {
+	xmax = *X;
+	ymax = *Y;
+	imax = i;
+      }
+    }
+  }      
+
+  set_variable ("peakval", ymax);
+  set_variable ("peakpos", xmax);
+  set_variable ("peaknum", imax);
+
+  if (!QUIET) gprint (GP_LOG, "peak %f @ %f (%d)\n", ymax, xmax, imax);
+
+  return (TRUE);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/periodogram.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/periodogram.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/periodogram.c	(revision 11389)
@@ -0,0 +1,114 @@
+# include "data.h"
+
+int periodogram (int argc, char **argv) {
+  
+  int i, N, Npt, Np, NP, VERBOSE;
+  float *tv, *fv;
+  float minP, maxP, minT, maxT, dTime;
+  float mean, var, w, tau, P, Pc, Ps, Po;
+  float C, S, cs, sn, cs2, sn2, ratio;
+  Vector *time, *flux, *power, *period;
+
+  VERBOSE = FALSE;
+  if ((N = get_argument (argc, argv, "-v"))) {
+    VERBOSE = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 7) {
+    gprint (GP_ERR, "USAGE: periodogram (time) (flux) (minP) (maxP) (period) (power)\n");
+    return (FALSE);
+  }
+  
+  if ((time = SelectVector (argv[1], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((flux = SelectVector (argv[2], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  minP = atof(argv[3]);
+  maxP = atof(argv[4]);
+  if ((period = SelectVector (argv[5], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((power = SelectVector (argv[6], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+
+  /* find the max baseline, mean, and variance */
+  minT = maxT = time[0].elements[0];
+  Npt = time[0].Nelements;
+  tv = time[0].elements;
+  fv = flux[0].elements;
+  mean = var = 0;
+  for (i = 0; i < Npt; i++, tv++, fv++) {
+    minT = MIN (minT, *tv);
+    maxT = MAX (maxT, *tv);
+    mean += *fv;
+  }
+  mean = mean / Npt;
+  fv = flux[0].elements;
+  for (i = 0; i < Npt; i++, fv++) {
+    var += SQ(*fv - mean);
+  }
+  var = var / (Npt - 1);
+
+  if (VERBOSE) gprint (GP_ERR, "mean: %f, var: %f, minT: %f, maxT: %f\n", mean, var, minT, maxT);
+
+  dTime = maxT - minT;
+  if (dTime == 0) {
+    gprint (GP_ERR, "ERROR: time range is zero\n");
+    return (FALSE);
+  }
+
+  Np = 0;
+  NP = 100;
+  REALLOCATE (power[0].elements, float, NP);
+  REALLOCATE (period[0].elements, float, NP);
+
+  P = minP;
+  while (P < maxP) {
+    w = 2*M_PI/P;
+    
+    /* find the period offset tau  */
+    tv = time[0].elements;
+    cs = sn = 0;
+    for (i = 0; i < Npt; i++, tv++) {
+      cs += cos (*tv*w*2);
+      sn += sin (*tv*2*2);
+    }
+    tau = 0.5*atan2 (sn, cs) / w;
+      
+    /* find the power at this period */
+    tv = time[0].elements;
+    fv = flux[0].elements;
+    cs = sn = cs2 = sn2 = 0;
+    for (i = 0; i < Npt; i++, tv++, fv++) {
+      C = cos (w*(*tv-tau));
+      S = sin (w*(*tv-tau));
+      // C = cos (w**tv);
+      // S = sin (w**tv);
+      cs += (*fv - mean) * C;
+      sn += (*fv - mean) * S;
+      cs2 += SQ(C);
+      sn2 += SQ(S);
+    }
+    Pc = SQ(cs) / cs2;
+    Ps = SQ(sn) / sn2;
+    Po = (Pc + Ps) / (2*var);
+
+    power[0].elements[Np] = Po;
+    period[0].elements[Np] = P;
+    Np ++;
+    if (Np >= NP) {
+      NP += 100;
+      REALLOCATE (power[0].elements, float, NP);
+      REALLOCATE (period[0].elements, float, NP);
+    }
+
+    ratio = 1 + 0.1*P/dTime;
+
+    if (VERBOSE) gprint (GP_ERR, "tau: %f, P: %f, ratio: %f, dTime: %f, nextP: %f\n", tau, P, ratio, dTime, P*ratio);
+
+    P *= ratio;
+  }
+
+  power[0].Nelements = Np;
+  period[0].Nelements = Np;
+  REALLOCATE (power[0].elements, float, Np);
+  REALLOCATE (period[0].elements, float, Np);
+ 
+  return (TRUE);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/plot.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/plot.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/plot.c	(revision 11389)
@@ -0,0 +1,74 @@
+# include "data.h"
+
+int plot (int argc, char **argv) {
+  
+  int N, Npts;
+  Graphdata graphmode;
+  Vector *xvec, *yvec, *dxmvec, *dxpvec, *dymvec, *dypvec;
+
+  if (!style_args (&graphmode, &argc, argv, -1)) return FALSE;
+
+  /* decide on error bars */
+  dxmvec = dxpvec = dymvec = dypvec = NULL;
+  if ((N = get_argument (argc, argv, "-dx"))) {
+    remove_argument (N, &argc, argv);
+    if ((dxmvec = SelectVector (argv[N], OLDVECTOR, TRUE)) == NULL) return (FALSE);    
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "+dx"))) {
+    remove_argument (N, &argc, argv);
+    if ((dxpvec = SelectVector (argv[N], OLDVECTOR, TRUE)) == NULL) return (FALSE);    
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "-dy"))) {
+    remove_argument (N, &argc, argv);
+    if ((dymvec = SelectVector (argv[N], OLDVECTOR, TRUE)) == NULL) return (FALSE);    
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "+dy"))) {
+    remove_argument (N, &argc, argv);
+    if ((dypvec = SelectVector (argv[N], OLDVECTOR, TRUE)) == NULL) return (FALSE);    
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 3) {
+    gprint (GP_ERR, "USAGE: plot <x> <y> [style]\n");
+    return (FALSE);
+  }
+  SetGraph (graphmode);
+
+  /* set errorbar mode (these are NOT sticky) */
+  graphmode.etype = 0;
+  if ((dymvec != NULL) && (dypvec == NULL)) dypvec = dymvec;
+  if ((dypvec != NULL) && (dymvec == NULL)) dymvec = dypvec;
+  if ((dypvec != NULL) || (dymvec != NULL)) graphmode.etype |= 0x01;
+  if ((dxmvec != NULL) && (dxpvec == NULL)) dxpvec = dxmvec;
+  if ((dxpvec != NULL) && (dxmvec == NULL)) dxmvec = dxpvec;
+  if ((dxpvec != NULL) || (dxmvec != NULL)) graphmode.etype |= 0x02;
+  
+  /* find vectors */
+  if ((xvec = SelectVector (argv[1], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((yvec = SelectVector (argv[2], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if (xvec[0].Nelements != yvec[0].Nelements) {
+    gprint (GP_ERR, "vectors %s and %s not the same length\n", argv[1], argv[2]);
+    return (FALSE);
+  }
+  Npts = xvec[0].Nelements;
+  if (Npts == 0) return (TRUE);
+
+  if (!PrepPlotting (Npts, &graphmode)) return (FALSE);
+  
+  PlotVector (Npts, xvec[0].elements);
+  PlotVector (Npts, yvec[0].elements);
+  if (graphmode.etype & 0x01) {
+    PlotVector (Npts, dymvec[0].elements);
+    PlotVector (Npts, dypvec[0].elements);
+  }
+  if (graphmode.etype & 0x02) {
+    PlotVector (Npts, dxmvec[0].elements);
+    PlotVector (Npts, dxpvec[0].elements);
+  }
+  
+  return (TRUE);
+
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/point.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/point.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/point.c	(revision 11389)
@@ -0,0 +1,70 @@
+# include "data.h"
+
+int point (int argc, char **argv) {
+  
+  int N, celestial, pixscale;
+  int Ximage, Nimage;
+  double ra, dec, dra, ddec;
+  double x1, y1, ra1, dec1;
+  Coords coords;
+  Buffer *buf;
+  KiiOverlay overlay;
+
+  Nimage = -1;
+  if ((N = get_argument (argc, argv, "-n"))) {
+    remove_argument (N, &argc, argv);
+    Nimage = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if (!GetImage (&Ximage, &Nimage)) return (FALSE);
+  
+  celestial = FALSE;
+  if ((N = get_argument (argc, argv, "-c"))) {
+    remove_argument (N, &argc, argv);
+    celestial = TRUE;
+  }
+  
+  pixscale = FALSE;
+  if ((N = get_argument (argc, argv, "-pixscale"))) {
+    remove_argument (N, &argc, argv);
+    pixscale = TRUE;
+  }
+
+  if (argc != 7) {
+    gprint (GP_ERR, "USAGE: point (overlay) TYPE x y dx dy [-c]\n");
+    return (FALSE);
+  }
+  
+  if (celestial) {
+    if ((buf = SelectBuffer (GetImageName(), OLDBUFFER, TRUE)) == NULL) return (FALSE);
+    GetCoords (&coords, &buf[0].header);
+  }
+
+  if (celestial) {
+    ra   = atof(argv[3]);
+    dec  = atof(argv[4]);
+    dra  = atof(argv[5]);
+    ddec = atof(argv[6]);
+
+    fRD_to_XY (&overlay.x, &overlay.y, ra, dec, &coords);
+    if (pixscale) {
+      overlay.dx = atof(argv[5]);
+      overlay.dy = atof(argv[6]);
+    } else {
+      ra1 = ra + dra;
+      dec1 = dec + ddec;
+      RD_to_XY (&x1, &y1, ra1, dec1, &coords);
+      overlay.dx = x1 - overlay.x;
+      overlay.dy = y1 - overlay.y;
+    }
+  }
+  else {
+    overlay.x  = atof(argv[3]);
+    overlay.y  = atof(argv[4]);
+    overlay.dx = atof(argv[5]);
+    overlay.dy = atof(argv[6]);
+  }
+  overlay.type = KiiOverlayTypeByName (argv[2]);
+  KiiLoadOverlay (Ximage, &overlay, 1, argv[1]);
+  return (TRUE);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/ps.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/ps.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/ps.c	(revision 11389)
@@ -0,0 +1,83 @@
+# include "data.h"
+
+int ps (int argc, char **argv) {
+
+  char filename[1024], pagename[1024];
+  int N, Source, Nsource, scaleMode, pageMode, IsImage;
+  
+  if ((N = get_argument (argc, argv, "--help"))) goto help;
+  if ((N = get_argument (argc, argv, "-h"))) goto help;
+
+  pageMode = KAPA_PS_NEWPLOT;
+
+  /* new page? */
+  if ((N = get_argument (argc, argv, "-newpage"))) {
+    remove_argument (N, &argc, argv);
+    pageMode = KAPA_PS_NEWPAGE;
+  }
+  if ((N = get_argument (argc, argv, "-raw"))) {
+    remove_argument (N, &argc, argv);
+    pageMode = KAPA_PS_RAWPAGE;
+  }
+
+  /* scale image? */
+  scaleMode = TRUE;
+  if ((N = get_argument (argc, argv, "-noscale"))) {
+    remove_argument (N, &argc, argv);
+    scaleMode = TRUE;
+  }
+
+  /* what file? */
+  filename[0] = 0;
+  if ((N = get_argument (argc, argv, "-name"))) {
+    remove_argument (N, &argc, argv);
+    strcpy (filename, argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  /* pagename ? */
+  strcpy (pagename, "default");
+  if ((N = get_argument (argc, argv, "-pagename"))) {
+    remove_argument (N, &argc, argv);
+    strcpy (pagename, argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  /* which tool */
+  Nsource = -1;
+  if ((N = get_argument (argc, argv, "-n"))) {
+    remove_argument (N, &argc, argv);
+    Nsource = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  /* which device */
+  if ((N = get_argument (argc, argv, "-g"))) {
+    remove_argument (N, &argc, argv);
+    SetImageDevice (FALSE);
+  }  
+  if ((N = get_argument (argc, argv, "-i"))) {
+    remove_argument (N, &argc, argv);
+    SetImageDevice (TRUE);
+  }  
+  
+  if ((argc > 1) && filename[0]) goto help;
+
+  if (argc > 1) strcpy (filename, argv[1]);
+
+  IsImage = GetCurrentDevice ();
+  if (IsImage) {
+    if (!GetImage (&Source, &Nsource)) return (FALSE);
+    if (!filename[0]) strcpy (filename, "Ximage.ps");
+  } else {
+    if (!GetGraph (NULL, &Source, &Nsource)) return (FALSE);
+    if (!filename[0]) strcpy (filename, "Xgraph.ps");
+  }
+  
+  /* tell Ximage/Xgraph to ps the image */
+  KiiPS (Source, scaleMode, pageMode, filename, pagename);
+  return (TRUE);
+
+help:
+  gprint (GP_ERR, "USAGE: ps [-name file.ps] [-g | -i] [-n device] [-raw] [-noscale] [-newpage] [-pagename (name]\n");
+  return (FALSE);
+}
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/queuedelete.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/queuedelete.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/queuedelete.c	(revision 11389)
@@ -0,0 +1,21 @@
+# include "data.h"
+
+int queuedelete (int argc, char **argv) {
+  
+  Queue *queue;
+
+  if (argc != 2) {
+    gprint (GP_ERR, "USAGE: queuedelete (name)\n");
+    return (FALSE);
+  }
+
+  queue = FindQueue (argv[1]);
+  if (queue == NULL) {
+    gprint (GP_ERR, "ERROR: queue %s not found\n", argv[1]);
+    return (FALSE);
+  }
+
+  DeleteQueue (queue);
+  return (TRUE);
+}
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/queuedrop.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/queuedrop.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/queuedrop.c	(revision 11389)
@@ -0,0 +1,38 @@
+# include "data.h"
+
+int queuedrop (int argc, char **argv) {
+  
+  int N;
+  char *Key;
+  char *line;
+  char *Value;
+  Queue *queue;
+
+  Key = NULL;
+  if ((N = get_argument (argc, argv, "-key"))) {
+    remove_argument (N, &argc, argv);
+    Key = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+    Value = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  if ((argc != 2) || (Key == NULL)) {
+    gprint (GP_ERR, "USAGE: queuedrop (queue) [-key N value]\n");
+    return (FALSE);
+  }
+
+  /* will create a queue if none exists */
+  queue = FindQueue (argv[1]);
+  if (queue == NULL) {
+    gprint (GP_ERR, "ERROR: queue %s not found\n", argv[1]);
+    return (FALSE);
+  }
+
+  /* drop all matching entries, if any exist */
+  while ((line = PopQueueMatch (queue, Key, Value)) != NULL) {
+    free (line);
+  }
+  return (TRUE);
+}
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/queueinit.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/queueinit.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/queueinit.c	(revision 11389)
@@ -0,0 +1,15 @@
+# include "data.h"
+
+int queueinit (int argc, char **argv) {
+
+  Queue *queue;
+
+  if (argc != 2) {
+    gprint (GP_ERR, "USAGE: queueinit (name)\n");
+    return (FALSE);
+  }
+
+  queue = CreateQueue (argv[1]);
+  InitQueue (queue);
+  return (TRUE);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/queuelist.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/queuelist.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/queuelist.c	(revision 11389)
@@ -0,0 +1,12 @@
+# include "data.h"
+
+int queuelist (int argc, char **argv) {
+  
+  if (argc != 1) {
+    gprint (GP_ERR, "USAGE: queuelist\n");
+    return (FALSE);
+  }
+
+  ListQueues ();
+  return (TRUE);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/queueload.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/queueload.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/queueload.c	(revision 11389)
@@ -0,0 +1,69 @@
+# include "data.h"
+
+int queueload (int argc, char **argv) {
+  
+  char *A, *B, *val;
+  int i, done, status;
+  int N, Nread, Nbytes, NBYTES;
+  FILE *f;
+  Queue *queue;
+
+  if (argc != 4) goto usage;
+  if (strcmp(argv[2], "-x")) goto usage;
+  
+  /* will create a queue if none exists */
+  queue = CreateQueue (argv[1]);
+
+  /* val will hold the result of the command */
+  NBYTES = 1024;
+  ALLOCATE (val, char, NBYTES);
+    
+  /* loop until command produces no more output,  REALLOCATE as needed. */
+  f = popen (argv[3], "r");
+  Nbytes = 0;
+  Nread = 1;
+  while (Nread > 0) {
+    Nread = fread (&val[Nbytes], 1, 1023, f);
+    if (Nread < 0) { 
+      gprint (GP_ERR, "error reading from command\n");
+    }
+    if (Nread > 0) {
+      Nbytes += Nread;
+      NBYTES = 1024 + Nbytes;
+      REALLOCATE (val, char, NBYTES);
+    }
+  }
+  val[Nbytes] = 0;
+  status = pclose (f);
+    
+  if (status) {
+    gprint (GP_ERR, "warning: exit status of command %d\n", status);
+  }
+      
+  A = B = val;
+  for (i = 0; B != (char *) NULL;) {
+    while (isspace (*A) && (*A != 0)) A++;
+    B = strchr (A, '\n');
+    if (B != (char *) NULL) { *B = 0; }
+    if (*A != 0) {
+      PushQueue (queue, A);
+      A = B + 1;
+      i++;
+    }
+  }      
+  free (val);
+    
+  return (TRUE);
+
+usage:
+  gprint (GP_ERR, "USAGE: queueload (queue) -x (command)\n");
+  return (FALSE);
+}
+
+
+/* 
+ * -key only needed for replace or unique : give an error otherwise
+ * -uniq searched for a match and does NOT replace if matched
+ * -replace searches for a match and replaces if matched
+ * should trigger an error if -uniq and -replace...
+ */
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/queuepop.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/queuepop.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/queuepop.c	(revision 11389)
@@ -0,0 +1,71 @@
+# include "data.h"
+
+int queuepop (int argc, char **argv) {
+  
+  int N;
+  char *Key;
+  char *var;
+  char *line;
+  char *Value;
+  Queue *queue;
+
+  var = (char *) NULL;
+  if ((N = get_argument (argc, argv, "-var"))) {
+    remove_argument (N, &argc, argv);
+    var = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  Key = NULL;
+  Value = NULL;
+  if ((N = get_argument (argc, argv, "-key"))) {
+    remove_argument (N, &argc, argv);
+    Key = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+    Value = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 2) {
+    gprint (GP_ERR, "USAGE: queuepop (queue) [-var variable] [-key N value]\n");
+    return (FALSE);
+  }
+
+  /* will create a queue if none exists */
+  queue = FindQueue (argv[1]);
+  if (queue == NULL) {
+    gprint (GP_ERR, "ERROR: queue %s not found\n", argv[1]);
+    return (FALSE);
+  }
+
+  if (Key == NULL) {
+    line = PopQueue (queue);
+  } else {
+    line = PopQueueMatch (queue, Key, Value);
+  }
+
+  if (var == NULL) {
+    if (line == NULL) {
+      gprint (GP_ERR, "queue %s is empty or match not found\n", argv[1]);
+      return (FALSE);
+    } else {
+      gprint (GP_LOG, "%s\n", line);
+      free (line);
+      return (TRUE);
+    }
+  }
+
+  if (line == NULL) {
+    set_str_variable (var, "NULL");
+  } else {
+    set_str_variable (var, line);
+    free (line);
+  }
+
+  free (var);
+  if (Key != NULL) free (Key);
+  if (Value != NULL) free (Value);
+
+  return (TRUE);
+}
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/queueprint.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/queueprint.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/queueprint.c	(revision 11389)
@@ -0,0 +1,21 @@
+# include "data.h"
+
+int queueprint (int argc, char **argv) {
+  
+  Queue *queue;
+
+  if (argc != 2) {
+    gprint (GP_ERR, "USAGE: queueprint (name)\n");
+    return (FALSE);
+  }
+
+  queue = FindQueue (argv[1]);
+  if (queue == NULL) {
+    gprint (GP_ERR, "ERROR: queue %s not found\n", argv[1]);
+    return (FALSE);
+  }
+
+  PrintQueue (queue);
+  return (TRUE);
+}
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/queuepush.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/queuepush.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/queuepush.c	(revision 11389)
@@ -0,0 +1,56 @@
+# include "data.h"
+
+int queuepush (int argc, char **argv) {
+  
+  char *Key;
+  int N, Unique, Replace;
+  Queue *queue;
+
+  Unique = FALSE;
+  if ((N = get_argument (argc, argv, "-uniq"))) {
+    remove_argument (N, &argc, argv);
+    Unique = TRUE;
+  }
+
+  Replace = FALSE;
+  if ((N = get_argument (argc, argv, "-replace"))) {
+    remove_argument (N, &argc, argv);
+    Replace = TRUE;
+  }
+
+  Key = NULL;
+  if ((N = get_argument (argc, argv, "-key"))) {
+    remove_argument (N, &argc, argv);
+    Key = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 3) {
+    gprint (GP_ERR, "USAGE: queuepush (queue) (value) [-key N] [-uniq] [-replace]\n");
+    return (FALSE);
+  }
+
+  /* will create a queue if none exists */
+  queue = CreateQueue (argv[1]);
+
+  if (Unique) {
+    PushQueueUnique (queue, argv[2], Key);
+  }
+  if (Replace) {
+    PushQueueReplace (queue, argv[2], Key);
+  }
+  if (!Unique && !Replace) {
+    PushQueue (queue, argv[2]);
+  }
+
+  if (Key != NULL) free (Key);
+  return (TRUE);
+}
+
+
+/* 
+ * -key only needed for replace or unique : give an error otherwise
+ * -uniq searched for a match and does NOT replace if matched
+ * -replace searches for a match and replaces if matched
+ * should trigger an error if -uniq and -replace...
+ */
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/queuesize.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/queuesize.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/queuesize.c	(revision 11389)
@@ -0,0 +1,36 @@
+# include "data.h"
+
+int queuesize (int argc, char **argv) {
+  
+  int N;
+  char *var;
+  Queue *queue;
+
+  var = (char *) NULL;
+  if ((N = get_argument (argc, argv, "-var"))) {
+    remove_argument (N, &argc, argv);
+    var = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 2) {
+    gprint (GP_ERR, "USAGE: queuesize (name) [-var variable]\n");
+    return (FALSE);
+  }
+
+  queue = FindQueue (argv[1]);
+  if (queue == NULL) {
+    gprint (GP_ERR, "ERROR: queue %s not found\n", argv[1]);
+    return (FALSE);
+  }
+
+  if (var == (char *) NULL) {
+    gprint (GP_ERR, "Nlines: %d\n", queue[0].Nlines);
+    return (TRUE);
+  }
+
+  set_int_variable (var, queue[0].Nlines);
+  free (var);
+  return (TRUE);
+}
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/radial.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/radial.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/radial.c	(revision 11389)
@@ -0,0 +1,97 @@
+# include "data.h"
+
+int circstats (int argc, char **argv) {
+  
+  int i, j;
+  double Npix, S1, S2, max, min, Sum, Mean, Stdev, IgnoreValue; 
+  double xc, yc, radius, R2, r;
+  float *V;
+  int xs, ys, xe, ye;
+  int Ignore, Quiet, N, Nx, Ny;
+  Buffer *buf;
+
+  Ignore = FALSE;
+  IgnoreValue = 0;
+  if ((N = get_argument (argc, argv, "-ignore"))) {
+    Ignore = TRUE;
+    remove_argument (N, &argc, argv);
+    IgnoreValue = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  Quiet = FALSE;
+  if ((N = get_argument (argc, argv, "-q"))) {
+    Quiet = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "-quiet"))) {
+    Quiet = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 5) goto usage;
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) goto missed;
+
+  xc = atof (argv[2]);
+  yc = atof (argv[3]);
+  radius = atof (argv[4]);
+  Nx = buf[0].matrix.Naxis[0];
+  Ny = buf[0].matrix.Naxis[1];
+
+  if (xc < 0) goto range;
+  if (yc < 0) goto range;
+  if (xc >= Nx) goto range;
+  if (yc >= Ny) goto range;
+
+  xs = MAX (0, xc - radius);
+  ys = MAX (0, yc - radius);
+  xe = MIN (Nx, xc + radius + 1);
+  ye = MAX (Ny, yc + radius + 1);
+  R2 = radius*radius;
+
+  S1 = S2 = Npix = 0;
+  min = max = *(float *)(buf[0].matrix.buffer) + (int)(yc)*buf[0].matrix.Naxis[0] + (int)(xc); 
+  for (j = ys; j < ye; j++) {
+    V = (float *)(buf[0].matrix.buffer) + j*buf[0].matrix.Naxis[0] + xs; 
+    for (i = xs; i < xe; i++, V++) {
+      r = SQ(i - xc) + SQ(j - yc);
+      if (r > R2) continue;
+      if (Ignore && (fabs (*V - IgnoreValue) < 1e-8)) continue;
+      S1 += *V;
+      S2 += (*V)*(*V);
+      Npix += 1.0;
+      max = MAX (max, *V);
+      min = MIN (min, *V);
+    }
+  }
+  Mean = S1 / Npix;
+  Sum  = Mean * M_PI * R2;
+  Stdev = sqrt (S2/Npix - Mean*Mean);
+
+  if (!Quiet) {
+    gprint (GP_LOG, "     mean     stdev       min       max    Npix     Total\n");
+    gprint (GP_LOG, "%9.4g %9.4g %9.4g %9.4g %7.0f %9.4g\n", Mean, Stdev, min, max, Npix, Sum);
+  }
+
+  set_variable ("MIN",    min);
+  set_variable ("MAX",    max);
+  set_variable ("MEAN",   Mean);
+  set_variable ("SUM",    Sum);
+  set_variable ("NPIX",   Npix);
+  set_variable ("SIGMA",  Stdev);
+
+  return (TRUE);
+
+ usage: 
+  gprint (GP_ERR, "USAGE: circstats <buffer> x y radius\n");
+  return (FALSE);
+
+ range:
+  gprint (GP_ERR, "ERROR: coordinates out of range\n");
+  return (FALSE);
+
+ missed:
+  gprint (GP_ERR, "ERROR: buffer not found\n");
+  return (FALSE);
+}
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/rd.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/rd.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/rd.c	(revision 11389)
@@ -0,0 +1,242 @@
+# include "data.h"
+
+/* there is some confusion in this function with the several possible options */
+int rd (int argc, char **argv) {
+  
+  int i, N, status, plane, Nplane, extend, Nextend, Nskip, JustHead;
+  int ccdsel, done;
+  char region[512], *ccdid, *filename;
+  FILE *f;
+  Buffer *buf;
+
+  JustHead = FALSE;
+  if ((N = get_argument (argc, argv, "-head"))) {
+    remove_argument (N, &argc, argv);
+    JustHead = TRUE;
+  }
+
+  plane = 1;
+  if ((N = get_argument (argc, argv, "-plane"))) {
+    remove_argument (N, &argc, argv);
+    plane  = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  extend = FALSE;
+  Nextend = -1;
+  if ((N = get_argument (argc, argv, "-x"))) {
+    remove_argument (N, &argc, argv);
+    Nextend  = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+    extend = TRUE;
+  }
+
+  ccdsel = FALSE;
+  ccdid = (char *) NULL;
+  if ((N = get_argument (argc, argv, "-n"))) {
+    remove_argument (N, &argc, argv);
+    ccdid  = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+    ccdsel = TRUE;
+  }
+
+  if (extend && ccdsel) {
+    gprint (GP_ERR, "only specify one of -n and -x\n");
+    return (FALSE);
+  }
+
+  if (argc != 3) {
+    gprint (GP_ERR, "USAGE: rd <buffer> <filename> [-head] [-plane N] [-n ccdid] [-x extnum]\n");
+    return (FALSE);
+  }
+
+  /* test if file exists */
+  f = fopen (argv[2], "r");
+  if (f == (FILE *) NULL) {
+    gprint (GP_ERR, "file %s not found\n", argv[2]);
+    return (FALSE);
+  }
+  fclose (f);
+
+  /* find matrix, free old data */
+  if ((buf = SelectBuffer (argv[1], ANYBUFFER, TRUE)) == NULL) return (FALSE);
+  gfits_free_matrix (&buf[0].matrix);
+  gfits_free_header (&buf[0].header);
+
+  /* save file name */
+  filename = filebasename (argv[2]);
+  strcpy (buf[0].file, filename);
+  free (filename);
+
+  status = FALSE;
+
+  if (extend) {
+    /* load in appropriate header */
+    Nskip = gfits_read_Xheader (argv[2], &buf[0].header, Nextend);
+    if (!Nskip) {
+      gprint (GP_ERR, "entry in %s not found\n", argv[2]);
+      DeleteBuffer (buf);
+      return (FALSE);
+    }
+    /* fix up header */
+    {
+      static char simple[] = "SIMPLE  =                    T / Standard FITS";
+      int Ns, No;
+
+      Ns = strlen (simple);
+      No = 80 - Ns;
+      strncpy (buf[0].header.buffer, simple, Ns);
+      memset (&buf[0].header.buffer[Ns], ' ', No);
+    }
+    if (JustHead) {
+      /* should be in CreateMatrix / CreateBuffer function */
+      buf[0].header.Naxes = 0;
+      ALLOCATE (buf[0].matrix.buffer, char, 1);
+      buf[0].matrix.size = 0;
+      buf[0].bitpix = 16;
+      buf[0].bzero = 0;
+      buf[0].bscale = 1;
+      buf[0].matrix.bitpix = 16;
+      buf[0].matrix.bzero = 0;
+      buf[0].matrix.bscale = 1;
+      buf[0].header.bitpix = 16;
+      buf[0].header.bzero = 0;
+      buf[0].header.bscale = 1;
+      return (TRUE);
+    }
+    /* load matrix data */
+    f = fopen (argv[2], "r");
+    if (f == (FILE *) NULL) {
+      gprint (GP_ERR, "file %s not found\n", argv[2]);
+      DeleteBuffer (buf);
+      return (FALSE);
+    }
+    fseek (f, Nskip, SEEK_SET);
+    status = gfits_load_matrix (f, &buf[0].matrix, &buf[0].header);
+    fclose (f);
+  } 
+
+  if (ccdsel) {
+    char *CCDKeyword, ID[64];
+
+    CCDKeyword = get_variable ("CCDKEYWORD");
+    if (CCDKeyword == (char *) NULL) {
+      gprint (GP_ERR, "CCDKEYWORD variable is not set; ");
+      gprint (GP_ERR, "using EXTNAME as default\n");
+      CCDKeyword = strcreate ("EXTNAME");
+    }
+    done = FALSE;
+    for (i = 0; !done; i++) {
+      Nskip = gfits_read_Xheader (argv[2], &buf[0].header, i);
+      if (!Nskip) {
+	gprint (GP_ERR, "extension %s in %s not found\n", ccdid, argv[2]);
+	DeleteBuffer (buf);
+	free (CCDKeyword);
+	return (FALSE);
+      }
+      if (!gfits_scan (&buf[0].header, CCDKeyword, "%s", 1, ID)) {
+	gprint (GP_ERR, "%s not in header\n", CCDKeyword);
+	DeleteBuffer (buf);
+	free (CCDKeyword);
+	return (FALSE);
+      }
+
+      /* compare as numbers if both are pure numbers, else as strings */
+      done = strnumcmp (ccdid, ID);
+
+      if (!done) gfits_free_header (&buf[0].header);
+    }
+    free (CCDKeyword);
+
+    /* fix up header */
+    {
+      static char simple[] = "SIMPLE  =                    T / Standard FITS";
+      int Ns, No;
+
+      Ns = strlen (simple);
+      No = 80 - Ns;
+      strncpy (buf[0].header.buffer, simple, Ns);
+      memset (&buf[0].header.buffer[Ns], ' ', No);
+    }
+    if (JustHead) {
+      buf[0].header.Naxes = 0;
+      ALLOCATE (buf[0].matrix.buffer, char, 1);
+      buf[0].matrix.size = 0;
+      buf[0].bitpix = 16;
+      buf[0].bzero = 0;
+      buf[0].bscale = 1;
+      buf[0].matrix.bitpix = 16;
+      buf[0].matrix.bzero = 0;
+      buf[0].matrix.bscale = 1;
+      buf[0].header.bitpix = 16;
+      buf[0].header.bzero = 0;
+      buf[0].header.bscale = 1;
+      return (TRUE);
+    }
+    /* load matrix data */
+    f = fopen (argv[2], "r");
+    if (f == (FILE *) NULL) {
+      gprint (GP_ERR, "file %s not found\n", argv[2]);
+      DeleteBuffer (buf);
+      return (FALSE);
+    }
+    fseek (f, Nskip, SEEK_SET);
+    status = gfits_load_matrix (f, &buf[0].matrix, &buf[0].header);
+    fclose (f);
+  }
+
+  if (!ccdsel && !extend) {
+    status = gfits_read_header (argv[2], &buf[0].header);
+    if (JustHead) {
+      buf[0].header.Naxes = 0;
+      ALLOCATE (buf[0].matrix.buffer, char, 1);
+      buf[0].matrix.size = 0;
+      buf[0].bitpix = 16;
+      buf[0].bzero = 0;
+      buf[0].matrix.bscale = 1;
+      buf[0].matrix.bitpix = 16;
+      buf[0].matrix.bzero = 0;
+      buf[0].matrix.bscale = 1;
+      return (TRUE);
+    }
+    Nplane = buf[0].header.Naxis[2];
+    if (Nplane > 0) {
+      if (plane > Nplane) {
+	gprint (GP_ERR, "-plane is too large: %d total planes\n", Nplane);
+	DeleteBuffer (buf);
+	return (FALSE);
+      }
+      buf[0].header.Naxis[2] = 0;
+      buf[0].header.Naxes = 2;
+      gfits_modify (&buf[0].header, "NAXIS", "%d", 1, 2);
+      gfits_delete (&buf[0].header, "NAXIS3", 1);
+    }
+    sprintf (region, "-1 -1 -1 -1 %d %d", (plane - 1), plane);
+    status = gfits_read_segment (argv[2], &buf[0].matrix, region);
+  }
+
+  if (!status) {
+    gprint (GP_ERR, "problem reading file, buffer not opened\n");
+    DeleteBuffer (buf);
+    return (FALSE);
+  }
+  if (buf[0].header.Naxes == 1) {
+    /* we need to return an array, so make Naxis[1] = 1 */
+    buf[0].header.Naxes = 2;
+    buf[0].header.Naxis[1] = 1;
+    buf[0].matrix.Naxis[1] = 1;
+  }    
+
+  buf[0].bitpix = buf[0].header.bitpix;    /* store the original values */
+  buf[0].bscale = buf[0].header.bscale;    /* store the original values */
+  buf[0].bzero  = buf[0].header.bzero;     /* store the original values */
+  buf[0].unsign = buf[0].header.unsign;
+  gprint (GP_LOG, "read %d bytes from %s into buffer %s\n", 
+	   buf[0].header.size + buf[0].matrix.size, argv[2], argv[1]);
+
+  /** now - convert the matrix values to floats for internal use **/
+  gfits_convert_format (&buf[0].header, &buf[0].matrix, -32, 1.0, 0.0, FT_UNSIGN_MODE);
+  
+  return (TRUE);
+
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/rdseg.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/rdseg.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/rdseg.c	(revision 11389)
@@ -0,0 +1,72 @@
+# include "data.h"
+
+/* there is some confusion in this function with the several possible options */
+int rdseg (int argc, char **argv) {
+  
+  int x, y, nx, ny, status;
+  char region[512], *filename;
+  FILE *f;
+  Buffer *buf;
+
+  if (argc != 7) {
+    gprint (GP_ERR, "USAGE: rdseg <buffer> <filename> x y nx ny\n");
+    return (FALSE);
+  }
+  x = atoi (argv[3]);
+  y = atoi (argv[4]);
+  nx = atoi (argv[5]);
+  ny = atoi (argv[6]);
+
+  /* test if file exists */
+  f = fopen (argv[2], "r");
+  if (f == (FILE *) NULL) {
+    gprint (GP_ERR, "file %s not found\n", argv[2]);
+    return (FALSE);
+  }
+  fclose (f);
+
+  /* find matrix, free old data */
+  if ((buf = SelectBuffer (argv[1], ANYBUFFER, TRUE)) == NULL) return (FALSE);
+  gfits_free_matrix (&buf[0].matrix);
+  gfits_free_header (&buf[0].header);
+
+  /* save file name */
+  filename = filebasename (argv[2]);
+  strcpy (buf[0].file, filename);
+  free (filename);
+
+  status = gfits_read_header (argv[2], &buf[0].header);
+  sprintf (region, "%d %d %d %d 0 1", x, nx + x, y, ny + y);
+  status = gfits_read_segment (argv[2], &buf[0].matrix, region);
+  gfits_modify (&buf[0].header, "NAXIS1", "%d", 1, nx);
+  gfits_modify (&buf[0].header, "NAXIS2", "%d", 1, ny);
+  buf[0].header.Naxis[0] = nx;
+  buf[0].header.Naxis[1] = ny;
+  buf[0].matrix.Naxis[0] = nx;
+  buf[0].matrix.Naxis[1] = ny;
+
+  if (!status) {
+    gprint (GP_ERR, "problem reading file, buffer not opened\n");
+    DeleteBuffer (buf);
+    return (FALSE);
+  }
+  if (buf[0].header.Naxes == 1) {
+    /* we need to return an array, so make Naxis[1] = 1 */
+    buf[0].header.Naxes = 2;
+    buf[0].header.Naxis[1] = 1;
+    buf[0].matrix.Naxis[1] = 1;
+  }    
+
+  buf[0].bitpix = buf[0].header.bitpix;    /* store the original values */
+  buf[0].bscale = buf[0].header.bscale;    /* store the original values */
+  buf[0].bzero  = buf[0].header.bzero;     /* store the original values */
+  buf[0].unsign = buf[0].header.unsign;
+  gprint (GP_LOG, "read %d bytes from %s into buffer %s\n", 
+	   buf[0].header.size + buf[0].matrix.size, argv[2], argv[1]);
+
+  /** now - convert the matrix values to floats for internal use **/
+  gfits_convert_format (&buf[0].header, &buf[0].matrix, -32, 1.0, 0.0, FT_UNSIGN_MODE);
+  
+  return (TRUE);
+
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/read_vectors.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/read_vectors.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/read_vectors.c	(revision 11389)
@@ -0,0 +1,281 @@
+ # include "data.h"
+
+FILE *f = (FILE *) NULL;
+char filename[256];
+
+int datafile (int argc, char **argv) {
+
+  if (argc < 2) {
+    gprint (GP_ERR, "USAGE: datafile (filename)\n");
+    return (FALSE);
+  }
+  
+  strcpy (filename, argv[1]);
+  if (f != (FILE *) NULL) { fclose (f); }
+  f = fopen (filename, "r");
+  if (f == (FILE *) NULL) {
+    gprint (GP_ERR, "failed to open file %s\n", argv[1]);
+    return (FALSE);
+  }
+  return (TRUE);
+}
+
+int read_vectors (int argc, char **argv) {
+  
+  int i, j, Nskip, Nvec, *col, done, status;
+  int Nbytes, nbytes, Nstart, NELEM, N, nread;
+  char *colstr, *c0, *c1, *buffer, *extname;
+  double value;
+  Vector **vec;
+
+  /* auto-sense table type */
+  if ((N = get_argument (argc, argv, "-fits"))) {
+    remove_argument (N, &argc, argv);
+    extname = strcreate (argv[N]);
+    if (extname == (char *) NULL) return (FALSE);
+    remove_argument (N, &argc, argv);
+    status = read_table_vectors (argc, argv, extname);
+    free (extname);
+    return (status);
+  }
+
+  Nskip = 0;
+  if ((N = get_argument (argc, argv, "-skip"))) {
+    remove_argument (N, &argc, argv);
+    Nskip = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  if ((argc < 3) || !(argc % 2)) {
+    gprint (GP_ERR, "USAGE: read name N name N ...\n");
+    return (FALSE);
+  }
+  /* read name N name N  */
+
+  if (f == (FILE *) NULL) {
+    gprint (GP_ERR, "no open file for read\n");
+    return (FALSE);
+  }
+  fseek (f, 0, SEEK_SET);
+
+  Nvec = (argc - 1) / 2;
+  ALLOCATE (vec, Vector *, Nvec);
+  ALLOCATE (col, int, Nvec);
+
+  for (i = 0; i < Nvec; i++) {
+    if ((vec[i] = SelectVector (argv[2*i + 1], ANYVECTOR, TRUE)) == NULL) {
+      gprint (GP_ERR, "USAGE: read name N name N ...\n");
+      free (vec);
+      free (col);
+      return (FALSE);    
+    }
+    colstr = argv[2*i+2];
+    for (j = 0; j < strlen (colstr); j++) {
+      if (!isdigit(colstr[j])) {
+	gprint (GP_ERR, "USAGE: read name N name N ...\n");
+	free (vec);
+	free (col);
+	return (FALSE);    
+      }
+    }
+    col[i] = atof (colstr);
+  }
+  
+  NELEM = 1000;
+  for (i = 0; i < Nvec; i++) {
+    REALLOCATE (vec[i][0].elements, float, NELEM);
+  }
+  
+  ALLOCATE (buffer, char, 0x10001);
+  bzero (buffer, 0x10001);
+  for (i = 0; i < Nskip; i++) {
+    scan_line (f, buffer);
+  }
+
+  Nstart = 0;
+  N = 0;
+  done = FALSE;
+  while (!done) {
+    Nbytes = 0x10000 - Nstart;
+    bzero (&buffer[Nstart], Nbytes);
+    nread = fread (&buffer[Nstart], 1, Nbytes, f);
+    if (ferror (f)) {
+      perror ("error reading data file");
+      break;
+    }
+    if (nread == 0) break;
+    nbytes = nread + Nstart;
+    
+    status = TRUE;
+    c0 = buffer; 
+    while (status) {
+      c1 = strchr (c0, '\n');
+      if (c1 == (char *) NULL) {
+	Nstart = strlen (c0);
+	memmove (buffer, c0, Nstart);
+	status = FALSE;
+      } else {
+	*c1 = 0;
+      }      
+      if ((*c0 != '#') && (*c0 != '!')) {
+	for (i = 0; (i < Nvec) && status; i++) {
+	  status = dparse (&value, col[i], c0);
+	  vec[i][0].elements[N] = value;
+	  if (!status) vec[i][0].elements[N] = 0.0/0.0;
+	}
+	if (status) N++;
+      }
+      c0 = c1 + 1;
+      if (N == NELEM) {
+	NELEM += 1000;
+	for (i = 0; i < Nvec; i++) {
+	  REALLOCATE (vec[i][0].elements, float, NELEM);
+	}
+      }
+	
+    }
+  }
+  for (i = 0; i < Nvec; i++) {
+    REALLOCATE (vec[i][0].elements, float, MAX (N,1));
+    vec[i][0].Nelements = N;
+  }
+  
+  free (vec);
+  free (col);
+  free (buffer);
+  return (TRUE);
+
+}
+
+int read_table_vectors (int argc, char **argv, char *extname) {
+
+  int i, j, k, Nbytes, Nread, Nextend, Ny, Binary;
+  char type[16];
+  FTable table;
+  Header header;
+  Vector **vec;
+
+  if (argc < 2) {
+    gprint (GP_ERR, "USAGE: read -fits extension name name ...\n");
+    gprint (GP_ERR, "  ('extension' may be a name or number)\n");
+    return (FALSE);
+  }
+
+  if (f == (FILE *) NULL) return (FALSE);
+  fseek (f, 0, SEEK_SET);
+  table.header = &header;
+
+  /* load appropriate extension (if extname is a number, use count) */
+  if (isdigit(extname[0])) {
+    Nextend = atoi (extname);
+
+    for (i = 0; i <= Nextend; i++) {
+      if (!gfits_load_header (f, &header)) return (FALSE);
+      Nbytes = gfits_matrix_size (&header);
+      /* skip the prior data buffers */
+      if (i < Nextend) { 
+	fseek (f, Nbytes, SEEK_CUR);
+	gfits_free_header (&header);
+	continue;
+      }
+      /* on the desired header, load buffer */
+      ALLOCATE (table.buffer, char, Nbytes);
+      Nread = fread (table.buffer, sizeof (char), Nbytes, f);
+      if (Nread != Nbytes) {
+	gfits_free_table  (&table);
+	gfits_free_header (&header);
+	return (FALSE);
+      }
+      table.size = Nbytes;
+    }
+  } else {
+    if (!gfits_fread_ftable (f, &table, extname)) return (FALSE);
+  }
+
+  /* identify table type (ascii / binary) */
+  Binary = FALSE;
+  gfits_scan (&header, "XTENSION", "%s", 1, type);
+  if (!strcmp (type, "BINTABLE")) {
+    Binary = TRUE;
+  } 
+  Ny = header.Naxis[1];
+
+  /* find columns which match requested vectors */
+  for (i = 1; i < argc; i++) {
+    void   *data;
+    char   *Pc;
+    short  *Ps;
+    int    *Pi;
+    float  *Pf;
+    double *Pd;
+    int Nval;
+    char name[80];
+      
+    Nval = 0;
+    if (Binary) {
+      if (!gfits_get_bintable_column_type (&header, argv[i], type, &Nval)) return (FALSE);
+      if (!gfits_get_bintable_column (&header, &table, argv[i], &data)) return (FALSE);
+    } else {
+      if (!gfits_get_table_column_type (&header, argv[i], type)) return (FALSE);
+      if (!gfits_get_table_column (&header, &table, argv[i], &data)) return (FALSE);
+    }
+    if (Nval == 0) return (FALSE);
+
+    ALLOCATE (vec, Vector *, Nval);
+    for (j = 0; j < Nval; j++) {
+      if (Nval == 1) 
+	sprintf (name, "%s", argv[i]);
+      else
+	sprintf (name, "%s:%d", argv[i], j);
+      if ((vec[j] = SelectVector (name, ANYVECTOR, TRUE)) == NULL) return (FALSE);    
+      REALLOCATE (vec[j][0].elements, float, MAX (Ny,1));
+      vec[j][0].Nelements = Ny;
+    }
+
+    if (!strcmp (type, "double")) {
+      Pd = (double *) data;
+      for (j = 0; j < Ny; j++) {
+	for (k = 0; k < Nval; k++, Pd++) {
+	  vec[k][0].elements[j] = *Pd;
+	}
+      }
+    }
+    if (!strcmp (type, "float")) {
+      Pf = (float *) data;
+      for (j = 0; j < Ny; j++) {
+	for (k = 0; k < Nval; k++, Pf++) {
+	  vec[k][0].elements[j] = *Pf;
+	}
+      }
+    }
+    if (!strcmp (type, "int")) {
+      Pi = (int *) data;
+      for (j = 0; j < Ny; j++) {
+	for (k = 0; k < Nval; k++, Pi++) {
+	  vec[k][0].elements[j] = *Pi;
+	}
+      }
+    }
+    if (!strcmp (type, "short")) {
+      Ps = (short *) data;
+      for (j = 0; j < Ny; j++) {
+	for (k = 0; k < Nval; k++, Ps++) {
+	  vec[k][0].elements[j] = *Ps;
+	}
+      }
+    }
+    if (!strcmp (type, "char")) {
+      Pc = (char *) data;
+      for (j = 0; j < Ny; j++) {
+	for (k = 0; k < Nval; k++, Pc++) {
+	  vec[k][0].elements[j] = *Pc;
+	}
+      }
+    }
+    free (data);
+    free (vec);
+  }
+  gfits_free_table (&table);
+  gfits_free_header (&header);
+  return (TRUE);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/rebin.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/rebin.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/rebin.c	(revision 11389)
@@ -0,0 +1,228 @@
+# include "data.h"
+
+int rebin (int argc, char **argv) {
+  
+  int i, j, status, n, nx, ny, Nx, Ny, x, y, N, *Npix, *Vn;
+  int Ignore, IgnoreValue, VERBOSE, Normalize, ExactScale;
+  char temp[1024];
+  float *Vout, *Vin, *Out, *In;
+  double scale, scale2, fx, fy, dX, dY;
+  Buffer *in, *out;
+
+  Vn = Npix = NULL;
+  Normalize = FALSE;
+  if ((N = get_argument (argc, argv, "-norm"))) {
+    remove_argument (N, &argc, argv);
+    Normalize = TRUE;
+  }
+
+  VERBOSE = FALSE;
+  if ((N = get_argument (argc, argv, "-v"))) {
+    remove_argument (N, &argc, argv);
+    VERBOSE = TRUE;
+  }
+
+  Ignore = FALSE;
+  IgnoreValue = 0.0;
+  if ((N = get_argument (argc, argv, "-ignore"))) {
+    Ignore = TRUE;
+    remove_argument (N, &argc, argv);
+    IgnoreValue = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 4) {
+    gprint (GP_ERR, "USAGE: rebin <from> <to> scale \n");
+    gprint (GP_ERR, "  negative integer scale expands image\n");
+    return (FALSE);
+  }
+
+  if ((in  = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  if ((out = SelectBuffer (argv[2], ANYBUFFER, TRUE)) == NULL) return (FALSE);
+  gfits_free_matrix (&out[0].matrix);
+  gfits_free_header (&out[0].header);
+
+  scale  = atof (argv[3]);
+  if ((scale == (int) scale) || ((1.0/scale) == (int)(1.0/scale))) {
+    ExactScale = TRUE;
+    if (scale > 0) {
+      nx = in[0].header.Naxis[0] / scale;
+      ny = in[0].header.Naxis[1] / scale;
+    } else {
+      nx = in[0].header.Naxis[0] * fabs(scale);
+      ny = in[0].header.Naxis[1] * fabs(scale);
+    }    
+  } else {
+    ExactScale = FALSE;
+    if (scale > 0) {
+      nx = (int) (in[0].header.Naxis[0] / scale) + 1;
+      ny = (int) (in[0].header.Naxis[1] / scale) + 1;
+    } else {
+      nx = (int) (in[0].header.Naxis[0] * fabs(scale)) + 1;
+      ny = (int) (in[0].header.Naxis[1] * fabs(scale)) + 1;
+    }      
+  }
+  if (VERBOSE) gprint (GP_LOG, "rebin %s to %s (%d,%d to %d,%d)\n", argv[1], argv[2], in[0].header.Naxis[0], in[0].header.Naxis[1], nx, ny);
+
+  Nx = in[0].header.Naxis[0];
+  Ny = in[0].header.Naxis[1];
+  out[0].bitpix = in[0].bitpix;
+  out[0].unsign = in[0].unsign;
+  out[0].bscale = in[0].bscale;
+  out[0].bzero  = in[0].bzero;
+  gfits_copy_header (&in[0].header, &out[0].header);
+  gfits_modify (&out[0].header, "NAXIS1", "%d", 1, nx);
+  gfits_modify (&out[0].header, "NAXIS2", "%d", 1, ny);
+
+  status =  gfits_scan (&out[0].header, "CDELT1", "%lf", 1, &dX);
+  status &= gfits_scan (&out[0].header, "CDELT2", "%lf", 1, &dY);
+  if (scale > 0) {
+    dX *= scale;
+    dY *= scale;
+  } else {
+    dX /= fabs(scale);
+    dY /= fabs(scale);
+  }    
+  if (status) {
+    gfits_modify (&out[0].header, "CDELT1", "%lf", 1, dX);
+    gfits_modify (&out[0].header, "CDELT2", "%lf", 1, dY);
+  }
+
+  status =  gfits_scan (&out[0].header, "CRPIX1", "%lf", 1, &dX);
+  status &= gfits_scan (&out[0].header, "CRPIX2", "%lf", 1, &dY);
+  if (scale > 0) {
+    dX /= scale;
+    dY /= scale;
+  } else {
+    dX *= fabs(scale);
+    dY *= fabs(scale);
+  }    
+  if (status) {
+    gfits_modify (&out[0].header, "CRPIX1", "%lf", 1, dX);
+    gfits_modify (&out[0].header, "CRPIX2", "%lf", 1, dY);
+  }
+
+  out[0].header.Naxis[0] = nx;
+  out[0].header.Naxis[1] = ny;
+  gfits_create_matrix (&out[0].header, &out[0].matrix);
+  temp[0] = 0;
+  if ((in[0].file[0] != '*') && (in[0].file[0] != '(')) {
+    strcpy (temp, "*");
+  }
+  strcat (temp, in[0].file);
+  strcpy (out[0].file, temp);
+
+  if (Normalize) {
+    ALLOCATE (Npix, int, nx*ny);
+    bzero (Npix, nx*ny*sizeof(int));
+  }
+
+  if (ExactScale) {
+    n = scale;
+    if (n > 0) {
+      for (j = 0; j < ny; j++) {
+	for (y = 0; y < n; y++) {
+	  Vout = (float *)(out[0].matrix.buffer) + j*nx;
+	  Vin  = (float *)(in[0].matrix.buffer)  + (j*n + y)*in[0].header.Naxis[0];
+	  if (Normalize) { Vn = Npix + j*nx; }
+	  for (i = 0; i < nx; i++, Vout++) {
+	    for (x = 0; x < n; x++, Vin++) {
+	      if (Ignore && (*Vin == IgnoreValue)) continue;
+	      *Vout += *Vin;
+	      if (Normalize) {(*Vn) ++;}
+	    }
+	    if (Normalize) {Vn ++;}
+	  }
+	}
+      }
+    } else {
+      n = fabs (n);
+      for (j = 0; j < in[0].header.Naxis[1]; j++) {
+	for (y = 0; y < n; y++) {
+	  Vout = (float *)(out[0].matrix.buffer) + (j*n + y)*nx;
+	  Vin  = (float *)(in[0].matrix.buffer)  + j*in[0].header.Naxis[0];
+	  if (Normalize) { Vn = Npix + j*nx; }
+	  for (i = 0; i < in[0].header.Naxis[0]; i++, Vin++) {
+	    if (Ignore && (*Vin == IgnoreValue)) { 
+	      Vout += n; 
+	      if (Normalize) Vn += n; 
+	      continue; 
+	    }
+	    for (x = 0; x < n; x++, Vout++) {
+	      *Vout = *Vin;
+	      if (Normalize) {(*Vn) ++; Vn ++;}
+	    }
+	  }
+	}
+      }
+    }
+    if (Normalize) {
+      Vn = Npix;
+      Vout = (float *)out[0].matrix.buffer;
+      for (i = 0; i < nx*ny; i++, Vout++, Vn++) {
+	if (*Vn) { 
+	  *Vout /= *Vn; 
+	} else {
+	  *Vout = 0;
+	}
+      }
+    }
+  } else {
+    
+    /* normalization is broken.  repair please */
+    if (Normalize) { gprint (GP_ERR, "normalize not enabled for fractional scaling\n"); }
+
+    if (scale < 0) scale = 1.0 / fabs(scale);
+    In = (float *)in[0].matrix.buffer;
+    Out = (float *)out[0].matrix.buffer;
+    scale2 = scale*scale;
+    if (scale > 1) {
+      for (i = 0; i < Ny; i++) {
+	y = 0.5 + (i - 0.5) / scale;
+	fy = 0.5 + MIN (0.5, (y + 0.5) * scale - i);
+	for (j = 0; j < Nx; j++, In++) {
+	  x = 0.5 + (j - 0.5) / scale;
+	  fx = 0.5 + MIN (0.5, (x + 0.5) * scale - j);
+	  Vout = Out + y*nx + x;
+	  *Vout += fx*fy*(*In);
+	  if (fx < 1) {
+	    *(Vout+1)    += (1-fx)*fy*(*In);
+	  }
+	  if (fy < 1) {
+	    *(Vout+nx) += fx*(1-fy)*(*In);
+	  }
+	  if ((fx < 1) && (fy < 1)) {
+	    *(Vout+1+nx) += (1-fx)*(1-fy)*(*In);
+	  }
+	}
+      }
+    } else {
+      for (i = 0; i < ny; i++) {
+	y = 0.5 + (i - 0.5) * scale;
+	fy = 0.5 + MIN (0.5, (y + 0.5) / scale - i);
+	for (j = 0; j < nx; j++, Out++) {
+	  x = 0.5 + (j - 0.5) * scale;
+	  fx = 0.5 + MIN (0.5, (x + 0.5) / scale - j);
+	  Vin = In + y*Nx + x;
+	  *Out += *Vin*fx*fy;
+	  if (fx < 1) {
+	    *Out += *(Vin+1)*(1-fx)*fy;
+	  }
+	  if (fy < 1) {
+	    *Out += *(Vin+Nx)*fx*(1-fy);
+	  }
+	  if ((fx < 1) && (fy < 1)) {
+	    *Out += *(Vin+1+Nx)*(1-fx)*(1-fy);
+	  }
+	  *Out = *Out * scale2;
+	}
+      }
+    }
+  }
+
+  if (Normalize) free (Npix);
+
+  return (TRUE);
+
+}
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/resize.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/resize.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/resize.c	(revision 11389)
@@ -0,0 +1,54 @@
+# include "data.h"
+
+int resize (int argc, char **argv) {
+
+  char *end;
+  double NX, NY;
+  int N, Source, Nsource, IsImage;
+  
+  /* display source */
+  Nsource = -1;
+  if ((N = get_argument (argc, argv, "-n"))) {
+    remove_argument (N, &argc, argv);
+    Nsource = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "-g"))) {
+    remove_argument (N, &argc, argv);
+    SetImageDevice (FALSE);
+  }  
+  if ((N = get_argument (argc, argv, "-i"))) {
+    remove_argument (N, &argc, argv);
+    SetImageDevice (TRUE);
+  }  
+  IsImage = GetCurrentDevice ();
+  if (IsImage) {
+    if (!GetImage (&Source, &Nsource)) return (FALSE);
+  } else {
+    if (!GetGraph (NULL, &Source, &Nsource)) return (FALSE);
+  }
+
+  if (argc != 3) {
+    gprint (GP_ERR, "USAGE: resize NX NY [-n] [-g | -i]\n");
+    return (FALSE);
+  }
+
+  /* NX & NY are pixels for the screen & points for PS 
+     convert units to points (1in = 72pt, 1cm = 28pt) */
+
+  /* have kapa convert physical units to screen units 
+     for now, fixed at 96 pix / in == 38 pix / cm
+  */
+
+  NX = strtod (argv[1], &end);
+  if (!strcmp (end, "in")) { NX *= 96; }
+  if (!strcmp (end, "cm")) { NX *= 38; }
+
+  NY = strtod (argv[2], &end);
+  if (!strcmp (end, "in")) { NY *= 96; }
+  if (!strcmp (end, "cm")) { NY *= 38; }
+
+  KiiResize (Source, NX, NY);
+  return (TRUE);
+}
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/roll.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/roll.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/roll.c	(revision 11389)
@@ -0,0 +1,45 @@
+# include "data.h"
+
+int roll (int argc, char **argv) {
+  
+  int Nbytes, Nextra;
+  int dX, dx, dy, nx, ny;
+  Buffer *buf;
+
+  if (argc != 4) {
+    gprint (GP_ERR, "USAGE: roll <buffer> dx dy\n");
+    return (FALSE);
+  }
+
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+
+  dx = atof (argv[2]);
+  dy = atof (argv[3]);
+  if (dy != 0) {
+    gprint (GP_ERR, "only x rolls implemented for now\n");
+  }
+
+  /* if (dx < 0), we are moving the start position back by dx pixels,
+     if (dx > 0), we are moving the start position forward by dx pixels */
+  
+  nx = buf[0].matrix.Naxis[0];
+  ny = buf[0].matrix.Naxis[1];
+
+  dX = abs(dx);
+  Nbytes = nx * ny * sizeof (float);
+  Nextra = (nx * ny + dX) * sizeof (float);
+
+  REALLOCATE (buf[0].matrix.buffer, char, Nextra);
+
+  if (dx < 0) {
+    memmove (buf[0].matrix.buffer, &buf[0].matrix.buffer[dX*sizeof(float)], Nbytes);
+  } else {
+    memmove (&buf[0].matrix.buffer[dX*sizeof(float)], buf[0].matrix.buffer, Nbytes);
+  }
+
+  REALLOCATE (buf[0].matrix.buffer, char, Nbytes);
+
+  return (TRUE);
+
+}
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/rotate.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/rotate.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/rotate.c	(revision 11389)
@@ -0,0 +1,298 @@
+# include "data.h"
+
+int rotate (int argc, char **argv) {
+  
+  int i, j, NX, NY, X, Y, Lx, Ly, N, newCenter;
+  float *in_buff, *out_buff, *c;
+  double angle, CosAngle, SinAngle, Xo, Yo, dX, dY, fx, fy, x, y, X1, Y1;
+  double pc11, pc12, pc21, pc22, PC11, PC12, PC21, PC22;
+  Buffer *buf;
+
+  Xo = 0;
+  Yo = 0;
+  if ((N = get_argument (argc, argv, "-center"))) {
+    newCenter = TRUE;
+    remove_argument (N, &argc, argv);
+    Xo  = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+    Yo  = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  else 
+    newCenter  = FALSE;
+
+  if (argc != 3) {
+    gprint (GP_ERR, "USAGE: rotate <buffer> <angle>\n");
+    return (FALSE);
+  }
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+
+  if ((atof (argv[1]) < -180) || (atof (argv[1]) > 180)) {
+    gprint (GP_ERR, "valid rotate angle between -180 and +180 degrees\n");
+    return (FALSE);
+  }
+
+  /* save starting values */
+  NX = buf[0].header.Naxis[0];
+  NY = buf[0].header.Naxis[1];
+  in_buff = (float *) buf[0].matrix.buffer;  /* don't lose reference */
+
+  if (!strcasecmp (argv[2], "LEFT") || (atof (argv[2]) == -90)) {
+    buf[0].header.Naxis[0] = NY;
+    buf[0].header.Naxis[1] = NX;
+    gfits_modify (&buf[0].header, "NAXIS1", "%d", 1, NY);
+    gfits_modify (&buf[0].header, "NAXIS2", "%d", 1, NX);
+    gfits_print  (&buf[0].header, "HISTORY", "%S", 1, "WARNING: rotated image!");
+    gfits_create_matrix (&buf[0].header, &buf[0].matrix);
+    out_buff = (float *)buf[0].matrix.buffer;
+    for (i = NX - 1; i > -1; i--) {
+      for (j = 0; j < NY; j++, out_buff++) {
+	*out_buff = in_buff[i + j*NX];
+      }
+    }
+    /* fix reference pixel */
+    gfits_scan (&buf[0].header, "CRPIX1", "%lf", 1, &Xo);
+    gfits_scan (&buf[0].header, "CRPIX2", "%lf", 1, &Yo);
+    X1 = Yo;
+    Y1 = NX - Xo;
+    gfits_modify (&buf[0].header, "CRPIX1", "%lf", 1, X1);
+    gfits_modify (&buf[0].header, "CRPIX2", "%lf", 1, Y1);
+    
+    /* fix rotate matrix */
+    gfits_scan (&buf[0].header, "PC001001", "%lf", 1, &pc11);
+    gfits_scan (&buf[0].header, "PC001002", "%lf", 1, &pc12);
+    gfits_scan (&buf[0].header, "PC002001", "%lf", 1, &pc21);
+    gfits_scan (&buf[0].header, "PC002002", "%lf", 1, &pc22);
+    PC11 = pc21;
+    PC12 = pc22;
+    PC21 = -pc11;
+    PC22 = -pc12;
+    gfits_modify (&buf[0].header, "PC001001", "%le", 1, PC11);
+    gfits_modify (&buf[0].header, "PC001002", "%le", 1, PC12);
+    gfits_modify (&buf[0].header, "PC002001", "%le", 1, PC21);
+    gfits_modify (&buf[0].header, "PC002002", "%le", 1, PC22);
+
+    free (in_buff);
+    return (TRUE);
+  }
+
+  if (!strcasecmp (argv[2], "RIGHT") || (atof (argv[2]) == 90)) {
+    buf[0].header.Naxis[0] = NY;
+    buf[0].header.Naxis[1] = NX;
+    gfits_modify (&buf[0].header, "NAXIS1", "%d", 1, NY);
+    gfits_modify (&buf[0].header, "NAXIS2", "%d", 1, NX);
+    gfits_print  (&buf[0].header, "HISTORY", "%S", 1, "WARNING: rotated image!");
+    gfits_create_matrix (&buf[0].header, &buf[0].matrix);
+    out_buff = (float *)buf[0].matrix.buffer;
+    for (i = 0; i < NX; i++) {
+      for (j = NY - 1; j > -1; j--, out_buff++) {
+	*out_buff = in_buff[i + j*NX];
+      }
+    }
+    /* fix reference pixel */
+    gfits_scan (&buf[0].header, "CRPIX1", "%lf", 1, &Xo);
+    gfits_scan (&buf[0].header, "CRPIX2", "%lf", 1, &Yo);
+    X1 = NY - Yo;
+    Y1 = Xo;
+    gprint (GP_ERR, "%f %f -> %f %f\n", Xo, Yo, X1, Y1);
+    gfits_modify (&buf[0].header, "CRPIX1", "%lf", 1, X1);
+    gfits_modify (&buf[0].header, "CRPIX2", "%lf", 1, Y1);
+    
+    /* fix rotate matrix */
+    gfits_scan (&buf[0].header, "PC001001", "%lf", 1, &pc11);
+    gfits_scan (&buf[0].header, "PC001002", "%lf", 1, &pc12);
+    gfits_scan (&buf[0].header, "PC002001", "%lf", 1, &pc21);
+    gfits_scan (&buf[0].header, "PC002002", "%lf", 1, &pc22);
+    PC11 = -pc21;
+    PC12 = -pc22;
+    PC21 = pc11;
+    PC22 = pc12;
+    gprint (GP_ERR, "%f %f  ->  %f %f\n", pc11, pc12, PC11, PC12);
+    gprint (GP_ERR, "%f %f  ->  %f %f\n", pc21, pc22, PC21, PC22);
+    gfits_modify (&buf[0].header, "PC001001", "%le", 1, PC11);
+    gfits_modify (&buf[0].header, "PC001002", "%le", 1, PC12);
+    gfits_modify (&buf[0].header, "PC002001", "%le", 1, PC21);
+    gfits_modify (&buf[0].header, "PC002002", "%le", 1, PC22);
+
+    free (in_buff);
+    return (TRUE);
+  }
+
+  if (!strcasecmp (argv[2], "UPSIDE") || (atof (argv[2]) == -180) || (atof (argv[2]) == 180)) {
+    gfits_print  (&buf[0].header, "HISTORY", "%S", 1, "WARNING: rotated image!");
+    gfits_create_matrix (&buf[0].header, &buf[0].matrix);
+    out_buff = (float *)buf[0].matrix.buffer;
+    for (j = NY - 1; j > -1; j--) {
+      for (i = NX - 1; i > -1; i--, out_buff++) {
+	*out_buff = in_buff[i + j*NX];
+      }
+    }
+    /* fix reference pixel */
+    gfits_scan (&buf[0].header, "CRPIX1", "%lf", 1, &Xo);
+    gfits_scan (&buf[0].header, "CRPIX2", "%lf", 1, &Yo);
+    X1 = NX - Xo;
+    Y1 = NY - Yo;
+    gfits_modify (&buf[0].header, "CRPIX1", "%lf", 1, X1);
+    gfits_modify (&buf[0].header, "CRPIX2", "%lf", 1, Y1);
+    
+    /* fix rotate matrix */
+    gfits_scan (&buf[0].header, "PC001001", "%lf", 1, &pc11);
+    gfits_scan (&buf[0].header, "PC001002", "%lf", 1, &pc12);
+    gfits_scan (&buf[0].header, "PC002001", "%lf", 1, &pc21);
+    gfits_scan (&buf[0].header, "PC002002", "%lf", 1, &pc22);
+    PC11 = -pc11;
+    PC12 = -pc12;
+    PC21 = -pc21;
+    PC22 = -pc22;
+    gfits_modify (&buf[0].header, "PC001001", "%le", 1, PC11);
+    gfits_modify (&buf[0].header, "PC001002", "%le", 1, PC12);
+    gfits_modify (&buf[0].header, "PC002001", "%le", 1, PC21);
+    gfits_modify (&buf[0].header, "PC002002", "%le", 1, PC22);
+
+    free (in_buff);
+    return (TRUE);
+  }
+
+  if (!strcasecmp (argv[2], "FLIPY")) {
+    gfits_print  (&buf[0].header, "HISTORY", "%S", 1, "WARNING: rotated image!");
+    gfits_create_matrix (&buf[0].header, &buf[0].matrix);
+    out_buff = (float *)buf[0].matrix.buffer;
+    for (j = NY - 1; j > -1; j--) {
+      for (i = 0; i < NX; i++, out_buff++) {
+	*out_buff = in_buff[i + j*NX];
+      }
+    }
+    /* fix reference pixel */
+    gfits_scan (&buf[0].header, "CRPIX1", "%lf", 1, &Xo);
+    gfits_scan (&buf[0].header, "CRPIX2", "%lf", 1, &Yo);
+    X1 = Xo;
+    Y1 = NY - Yo;
+    gfits_modify (&buf[0].header, "CRPIX1", "%lf", 1, X1);
+    gfits_modify (&buf[0].header, "CRPIX2", "%lf", 1, Y1);
+    
+    /* fix rotate matrix */
+    gfits_scan (&buf[0].header, "PC001001", "%lf", 1, &pc11);
+    gfits_scan (&buf[0].header, "PC001002", "%lf", 1, &pc12);
+    gfits_scan (&buf[0].header, "PC002001", "%lf", 1, &pc21);
+    gfits_scan (&buf[0].header, "PC002002", "%lf", 1, &pc22);
+    PC11 = pc11;
+    PC12 = -pc12;
+    PC21 = pc21;
+    PC22 = -pc22;
+    gfits_modify (&buf[0].header, "PC001001", "%le", 1, PC11);
+    gfits_modify (&buf[0].header, "PC001002", "%le", 1, PC12);
+    gfits_modify (&buf[0].header, "PC002001", "%le", 1, PC21);
+    gfits_modify (&buf[0].header, "PC002002", "%le", 1, PC22);
+
+    free (in_buff);
+    return (TRUE);
+  }
+
+  if (!strcasecmp (argv[2], "FLIPX")) {
+    gfits_print  (&buf[0].header, "HISTORY", "%S", 1, "WARNING: rotated image!");
+    gfits_create_matrix (&buf[0].header, &buf[0].matrix);
+    out_buff = (float *)buf[0].matrix.buffer;
+    for (j = 0; j < NY; j++) {
+      for (i = NX - 1; i > -1; i--, out_buff++) {
+	*out_buff = in_buff[i + j*NX];
+      }
+    }
+    /* fix reference pixel */
+    gfits_scan (&buf[0].header, "CRPIX1", "%lf", 1, &Xo);
+    gfits_scan (&buf[0].header, "CRPIX2", "%lf", 1, &Yo);
+    X1 = NX - Xo;
+    Y1 = Yo;
+    gfits_modify (&buf[0].header, "CRPIX1", "%lf", 1, X1);
+    gfits_modify (&buf[0].header, "CRPIX2", "%lf", 1, Y1);
+    
+    /* fix rotate matrix */
+    gfits_scan (&buf[0].header, "PC001001", "%lf", 1, &pc11);
+    gfits_scan (&buf[0].header, "PC001002", "%lf", 1, &pc12);
+    gfits_scan (&buf[0].header, "PC002001", "%lf", 1, &pc21);
+    gfits_scan (&buf[0].header, "PC002002", "%lf", 1, &pc22);
+    PC11 = -pc11;
+    PC12 = pc12;
+    PC21 = -pc21;
+    PC22 = pc22;
+    gfits_modify (&buf[0].header, "PC001001", "%le", 1, PC11);
+    gfits_modify (&buf[0].header, "PC001002", "%le", 1, PC12);
+    gfits_modify (&buf[0].header, "PC002001", "%le", 1, PC21);
+    gfits_modify (&buf[0].header, "PC002002", "%le", 1, PC22);
+
+    free (in_buff);
+    return (TRUE);
+  }
+
+  angle = atof (argv[2]);
+  CosAngle = cos (angle*RAD_DEG);
+  SinAngle = sin (angle*RAD_DEG);
+  
+  gprint (GP_ERR, "rotating: %f %f %f\n", angle, CosAngle, SinAngle);
+
+  Lx = NX*fabs(CosAngle) + NY*fabs(SinAngle);
+  Ly = NX*fabs(SinAngle) + NY*fabs(CosAngle);
+  dX = MAX(0,NY*SinAngle);
+  dY = MAX(0,-NX*SinAngle);
+  /*
+  gprint (GP_ERR, "%f %f  -->  ", Xo, Yo);
+  X1 = Xo*CosAngle - Yo*SinAngle + dX;
+  Y1 =  Xo*SinAngle + Yo*CosAngle + dY;
+  gprint (GP_ERR, "%f %f\n", X1, Y1);
+  */
+
+  /* fix reference pixel */
+  gfits_scan (&buf[0].header, "CRPIX1", "%lf", 1, &Xo);
+  gfits_scan (&buf[0].header, "CRPIX2", "%lf", 1, &Yo);
+  /*
+  X1 = (Xo - dX)*CosAngle - (Yo - dY)*SinAngle;
+  Y1 = (dX - Xo)*SinAngle + (Yo - dY)*CosAngle;
+  */
+  X1 = Xo*CosAngle - Yo*SinAngle + dX;
+  Y1 =  Xo*SinAngle + Yo*CosAngle + dY;
+  gfits_modify (&buf[0].header, "CRPIX1", "%lf", 1, X1);
+  gfits_modify (&buf[0].header, "CRPIX2", "%lf", 1, Y1);
+
+  /* fix rotate matrix */
+  gfits_scan (&buf[0].header, "PC001001", "%lf", 1, &pc11);
+  gfits_scan (&buf[0].header, "PC001002", "%lf", 1, &pc12);
+  gfits_scan (&buf[0].header, "PC002001", "%lf", 1, &pc21);
+  gfits_scan (&buf[0].header, "PC002002", "%lf", 1, &pc22);
+  PC11 = pc11*CosAngle - pc21*SinAngle;
+  PC12 = pc12*CosAngle - pc22*SinAngle;
+  PC21 = pc21*CosAngle + pc11*SinAngle;
+  PC22 = pc22*CosAngle + pc12*SinAngle;
+  gfits_modify (&buf[0].header, "PC001001", "%le", 1, PC11);
+  gfits_modify (&buf[0].header, "PC001002", "%le", 1, PC12);
+  gfits_modify (&buf[0].header, "PC002001", "%le", 1, PC21);
+  gfits_modify (&buf[0].header, "PC002002", "%le", 1, PC22);
+
+  buf[0].header.Naxis[0] = Lx;
+  buf[0].header.Naxis[1] = Ly;
+  gfits_modify (&buf[0].header, "NAXIS1", "%d", 1, Lx);
+  gfits_modify (&buf[0].header, "NAXIS2", "%d", 1, Ly);
+  gfits_create_matrix (&buf[0].header, &buf[0].matrix);
+  gfits_print  (&buf[0].header, "HISTORY", "%S", 1, "WARNING: rotated image!");
+  out_buff = (float *)buf[0].matrix.buffer;
+  for (j = 0; j < Ly; j++) {
+    for (i = 0; i < Lx; i++, out_buff++) {
+
+      x = (i - dX)*CosAngle + (j - dY)*SinAngle;
+      y = (dX - i)*SinAngle + (j - dY)*CosAngle;
+      X = (int) x;
+      Y = (int) y;
+
+      if (X < 0) continue;
+      if (X >= NX - 1) continue;
+      if (Y < 0) continue;
+      if (Y >= NY - 1) continue;
+
+      c = &in_buff[X * NX*Y];
+      fx = x - X;
+      fy = y - Y;
+      *out_buff = (c[0]*(1-fx) + c[1]*fx)*(1-fy) + (c[NX+1]*fx + c[NX]*(1-fx))*fy;
+    }
+  }
+  free (in_buff);
+  return (TRUE);
+
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/save.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/save.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/save.c	(revision 11389)
@@ -0,0 +1,30 @@
+# include "data.h"
+
+int save (int argc, char **argv) {
+  
+  int N, celestial;
+  int Ximage, Nimage;
+  
+  Nimage = -1;
+  if ((N = get_argument (argc, argv, "-n"))) {
+    remove_argument (N, &argc, argv);
+    Nimage = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if (!GetImage (&Ximage, &Nimage)) return (FALSE);
+
+  celestial = FALSE;
+  if ((N = get_argument (argc, argv, "-c"))) {
+    remove_argument (N, &argc, argv);
+    celestial = TRUE;
+  }
+
+  if (argc != 3) {
+    gprint (GP_ERR, "USAGE: save (overlay) <filename> [-c]\n");
+    gprint (GP_ERR, "  -c: write contour in celestial coords\n");
+    return (FALSE);
+  }
+
+  KiiSaveOverlay (Ximage, celestial, argv[1], argv[2]);
+  return (TRUE);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/section.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/section.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/section.c	(revision 11389)
@@ -0,0 +1,58 @@
+# include "data.h"
+
+int section (int argc, char **argv) {
+  
+  int N, List;
+  int Ngraph, Xgraph;
+  Graphdata graphmode;
+  KapaSection section;
+
+  List = FALSE;
+  if ((N = get_argument (argc, argv, "-list"))) {
+    remove_argument (N, &argc, argv);
+    List = TRUE;
+  }
+
+  Ngraph = -1;
+  if ((N = get_argument (argc, argv, "-n"))) {
+    remove_argument (N, &argc, argv);
+    Ngraph = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if (!GetGraph (&graphmode, &Xgraph, &Ngraph)) return (FALSE);
+
+  /* list sections */
+  if (argc == 1) {
+    KapaGetSection (Xgraph, "*");
+    gprint (GP_ERR, "USAGE: section name [x y dx dy]\n");
+    return (TRUE);
+  } 
+  
+  if (argc == 2) {
+    /* select / show section */
+    if (List) {
+      KapaGetSection (Xgraph, argv[1]);
+    } else {
+      KapaSelectSection (Xgraph, argv[1]);
+    }
+    return (TRUE);
+  } 
+  
+  if (argc == 6) {
+    /* set section */
+    section.name = argv[1];
+    section.x = atof (argv[2]);
+    section.y = atof (argv[3]);
+    section.dx = atof (argv[4]);
+    section.dy = atof (argv[5]);
+    KapaSetSection (Xgraph, &section);
+    return (TRUE);
+  }
+  gprint (GP_ERR, "USAGE: section name [x y dx dy]\n");
+  return (FALSE);
+}
+
+/* should do some range checking on x y dx dy
+   should be between 0.0 and 1.0, precision of 0.001
+   is sufficient
+*/
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/select.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/select.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/select.c	(revision 11389)
@@ -0,0 +1,46 @@
+# include "data.h"
+
+int vect_select (int argc, char **argv) {
+  
+  int  i, size;
+  char *out;
+  Vector *in1, *in2, *tvec, *ovec;
+
+  out = NULL;
+  in1 = in2 = ovec = tvec = NULL;
+
+  /** check basic syntax **/
+  if ((argc != 8) || strcmp(argv[2], "=") || strcmp (argv[4], "if") || strcmp (argv[6], "else")) {
+    gprint (GP_ERR, "SYNTAX: select vec = vec if (logic expression) else vec\n");
+    return (FALSE);
+  }
+  if ((in1  = SelectVector (argv[3], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((in2  = SelectVector (argv[7], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((ovec = SelectVector (argv[1], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+
+  out = dvomath (argc - 5, &argv[5], &size, 1);
+  if (out == NULL) {
+    print_error ();
+    goto error;
+  }
+  if ((tvec = SelectVector (out, OLDVECTOR, TRUE)) == NULL) goto error;
+  /* check size of in1, in2, tvec: must match */
+
+  REALLOCATE (ovec[0].elements, float, MAX (tvec[0].Nelements, 1));
+  for (i = 0; i < tvec[0].Nelements; i++) {
+    ovec[0].elements[i] = tvec[0].elements[i] ? in1[0].elements[i] : in2[0].elements[i];
+  }
+  ovec[0].Nelements = tvec[0].Nelements;
+  REALLOCATE (ovec[0].elements, float, MAX (ovec[0].Nelements, 1));
+  
+  DeleteVector (tvec);
+  free (out);
+  return (TRUE);
+
+ error:
+  DeleteVector (tvec);
+  DeleteVector (ovec);
+  DeleteNamedVector (out);
+  free (out);
+  return (FALSE);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/set.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/set.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/set.c	(revision 11389)
@@ -0,0 +1,47 @@
+# include "data.h"
+
+int set (int argc, char **argv) {
+  
+  int size;
+  char *out;
+
+  /** check basic form for line **/
+  if ((argc < 3) || strcmp(argv[2], "=")) {
+    gprint (GP_ERR, "%s = (matrix expression)\n", argv[0]);
+    return (FALSE);
+  }
+
+  out = dvomath (argc - 3, &argv[3], &size, -1);
+  if (out == NULL) {
+    print_error ();
+    return (FALSE);
+  }
+  
+  switch (size) {
+    case 0:
+      set_str_variable (argv[1], out);
+      free (out);
+      break;
+
+    case 1:
+      if (!MoveNamedVector (argv[1], out)) {
+	DeleteNamedVector (out);
+	free (out);
+	gprint (GP_ERR, "invalid output vector name\n");
+	return (FALSE);
+      }
+      free (out);
+      break;
+  
+    case 2:
+      if (!MoveNamedBuffer (argv[1], out)) {
+	DeleteNamedBuffer (out);
+	free (out);
+	gprint (GP_ERR, "invalid output matrix name\n");
+	return (FALSE);
+      }
+      free (out);
+      break;
+  }
+  return (TRUE);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/shift.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/shift.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/shift.c	(revision 11389)
@@ -0,0 +1,110 @@
+# include "data.h"
+
+int shift (int argc, char **argv) {
+ 
+  int i, j, N, ROLL;
+  int nx, ny, dx, dy, DXin, DXot, DYin, DYot;
+  float *Vin, *Vot;
+  double Dx, Dy, fdx, fdy;
+  Buffer *in, *out;
+
+  ROLL = FALSE;
+  if ((N = get_argument (argc, argv, "-roll"))) {
+    remove_argument (N, &argc, argv);
+    ROLL = TRUE;
+  }
+
+  if (argc != 5) {
+    gprint (GP_ERR, "USAGE: shift (input) (output) dx dy\n");
+    return (FALSE);
+  }
+
+  // define the input buffer and examine the shift
+  if ((in  = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+
+  Dx = atof (argv[3]);
+  Dy = atof (argv[4]);
+
+  dx = Dx;
+  dy = Dy;
+  fdx = Dx - dx;
+  fdy = Dy - dy;
+  if (fdx < -0.000001) {dx -= 1; fdx += 1;}
+  if (fdy < -0.000001) {dy -= 1; fdy += 1;}
+  // we always specify a positive fractional shift
+  // the above choice defines a minimum fractional shift of 1e-5
+
+  nx = in[0].matrix.Naxis[0];
+  ny = in[0].matrix.Naxis[1];
+
+  if ((dx > nx) || (dy > ny)) {
+    gprint (GP_ERR, "shifting data out of image\n");
+    return (FALSE);
+  }
+  
+  // define the output buffer
+  if ((out = SelectBuffer (argv[2], ANYBUFFER, TRUE)) == NULL) return (FALSE);
+
+  gfits_free_matrix (&out[0].matrix);
+  gfits_free_header (&out[0].header);
+  CreateBuffer (out, nx, ny, -32, 0.0, 1.0);
+
+  DXin = (dx < 0) ? -dx : 0;
+  DXot = (dx < 0) ?   0 : dx;
+  DYin = (dy < 0) ? -dy : 0;
+  DYot = (dy < 0) ?   0 : dy;
+  
+  for (j = 0; j < ny - abs(dy); j++) {
+    Vin = (float *)(in[0].matrix.buffer)  + (j + DYin)*nx + DXin;  
+    Vot = (float *)(out[0].matrix.buffer) + (j + DYot)*nx + DXot; 
+    for (i = 0; i < nx - abs(dx); i++, Vin++, Vot++) {
+      *Vot = *Vin;
+    }
+    // fill in the exposed x-border with 0.0
+    Vot = (dx > 0) ? 
+      (float *)(out[0].matrix.buffer) + (j + DYot)*nx : 
+      (float *)(out[0].matrix.buffer) + (j + DYot)*nx + nx - abs(dx);
+    for (i = 0; i < abs(dx); i++, Vot++) {
+      *Vot = 0.0;
+    }	
+  }
+
+  // fill in the exposed y-border with 0.0
+  Vot = (dy > 0) ? 
+    (float *)(out[0].matrix.buffer) :
+    (float *)(out[0].matrix.buffer) + (ny - abs(dy))*nx;
+
+  for (j = 0; j < nx * abs(dy); j++, Vot++) {
+    *Vot = 0.0;
+  }   
+
+  // apply the fractional shift 
+  gprint (GP_ERR, "%f %f\n", fdx, fdy);
+  if ((fdx > 0) || (fdy > 0)) {
+    double f00, f01, f10, f11;
+    float value;
+
+    f00 = (1-fdx)*(1-fdy);
+    f01 =    fdx *(1-fdy);
+    f10 = (1-fdx)*   fdy;
+    f11 =    fdx *   fdy;
+
+    Vin = (float *)out[0].matrix.buffer;
+    Vot = (float *)out[0].matrix.buffer;
+    for (j = 0; j < ny - 1; j++) {
+      for (i = 0; i < nx - 1; i++, Vin++, Vot++) {
+	value  = Vin[   0] * f00;
+	value += Vin[   1] * f01;
+	value += Vin[nx  ] * f10;
+	value += Vin[nx+1] * f11;
+	*Vot = value;
+      }
+      Vin ++;
+      Vot ++;
+    }
+  }   
+
+  return (TRUE);
+
+}
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/sort.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/sort.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/sort.c	(revision 11389)
@@ -0,0 +1,64 @@
+# include "data.h"
+
+int sort_vectors (int argc, char **argv) {
+  
+  int i, j, Nvec, Nval;
+  float *temp, *index, *T, *V, *I;
+  Vector **vec;
+
+  if (argc < 2) {
+    gprint (GP_ERR, "USAGE: sort (vector) [vectors ...] \n");
+    gprint (GP_ERR, "  first vector is sort key for others\n");
+    return (FALSE);
+  }
+
+  Nvec = (argc - 1);
+  ALLOCATE (vec, Vector *, Nvec);
+
+  Nval = 0;
+  /* find vectors and check sizes */
+  for (i = 0; i < Nvec; i++) {
+    if ((vec[i] = SelectVector (argv[i + 1], OLDVECTOR, FALSE)) == NULL) {
+      gprint (GP_ERR, "USAGE: sort vector vector ...\n");
+      free (vec);
+      return (FALSE);    
+    }
+    if (i == 0) {
+      Nval = vec[i][0].Nelements;
+    } else {
+      if (Nval != vec[i][0].Nelements) {
+	free (vec);
+	gprint (GP_ERR, "vectors must all be same length\n");
+	return (FALSE);
+      }
+    }
+  }
+  
+  /* create index (use float to use sortpair) */
+  ALLOCATE (index, float, Nval);
+  for (i = 0; i < Nval; i++) index[i] = i;
+
+  /* sort key & index */
+  fsortpair (vec[0][0].elements, index, Nval);
+
+  ALLOCATE (temp, float, Nval);
+  for (i = 1; i < Nvec; i++) {
+    T = temp;
+    V = vec[i][0].elements;
+    I = index;
+    for (j = 0; j < Nval; j++, T++, I++) {
+      *T = V[(int)(*I)];
+    }
+    /* swap .elements (== V) and temp */ 
+    vec[i][0].elements = temp;
+    temp = V;
+  }
+  free (temp);
+  free (vec);
+  free (index);
+
+  return (TRUE);
+
+}
+
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/spline_apply.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/spline_apply.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/spline_apply.c	(revision 11389)
@@ -0,0 +1,100 @@
+# include "data.h"
+
+void spline (float *x, float *y, int N, float *y2);
+float splint (float *x, float *y, float *y2, int N, float X);
+
+int spline_apply (int argc, char **argv) {
+  
+  int i, j, I, J;
+  int nx, ny, Nx, Ny, xdir;
+  float rx, ry, x, y;
+  float *Tx1, *Tx2, *Txc, *Ty1, *Ty2, *Tyc, *V, *V1, *V2;
+  Buffer *out, *y1, *y2;
+
+  if (argc != 7) {
+    gprint (GP_ERR, "USAGE: spline_apply <Y> <Y2> <out> (x/y) Nx Ny\n");
+    return (FALSE);
+  }
+
+  if ((y1  = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  if ((y2  = SelectBuffer (argv[2], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  if ((out = SelectBuffer (argv[3], ANYBUFFER, TRUE)) == NULL) return (FALSE);
+
+  xdir = FALSE;
+  if (!strcmp (argv[4], "x")) xdir = TRUE; 
+
+  nx = atoi (argv[5]);
+  ny = atoi (argv[6]);
+
+  Nx = y1[0].matrix.Naxis[0];
+  Ny = y1[0].matrix.Naxis[1];
+
+  rx = Nx / (float) nx;
+  ry = Ny / (float) ny;
+
+  /* create an output matrix buffer with desired nx, ny */
+  gfits_free_matrix (&out[0].matrix);
+  gfits_free_header (&out[0].header);
+
+  out[0].bitpix = y1[0].bitpix;
+  out[0].unsign = y1[0].unsign;
+  out[0].bscale = y1[0].bscale;
+  out[0].bzero  = y1[0].bzero;
+  gfits_copy_header (&y1[0].header, &out[0].header);
+  gfits_modify (&out[0].header, "NAXIS1", "%d", 1, nx);
+  gfits_modify (&out[0].header, "NAXIS2", "%d", 1, ny);
+
+  out[0].header.Naxis[0] = nx;
+  out[0].header.Naxis[1] = ny;
+  gfits_create_matrix (&out[0].header, &out[0].matrix);
+  if ((y1[0].file[0] != '*') && (y1[0].file[0] != '(')) {
+    sprintf (out[0].file, "*%s", y1[0].file);
+  } else {
+    sprintf (out[0].file, "%s", y1[0].file);
+  }
+
+  ALLOCATE (Ty2, float, Ny);
+  ALLOCATE (Ty1, float, Ny);
+  ALLOCATE (Tyc, float, Ny);
+  for (i = 0; i < Ny; i++) { Tyc[i] = i; }
+
+  ALLOCATE (Tx1, float, Nx);
+  ALLOCATE (Tx2, float, Nx);
+  ALLOCATE (Txc, float, Nx);
+  for (i = 0; i < Nx; i++) { Txc[i] = i; }
+
+  V = (float *)(out[0].matrix.buffer);
+
+  for (J = 0; J < ny; J++) {
+    y = J * ry;
+
+    /* construct spline for each element in this row */
+    for (i = 0; i < Nx; i++) {
+      V1 = (float *)(y1[0].matrix.buffer) + i;
+      V2 = (float *)(y2[0].matrix.buffer) + i;
+      for (j = 0; j < Ny; j++, V1+=Nx, V2+=Nx) {
+	Ty1[j] = *V1;
+	Ty2[j] = *V2;
+      }
+      Tx1[i] = splint (Tyc, Ty1, Ty2, Ny, y);
+    }
+    spline (Txc, Tx1, Nx, Tx2);
+
+    /* apply x-dir spline to new image */
+    for (I = 0; I < nx; I++, V++) {
+      x = I * rx;
+      *V = splint (Txc, Tx1, Tx2, Nx, x);
+    }
+  }
+
+  free (Ty1);
+  free (Ty2);
+  free (Tyc);
+  
+  free (Tx1);
+  free (Tx2);
+  free (Txc);
+  
+  return (TRUE);
+
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/spline_construct.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/spline_construct.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/spline_construct.c	(revision 11389)
@@ -0,0 +1,71 @@
+# include "data.h"
+
+int spline_construct (int argc, char **argv) {
+  
+  int i, j, Nx, Ny, xdir;
+  float *Tx, *Ty, *Ty2, *V;
+  Buffer *in, *out;
+
+  if (argc != 4) {
+    gprint (GP_ERR, "USAGE: spline_construct <in> <out> (x/y)\n");
+    return (FALSE);
+  }
+
+  if ((in  = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  if ((out = SelectBuffer (argv[2], ANYBUFFER, TRUE)) == NULL) return (FALSE);
+
+  free (out[0].matrix.buffer);
+  free (out[0].header.buffer);
+  if ((in[0].file[0] != '*') && (in[0].file[0] != '(')) {
+    sprintf (out[0].file, "*%s", in[0].file);
+  } else {
+    sprintf (out[0].file, "%s", in[0].file);
+  }
+  out[0].bitpix = in[0].bitpix;
+  out[0].unsign = in[0].unsign;
+  out[0].bscale = in[0].bscale;
+  out[0].bzero  = in[0].bzero;
+  gfits_copy_matrix_info (&in[0].matrix, &out[0].matrix);
+  gfits_copy_header (&in[0].header, &out[0].header);
+  gfits_create_matrix (&out[0].header, &out[0].matrix);
+
+  xdir = FALSE;
+  if (!strcmp (argv[3], "x")) xdir = TRUE; 
+  /* ideally, the resulting image should carry this info (in header?) */
+
+  Nx = in[0].matrix.Naxis[0];
+  Ny = in[0].matrix.Naxis[1];
+
+  ALLOCATE (Ty2, float, Ny);
+  ALLOCATE (Ty, float, Ny);
+  ALLOCATE (Tx, float, Ny);
+
+  /** for now only perform the operation for the ydir splines */
+
+  /* construct coordinate vector */
+  for (j = 0; j < Ny; j++) { Tx[j] = j; }
+  
+  for (i = 0; i < Nx; i++) {
+    
+    /* construct temp vector with values to spline */
+    V = (float *)(in[0].matrix.buffer) + i;
+    for (j = 0; j < Ny; j++, V+=Nx) {
+      Ty[j] = *V;
+    }
+  
+    spline (Tx, Ty, Ny, Ty2);
+  
+    /* copy derivatives to output buffer */
+    V = (float *)(out[0].matrix.buffer) + i;
+    for (j = 0; j < Ny; j++, V+=Nx) {
+      *V = Ty2[j];
+    }
+  }
+
+  free (Tx);
+  free (Ty);
+  free (Ty2);
+  
+  return (TRUE);
+
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/stats.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/stats.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/stats.c	(revision 11389)
@@ -0,0 +1,120 @@
+# include "data.h"
+
+int stats (int argc, char **argv) {
+  
+  int i, j, Nmode, Imode;
+  double Npix, N1, N2, max, min, range, median, mode, IgnoreValue;
+  float *V;
+  int sx, sy, nx, ny, *hist, Nhist, bin;
+  int Ignore, Quiet, N;
+  Buffer *buf;
+
+  IgnoreValue = 0;
+  Ignore = FALSE;
+  if ((N = get_argument (argc, argv, "-ignore"))) {
+    Ignore = TRUE;
+    remove_argument (N, &argc, argv);
+    IgnoreValue = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  Quiet = FALSE;
+  if ((N = get_argument (argc, argv, "-q"))) {
+    Quiet = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "-quiet"))) {
+    Quiet = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  if ((argc != 2) && (argc != 6)) {
+    gprint (GP_ERR, "USAGE: stats <buffer> sx sy nx ny\n");
+    gprint (GP_ERR, "OR:    stats <buffer>\n");
+    return (FALSE);
+  }
+
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+
+  if (argc == 6) {
+    sx = strcmp (argv[2], "-") ? atof (argv[2]) : 0;
+    sy = strcmp (argv[3], "-") ? atof (argv[3]) : 0;
+    nx = strcmp (argv[4], "-") ? atof (argv[4]) : buf[0].matrix.Naxis[0];
+    ny = strcmp (argv[5], "-") ? atof (argv[5]) : buf[0].matrix.Naxis[1];
+  } else {
+    sx = 0;
+    sy = 0;
+    nx = buf[0].matrix.Naxis[0];
+    ny = buf[0].matrix.Naxis[1];
+  }
+
+  Npix = N1 = N2 = 0;
+  if ((sx < 0) || (sy < 0) || 
+      (sx+nx > buf[0].matrix.Naxis[0]) || 
+      (sy+ny > buf[0].matrix.Naxis[1])) {
+    gprint (GP_ERR, "region out of range\n");
+    return (FALSE);
+  }
+
+  max = min = *((float *)(buf[0].matrix.buffer) + sy*buf[0].matrix.Naxis[0] + sx);
+  for (j = sy; j < sy + ny; j++) {
+    V = (float *)(buf[0].matrix.buffer) + j*buf[0].matrix.Naxis[0] + sx; 
+    for (i = 0; i < nx; i++, V++) {
+      if (Ignore && (fabs (*V - IgnoreValue) < 1e-8)) continue;
+      N1 += *V;
+      N2 += (*V)*(*V);
+      Npix += 1.0;
+      max = MAX (max, *V);
+      min = MIN (min, *V);
+    }
+  }
+  N1 = N1 / Npix;
+
+/* calculate mode, median */
+  median = mode = 0.5*(max + min);
+  if ((max - min) != 0) {
+    range = 0xffff / (max - min);
+    ALLOCATE (hist, int, 0x10000);
+    bzero (hist, 0x10000*sizeof(int));
+    for (j = sy; j < sy + ny; j++) {
+      V = (float *)(buf[0].matrix.buffer) + j*buf[0].matrix.Naxis[0] + sx; 
+      for (i = 0; i < nx; i++, V++) {
+	if (Ignore && (fabs (*V - IgnoreValue) < 1e-8)) continue;
+	bin = MIN (MAX (0, (*V - min) * range), 0xffff);
+	hist[bin] ++;
+      }
+    }
+    Nhist = 0;
+    for (i = 0; (i < 0xffff) && (Nhist < 0.5*Npix); i++) 
+      Nhist += hist[i];
+    median = i / range + min;
+    Nmode = hist[0];
+    Imode = 0;
+    for (i = 1; i < 0x10000; i++) {
+      if (hist[i] > Nmode) {
+	Nmode = hist[i];
+	Imode = i;
+      }
+    }
+    mode = Imode / range + min;
+    free (hist);
+  }  
+  
+  if (!Quiet) {
+    gprint (GP_LOG, "  mean    stdev    min     max   median   Npix   Total\n");
+    gprint (GP_LOG, "%7.4g %7.4g %7.4g %7.4g %7.4g %7.0f %7.4g\n", N1, sqrt (N2/Npix - N1*N1), 
+	    min, max, median, Npix, Npix*N1);
+  }
+
+  set_variable ("MIN",    min);
+  set_variable ("MAX",    max);
+  set_variable ("MEDIAN", median);
+  set_variable ("MEAN",   N1);
+  set_variable ("MODE",   mode);
+  set_variable ("TOTAL",  N1*Npix);
+  set_variable ("NPIX",   Npix);
+  set_variable ("SIGMA",  sqrt (N2/Npix - N1*N1));
+
+  return (TRUE);
+}
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/style.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/style.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/style.c	(revision 11389)
@@ -0,0 +1,16 @@
+# include "data.h"
+
+int style (int argc, char **argv) {
+  
+  Graphdata graphmode;
+
+  if (!style_args (&graphmode, &argc, argv, -1)) return FALSE;
+
+  if (argc > 1) {
+    gprint (GP_ERR, "USAGE: style [-n Ngraph] [-x plot style] [-c color] [-pt point type] [-lt line type] [-lw line width] [-sz size]\n");
+    return (FALSE);
+  }
+  SetGraph (graphmode);
+
+  return (TRUE);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/subraster.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/subraster.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/subraster.c	(revision 11389)
@@ -0,0 +1,86 @@
+# include "data.h"
+
+int subraster (int argc, char **argv) {
+  
+  int i, j;
+  float *Vin, *Vout;
+  int sx, sy, nx, ny;
+  int Sx, Sy, Nx, Ny;
+  int NX, NY;
+  Buffer *ibuf, *obuf;
+
+  if (argc != 11) {
+    gprint (GP_ERR, "USAGE: extract <from> <to> sx sy nx ny Sx Sy Nx Ny\n");
+    return (FALSE);
+  }
+
+  if ((ibuf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  NX = ibuf[0].matrix.Naxis[0];
+  NY = ibuf[0].matrix.Naxis[1];
+
+  sx = atof (argv[3]);
+  sy = atof (argv[4]);
+  nx = atof (argv[5]);
+  ny = atof (argv[6]);
+
+  Sx = atof (argv[7]);
+  Sy = atof (argv[8]);
+  Nx = atof (argv[9]);
+  Ny = atof (argv[10]);
+
+  if ((Sy + ny > Ny) || (Sx + nx > Nx)) {
+    gprint (GP_ERR, "mismatch between source and dest regions\n");
+    gprint (GP_ERR, "%d + %d > %d or %d + %d > %d\n", Sy, ny, Ny, Sx, nx, Nx);
+    return (FALSE);
+  }
+
+  /* region is not on first image */
+  if ((sx + nx < 0) || (sy + ny < 0) || 
+      (sx > ibuf[0].matrix.Naxis[0]) || 
+      (sy > ibuf[0].matrix.Naxis[1])) {
+    gprint (GP_ERR, "region outside of source image\n");
+    return (FALSE);
+  }
+
+  if ((Sx + nx > Nx) || (Sy + ny > Ny)) {
+    gprint (GP_ERR, "source region larger than dest region\n");
+    return (FALSE);
+  }
+  if ((Sx < 0) || (Sy < 0)) {
+    gprint (GP_ERR, "dest region out of range\n");
+    return (FALSE);
+  }
+
+  if ((obuf = SelectBuffer (argv[2], ANYBUFFER, TRUE)) == NULL) return (FALSE);
+  gfits_free_matrix (&obuf[0].matrix);
+  gfits_free_header (&obuf[0].header);
+
+  obuf[0].bitpix = ibuf[0].bitpix;
+  obuf[0].unsign = ibuf[0].unsign;
+  obuf[0].bscale = ibuf[0].bscale;
+  obuf[0].bzero  = ibuf[0].bzero;
+  /* strcpy (obuf[0].name, ibuf[0].name); */
+  strcpy (obuf[0].file, ibuf[0].file);
+  gfits_copy_header (&ibuf[0].header, &obuf[0].header);
+  gfits_modify (&obuf[0].header, "NAXIS1", "%d", 1, Nx);
+  gfits_modify (&obuf[0].header, "NAXIS2", "%d", 1, Ny);
+  obuf[0].header.Naxis[0] = Nx;
+  obuf[0].header.Naxis[1] = Ny;
+  gfits_create_matrix (&obuf[0].header, &obuf[0].matrix);
+
+  for (j = 0; j < ny; j++) {
+    if (j + sy < 0) continue;
+    if (j + sy >= NY) continue;
+    Vin = (float *)(ibuf[0].matrix.buffer) + (j + sy)*ibuf[0].matrix.Naxis[0] + sx;  
+    Vout = (float *)(obuf[0].matrix.buffer) + (j + Sy)*obuf[0].matrix.Naxis[0] + Sx;   
+    for (i = 0; i < nx; i++, Vin++, Vout++) {
+      if (i + sx < 0) continue;
+      if (i + sx >= NX) continue;
+      *Vout = *Vin;
+    }
+  }
+
+  return (TRUE);
+
+}
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/subset.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/subset.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/subset.c	(revision 11389)
@@ -0,0 +1,51 @@
+# include "data.h"
+
+/* need to check dimensions of vectors */
+
+int subset (int argc, char **argv) {
+  
+  char *out;
+  int  i, j, size;
+  Vector *ivec, *ovec, *tvec;
+
+  out = NULL;
+  ivec = ovec = tvec = NULL;
+
+  if ((argc < 6) || strcmp(argv[2], "=") || strcmp (argv[4], "if")) {
+    gprint (GP_ERR, "SYNTAX: subset vec = vec if (logic expression)\n");
+    return (FALSE);
+  }
+
+  if ((ovec = SelectVector (argv[1], ANYVECTOR, TRUE)) == NULL) goto error;
+  if ((ivec = SelectVector (argv[3], OLDVECTOR, TRUE)) == NULL) goto error;
+
+  out = dvomath (argc - 5, &argv[5], &size, 1);
+  if (out == NULL) {
+    print_error ();
+    goto error;
+  }
+  if ((tvec = SelectVector (out, OLDVECTOR, TRUE)) == NULL) goto error;
+  /* check size of ivec, tvec: must match */
+
+  REALLOCATE (ovec[0].elements, float, MAX (tvec[0].Nelements, 1));
+  for (j = i = 0; i < tvec[0].Nelements; i++) {
+    if (tvec[0].elements[i]) {
+      ovec[0].elements[j] = ivec[0].elements[i];
+      j++;
+    }
+  }
+  ovec[0].Nelements = j;
+  REALLOCATE (ovec[0].elements, float, MAX (ovec[0].Nelements, 1));
+
+  DeleteVector (tvec);
+  free (out);
+  return (TRUE);
+
+ error:
+  DeleteVector (tvec);
+  DeleteVector (ovec);
+  DeleteNamedVector (out);
+  free (out);
+  return (FALSE);
+}
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/svd.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/svd.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/svd.c	(revision 11389)
@@ -0,0 +1,71 @@
+# include "data.h"
+
+int svd (int argc, char **argv) {
+  
+  int i, Nx, Ny, status;
+  float *in, *out, *A, *U, *W, *V;
+  Vector *Vw;
+  Buffer *Ma, *Mu, *Mv;
+
+  if (argc != 6) goto usage;
+  if (strcmp (argv[2], "=")) goto usage;
+
+  if ((Ma = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  if ((Mu = SelectBuffer (argv[3], ANYBUFFER, TRUE)) == NULL) return (FALSE);
+  if ((Vw = SelectVector (argv[4], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((Mv = SelectBuffer (argv[5], ANYBUFFER, TRUE)) == NULL) return (FALSE);
+
+  Nx = Ma[0].header.Naxis[0];
+  Ny = Ma[0].header.Naxis[1];
+
+  /* U is Nx, Ny */
+  gfits_free_matrix (&Mu[0].matrix);
+  gfits_free_header (&Mu[0].header);
+  Mu[0].bitpix = Ma[0].bitpix;
+  Mu[0].unsign = Ma[0].unsign;
+  Mu[0].bscale = Ma[0].bscale;
+  Mu[0].bzero  = Ma[0].bzero;
+  gfits_copy_header (&Ma[0].header, &Mu[0].header);
+  gfits_create_matrix (&Mu[0].header, &Mu[0].matrix);
+  
+  /* V is Nx, Nx */
+  gfits_free_matrix (&Mv[0].matrix);
+  gfits_free_header (&Mv[0].header);
+  Mv[0].bitpix = Ma[0].bitpix;
+  Mv[0].unsign = Ma[0].unsign;
+  Mv[0].bscale = Ma[0].bscale;
+  Mv[0].bzero  = Ma[0].bzero;
+  gfits_copy_header (&Ma[0].header, &Mv[0].header);
+  gfits_modify (&Mv[0].header, "NAXIS2", "%d", 1, Nx);
+  Mv[0].header.Naxis[1] = Nx;
+  gfits_create_matrix (&Mv[0].header, &Mv[0].matrix);
+
+  /* w is Nx */
+  Vw[0].Nelements = Nx;
+  REALLOCATE (Vw[0].elements, float, Nx);
+
+  /* pointers to the various arrays */
+  A = (float *) Ma[0].matrix.buffer;
+  U = (float *) Mu[0].matrix.buffer;
+  W = (float *) Vw[0].elements;
+  V = (float *) Mv[0].matrix.buffer;
+
+  /* copy A to U (svdcmp replaces A with U) */
+  in  = A;
+  out = U;
+  for (i = 0; i < Nx*Ny; i++, in++, out++) *out = *in;
+  /* use a bcopy instead? */
+
+  status = svdcmp (U, W, V, Nx, Ny);
+  if (!status) {
+    gprint (GP_ERR, "error running svdcmp\n");
+    return (FALSE);
+  }
+  return (TRUE);
+
+ usage:
+  gprint (GP_ERR, "USAGE: svd A = U w Vt\n");
+  return (FALSE);
+  
+}
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/swapbytes.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/swapbytes.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/swapbytes.c	(revision 11389)
@@ -0,0 +1,29 @@
+# include "data.h"
+
+int swapbytes (int argc, char **argv) {
+  
+  int i, nx, ny;
+  char *V, tmp;
+  Buffer *buf;
+
+  if (argc != 2) {
+    gprint (GP_ERR, "USAGE: swapbytes <buffer>\n");
+    return (FALSE);
+  }
+
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+
+  nx = buf[0].matrix.Naxis[0];
+  ny = buf[0].matrix.Naxis[1];
+
+  gprint (GP_ERR, "npix: %d\n", nx*ny);
+
+  V = buf[0].matrix.buffer;
+  for (i = 0; i < nx*ny; i++, V+=4) {
+    tmp = V[0]; V[0] = V[3]; V[3] = tmp;
+    tmp = V[1]; V[1] = V[2]; V[2] = tmp;
+  }
+
+  return (TRUE);
+}
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/test/fit.sh
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/test/fit.sh	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/test/fit.sh	(revision 11389)
@@ -0,0 +1,207 @@
+
+list tests
+ test1
+ test2
+ test3
+ test4
+ test5
+ test6
+ test7
+ test8
+end
+
+# fit a line without errors
+macro test1
+ $PASS = 1
+ break -auto off
+
+ create x 0 100
+ set y = 3 + 5*x
+ fit -q x y 1
+
+ if ($Cn != 1)
+   $PASS = 0
+ end
+ if (abs($C0 - 3) > 1e-5)
+   $PASS = 0
+ end
+ if (abs($C1 - 5) > 1e-5)
+   $PASS = 0
+ end
+end
+
+# fit a line with errors
+macro test2
+ $PASS = 1
+ break -auto off
+
+ create x 0 100
+ set dy = 0.1*rnd(x) - 0.05
+ set y = 3 + 5*x + dy
+ fit -q x y 1
+
+ if ($Cn != 1)
+   $PASS = 0
+ end
+ if (abs($C0 - 3) > 0.01)
+   $PASS = 0
+ end
+ if (abs($C1 - 5) > 0.01)
+   $PASS = 0
+ end
+end
+
+# fit a line with errors and weights
+macro test3
+ $PASS = 1
+ break -auto off
+
+ create x 0 100
+ set dy = 0.1*rnd(x) - 0.05
+ set y = 3 + 5*x + dy
+ set dy = 0.1 + zero(x)
+ fit -q x y 1 -dy dy
+
+ if ($Cn != 1)
+   $PASS = 0
+ end
+ if (abs($C0 - 3) > 0.02)
+   $PASS = 0
+ end
+ if (abs($C1 - 5) > 0.02)
+   $PASS = 0
+ end
+end
+
+# fit a line with errors, weights, and outliers 
+macro test4
+ $PASS = 1
+ break -auto off
+
+ create x 0 100
+ set dy = 0.1*rnd(x) - 0.05
+ set y = 3 + 5*x + dy
+ set dy = 0.1 + zero(x)
+ y[5] = 23
+ y[20] = -10
+ y[50] = 0.0
+ fit -q x y 1 -dy dy -clip 3 3
+
+ if ($Cn != 1)
+   $PASS = 0
+ end
+ if ($Cnv != 97)
+   $PASS = 0
+ end
+ if (abs($C0 - 3) > 0.02)
+   $PASS = 0
+ end
+ if (abs($C1 - 5) > 0.02)
+   $PASS = 0
+ end
+end
+
+# fit a quadratic without errors
+macro test5
+ $PASS = 1
+ break -auto off
+
+ create x 0 100
+ set y = 3 + 5*x - 4*x^2
+ fit -q x y 2
+
+ if ($Cn != 2)
+   $PASS = 0
+ end
+ if (abs($C0 - 3) > 1e-5)
+   $PASS = 0
+ end
+ if (abs($C1 - 5) > 1e-5)
+   $PASS = 0
+ end
+ if (abs($C2 + 4) > 1e-5)
+   $PASS = 0
+ end
+end
+
+# fit a quadratic with errors
+macro test6
+ $PASS = 1
+ break -auto off
+
+ create x 0 100
+ set dy = 0.1*rnd(x) - 0.05
+ set y = 3 + 5*x - 4*x^2 + dy
+ fit -q x y 2
+
+ if ($Cn != 2)
+   $PASS = 0
+ end
+ if (abs($C0 - 3) > 0.05)
+   $PASS = 0
+ end
+ if (abs($C1 - 5) > 0.05)
+   $PASS = 0
+ end
+ if (abs($C2 + 4) > 0.05)
+   $PASS = 0
+ end
+end
+
+# fit a quadratic with errors and weights
+macro test7
+ $PASS = 1
+ break -auto off
+
+ create x 0 100
+ set dy = 0.1*rnd(x) - 0.05
+ set y = 3 + 5*x - 4*x^2 + dy
+ set dy = 0.1 + zero(x)
+ fit -q x y 2 -dy dy
+
+ if ($Cn != 2)
+   $PASS = 0
+ end
+ if (abs($C0 - 3) > 0.05)
+   $PASS = 0
+ end
+ if (abs($C1 - 5) > 0.05)
+   $PASS = 0
+ end
+ if (abs($C2 + 4) > 0.05)
+   $PASS = 0
+ end
+end
+
+# fit a quadratic with errors, weights, and outliers 
+macro test8
+ $PASS = 1
+ break -auto off
+
+ create x 0 100
+ set dy = 0.1*rnd(x) - 0.05
+ set y = 3 + 5*x - 4*x^2 + dy
+ set dy = 0.1 + zero(x)
+ y[5] = 23
+ y[20] = -10
+ y[50] = 0.0
+
+ # it takes 4 iterations to successfully reject the outliers above...
+ fit -q x y 2 -dy dy -clip 3 4
+
+ if ($Cn != 2)
+   $PASS = 0
+ end
+ if ($Cnv != 97)
+   $PASS = 0
+ end
+ if (abs($C0 - 3) > 0.05)
+   $PASS = 0
+ end
+ if (abs($C1 - 5) > 0.05)
+   $PASS = 0
+ end
+ if (abs($C2 + 4) > 0.05)
+   $PASS = 0
+ end
+end
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/test/peak.sh
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/test/peak.sh	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/test/peak.sh	(revision 11389)
@@ -0,0 +1,119 @@
+
+list tests
+ test1
+ test2
+ test3
+ test4
+ test5
+end
+
+# test using full range
+macro test1
+ $PASS = 1
+ break -auto off
+
+ create x 0 100
+ set y = zero (x)
+ y[50] = 1
+
+ peak -q x y 0 100
+
+ if ($peakpos != 50)
+   $PASS = 0
+ end
+ if ($peaknum != 51)
+   $PASS = 0
+ end
+ if ($peakval != 1)
+   $PASS = 0
+ end
+end
+
+# test using auto range
+macro test2
+ $PASS = 1
+ break -auto off
+
+ create x 0 100
+ set y = zero (x)
+ y[50] = 1
+
+ peak -q x y 
+
+ if ($peakpos != 50)
+   $PASS = 0
+ end
+ if ($peaknum != 51)
+   $PASS = 0
+ end
+ if ($peakval != 1)
+   $PASS = 0
+ end
+end
+
+# test using constrained range
+macro test3
+ $PASS = 1
+ break -auto off
+
+ create x 0 100
+ set y = zero (x)
+ y[60] = 2
+ y[50] = 1
+ y[40] = 2
+
+ peak -q x y 45 55
+
+ if ($peakpos != 50)
+   $PASS = 0
+ end
+ if ($peaknum != 51)
+   $PASS = 0
+ end
+ if ($peakval != 1)
+   $PASS = 0
+ end
+end
+
+# test memory usage
+macro test4
+ $PASS = 1
+ break -auto off
+
+ create x 0 100
+ set y = zero (x)
+ y[60] = 2
+ y[50] = 1
+ y[40] = 2
+
+ echo "peak:"
+ exec ps aux | grep mana | grep -v grep
+ for i 0 100000
+   peak -q x y 45 55
+ end
+ exec ps aux | grep mana | grep -v grep
+
+ ## HOW do we test this?
+end
+
+# test memory usage
+macro test5
+ $PASS = 1
+ break -auto off
+
+ create x 0 100
+ set y = zero (x)
+ y[60] = 2
+ y[50] = 1
+ y[40] = 2
+
+ echo "peak:"
+ exec ps aux | grep mana | grep -v grep
+ for i 0 1000
+   peak x y 45 55
+ end
+ exec ps aux | grep mana | grep -v grep
+
+ ## HOW do we test this?
+end
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/test/periodogram.sh
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/test/periodogram.sh	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/test/periodogram.sh	(revision 11389)
@@ -0,0 +1,100 @@
+
+list tests
+ test1
+ test2
+ test3
+end
+
+# test using even samples
+macro test1
+ $PASS = 1
+ break -auto off
+
+ local P PI
+ $PI = 3.14159265359
+ $P  = 15.0
+
+ create t 0 100
+ set f = sin(2*$PI*t/$P)
+ periodogram t f 5 50 period power
+
+ peak -q period power
+
+ if (abs ($peakpos - $P) > 0.5)
+   $PASS = 0
+ end
+end
+
+# test using random samples
+macro test2
+ $PASS = 1
+ break -auto off
+
+ local P PI
+ $PI = 3.14159265359
+ $P  = 15.0
+
+ create x 0 100
+ set t = 100 * rnd(x) 
+ set f = sin(2*$PI*t/$P)
+ periodogram t f 5 50 period power
+
+ # lim -n 0 t f; clear; box; plot -x 2 -pt 2 t f
+ # lim -n 1 period power; clear; box; plot period power
+
+ peak -q period power
+
+ if (abs ($peakpos - $P) > 0.5)
+   $PASS = 0
+ end
+end
+
+# test using random samples, higher frequency
+macro test3
+ $PASS = 1
+ break -auto off
+
+ local P PI
+ $PI = 3.14159265359
+ $P  = 2.0
+
+ create x 0 100
+ set t = 100 * rnd(x) 
+ set f = sin(2*$PI*t/$P)
+
+ periodogram t f 1 10 period power
+
+ # lim -n 0 t f; clear; box; plot -x 2 -pt 2 t f
+ # lim -n 1 period power; clear; box; plot period power
+
+ peak -q period power
+
+ if (abs ($peakpos - $P) > 0.05)
+   $PASS = 0
+ end
+end
+
+# test using random samples, offset start
+macro test4
+ $PASS = 1
+ break -auto off
+
+ local P PI
+ $PI = 3.14159265359
+ $P  = 15.0
+
+ create x 500 800
+ set t = 300 * rnd(x) + 500
+ set f = sin(2*$PI*t/$P)
+
+ periodogram t f 2 30 period power
+
+  lim -n 0 t f; clear; box; plot -x 2 -pt 2 t f
+  lim -n 1 period power; clear; box; plot period power
+
+ peak -q period power
+
+ if (abs ($peakpos - $P) > 0.05)
+   $PASS = 0
+ end
+end
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/test/queues.sh
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/test/queues.sh	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/test/queues.sh	(revision 11389)
@@ -0,0 +1,348 @@
+
+list tests
+ test1
+ test2
+ test3
+ test4
+ test4.1
+ test5
+ test5.1
+ testmem1
+ testmem2
+ testmem3
+ testmem4.0
+ testmem4.1
+ testmem4.2
+ testmem4.3
+ testmem5.0
+ testmem5.1
+end
+
+# test queueinit
+macro test1
+
+ queueinit dummy
+ queuesize dummy -var N
+
+ if ($N != 0)
+   $PASS = 0
+ end
+end
+
+# test queueinit
+macro testmem1
+
+ list word -x "ps -p $PID -o rss"
+ $startmem = $word:1
+
+ output /dev/null
+ for i 0 10000
+   queueinit dummy
+ end
+ output stdout
+
+ list word -x "ps -p $PID -o rss"
+ $endmem = $word:1
+
+ if ({$endmem - $startmem} > 10)
+   $PASS = 0
+   echo "growth: {$endmem-$startmem}"
+   echo "kB/loop: {($endmem-$startmem)/10000}"
+ end
+end
+
+# test queuesize
+macro test2
+
+ queueinit dummy
+ queuepush dummy foobar
+ queuesize dummy -var N
+
+ if ($N != 1)
+   $PASS = 0
+ end
+end
+
+# test queuesize
+macro testmem2
+
+ queueinit dummy
+ queuepush dummy foobar
+
+ list word -x "ps -p $PID -o rss"
+ $startmem = $word:1
+
+ output /dev/null
+ for i 0 10000
+   queuesize dummy -var N
+ end
+ output stdout
+
+ list word -x "ps -p $PID -o rss"
+ $endmem = $word:1
+
+ if ({$endmem - $startmem} > 10)
+   $PASS = 0
+   echo "growth: {$endmem-$startmem}"
+   echo "kB/loop: {($endmem-$startmem)/10000}"
+ end
+end
+
+# test queuedelete
+macro test3
+
+ queueinit dummy
+ queuepush dummy foobar
+ queuepush dummy foobar
+ queuepush dummy foobar
+
+ queuedelete dummy
+ queuepush dummy foobar
+ queuesize dummy -var N
+
+ if ($N != 1)
+   $PASS = 0
+ end
+end
+
+# test queuedelete
+macro testmem3
+
+ list word -x "ps -p $PID -o rss"
+ $startmem = $word:1
+
+ output /dev/null
+ for i 0 10000
+   queueinit dummy
+   queuepush dummy foobar
+   queuedelete dummy
+ end
+ output stdout
+
+ list word -x "ps -p $PID -o rss"
+ $endmem = $word:1
+
+ if ({$endmem - $startmem} > 10)
+   $PASS = 0
+   echo "growth: {$endmem-$startmem}"
+   echo "kB/loop: {($endmem-$startmem)/10000}"
+ end
+end
+
+# test queuepush / queuepop
+macro test4
+
+ queueinit dummy
+ queuepush dummy foobar
+ queuepop  dummy -var N
+
+ if ("$N" != "foobar")
+   $PASS = 0
+ end
+end
+
+# test queuepush / queuepop
+macro test4.1
+
+ queueinit dummy
+ queuepush dummy foo1
+ queuepush dummy foo2
+ queuepush dummy foo3
+
+ queuepop  dummy -var N
+ if ("$N" != "foo1")
+   $PASS = 0
+ end
+ queuepop  dummy -var N
+ if ("$N" != "foo2")
+   $PASS = 0
+ end
+ queuepop  dummy -var N
+ if ("$N" != "foo3")
+   $PASS = 0
+ end
+ queuesize dummy -var N
+ if ($N != 0)
+   $PASS = 0
+ end
+end
+
+# test queuedelete
+macro testmem4.0
+
+ list word -x "ps -p $PID -o rss"
+ $startmem = $word:1
+
+ output /dev/null
+ for i 0 10000
+   queueinit dummy
+   queuepush dummy foobar
+   queuepop dummy -var N
+ end
+ output stdout
+
+ list word -x "ps -p $PID -o rss"
+ $endmem = $word:1
+
+ if ({$endmem - $startmem} > 10)
+   $PASS = 0
+   echo "growth: {$endmem-$startmem}"
+   echo "kB/loop: {($endmem-$startmem)/10000}"
+ end
+end
+
+# test queuedelete
+macro testmem4.1
+
+ list word -x "ps -p $PID -o rss"
+ $startmem = $word:1
+
+ output /dev/null
+ for i 0 10000
+   queueinit dummy
+   queuepush dummy foobar
+   queuepop dummy
+ end
+ output stdout
+
+ list word -x "ps -p $PID -o rss"
+ $endmem = $word:1
+
+ if ({$endmem - $startmem} > 10)
+   $PASS = 0
+   echo "growth: {$endmem-$startmem}"
+   echo "kB/loop: {($endmem-$startmem)/10000}"
+ end
+end
+
+# test queuedelete
+macro testmem4.2
+
+ list word -x "ps -p $PID -o rss"
+ $startmem = $word:1
+
+ output /dev/null
+ for i 0 10000
+   queueinit dummy
+   queuepush dummy foobar
+ end
+ output stdout
+
+ list word -x "ps -p $PID -o rss"
+ $endmem = $word:1
+
+ if ({$endmem - $startmem} > 10)
+   $PASS = 0
+   echo "growth: {$endmem-$startmem}"
+   echo "kB/loop: {($endmem-$startmem)/10000}"
+ end
+end
+
+# test queuedelete
+macro testmem4.3
+
+ list word -x "ps -p $PID -o rss"
+ $startmem = $word:1
+
+ queueinit dummy
+
+ output /dev/null
+ for i 0 10000
+   queuepush dummy foobar
+   queuepop dummy
+ end
+ output stdout
+
+ list word -x "ps -p $PID -o rss"
+ $endmem = $word:1
+
+ if ({$endmem - $startmem} > 10)
+   $PASS = 0
+   echo "growth: {$endmem-$startmem}"
+   echo "kB/loop: {($endmem-$startmem)/10000}"
+ end
+end
+
+# test queuepush / queuepop with keys
+macro test5
+
+ queueinit dummy
+ queuepush dummy "test 1 word"
+ queuepush dummy "test 2 word"
+ queuepush dummy "test 3 word"
+ queuepop  dummy -var N -key 1 2
+
+ if ("$N" != "test 2 word")
+   $PASS = 0
+ end
+end
+
+# test queuepush / queuepop
+macro test5.1
+
+ queueinit dummy
+ queuepush dummy "test 1 word"
+ queuepush dummy "test 2 word"
+ queuepush dummy "bird 2 word"
+ queuepop  dummy -var N -key 0:1 test:2
+
+ if ("$N" != "test 2 word")
+   $PASS = 0
+ end
+end
+
+# test queuedelete
+macro testmem5.0
+
+ queueinit dummy
+
+ list word -x "ps -p $PID -o rss"
+ $startmem = $word:1
+
+ output /dev/null
+ for i 0 10000
+   queuepush dummy "test 1 word"
+   queuepush dummy "test 2 word"
+   queuepush dummy "test 3 word"
+   queuepop dummy -var N -key 1 2
+   queuepop dummy -var N -key 1 1
+   queuepop dummy -var N -key 1 3
+ end
+ output stdout
+
+ list word -x "ps -p $PID -o rss"
+ $endmem = $word:1
+
+ if ({$endmem - $startmem} > 10)
+   $PASS = 0
+   echo "growth: {$endmem-$startmem}"
+   echo "kB/loop: {($endmem-$startmem)/10000}"
+   queuelist
+ end
+end
+
+# test queuedelete
+macro testmem5.1
+
+ queueinit dummy
+
+ list word -x "ps -p $PID -o rss"
+ $startmem = $word:1
+
+ output /dev/null
+ for i 0 10000
+   queuepush dummy "test 1 word"
+   queuepop dummy -var N -key 1 1
+ end
+ output stdout
+
+ list word -x "ps -p $PID -o rss"
+ $endmem = $word:1
+
+ if ({$endmem - $startmem} > 10)
+   $PASS = 0
+   echo "growth: {$endmem-$startmem}"
+   echo "kB/loop: {($endmem-$startmem)/10000}"
+ end
+end
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/test/stats.sh
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/test/stats.sh	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/test/stats.sh	(revision 11389)
@@ -0,0 +1,156 @@
+
+$skip = 0
+
+list tests
+ test1
+ test2
+ test3
+end
+
+# test using full range
+macro test1
+ $PASS = 1
+ break -auto off
+
+ gaussdev dev {100*100} 0.0 1.0
+ dimenup dev buf 100 100
+ stats -q buf 
+ $npix = 100*100
+
+ if ($STATUS == 0)
+   echo "failed command"
+   $PASS = 0
+ end
+ if ($NPIX != $npix) 
+   echo "failed npix"
+   $PASS = 0
+ end
+ if (abs($MEAN - 0.0) > (2.0/sqrt($npix))) 
+   echo "failed mean"
+   $PASS = 0
+ end
+ if (abs($MEDIAN - 0.0) > (2.0/sqrt($npix))) 
+   echo "failed median"
+   $PASS = 0
+ end
+ if (abs($SIGMA - 1.0) > (2.0/sqrt($npix))) 
+   echo "failed sigma"
+   $PASS = 0
+ end
+ if ($MIN < -4.0) 
+   echo "failed min"
+   $PASS = 0
+ end
+ if ($MAX > +4.0)
+   echo "failed max"
+   $PASS = 0
+ end
+# I don't this MODE is being correctly calculated.
+ if ($skip && (abs($MODE - 0.0) > (2.0/sqrt($npix))))
+   echo "MODE fails: known problem with mode"
+   $PASS = 0
+ end
+ if (abs($TOTAL - $MEAN*$npix) > (2.0/sqrt($npix))) 
+   echo "failed total"
+   $PASS = 0
+ end
+end
+
+# test using full range
+macro test2
+ $PASS = 1
+ break -auto off
+
+ gaussdev dev {100*100} 0.0 1.0
+ dimenup dev buf 100 100
+ stats -q buf  - - - -
+ $npix = 100*100
+
+ if ($STATUS == 0)
+   echo "failed command"
+   $PASS = 0
+ end
+ if ($NPIX != $npix) 
+   echo "failed npix"
+   $PASS = 0
+ end
+ if (abs($MEAN - 0.0) > (2.0/sqrt($npix))) 
+   echo "failed mean"
+   $PASS = 0
+ end
+ if (abs($MEDIAN - 0.0) > (2.0/sqrt($npix))) 
+   echo "failed median"
+   $PASS = 0
+ end
+ if (abs($SIGMA - 1.0) > (2.0/sqrt($npix))) 
+   echo "failed sigma"
+   $PASS = 0
+ end
+ if ($MIN < -4.0) 
+   echo "failed min"
+   $PASS = 0
+ end
+ if ($MAX > +4.0)
+   echo "failed max"
+   $PASS = 0
+ end
+# I don't this MODE is being correctly calculated.
+ if ($skip && (abs($MODE - 0.0) > (2.0/sqrt($npix))))
+   echo "MODE fails: known problem with mode"
+   $PASS = 0
+ end
+ if (abs($TOTAL - $MEAN*$npix) > (2.0/sqrt($npix))) 
+   echo $TOTAL {$MEAN*$npix} {abs($TOTAL - $MEAN*$npix) > (2.0/sqrt($npix))) 
+   echo "failed total"
+   $PASS = 0
+ end
+end
+
+# test using full range
+macro test3
+ $PASS = 1
+ break -auto off
+
+ gaussdev dev {100*100} 0.0 1.0
+ dimenup dev buf 100 100
+ stats -q buf 10 10 10 10
+ $npix = 10*10
+
+ if ($STATUS == 0)
+   echo "failed command"
+   $PASS = 0
+ end
+ if ($NPIX != $npix) 
+   echo "failed npix"
+   $PASS = 0
+ end
+ if (abs($MEAN - 0.0) > (2.0/sqrt($npix))) 
+   echo "failed mean"
+   $PASS = 0
+ end
+ if (abs($MEDIAN - 0.0) > (2.0/sqrt($npix))) 
+   echo "failed median"
+   $PASS = 0
+ end
+ if (abs($SIGMA - 1.0) > (2.0/sqrt($npix))) 
+   echo "failed sigma"
+   $PASS = 0
+ end
+ if ($MIN < -4.0) 
+   echo "failed min"
+   $PASS = 0
+ end
+ if ($MAX > +4.0)
+   echo "failed max"
+   $PASS = 0
+ end
+# I don't this MODE is being correctly calculated.
+ if ($skip && (abs($MODE - 0.0) > (2.0/sqrt($npix))))
+   echo "MODE fails: known problem with mode"
+   $PASS = 0
+ end
+ if (abs($TOTAL - $MEAN*$npix) > (2.0/sqrt($npix))) 
+   echo "failed total"
+   $PASS = 0
+ end
+end
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/test/vgauss.sh
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/test/vgauss.sh	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/test/vgauss.sh	(revision 11389)
@@ -0,0 +1,99 @@
+
+list tests
+ test1
+ test2
+ test3
+end
+
+macro test1
+ $PASS = 1
+ break -auto off
+
+ create x -10 10 0.1
+ set y = 5 * exp(-0.5*x^2/3^2)
+
+ $C0 = 0.5
+ $C1 = 2
+ $C2 = 10
+ $C3 = 1
+ set dy = sqrt(y)
+
+ vgauss -q x y dy yfit
+
+ if (abs($C0 - 0.0) > 0.01)
+   $PASS = 0
+ end
+ if (abs($C1 - 3.0) > 0.01)
+   $PASS = 0
+ end
+ if (abs($C2 - 5.0) > 0.01)
+   $PASS = 0
+ end
+ if (abs($C3 - 0.0) > 0.01)
+   $PASS = 0
+ end
+end
+
+# noise of 0.1
+macro test2
+ $PASS = 1
+ break -auto off
+
+ create x -10 10 0.1
+ set y = 1000 * exp(-0.5*x^2/3^2)
+ set dy = (rnd(y) - 0.5)/0.5
+ set y = y + dy
+
+ $C0 = 0.5
+ $C1 = 2
+ $C2 = 900
+ $C3 = 1
+
+ vgauss -q x y dy yfit
+
+ if (abs($C0 - 0.0) > 0.01)
+   $PASS = 0
+ end
+ if (abs($C1 - 3.0) > 0.01)
+   $PASS = 0
+ end
+ if (abs($C2 - 1000.0) > 0.1)
+   $PASS = 0
+ end
+ if (abs($C3 - 0.0) > 0.1)
+   $PASS = 0
+ end
+end
+
+# poisson-distributed noise
+macro test3
+ $PASS = 1
+ break -auto off
+
+ create x -10 10 0.1
+ set y = 1000 * exp(-0.5*x^2/3^2)
+
+ gaussdev dY y[] 0.0 1.0
+ set dy = dY * sqrt(y)
+ set y = y + dy
+
+ $C0 = 0.5
+ $C1 = 2
+ $C2 = 900
+ $C3 = 1
+
+ vgauss -q x y dy yfit
+
+ if (abs($C0 - 0.0) > 0.01)
+   $PASS = 0
+ end
+ if (abs($C1 - 3.0) > 0.01)
+   $PASS = 0
+ end
+ if (abs($C2 - 1000.0) > 1)
+   $PASS = 0
+ end
+ if (abs($C3 - 0.0) > 0.2)
+   $PASS = 0
+ end
+end
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/test/vmaxwell.sh
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/test/vmaxwell.sh	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/test/vmaxwell.sh	(revision 11389)
@@ -0,0 +1,103 @@
+
+list tests
+# test1
+ test2
+# test3
+end
+
+macro test1
+ $PASS = 1
+ break -auto off
+
+ create x -10 10 0.1
+ set y = 5 * exp(-0.5*x^2/3^2)
+
+ $C0 = 0.5
+ $C1 = 2
+ $C2 = 10
+ $C3 = 1
+ set dy = sqrt(y)
+
+ vgauss -q x y dy yfit
+
+ if (abs($C0 - 0.0) > 0.01)
+   $PASS = 0
+ end
+ if (abs($C1 - 3.0) > 0.01)
+   $PASS = 0
+ end
+ if (abs($C2 - 5.0) > 0.01)
+   $PASS = 0
+ end
+ if (abs($C3 - 0.0) > 0.01)
+   $PASS = 0
+ end
+end
+
+# noise of 0.1
+macro test2
+ $PASS = 1
+ break -auto off
+
+ create x 0 1000 1
+ set y = 1000 * (x-200)^2 * exp(-0.5*(x-300)^2/30^2)
+ set dy = (rnd(y) - 0.5)/0.5
+ set y = y + dy
+
+ lim x y; clear; box; plot -x 1 -c black x y
+
+ $C0 = 250
+ $C1 = 25
+ $C2 = 900
+ $C3 = 1
+ $C4 = 190
+
+ vmaxwell x y dy yfit
+ plot x yfit -c red
+
+ if (abs($C0 - 0.0) > 0.01)
+   $PASS = 0
+ end
+ if (abs($C1 - 3.0) > 0.01)
+   $PASS = 0
+ end
+ if (abs($C2 - 1000.0) > 0.1)
+   $PASS = 0
+ end
+ if (abs($C3 - 0.0) > 0.1)
+   $PASS = 0
+ end
+end
+
+# poisson-distributed noise
+macro test3
+ $PASS = 1
+ break -auto off
+
+ create x -10 10 0.1
+ set y = 1000 * exp(-0.5*x^2/3^2)
+
+ gaussdev dY y[] 0.0 1.0
+ set dy = dY * sqrt(y)
+ set y = y + dy
+
+ $C0 = 0.5
+ $C1 = 2
+ $C2 = 900
+ $C3 = 1
+
+ vgauss -q x y dy yfit
+
+ if (abs($C0 - 0.0) > 0.01)
+   $PASS = 0
+ end
+ if (abs($C1 - 3.0) > 0.01)
+   $PASS = 0
+ end
+ if (abs($C2 - 1000.0) > 1)
+   $PASS = 0
+ end
+ if (abs($C3 - 0.0) > 0.2)
+   $PASS = 0
+ end
+end
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/teststats.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/teststats.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/teststats.c	(revision 11389)
@@ -0,0 +1,117 @@
+# include "data.h"
+
+int teststats (int argc, char **argv) {
+  
+  int i, N;
+  double max, min, sum, var, dvar, mean, stdev;
+  float *X, IgnoreValue;
+  int Ignore, Quiet;
+
+  int *Nval, bin, Nmode, Nmed;
+  double dx, mode, median;
+  Vector *vec;
+
+  Ignore = FALSE;
+  if (N = get_argument (argc, argv, "-ignore")) {
+    Ignore = TRUE;
+    remove_argument (N, &argc, argv);
+    IgnoreValue = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  Quiet = FALSE;
+  if (N = get_argument (argc, argv, "-q")) {
+    Quiet = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+  if (N = get_argument (argc, argv, "-quiet")) {
+    Quiet = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 2) {
+    gprint (GP_ERR, "USAGE: teststats (vector)\n");
+    return (FALSE);
+  }
+
+  if ((vec = SelectVector (argv[1], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+
+  Mean = Stdev = 0; 
+  /* first pass: measure the sample statistics */
+  for (j = 0; j < 3; j++) {
+    /* calculate mean, npix */
+    X = vec[0].elements;
+    max = min = *X;
+    sum = N = 0;
+    for (i = 0; i < vec[0].Nelements; i++, X++) {
+      if (!finite (*X)) continue;
+      if (Ignore && (*X == IgnoreValue)) continue;
+      if ((j > 0) && (fabs (*X - Mean) > 3*stdev)) continue;
+      sum += *X;
+      N++;
+    }      
+    mean = sum / N;
+    /* calculate stdev */
+    X = vec[0].elements;
+    var = 0;
+    for (i = 0; i < vec[0].Nelements; i++, X++) {
+      if (!finite (*X)) continue;
+      if (Ignore && (*X == IgnoreValue)) continue;
+      if ((j > 0) && (fabs (*X - mean) > 3*stdev)) continue;
+      dvar = (*X - mean);
+      var += dvar*dvar;
+    }      
+    stdev = sqrt (var / N);
+    Mean = mean;
+  }
+  mean = Mean;
+  set_variable ("MEAN_C",     mean);
+  set_variable ("SIGMA_C",    stdev);
+
+  /* construct histogram with resolution of 0.1*stdev and range -1000*dx : 1000*dx centered on mean */
+  dx = 0.1*stdev;
+  min = mean - 1000*dx;
+  max = mean + 1000*dx;
+  NVAL = 1 + (int)((max - min) / dx);
+  ALLOCATE (Nval, int, NVAL);
+  bzero (Nval, NVAL*sizeof(int));
+  X = vec[0].elements;
+  for (i = 0; i < vec[0].Nelements; i++, X++) {
+    if (!finite (*X)) continue;
+    if (Ignore && (*X == IgnoreValue)) continue;
+    bin = MAX (0, MIN (NVAL, (*X - min) / dx));
+    Nval[bin] ++;
+  }      
+
+  /* find mode */
+  Nmode = 0;
+  mode = Nval[Nmode];
+  for (i = 0; i < NVAL; i++) {
+    if (mode < Nval[i]) {
+      Nmode = i;
+      mode = Nval[Nmode];
+    }
+  }
+  mode = Nmode * dx + min;
+
+  
+
+  if (!Quiet) {
+    gprint (GP_ERR, "mean: %f, stdev: %f, min: %f, max: %f, median: %f, mode: %f, Npts: %d\n", 
+	     mean, stdev, min, max, median, mode, N);
+  }
+
+  set_variable ("MIN",      min);
+  set_variable ("MAX",      max);
+  set_variable ("MEDIAN",   median);
+  set_variable ("MODE",     mode);
+  set_variable ("TOTAL",    sum);
+  set_variable ("MEAN",     mean);
+  set_variable ("SIGMA",    stdev);
+
+  set_int_variable ("NPIX", N);
+
+  free (Nval);
+  return (TRUE);
+}
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/textline.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/textline.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/textline.c	(revision 11389)
@@ -0,0 +1,62 @@
+# include "data.h"
+
+int textline (int argc, char **argv) {
+
+  int N, size, FracPositions;
+  char name[64];
+  double x, y, angle;
+  int Ngraph, Xgraph;
+  Graphdata graphmode;
+
+  Ngraph = -1;
+  if ((N = get_argument (argc, argv, "-n"))) {
+    remove_argument (N, &argc, argv);
+    Ngraph = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if (!GetGraph (&graphmode, &Xgraph, &Ngraph)) return (FALSE);
+
+  if ((N = get_argument (argc, argv, "-fn"))) {
+    remove_argument (N, &argc, argv);
+    strcpy (name, argv[N]);
+    remove_argument (N, &argc, argv);
+    size = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+    KapaSetFont (Xgraph, name, size);
+  } 
+
+  /* FracPositions uses coordinates of 0-1 relative to axis range */
+  FracPositions = FALSE;
+  if ((N = get_argument (argc, argv, "-frac"))) {
+    remove_argument (N, &argc, argv);
+    FracPositions = TRUE;
+  } 
+
+  angle = 0.0;
+  if ((N = get_argument (argc, argv, "-rot"))) {
+    remove_argument (N, &argc, argv);
+    angle = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  } 
+
+  if (argc != 4) {
+    gprint (GP_ERR, "USAGE: text x y (line) [-fn (font) size] [-rot angle]\n");
+    return (FALSE);
+  }
+
+  if (strlen (argv[3]) > 127) {
+    gprint (GP_ERR, "labels currently limited to 127 chars\n");
+    return (FALSE);
+  }
+
+  x = atof (argv[1]);
+  y = atof (argv[2]);
+  
+  if (FracPositions) {
+    x =  x * (graphmode.xmax - graphmode.xmin) + graphmode.xmin;
+    y =  y * (graphmode.ymax - graphmode.ymin) + graphmode.ymin;
+  }    
+
+  KapaSendTextline (Xgraph, argv[3], x, y, angle);
+  return (TRUE);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/tv.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/tv.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/tv.c	(revision 11389)
@@ -0,0 +1,137 @@
+# include "data.h"
+
+int tv (int argc, char **argv) {
+  
+  int N, Ximage, Nimage;
+  Coords coords;
+  Buffer *buf;
+  KiiImage image;
+  KiiDisplayMode mode;
+
+  Nimage = -1;
+  if ((N = get_argument (argc, argv, "-n"))) {
+    remove_argument (N, &argc, argv);
+    Nimage = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if (!GetImage (&Ximage, &Nimage)) return (FALSE);
+
+  /* shell exits on pipe close, FIX */
+  if ((N = get_argument (argc, argv, "-kill"))) {
+    KiiClose (Ximage);
+    Ximage = 0;
+    return (TRUE);
+  }
+
+  mode.logflux = FALSE;
+  if ((N = get_argument (argc, argv, "-log"))) {
+    remove_argument (N, &argc, argv);
+    mode.logflux = TRUE;
+  }
+
+  if ((argc != 2) && (argc != 4)) {
+    gprint (GP_ERR, "USAGE: tv <buffer> [zero range] [-n Nimage] [-log] [-kill]\n");
+    return (FALSE);
+  }
+
+  GetImageScale (&mode.zero, &mode.range);
+  if (argc == 4) {
+    mode.zero = atof (argv[2]);
+    mode.range = atof (argv[3]);
+    if (mode.range == 0.0) mode.range = 0.001;
+    SetImageScale (mode.zero, mode.range);
+  }
+
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  GetCoords (&coords, &buf[0].header);
+  
+  image.data1d = (float *) buf[0].matrix.buffer;
+  image.Nx = buf[0].matrix.Naxis[0];
+  image.Ny = buf[0].matrix.Naxis[1];
+  image.file = buf[0].file;
+  image.name = buf[0].name;
+
+  KiiNewPicture1D (Ximage, &image, &mode, &coords);
+
+  SetImageName (argv[1]);
+  set_str_variable ("TV", argv[1]);
+  return (TRUE);
+}
+
+
+/* 
+projections and coordinates:
+
+IRAS:
+CTYPE1  = 'LL      '                    /TANGENT PLANE (L)                     
+CRVAL1  =         0.100000D+02          /R.A. OF MAP CENTER  *** SEE COMMENT   
+CDELT1  =        -0.133333D-01          /SEPARATION IN L (DEG)                 
+CRPIX1  =                  128          /MAPCENTER IN L                        
+CROTA1  =         0.000000E+00          /NO ROTATION            
+                                                                               
+CTYPE2  = 'MM      '                    /TANGENT PLANE (M)                     
+CRVAL2  =         0.410000D+02          /DEC. OF MAP CENTER  *** SEE COMMENT   
+CDELT2  =         0.133333D-01          /SEPARATION IN M (DEG)                 
+CRPIX2  =                  128          /MAP CENTER IN M                       
+CROTA2  =         0.000000E+00          /NO ROTATION                           
+
+HIRAS:
+CTYPE1  = 'RA---TAN          ' / PRIMARY AXIS NAME                             
+CRVAL1  =   1.000000000000E+01 / PRIMARY REFERENCE VALUE                       
+CDELT1  =  -5.555555555556E-03 / PRIMARY PIXEL SEPARATION                      
+CRPIX1  =   2.560000000000E+02 / PRIMARY REFERENCE PIXEL                       
+CUNIT1  = 'DEGREE            ' / PRIMARY AXIS UNITS                            
+
+CDELT2  =   5.555555555556E-03 / PRIMARY PIXEL SEPARATION                      
+CRPIX2  =   2.560000000000E+02 / PRIMARY REFERENCE PIXEL                       
+CRVAL2  =   4.100000000000E+01 / PRIMARY REFERENCE VALUE                       
+CTYPE2  = 'DEC--TAN          ' / PRIMARY AXIS NAME                             
+CUNIT2  = 'DEGREE            ' / PRIMARY AXIS UNITS                            
+
+PROJTYPE= 'GNOMON    '                                                         
+COORDSYS= 'EQUATORIAL     '                                                    
+
+gene (small FOV linear):
+RA_O
+RA_X 
+RA_Y 
+DEC_O
+DEC_X
+DEC_Y
+
+
+*/
+
+# ifdef NEWTVMODE  
+  {
+    double *pixvalues, slope;
+
+    ALLOCATE (pixvalues, double, Ncolors + 1);
+    range = fabs (range);
+    for (i = 0; i < Ncolors + 1; i++) {
+      if (ISLOG) {
+	pixvalues[i] = i*range / NNcol + zero;
+      }
+      if (!ISLOG) {
+	pixvalues[i] = pow (10.0, i*log10(range - 1.0) / NNcol) + zero - 1.0;
+      }      
+    } 
+    for (j = 0; j < Npix; j++, in++, out++) {
+      if (*in < pixvalues[0]) {
+	i = 0;
+      } else {
+	if (*in > pixvalues[NNcol]) {
+	  i = NNcol;
+	} else {
+	  for (i = 0; (*in < pixvalues[i]) || (*in > pixvalues[i+1]); ) {
+	    slope = 1.0 / (pixvalues[i+1] - pixvalues[i]);
+	    i = MIN (MAX (0, i + (*in - pixvalues[i]) * slope), NNcol);
+	  }
+	}	
+      }
+      /* for (i = 0; (i < Ncolors - 1) && (pixvalues[i] < *in); i++); */
+      *out = i;
+    }
+    free (pixvalues);
+  }
+# endif
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/tvcontour.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/tvcontour.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/tvcontour.c	(revision 11389)
@@ -0,0 +1,285 @@
+# include "data.h"
+# define LL { \
+ dx =  d00 / (*v01 - *v00); \
+ dy = -d00 / (*v10 - *v00); \
+ x = i - 0.5; \
+ y = j - dy - 0.5; }
+
+# define UL { \
+ tmp = d00 / (*v10 - *v00); \
+ dy = 1 - tmp; \
+ dx =  d10 / (*v11 - *v10); \
+ x = i - 0.5; \
+ y = j + tmp - 0.5; }
+      
+# define LR { \
+ tmp = d00 / (*v01 - *v00); \
+ dx = 1 - tmp; \
+ dy = d01 / (*v11 - *v01); \
+ x = i + tmp - 0.5; \
+ y = j - 0.5; }
+
+# define UR { \
+ tmp = d10 / (*v11 - *v10); \
+ dx = 1 - tmp; \
+ dy = -d11 / (*v01 - *v11); \
+ x = i + tmp - 0.5; \
+ y = j + 1 - 0.5; }
+      
+# define HZ { \
+ tmp = d00 / (*v10 - *v00); \
+ dy = d01 / (*v11 - *v01) - tmp; \
+ dx = 1; \
+ x = i - 0.5; \
+ y = j + tmp - 0.5; }
+
+# define VT { \
+ tmp = d00 / (*v01 - *v00); \
+ dx = d10 / (*v11 - *v10) - tmp; \
+ x = i + tmp - 0.5; \
+ dy = 1; \
+ y = j - 0.5; }
+
+# define DUMP { \
+overlay[Noverlay].type = KII_OVERLAY_LINE; \
+overlay[Noverlay].x = Npix*x; \
+overlay[Noverlay].y = Npix*y; \
+overlay[Noverlay].dx = Npix*dx; \
+overlay[Noverlay].dy = Npix*dy; \
+Noverlay ++; \
+CHECK_REALLOCATE (overlay, KiiOverlay, NOVERLAY, Noverlay, 1000); \
+}
+
+int tvcontour (int argc, char **argv) {
+
+  int i, j, ii, jj, Npix, Nx, Ny;
+  float level, d00, d01, d10, d11, tmp;
+  float x, y, dx, dy;
+  float *v00, *v01, *v10, *v11;
+  float *Vout, *Vin, *matrix;
+  int Ximage, Nimage, N, Noverlay, NOVERLAY;
+  Buffer *buf;
+  KiiOverlay *overlay;
+  
+  Nimage = -1;
+  if ((N = get_argument (argc, argv, "-n"))) {
+    remove_argument (N, &argc, argv);
+    Nimage = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if (!GetImage (&Ximage, &Nimage)) return (FALSE);
+
+  if ((argc != 4) && (argc != 5)) {
+    gprint (GP_ERR, "USAGE: contour <buffer> (overlay) level [Npix]\n");
+    return (FALSE);
+  }
+
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+
+  level = atof (argv[3]);
+  if (argc == 5) 
+    Npix = (int) MAX (atof (argv[4]), 1); 
+  else 
+    Npix = 1;
+  level *= Npix*Npix;
+
+  /*** make rebinned image ***/
+  Nx = buf[0].header.Naxis[0]/Npix;
+  Ny = buf[0].header.Naxis[1]/Npix;
+  if (Npix != 1) {
+    gprint (GP_LOG, "rebin by a factor of %d (%d,%d)\n", Npix, Nx, Ny);
+    ALLOCATE (matrix, float, Nx*Ny);
+    bzero (matrix, Nx*Ny*sizeof(float));
+	
+    for (j = 0; j < Ny; j++) {
+      for (jj = 0; jj < Npix; jj++) {
+	Vout = matrix + j*Nx;
+	Vin  = (float *)(buf[0].matrix.buffer) + (j*Npix + jj)*buf[0].header.Naxis[0];
+	for (i = 0; i < Nx; i++, Vout++) {
+	  for (ii = 0; ii < Npix; ii++, Vin++) {
+	    *Vout += *Vin;
+	  }
+	}
+      }
+    }
+  } else {
+    gprint (GP_ERR, "using scale of 1\n");
+    matrix = (float *)(buf[0].matrix.buffer);
+  }
+
+  Noverlay = 0;
+  NOVERLAY = 1000;
+  ALLOCATE (overlay, KiiOverlay, NOVERLAY);
+
+  v00 = matrix;
+  v01 = matrix + 1;
+  v10 = matrix + Nx;
+  v11 = matrix + Nx + 1;
+  d01 = (level - *v00);
+  d11 = (level - *v10);
+  for (j = 1; j < Ny; j++) {
+    if (!(j%10)) gprint (GP_ERR, ".");
+    for (i = 1; i < Nx; i++, v00++, v01++, v10++, v11++) {
+
+      d00 = d01;
+      d10 = d11;
+      d01 = (level - *v01);
+      d11 = (level - *v11);
+
+      if (((d00 > 0) && (d01 > 0) && (d10 > 0) && (d11 > 0)) ||
+	  ((d00 < 0) && (d01 < 0) && (d10 < 0) && (d11 < 0)))
+	continue;
+
+      if ((d00 > 0) && (d10 <= 0)) { 
+	if ((d01 <= 0) && (d11 <= 0)) { /* \  */
+	  LL;
+	  DUMP;
+	  continue;
+	}
+	if ((d01 > 0) && (d11 <= 0)) { /* -  */
+	  HZ;
+	  DUMP;
+	  continue;
+	}
+	if ((d01 > 0) && (d11 > 0)) { /* /  */
+	  UL;
+	  DUMP;
+	  continue;
+	}
+	if ((d01 <= 0) && (d11 > 0)) { /* \\  */
+	  LL;
+	  DUMP;
+	  UR;
+	  DUMP;
+	  continue;
+	}
+      }
+
+      if ((d00 <= 0) && (d10 > 0)) {
+	if ((d01 > 0) && (d11 > 0)) { /* \  */
+	  LL;
+	  DUMP;
+	  continue;
+	}
+	if ((d01 <= 0) && (d11 > 0)) { /* -  */
+	  HZ;
+	  DUMP;
+	  continue;
+	}
+	if ((d01 <= 0) && (d11 <= 0)) { /* /  */
+	  UL;
+	  DUMP;
+	  continue;
+	}
+	if ((d01 > 0) && (d11 <= 0)) { /* //  */
+	  UL;
+	  DUMP;
+	  LR;
+	  DUMP;
+	  continue;
+	}
+      }
+      
+
+      if ((d00 <= 0) && (d10 <= 0)) { 
+	if ((d01 > 0) && (d11 <= 0)) {
+	  LR;
+	  DUMP;
+	  continue;
+	}
+	if ((d01 <= 0) && (d11 > 0)) {
+	  UR;
+	  DUMP;
+	  continue;
+	}
+	if ((d01 > 0) && (d11 > 0)) {
+	  VT;
+	  DUMP;
+	  continue;
+	}
+      }
+
+      if ((d00 > 0) && (d10 > 0)) { 
+	if ((d01 <= 0) && (d11 > 0)) {
+	  LR;
+	  DUMP;
+	  continue;
+	}
+	if ((d01 > 0) && (d11 <= 0)) {
+	  UR;
+	  DUMP;
+	  continue;
+	}
+	if ((d01 <= 0) && (d11 <= 0)) {
+	  VT;
+	  DUMP;
+	  continue;
+	}
+      }
+
+    }
+    /* skip left-hand edge */
+    v00++; v01++; v10++; v11++;
+    d01 = (level - *v00);
+    d11 = (level - *v10);
+  }
+
+  /****** bottom line *******/
+  v00 = matrix;  
+  v01 = matrix + 1;  
+  y = 0;
+  dx = 0;
+  dy = -0.5;
+  for (i = 1; i < Nx; i++, v00++, v01++) { /* do the edges */
+    if (((*v00 > level) && (*v01 <= level)) || ((*v00 <= level) && (*v01 > level))) {
+      x = i + (level - *v01)/(*v01 - *v00);
+      DUMP;
+    }
+  }
+
+  /********** top line *******/
+  v00 = matrix + Nx*(Ny - 1);  
+  v01 = v00 + 1;
+  y = Ny - 1;
+  dx = 0;
+  dy = 0.5;
+  for (i = 1; i < Nx; i++, v00++, v01++) { /* do the edges */
+    if (((*v00 > level) && (*v01 <= level)) || ((*v00 <= level) && (*v01 > level))) {
+      x = i + (level - *v01)/(*v01 - *v00);
+      DUMP;
+    }
+  }
+
+  /******** left line *********/
+  v00 = matrix; 
+  v01 = matrix + Nx;
+  x = 0;
+  dx = -0.5;
+  dy = 0;
+  for (j = 1; j < Ny; j++, v00+=Nx, v01+=Nx) { /* do the edges */
+    if (((*v00 > level) && (*v01 <= level)) || ((*v00 <= level) && (*v01 > level))) {
+      y = j + (level - *v01)/(*v01 - *v00);
+      DUMP;
+    }
+  }
+
+  /******** right line *********/
+  v00 = matrix + Nx - 1; 
+  v01 = v00 + Nx;
+  x = Nx - 1;
+  dx = 0.5;
+  dy = 0;
+  for (j = 1; j < Ny; j++, v00+=Nx, v01+=Nx) { /* do the edges */
+    if (((*v00 > level) && (*v01 <= level)) || ((*v00 <= level) && (*v01 > level))) {
+      y = j + (level - *v01)/(*v01 - *v00);
+      DUMP;
+    }
+  }
+  
+  KiiLoadOverlay (Ximage, overlay, Noverlay, argv[2]);
+  free (overlay);
+
+  if (Npix != 1) free (matrix);
+  gprint (GP_ERR, "\n");
+  return (TRUE);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/tvgrid.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/tvgrid.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/tvgrid.c	(revision 11389)
@@ -0,0 +1,170 @@
+# include "data.h"
+# define TEN(X) (pow(10.0, (double)(X)))
+
+int tvgrid (int argc, char **argv) {
+  
+  int ndig1, ndig2, NX, NY, connect;
+  int tDEC, tRA;
+  double ra, dec, ra0, dec0, ra1, dec1;
+  double x0, y0, x1, y1;
+  double dDEC, fDEC, dRA, fRA;
+  char format[16];
+  Coords coords;
+  int Ximage, Nimage, N, Noverlay, NOVERLAY;
+  Buffer *buf;
+  KiiOverlay *overlay;
+
+  Nimage = -1;
+  if ((N = get_argument (argc, argv, "-n"))) {
+    remove_argument (N, &argc, argv);
+    Nimage = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if (!GetImage (&Ximage, &Nimage)) return (FALSE);
+  
+  if (argc != 3) {
+    gprint (GP_ERR, "USAGE: tvgrid (overlay) (buffer)\n");
+    gprint (GP_ERR, " (overlay) may be: red, green, blue, yellow\n");
+    return (FALSE);
+  }
+
+  if ((buf = SelectBuffer (argv[2], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  GetCoords (&coords, &buf[0].header);
+
+  XY_to_RD (&ra0, &dec0, 0.0, 0.0, &coords);
+  XY_to_RD (&ra1, &dec1, (double)buf[0].header.Naxis[0], (double)buf[0].header.Naxis[1], &coords);
+  gprint (GP_ERR, "%f %f  %f %f\n", ra0, dec0, ra1, dec1);
+  
+  Noverlay = 0;
+  NOVERLAY = 1000;
+  ALLOCATE (overlay, KiiOverlay, NOVERLAY);
+
+  dDEC = fabs(dec1 - dec0);
+  tDEC = log10(dDEC) - log10(5.0);
+  fDEC = log10(dDEC) - tDEC;
+  if ((fDEC > log10(0.5)) && (fDEC < log10(1.0))) {
+    dDEC = TEN (tDEC + log10(0.1));
+  }
+  if ((fDEC > log10(1.0)) && (fDEC < log10(2.0))) {
+    dDEC = TEN (tDEC + log10(0.2));
+  }
+  if ((fDEC > log10(2.0)) && (fDEC < log10(5.0))) {
+    dDEC = TEN (tDEC + log10(0.5));
+  }
+  if ((fDEC > log10(5.0)) && (fDEC < log10(10.0))) {
+    dDEC = TEN (tDEC + log10(1.0));
+  }
+  if ((fDEC > log10(10.0)) && (fDEC < log10(20.0))) {
+    dDEC = TEN (tDEC + log10(2.0));
+  }
+  if ((fDEC > log10(20.0)) && (fDEC < log10(50.0))) {
+    dDEC = TEN (tDEC + log10(5.0));
+  }
+  ndig2 = ((log10(dDEC) < 0) ? fabs(log10(dDEC)) : 0);
+  ndig1 = 3 + log10(MAX(dec0, dec1)) + ndig2;
+  sprintf (format, "%%%d.%df", ndig1, ndig2);
+  gprint (GP_ERR, "format: %s..\n", format);
+
+  NX = buf[0].header.Naxis[0];
+  NY = buf[0].header.Naxis[1];
+
+  x0 = y0 = 0;
+  dRA = MAX (fabs(ra1 - ra0) / 100.0, 0.1);
+  connect = FALSE;
+  for (dec = dDEC * ((int)(MIN(dec0,dec1)/dDEC) + 1); dec < MAX(dec0,dec1); dec += dDEC) {
+    for (ra = 0; ra < 361; ra += dRA) {
+      RD_to_XY (&x1, &y1, ra, dec, &coords);
+      if ((x1 >= 0) && (x1 < NX) && (y1 >= 0) && (y1 < NY)) {
+	if (connect) {
+	  overlay[Noverlay].type = KII_OVERLAY_LINE;
+	  overlay[Noverlay].x = x0;
+	  overlay[Noverlay].y = y0;
+	  overlay[Noverlay].dx = x1 - x0;
+	  overlay[Noverlay].dy = y1 - y0;
+	  Noverlay ++;
+	  CHECK_REALLOCATE (overlay, KiiOverlay, NOVERLAY, Noverlay, 1000);
+	}
+	x0 = x1;
+	y0 = y1;
+	connect = TRUE;
+      } else {
+	connect = FALSE;
+      }
+    }
+  }
+
+  dRA = fabs(ra1 - ra0);
+  tRA = log10(dRA) - log10(5.0);
+  fRA = log10(dRA) - tRA;
+  if ((fRA > log10(0.5)) && (fRA < log10(1.0))) {
+    dRA = TEN (tRA + log10(0.1));
+  }
+  if ((fRA > log10(1.0)) && (fRA < log10(2.0))) {
+    dRA = TEN (tRA + log10(0.2));
+  }
+  if ((fRA > log10(2.0)) && (fRA < log10(5.0))) {
+    dRA = TEN (tRA + log10(0.5));
+  }
+  if ((fRA > log10(5.0)) && (fRA < log10(10.0))) {
+    dRA = TEN (tRA + log10(1.0));
+  }
+  if ((fRA > log10(10.0)) && (fRA < log10(20.0))) {
+    dRA = TEN (tRA + log10(2.0));
+  }
+  if ((fRA > log10(20.0)) && (fRA < log10(50.0))) {
+    dRA = TEN (tRA + log10(5.0));
+  }
+  ndig2 = ((log10(dRA) < 0) ? fabs(log10(dRA)) : 0);
+  ndig1 = 3 + log10(MAX(ra0, ra1)) + ndig2;
+  sprintf (format, "%%%d.%df", ndig1, ndig2);
+  gprint (GP_ERR, "format: %s..\n", format);
+
+  dDEC = MAX (fabs(dec1 - dec0) / 100.0, 0.1);
+  connect = FALSE;
+  for (ra = dRA * ((int)(MIN(ra0,ra1)/dRA) + 1); ra < MAX(ra0,ra1); ra += dRA) {
+    for (dec = -90; dec < 90; dec += dDEC) {
+      RD_to_XY (&x1, &y1, ra, dec, &coords);
+      if ((x1 >= 0) && (x1 < NX) && (y1 >= 0) && (y1 < NY)) {
+	if (connect) {
+	  overlay[Noverlay].type = KII_OVERLAY_LINE;
+	  overlay[Noverlay].x = x0;
+	  overlay[Noverlay].y = y0;
+	  overlay[Noverlay].dx = x1 - x0;
+	  overlay[Noverlay].dy = y1 - y0;
+	  Noverlay ++;
+	  CHECK_REALLOCATE (overlay, KiiOverlay, NOVERLAY, Noverlay, 1000);
+	}
+	x0 = x1;
+	y0 = y1;
+	connect = TRUE;
+      } else {
+	connect = FALSE;
+      }
+    }
+  }
+
+  # if (0)
+  /* write the labels on the axes */
+  dDEC = fabs(dec1 - dec0) / 100;
+  for (ra = dRA * ((int)(MIN(ra0, ra1)/dRA) + 1); ra < MAX(ra0, ra1); ra += dRA) {
+    RD_to_XY (&x0, &y0, ra + 0.1*dRA, MIN(dec0, dec1), &coords);
+    sprintf (label, format, ra);
+    sprintf (buffer, "%15s %20.10f %20.10f %20.10f %20.10f ", "TEXT", x0, y0, (double)(strlen(label) + 1), 0.0);
+    write (Ximage, buffer, 128);
+    write (Ximage, label, strlen(label) + 1);
+    RD_to_XY (&x0, &y0, ra, MIN(dec0, dec1), &coords);
+    for (dec = MIN(dec0, dec1) + dDEC; dec < MAX(dec0,dec1); dec += dDEC) {
+      RD_to_XY (&x1, &y1, ra, dec, &coords);
+      sprintf (buffer, "%15s %20.10f %20.10f %20.10f %20.10f ", "LINE", x0, y0, (x1 - x0), (y1 - y0));
+      write (Ximage, buffer, 128);
+      x0 = x1;
+      y0 = y1;
+    }
+  }
+  # endif
+
+  KiiLoadOverlay (Ximage, overlay, Noverlay, argv[1]);
+  free (overlay);
+
+  return (TRUE);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/ungridify.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/ungridify.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/ungridify.c	(revision 11389)
@@ -0,0 +1,56 @@
+# include "data.h"
+
+int ungridify (int argc, char **argv) {
+
+  int i, j, n;
+  int Nx, Ny, NX, NY;
+  int Xmin, Xmax, Ymin, Ymax;
+  float *v, *x, *y, *z;
+  Buffer *bf;
+  Vector *vx, *vy, *vz;
+
+  if (argc != 9) {
+    gprint (GP_ERR, "USAGE: ungridify buffer Xmin Xmax Ymin Ymax x y z\n");
+    return (FALSE);
+  }
+  
+  if ((bf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  Xmin = atof (argv[2]);
+  Xmax = atof (argv[3]);
+  Ymin = atof (argv[4]);
+  Ymax = atof (argv[5]);
+  Nx = Xmax - Xmin;
+  Ny = Ymax - Ymin;
+  
+  NX = bf[0].matrix.Naxis[0];
+  NY = bf[0].matrix.Naxis[1];
+
+  if ((vx = SelectVector (argv[6], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((vy = SelectVector (argv[7], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((vz = SelectVector (argv[8], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+  REALLOCATE (vx[0].elements, float, Nx*Ny);
+  REALLOCATE (vy[0].elements, float, Nx*Ny);
+  REALLOCATE (vz[0].elements, float, Nx*Ny);
+
+  x = vx[0].elements;
+  y = vy[0].elements;
+  z = vz[0].elements;
+  n = 0;
+  v = (float *)bf[0].matrix.buffer;
+  for (j = Ymin; j < Ymax; j++) {
+    for (i = Xmin; i < Xmax; i++, x++, y++, z++, n++) {
+      vx[0].elements[n] = i;
+      vy[0].elements[n] = j;
+      if (i < 0) continue;
+      if (i >= NX) continue;
+      if (j < 0) continue;
+      if (j >= NY) continue;
+      vz[0].elements[n] = v[i+j*NX];
+    }
+  }
+  if (n != Nx*Ny) {
+    gprint (GP_ERR, "error in ungrid: %d vs %d (%d x %d)\n", n, Nx*Ny, Nx, Ny);
+  }
+  vx[0].Nelements = vy[0].Nelements = vz[0].Nelements = n;
+  return (TRUE);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/uniq.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/uniq.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/uniq.c	(revision 11389)
@@ -0,0 +1,39 @@
+# include "data.h"
+
+int uniq (int argc, char **argv) {
+  
+  int Nnew, i, j, found;
+  float *v1, *v2;
+  Vector *ivec, *ovec;
+
+  if (argc != 3) {
+    gprint (GP_ERR, "USAGE: uniq (in) (out)\n");
+    return (FALSE);
+  }
+
+  if ((ivec = SelectVector (argv[1], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((ovec = SelectVector (argv[2], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+
+  /* allocate the maximum possible needed */
+  ALLOCATE (ovec[0].elements, float, ivec[0].Nelements);
+
+  Nnew = 0;
+  v1 = ivec[0].elements;
+  for (i = 0; i < ivec[0].Nelements; i++, v1++) {
+    v2 = ovec[0].elements;
+    found = FALSE;
+    for (j = 0; !found && (j < Nnew); j++, v2++) {
+      if (*v1 == *v2) found = TRUE;
+    }
+    if (!found) {
+      ovec[0].elements[Nnew] = *v1;
+      Nnew ++;
+    }
+  }
+
+  ovec[0].Nelements = Nnew;
+  REALLOCATE (ovec[0].elements, float, ovec[0].Nelements);
+
+  return (TRUE);
+}
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/unsign.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/unsign.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/unsign.c	(revision 11389)
@@ -0,0 +1,28 @@
+# include "data.h"
+
+int unsign (int argc, char **argv) {
+  
+  if (argc == 1) {
+    if (FT_UNSIGN_MODE) 
+      gprint (GP_ERR, "mode is now UNSIGNED int \n");
+    else
+      gprint (GP_ERR, "mode is now SIGNED int \n");
+    return (TRUE);
+  }
+
+  if (argc == 2) {
+    if (!strcmp (argv[1], "1")) {
+      FT_UNSIGN_MODE = TRUE;
+      set_int_variable ("UNSIGN", 1);
+      return (TRUE);
+    }
+    if (!strcmp (argv[1], "0")) {
+      FT_UNSIGN_MODE = FALSE;
+      set_int_variable ("UNSIGN", 0);
+      return (TRUE);
+    }
+  }
+
+  gprint (GP_ERR, "USAGE: unsign [0/1]\n");
+  return (FALSE);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/vbin.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/vbin.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/vbin.c	(revision 11389)
@@ -0,0 +1,66 @@
+# include "data.h"
+
+int vbin (int argc, char **argv) {
+  
+  int i, j, n, N, Nin, Nout;
+  int Normalize, Ignore;
+  float *Vout, *Vin, IgnoreValue;
+  double scale;
+  Vector *in, *out;
+
+  Normalize = FALSE;
+  if ((N = get_argument (argc, argv, "-norm"))) {
+    remove_argument (N, &argc, argv);
+    Normalize = TRUE;
+  }
+
+  Ignore = FALSE;
+  IgnoreValue = 0.0;
+  if ((N = get_argument (argc, argv, "-ignore"))) {
+    Ignore = TRUE;
+    remove_argument (N, &argc, argv);
+    IgnoreValue = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 4) {
+    gprint (GP_ERR, "USAGE: vbin <input> <output> scale \n");
+    gprint (GP_ERR, "  (use interpolate to expand)\n");
+    return (FALSE);
+  }
+
+  if ((in  = SelectVector (argv[1], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((out = SelectVector (argv[2], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+
+  scale  = atof (argv[3]);
+  if ((int)(scale) != scale) {
+    gprint (GP_ERR, "integer binning only, please\n");
+    return (FALSE);
+  }
+
+  Nin  = in[0].Nelements;
+  Nout = Nin / scale;
+
+  REALLOCATE (out[0].elements, float, Nout);
+  out[0].Nelements = Nout;
+
+  Vin  = in[0].elements;
+  Vout = out[0].elements;
+  for (n = j = 0; j < Nout; j++, Vout++) {
+    *Vout = 0;
+    for (N = i = 0; (i < scale) && (n < Nin); n++, i++, Vin++) {
+      if (!finite (*Vin)) continue;
+      if (Ignore && (*Vin == IgnoreValue)) continue;
+      *Vout += *Vin;
+      N ++;
+    } 
+    if (Normalize) {
+      if (N > 0) { 
+	*Vout /= (float) N; 
+      } else {
+	*Vout = 0;
+      }
+    }
+  }
+  return (TRUE);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/vclip.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/vclip.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/vclip.c	(revision 11389)
@@ -0,0 +1,73 @@
+# include "data.h"
+
+int vclip (int argc, char **argv) {
+
+  int i, Npix, DO_NAN, DO_INF, N;
+  double min, Vmin, max, Vmax, nan_val, inf_val;
+  float *in;
+  Vector *vec;
+
+  inf_val = nan_val = min = Vmin = max = Vmax = 0;
+
+  DO_NAN = FALSE;
+  if ((N = get_argument (argc, argv, "-nan"))) {
+    remove_argument (N, &argc, argv);
+    nan_val  = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+    DO_NAN = TRUE;
+  }
+
+  DO_INF = FALSE;
+  if ((N = get_argument (argc, argv, "-inf"))) {
+    remove_argument (N, &argc, argv);
+    inf_val  = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+    DO_INF = TRUE;
+  }
+
+  if ((argc != 6) && (!(DO_INF || DO_NAN))) {
+    gprint (GP_ERR, "USAGE: vclip (vector) [min Vmin max Vmax] [-inf val] [-nan val]\n");
+    return (FALSE);
+  }
+
+  if ((vec = SelectVector (argv[1], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+
+  if (argc == 6) {
+    min = atof (argv[2]);
+    Vmin = atof (argv[3]);
+    max = atof (argv[4]);
+    Vmax = atof (argv[5]);
+  }
+
+  Npix = vec[0].Nelements;
+  in =   vec[0].elements;
+
+  if (argc == 6) {
+    for (i = 0; i < Npix; i++, in++) {
+      if (*in < min) 
+	*in = Vmin;
+      if (*in > max)
+	*in = Vmax;
+    }
+  }
+  in = vec[0].elements;
+  if (DO_NAN) {
+    for (i = 0; i < Npix; i++, in++) {
+      if (isnan (*in)) {
+	*in = nan_val;
+      }
+    }
+  }
+  in = vec[0].elements;
+  if (DO_INF) {
+    for (i = 0; i < Npix; i++, in++) {
+      if (!finite (*in)) {
+	*in = inf_val;
+      }
+    }
+  }
+  return (TRUE);
+
+}
+
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/vcontour.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/vcontour.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/vcontour.c	(revision 11389)
@@ -0,0 +1,278 @@
+# include "data.h"
+# define LL { \
+ dx =  d00 / (*v01 - *v00); \
+ dy = -d00 / (*v10 - *v00); \
+ x = i - 0.5; \
+ y = j - dy - 0.5; }
+
+# define UL { \
+ tmp = d00 / (*v10 - *v00); \
+ dy = 1 - tmp; \
+ dx =  d10 / (*v11 - *v10); \
+ x = i - 0.5; \
+ y = j + tmp - 0.5; }
+      
+# define LR { \
+ tmp = d00 / (*v01 - *v00); \
+ dx = 1 - tmp; \
+ dy = d01 / (*v11 - *v01); \
+ x = i + tmp - 0.5; \
+ y = j - 0.5; }
+
+# define UR { \
+ tmp = d10 / (*v11 - *v10); \
+ dx = 1 - tmp; \
+ dy = -d11 / (*v01 - *v11); \
+ x = i + tmp - 0.5; \
+ y = j + 1 - 0.5; }
+      
+# define HZ { \
+ tmp = d00 / (*v10 - *v00); \
+ dy = d01 / (*v11 - *v01) - tmp; \
+ dx = 1; \
+ x = i - 0.5; \
+ y = j + tmp - 0.5; }
+
+# define VT { \
+ tmp = d00 / (*v01 - *v00); \
+ dx = d10 / (*v11 - *v10) - tmp; \
+ x = i + tmp - 0.5; \
+ dy = 1; \
+ y = j - 0.5; }
+
+# define DUMP { \
+overlay[Noverlay].type = KII_OVERLAY_LINE; \
+overlay[Noverlay].x = Npix*x; \
+overlay[Noverlay].y = Npix*y; \
+overlay[Noverlay].dx = Npix*dx; \
+overlay[Noverlay].dy = Npix*dy; \
+Noverlay ++; \
+CHECK_REALLOCATE (overlay, KiiOverlay, NOVERLAY, Noverlay, 1000); \
+}
+
+int vcontour (int argc, char **argv) {
+
+  int i, j, ii, jj, n, Nbuf, Npix, Nx, Ny, Nline;
+  float level, d00, d01, d10, d11, tmp;
+  float x, y, dx, dy;
+  float *v00, *v01, *v10, *v11;
+  float *Vout, *Vin, *matrix;
+  char *buffer, line[17];
+  int Ximage, Nimage, N;
+  Vector *xvec, *yvec, *zvec;
+
+  gprint (GP_ERR, "vcontour not working yet\n");
+  return (FALSE);
+
+  if (argc != 7) {
+    gprint (GP_ERR, "USAGE: vcontour x y z Xc Yc (level)\n");
+    return (FALSE);
+  }
+  
+  if ((xvec = SelectVector (argv[1], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((yvec = SelectVector (argv[2], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((zvec = SelectVector (argv[3], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((foo = SelectVector (argv[4], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((foo = SelectVector (argv[5], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+
+  level = atof (argv[6]);
+
+  /* convert the x,y,z vectors to a matrix */
+  *V = xvec[0].elements;
+  max = min = *V;
+  for (i = 0; i < xvec[0].Nelements; i++, V++) {
+    if (!finite (*V)) continue;
+    max = MAX (*V, max);
+    min = MIN (*V, min);
+  }      
+  Xmax = max; Xmin = min;
+
+  *V = yvec[0].elements;
+  max = min = *V;
+  for (i = 0; i < yvec[0].Nelements; i++, V++) {
+    if (!finite (*V)) continue;
+    max = MAX (*V, max);
+    min = MIN (*V, min);
+  }      
+  Ymax = max; Ymin = min;
+
+  /* not really finished */
+
+  Noverlay = 0;
+  NOVERLAY = 1000;
+  ALLOCATE (overlay, KiiOverlay, NOVERLAY);
+
+  v01 = matrix + 1;
+  v10 = matrix + Nx;
+  v11 = matrix + Nx + 1;
+  d01 = (level - *v00);
+  d11 = (level - *v10);
+  for (j = 1; j < Ny; j++) {
+    if (!(j%10)) gprint (GP_ERR, ".");
+    for (i = 1; i < Nx; i++, v00++, v01++, v10++, v11++) {
+
+      d00 = d01;
+      d10 = d11;
+      d01 = (level - *v01);
+      d11 = (level - *v11);
+
+      if (((d00 > 0) && (d01 > 0) && (d10 > 0) && (d11 > 0)) ||
+	  ((d00 < 0) && (d01 < 0) && (d10 < 0) && (d11 < 0)))
+	continue;
+
+      if ((d00 > 0) && (d10 <= 0)) { 
+	if ((d01 <= 0) && (d11 <= 0)) { /* \  */
+	  LL;
+	  DUMP;
+	  continue;
+	}
+	if ((d01 > 0) && (d11 <= 0)) { /* -  */
+	  HZ;
+	  DUMP;
+	  continue;
+	}
+	if ((d01 > 0) && (d11 > 0)) { /* /  */
+	  UL;
+	  DUMP;
+	  continue;
+	}
+	if ((d01 <= 0) && (d11 > 0)) { /* \\  */
+	  LL;
+	  DUMP;
+	  UR;
+	  DUMP;
+	  continue;
+	}
+      }
+
+      if ((d00 <= 0) && (d10 > 0)) {
+	if ((d01 > 0) && (d11 > 0)) { /* \  */
+	  LL;
+	  DUMP;
+	  continue;
+	}
+	if ((d01 <= 0) && (d11 > 0)) { /* -  */
+	  HZ;
+	  DUMP;
+	  continue;
+	}
+	if ((d01 <= 0) && (d11 <= 0)) { /* /  */
+	  UL;
+	  DUMP;
+	  continue;
+	}
+	if ((d01 > 0) && (d11 <= 0)) { /* //  */
+	  UL;
+	  DUMP;
+	  LR;
+	  DUMP;
+	  continue;
+	}
+      }
+      
+
+      if ((d00 <= 0) && (d10 <= 0)) { 
+	if ((d01 > 0) && (d11 <= 0)) {
+	  LR;
+	  DUMP;
+	  continue;
+	}
+	if ((d01 <= 0) && (d11 > 0)) {
+	  UR;
+	  DUMP;
+	  continue;
+	}
+	if ((d01 > 0) && (d11 > 0)) {
+	  VT;
+	  DUMP;
+	  continue;
+	}
+      }
+
+      if ((d00 > 0) && (d10 > 0)) { 
+	if ((d01 <= 0) && (d11 > 0)) {
+	  LR;
+	  DUMP;
+	  continue;
+	}
+	if ((d01 > 0) && (d11 <= 0)) {
+	  UR;
+	  DUMP;
+	  continue;
+	}
+	if ((d01 <= 0) && (d11 <= 0)) {
+	  VT;
+	  DUMP;
+	  continue;
+	}
+      }
+
+    }
+    /* skip left-hand edge */
+    v00++; v01++; v10++; v11++;
+    d01 = (level - *v00);
+    d11 = (level - *v10);
+  }
+
+  /****** bottom line *******/
+  v00 = matrix;  
+  v01 = matrix + 1;  
+  y = 0;
+  dx = 0;
+  dy = -0.5;
+  for (i = 1; i < Nx; i++, v00++, v01++) { /* do the edges */
+    if (((*v00 > level) && (*v01 <= level)) || ((*v00 <= level) && (*v01 > level))) {
+      x = i + (level - *v01)/(*v01 - *v00);
+      DUMP;
+      continue;
+    }
+  }
+
+  /********** top line *******/
+  v00 = matrix + Nx*(Ny - 1);  
+  v01 = v00 + 1;
+  y = Ny - 1;
+  dx = 0;
+  dy = 0.5;
+  for (i = 1; i < Nx; i++, v00++, v01++) { /* do the edges */
+    if (((*v00 > level) && (*v01 <= level)) || ((*v00 <= level) && (*v01 > level))) {
+      x = i + (level - *v01)/(*v01 - *v00);
+      DUMP;
+      continue;
+    }
+  }
+
+  /******** left line *********/
+  v00 = matrix; 
+  v01 = matrix + Nx;
+  x = 0;
+  dx = -0.5;
+  dy = 0;
+  for (j = 1; j < Ny; j++, v00+=Nx, v01+=Nx) { /* do the edges */
+    if (((*v00 > level) && (*v01 <= level)) || ((*v00 <= level) && (*v01 > level))) {
+      y = j + (level - *v01)/(*v01 - *v00);
+      DUMP;
+      continue;
+    }
+  }
+
+  /******** right line *********/
+  v00 = matrix + Nx - 1; 
+  v01 = v00 + Nx;
+  x = Nx - 1;
+  dx = 0.5;
+  dy = 0;
+  for (j = 1; j < Ny; j++, v00+=Nx, v01+=Nx) { /* do the edges */
+    if (((*v00 > level) && (*v01 <= level)) || ((*v00 <= level) && (*v01 > level))) {
+      y = j + (level - *v01)/(*v01 - *v00);
+      DUMP;
+      continue;
+    }
+  }
+  
+  KiiLoadOverlay (Ximage, overlay, Noverlay, argv[2]);
+  free (overlay);
+
+  if (Npix != 1) free (matrix);
+  gprint (GP_ERR, "\n");
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/vgauss.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/vgauss.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/vgauss.c	(revision 11389)
@@ -0,0 +1,104 @@
+# include "data.h"
+
+/* local private functions */
+float fgaussOD (float, float *, int, float *);
+
+# define GET_VAR(V,A) \
+  c = get_variable (A); \
+  if (c == NULL) { \
+    gprint (GP_ERR, "missing fit parameter A\n"); \
+    return (FALSE); \
+  } \
+  V = atof (c);
+
+int vgauss (int argc, char **argv) {
+
+  int i, N, Npts, Npar, Quiet;
+  float par[4], *v1, *v2, *dy, **covar;
+  float chisq, ochisq, dchisq;
+  Vector *xvec, *yvec, *svec, *ovec;
+  char *c, name[16];
+
+  Quiet = FALSE;
+  if ((N = get_argument (argc, argv, "-q"))) {
+    Quiet = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "-quiet"))) {
+    Quiet = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 5) {
+    gprint (GP_ERR, "USAGE: vgauss <x> <y> <dy> (out)\n");
+    gprint (GP_ERR, " uses guesses: C0 (mean), C1 (sigma), C2 (norm), C3 (sky)\n");
+    return (FALSE);
+  }
+  
+  if ((xvec = SelectVector (argv[1], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((yvec = SelectVector (argv[2], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((svec = SelectVector (argv[3], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((ovec = SelectVector (argv[4], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+
+  Npts = xvec[0].Nelements;
+  ALLOCATE (dy, float, Npts);
+  REALLOCATE (ovec[0].elements, float, Npts);
+
+  GET_VAR (par[0], "C0");
+  GET_VAR (par[1], "C1");
+  GET_VAR (par[2], "C2");
+  GET_VAR (par[3], "C3");
+  Npar = 4;
+
+  v1 = svec[0].elements;
+  v2 = dy;
+  for (i = 0; i < Npts; i++, v1++, v2++) {
+      *v2 = (*v1 == 0.0) ? 0.0 : 1.0 / (*v1 * *v1);
+  } 
+  
+  ochisq = mrqinit (xvec[0].elements, yvec[0].elements, dy, Npts, par, Npar, fgaussOD, !Quiet);
+  dchisq = ochisq + 2*Npts;
+
+  for (i = 0; (i < 20) && ((dchisq > 0.1*(Npts - Npar)) || (dchisq <= 0.0)); i++) {
+    chisq = mrqmin (xvec[0].elements, yvec[0].elements, dy, Npts, par, Npar, fgaussOD, !Quiet);
+    dchisq = ochisq - chisq;
+    ochisq = chisq;
+    if (!Quiet) gprint (GP_ERR, "dchisq: %f, Ndof: %d\n", dchisq, Npts - Npar);
+  }  
+  if (!Quiet) gprint (GP_ERR, "%d iterations\n", i); 
+
+  for (i = 0; i < Npts; i++) {
+    ovec[0].elements[i] = fgaussOD (xvec[0].elements[i], par, Npar, dy);
+  }
+  ovec[0].Nelements = Npts;
+  /* set output *before* variable renomalization */
+
+  covar = mrqcovar (Npar);
+  for (i = 0; i < Npar; i++) {
+    sprintf (name, "C%d", i);
+    set_variable (name, par[i]);
+    if (!Quiet) gprint (GP_ERR, "%d  %f  %f\n", i, par[i], sqrt(covar[i][i]));
+    sprintf (name, "dC%d", i);
+    set_variable (name, sqrt(covar[i][i]));
+  }
+
+  mrqfree (Npar);
+  return (TRUE);
+}
+
+/* pars: x_o, sigma, I, back */
+float fgaussOD (float x, float *par, int Npar, float *dpar) {
+
+  float z, r, f;
+
+  z = (x - par[0])/par[1];
+  r = exp (-0.5*SQ(z));
+  f = par[2]*r + par[3];
+
+  dpar[0] = par[2]*r*z/par[1];
+  dpar[1] = par[2]*r*z*z/par[1];
+  dpar[2] = r;
+  dpar[3] = 1;
+  
+  return (f);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/vgrid.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/vgrid.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/vgrid.c	(revision 11389)
@@ -0,0 +1,72 @@
+# include "data.h"
+
+int vgrid (int argc, char **argv) {
+
+  int i, Nx, Ny, Xb, Yb;
+  float Xmin, Xmax, dX, Ymin, Ymax, dY;
+  float *buf, *val, *x, *y, *z;
+  int *Nval;
+  Buffer *bf;
+  Vector *vx, *vy, *vz;
+
+  if (argc != 11) {
+    gprint (GP_ERR, "USAGE: vgrid x y z buffer Xmin Xmax dX Ymin Ymax dY\n");
+    return (FALSE);
+  }
+  
+  if ((vx = SelectVector (argv[1], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((vy = SelectVector (argv[2], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((vz = SelectVector (argv[3], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((bf = SelectBuffer (argv[4], ANYBUFFER, TRUE)) == NULL) return (FALSE);
+
+  if (vx[0].Nelements != vy[0].Nelements) return (FALSE);
+  if (vx[0].Nelements != vz[0].Nelements) return (FALSE);
+
+  Xmin = atof (argv[5]);
+  Xmax = atof (argv[6]);
+  dX   = atof (argv[7]);
+
+  Ymin = atof (argv[8]);
+  Ymax = atof (argv[9]);
+  dY   = atof (argv[10]);
+
+  Nx = (Xmax - Xmin) / dX + 1;
+  Ny = (Ymax - Ymin) / dY + 1;
+  
+  gfits_free_matrix (&bf[0].matrix);
+  gfits_free_header (&bf[0].header);
+  CreateBuffer (bf, Nx, Ny, -32, 0.0, 1.0);
+  strcpy (bf[0].file, "(empty)");
+
+  ALLOCATE (val, float, Nx*Ny);
+  bzero (val, Nx*Ny*sizeof(float));
+  ALLOCATE (Nval, int, Nx*Ny);
+  bzero (Nval, Nx*Ny*sizeof(int));
+
+  x = vx[0].elements;
+  y = vy[0].elements;
+  z = vz[0].elements;
+  for (i = 0; i < vx[0].Nelements; i++, x++, y++, z++) {
+    Xb = (*x - Xmin) / dX;
+    Yb = (*y - Ymin) / dY;
+    if (Xb >= Nx) continue;
+    if (Yb >= Ny) continue;
+    val[Xb + Yb*Nx] = *z;
+    Nval[Xb + Yb*Nx]++;
+  }
+
+  buf = (float *) bf[0].matrix.buffer;
+  for (i = 0; i < Nx*Ny; i++) {
+    if (Nval[i] == 0) {
+      buf[i] = 0;
+      continue;
+    }
+    buf[i] = val[i] / Nval[i];
+  }
+
+  free (val);
+  free (Nval);
+
+  return (TRUE);
+
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/vload.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/vload.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/vload.c	(revision 11389)
@@ -0,0 +1,71 @@
+# include "data.h"
+
+int vload (int argc, char **argv) {
+  
+  int i, N, Noverlay;
+  int Ximage, Nimage, type;
+  double dx, dy, size;
+  KiiOverlay *overlay;
+  Vector *vecx, *vecy;
+  
+  Nimage = -1;
+  if ((N = get_argument (argc, argv, "-n"))) {
+    remove_argument (N, &argc, argv);
+    Nimage = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if (!GetImage (&Ximage, &Nimage)) return (FALSE);
+
+  type = KII_OVERLAY_BOX;
+  if ((N = get_argument (argc, argv, "-type"))) {
+    remove_argument (N, &argc, argv);
+    type = KiiOverlayTypeByName (argv[N]);
+    remove_argument (N, &argc, argv);
+    if (!type) {
+      gprint (GP_ERR, "unknown Kii point type %s\n", argv[N]);
+      return (FALSE);
+    }
+  }
+
+  size = 1.0;
+  if ((N = get_argument (argc, argv, "-size"))) {
+    remove_argument (N, &argc, argv);
+    size = fabs(atof (argv[N]));
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 4) {
+    gprint (GP_ERR, "USAGE: vload (overlay) (xvec) (yvec) [-n]\n");
+    return (FALSE);
+  }
+  
+  if (type == KII_OVERLAY_CIRCLE) {
+    dx = dy = size / 2;
+  } else {
+    dx = dy = size;
+  }    
+
+  if ((vecx = SelectVector (argv[2], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((vecy = SelectVector (argv[3], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if (vecx[0].Nelements != vecy[0].Nelements) {
+    gprint (GP_ERR, "mismatched vector lengths\n");
+    return (FALSE);
+  }
+
+  Noverlay = vecx[0].Nelements;
+  ALLOCATE (overlay, KiiOverlay, Noverlay);
+
+  for (i = 0; i < Noverlay; i++) {
+    overlay[i].type = type;
+    overlay[i].text = NULL;
+    overlay[i].x = vecx[0].elements[i]+0.5;
+    overlay[i].y = vecy[0].elements[i]+0.5;
+    overlay[i].dx = dx;
+    overlay[i].dy = dy;
+  }
+
+  KiiLoadOverlay (Ximage, overlay, Noverlay, argv[1]);
+  free (overlay);
+  return (TRUE);
+}
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/vmaxwell.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/vmaxwell.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/vmaxwell.c	(revision 11389)
@@ -0,0 +1,106 @@
+# include "data.h"
+
+/* local private functions */
+float fmaxwellOD (float, float *, int, float *);
+
+# define GET_VAR(V,A) \
+  c = get_variable (A); \
+  if (c == NULL) { \
+    gprint (GP_ERR, "missing fit parameter A\n"); \
+    return (FALSE); \
+  } \
+  V = atof (c);
+
+int vmaxwell (int argc, char **argv) {
+
+  int i, N, Npts, Npar, Quiet;
+  float par[5], *v1, *v2, *dy, **covar;
+  float chisq, ochisq, dchisq;
+  Vector *xvec, *yvec, *svec, *ovec;
+  char *c, name[16];
+
+  Quiet = FALSE;
+  if ((N = get_argument (argc, argv, "-q"))) {
+    Quiet = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "-quiet"))) {
+    Quiet = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 5) {
+    gprint (GP_ERR, "USAGE: vmaxwell <x> <y> <dy> (out)\n");
+    gprint (GP_ERR, " uses guesses: C0 (mean), C1 (sigma), C2 (norm), C3 (sky), C4 (ref)\n");
+    return (FALSE);
+  }
+  
+  if ((xvec = SelectVector (argv[1], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((yvec = SelectVector (argv[2], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((svec = SelectVector (argv[3], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((ovec = SelectVector (argv[4], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+
+  Npts = xvec[0].Nelements;
+  ALLOCATE (dy, float, Npts);
+  REALLOCATE (ovec[0].elements, float, Npts);
+
+  GET_VAR (par[0], "C0");
+  GET_VAR (par[1], "C1");
+  GET_VAR (par[2], "C2");
+  GET_VAR (par[3], "C3");
+  GET_VAR (par[4], "C4");
+  Npar = 5;
+  /* careful of variable renomalization */
+
+  v1 = svec[0].elements;
+  v2 = dy;
+  for (i = 0; i < Npts; i++, v1++, v2++) *v2 = 1.0 / (*v1 * *v1);
+  
+  ochisq = mrqinit (xvec[0].elements, yvec[0].elements, dy, Npts, par, Npar, fmaxwellOD, !Quiet);
+  dchisq = ochisq + 2*Npts;
+
+  for (i = 0; (i < 20) && ((dchisq > 0.1*(Npts - Npar)) || (dchisq <= 0.0)); i++) {
+    chisq = mrqmin (xvec[0].elements, yvec[0].elements, dy, Npts, par, Npar, fmaxwellOD, !Quiet);
+    dchisq = ochisq - chisq;
+    ochisq = chisq;
+    if (!Quiet) gprint (GP_ERR, "dchisq: %f, Ndof: %d\n", dchisq, Npts - Npar);
+  }  
+  if (!Quiet) gprint (GP_ERR, "%d iterations\n", i); 
+
+  for (i = 0; i < Npts; i++) {
+    ovec[0].elements[i] = fmaxwellOD (xvec[0].elements[i], par, Npar, dy);
+  }
+  ovec[0].Nelements = Npts;
+  /* set output *before* variable renomalization */
+
+  covar = mrqcovar (Npar);
+  for (i = 0; i < Npar; i++) {
+    sprintf (name, "C%d", i);
+    set_variable (name, par[i]);
+    if (!Quiet) gprint (GP_ERR, "%d  %f  %f\n", i, par[i], sqrt(covar[i][i]));
+    sprintf (name, "dC%d", i);
+    set_variable (name, sqrt(covar[i][i]));
+  }
+
+  mrqfree (Npar);
+  return (TRUE);
+}
+
+/* pars: x_o, -0.5/sigma^2, I, back, ref */
+float fmaxwellOD (float x, float *par, int Npar, float *dpar) {
+
+  float z, r, f;
+
+  z = (x - par[0])/par[1];
+  r = SQ(x - par[4])*exp (-0.5*SQ(z));
+  f = par[2]*r + par[3];
+
+  dpar[0] = par[2]*r*z/par[1];
+  dpar[1] = par[2]*r*z*z/par[1];
+  dpar[2] = r;
+  dpar[3] = 1;
+  dpar[4] = -par[2]*(x - par[4])*exp(-0.5*SQ(z));
+  
+  return (f);
+
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/vpop.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/vpop.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/vpop.c	(revision 11389)
@@ -0,0 +1,23 @@
+# include "data.h"
+
+int vpop (int argc, char **argv) {
+
+  int Npix;
+  Vector *vec;
+
+  if (argc != 2) {
+    gprint (GP_ERR, "USAGE: vpop (vector)\n");
+    gprint (GP_ERR, "  remove first element of vector\n");
+    return (FALSE);
+  }
+
+  if ((vec = SelectVector (argv[1], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  Npix = vec[0].Nelements;
+  if (Npix < 1) return (TRUE);
+
+  if (Npix > 1) {
+    memmove (&vec[0].elements[0], &vec[0].elements[1], Npix*sizeof(float));
+  }
+  vec[0].Nelements = Npix - 1;
+  return (TRUE);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/vroll.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/vroll.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/vroll.c	(revision 11389)
@@ -0,0 +1,23 @@
+# include "data.h"
+
+int vroll (int argc, char **argv) {
+
+  int Npix;
+  float first;
+  Vector *vec;
+
+  if (argc != 2) {
+    gprint (GP_ERR, "USAGE: vroll (vector)\n");
+    gprint (GP_ERR, "  roll vector elements (first goes to end)\n");
+    return (FALSE);
+  }
+
+  if ((vec = SelectVector (argv[1], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  Npix = vec[0].Nelements;
+  if (Npix < 2) return (TRUE);
+
+  first = vec[0].elements[0];
+  memmove (&vec[0].elements[0], &vec[0].elements[1], Npix*sizeof(float));
+  vec[0].elements[Npix-1] = first;
+  return (TRUE);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/vsmooth.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/vsmooth.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/vsmooth.c	(revision 11389)
@@ -0,0 +1,55 @@
+# include "data.h"
+
+int vsmooth (int argc, char **argv) {
+  
+  int i, n, N, Nx, Ns, Ngauss;
+  float *vi, *vo, *gauss, *gaussnorm;
+  float g, s, sigma, Nsigma;
+  Vector *in;
+
+  Nsigma = 3;
+  if ((N = get_argument (argc, argv, "-Nsigma"))) {
+    remove_argument (N, &argc, argv);
+    Nsigma = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 3) {
+    gprint (GP_ERR, "USAGE: vsmooth (input) sigma\n");
+    return (FALSE);
+  }
+  
+  if ((in  = SelectVector (argv[1], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  sigma = atof (argv[2]);
+  Nx = in[0].Nelements;
+  vi = in[0].elements;
+
+  /* build a 1D gaussian */
+  Ns = (int) (Nsigma*sigma + 0.5);
+  Ngauss = 2*Ns + 1;
+  ALLOCATE (gaussnorm, float, Ngauss);
+  gauss = &gaussnorm[Ns];
+  for (i = -Ns; i < Ns + 1; i++) {
+    gauss[i] = exp ((i*i)/(-2*sigma*sigma));
+  }
+
+  ALLOCATE (vo, float, Nx);
+
+  for (i = 0; i < Nx; i++) {
+    g = s = 0;
+    for (n = -Ns; n < Ns + 1; n++) {
+      if (i+n < 0) continue;
+      if (i+n >= Nx) continue;
+      s += gauss[n]*vi[i+n];
+      g += gauss[n];
+    }
+    vo[i] = s / g;
+  }
+
+  free (in[0].elements);
+  free (gaussnorm);
+
+  in[0].elements = vo;
+  return (TRUE);
+}
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/vstat.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/vstat.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/vstat.c	(revision 11389)
@@ -0,0 +1,115 @@
+# include "data.h"
+
+int vstat (int argc, char **argv) {
+  
+  int i, N;
+  double max, min, sum, var, dvar, mean, stdev;
+  float *X, IgnoreValue;
+  int Ignore, Quiet;
+
+  int *Nval, bin, Nmode, Nmed;
+  double dx, mode, median;
+  Vector *vec;
+
+  IgnoreValue = 0;
+  Ignore = FALSE;
+  if ((N = get_argument (argc, argv, "-ignore"))) {
+    Ignore = TRUE;
+    remove_argument (N, &argc, argv);
+    IgnoreValue = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  Quiet = FALSE;
+  if ((N = get_argument (argc, argv, "-q"))) {
+    Quiet = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "-quiet"))) {
+    Quiet = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 2) {
+    gprint (GP_ERR, "USAGE: vstat (vector)\n");
+    return (FALSE);
+  }
+
+  if ((vec = SelectVector (argv[1], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+
+  /* we need two passes, one for max, min, mean, sum, one for median, stdev, etc */
+
+  /* calculate max, min, mean, sum, npix */
+  X = vec[0].elements;
+  max = -HUGE_VAL;
+  min = HUGE_VAL;
+  sum = N = 0;
+  for (i = 0; i < vec[0].Nelements; i++, X++) {
+    if (!finite (*X)) continue;
+    if (Ignore && (*X == IgnoreValue)) continue;
+    max = MAX (*X, max);
+    min = MIN (*X, min);
+    sum += *X;
+    N++;
+  }      
+  mean = sum / N;
+
+  /* calculate median and mode with resolution of (max - min) / 1000 */ 
+  dx = (max - min) / 1000;
+  if (dx == 0) {
+    median = mode = min;
+    stdev = 0.0;
+    goto skip;
+  }
+
+  ALLOCATE (Nval, int, 1002);
+  bzero (Nval, 1000*sizeof(int));
+  X = vec[0].elements;
+  var = 0;
+  for (i = 0; i < vec[0].Nelements; i++, X++) {
+    if (!finite (*X)) continue;
+    if (Ignore && (*X == IgnoreValue)) continue;
+    bin = MAX (0, MIN (1000, (*X - min) / dx));
+    Nval[bin] ++;
+    dvar = (*X - mean);
+    var += dvar*dvar;
+  }      
+  stdev = sqrt (var / N);
+
+  Nmode = 0;
+  mode = Nval[Nmode];
+  median = 0;
+  Nmed = -1;
+  for (i = 0; i < 1001; i++) {
+    if (Nmed == -1) {
+      median += Nval[i];
+      if (median >= N / 2.0) {
+	Nmed = i;
+	median = i * dx + min;
+      }
+    }
+    if (mode < Nval[i]) {
+      Nmode = i;
+      mode = Nval[Nmode];
+    }
+  }
+  mode = Nmode * dx + min;
+  free (Nval);
+
+skip:
+  if (!Quiet) {
+    gprint (GP_ERR, "mean: %g, stdev: %g, min: %g, max: %g, median: %g, mode: %g, Npts: %d\n", 
+	     mean, stdev, min, max, median, mode, N);
+  }
+
+  set_variable ("MIN",      min);
+  set_variable ("MAX",      max);
+  set_variable ("MEDIAN",   median);
+  set_variable ("MEAN",     mean);
+  set_variable ("MODE",     mode);
+  set_variable ("TOTAL",    sum);
+  set_int_variable ("NPIX", N);
+  set_variable ("SIGMA",    stdev);
+  return (TRUE);
+}
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/wd.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/wd.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/wd.c	(revision 11389)
@@ -0,0 +1,183 @@
+# include "data.h"
+
+int wd (int argc, char **argv) {
+  
+  int N, Extend;
+  int newUnsign, newBitpix, newScale, newZero;
+  int outUnsign, outBitpix;
+  double outScale, outZero;
+  Header temp_header;
+  Matrix temp_matrix;
+  Buffer *buf;
+
+  Extend  = FALSE;
+  if ((N = get_argument (argc, argv, "-extend"))) {
+    remove_argument (N, &argc, argv);
+    Extend  = TRUE;
+  }
+
+  outZero = 0;
+  newZero = FALSE;
+  if ((N = get_argument (argc, argv, "-bzero"))) {
+    remove_argument (N, &argc, argv);
+    outZero  = atof(argv[N]);
+    newZero  = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  outScale = 1;
+  newScale = FALSE;
+  if ((N = get_argument (argc, argv, "-bscale"))) {
+    remove_argument (N, &argc, argv);
+    outScale = atof(argv[N]);
+    newScale = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  outBitpix = 16;
+  newBitpix = FALSE;
+  if ((N = get_argument (argc, argv, "-bitpix"))) {
+    remove_argument (N, &argc, argv);
+    outBitpix = atof(argv[N]);
+    newBitpix = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  outUnsign = FALSE;
+  newUnsign = FALSE;
+  if ((N = get_argument (argc, argv, "-unsign"))) {
+    remove_argument (N, &argc, argv);
+    outUnsign = -1;
+    if (!strcasecmp (argv[N], "t") || !strcasecmp (argv[N], "true")) outUnsign = TRUE;
+    if (!strcasecmp (argv[N], "f") || !strcasecmp (argv[N], "false")) outUnsign = FALSE;
+    if (outUnsign == -1) {
+      gprint (GP_ERR, "-unsign options: t, f, true, false\n");
+      return (FALSE);
+    }
+    newUnsign = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 3) {
+    gprint (GP_ERR, "USAGE: wd <buffer> <filename> [-bitpix N] [-bscale X] [-bzero X] [-newplane]\n");
+    return (FALSE);
+  }
+
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+
+  if (!newBitpix) outBitpix = buf[0].bitpix;
+  if (!newScale) outScale = buf[0].bscale;
+  if (!newZero) outZero = buf[0].bzero;
+  if (!newUnsign) outUnsign = buf[0].unsign;
+
+  /* Convert the buffer from (float) to correct format */
+  /* save the (float) version, write out a temporary buffer */
+  temp_matrix = buf[0].matrix;
+  ALLOCATE (temp_matrix.buffer, char, MAX(1, temp_matrix.size));
+  memcpy (temp_matrix.buffer, buf[0].matrix.buffer, temp_matrix.size);
+  temp_header = buf[0].header;
+  ALLOCATE (temp_header.buffer, char, MAX(1, temp_header.size));
+  memcpy (temp_header.buffer, buf[0].header.buffer, temp_header.size);
+
+  if (temp_header.Naxes) gfits_convert_format (&temp_header, &temp_matrix, outBitpix, outScale, outZero, outUnsign);
+
+  if (Extend) {
+    Header Xhead;
+    FILE *f;
+    int status, Nextend;
+
+    /* assume failure means non-existent file */
+    if (!gfits_read_header (argv[2], &Xhead)) {
+
+      Xhead.simple = TRUE;
+      Xhead.bitpix = 16;
+      Xhead.Naxes = 0;
+      
+      Xhead.extend = TRUE;
+      Xhead.bscale = 1.0;
+      Xhead.bzero  = 0.0;
+      Xhead.unsign = FALSE;
+      
+      gfits_create_header (&Xhead);
+      gfits_modify (&Xhead, "NEXTEND", "%d", 1, 0);
+      f = fopen (argv[2], "w");
+      fclose (f);
+    }
+
+    gfits_modify (&Xhead, "EXTEND", "%t", 1, TRUE);
+
+    Nextend = 0;
+    gfits_scan (&Xhead, "NEXTEND", "%d", 1, &Nextend);
+    Nextend ++;
+    gfits_modify (&Xhead, "NEXTEND", "%d", 1, Nextend);
+
+    /* write the main header to the start of the file */
+    f = fopen (argv[2], "r+");
+    if (f == NULL) {
+      gprint (GP_ERR, "failed to write file\n");
+      status = FALSE;
+      goto done1;
+    }
+    
+    /* position to begining of file to write header */
+    fseek (f, 0, SEEK_SET);
+    status = fwrite (Xhead.buffer, 1, Xhead.size, f);
+    if (status != Xhead.size) {
+      gprint (GP_ERR, "ERROR: failed writing data to image header\n");
+      status = FALSE;
+      goto done1;
+    }
+    
+    /* fix up header */
+    {
+      static char simple[] = "XTENSION= 'IMAGE  '            / Image extension";
+      int Ns, No;
+      Ns = strlen (simple);
+      No = 80 - Ns;
+      strncpy (temp_header.buffer, simple, Ns);
+      memset (&temp_header.buffer[Ns], ' ', No);
+    }
+
+    /* position to end of file to write new extend */
+    fseek (f, 0, SEEK_END);
+    status = fwrite (temp_header.buffer, 1, temp_header.size, f);
+    fclose (f);
+    if (status != temp_header.size) {
+      gprint (GP_ERR, "failed to write file\n");
+      status = FALSE;
+      goto done1;
+    }
+    /* write the matrix buffer (automatically goes to end of file */
+    if (!gfits_write_matrix (argv[2], &temp_matrix)) {
+      gprint (GP_ERR, "failed to write file\n");
+      status = FALSE;
+      goto done1;
+    }
+    status = TRUE;
+  done1:
+    gfits_free_header (&Xhead);
+    gfits_free_header (&temp_header);
+    gfits_free_matrix (&temp_matrix);
+    return (status);
+  }
+  
+  /* the actual write-to-disk goes here */
+  if (!gfits_write_header (argv[2], &temp_header)) {
+    gprint (GP_ERR, "failed to write header\n");
+    gfits_free_header (&temp_header);
+    gfits_free_matrix (&temp_matrix);
+    return (FALSE);
+  }
+  
+  if (!gfits_write_matrix (argv[2], &temp_matrix)) {
+    gprint (GP_ERR, "failed to write matrix\n");
+    gfits_free_header (&temp_header);
+    gfits_free_matrix (&temp_matrix);
+    return (FALSE);
+  }
+
+  gfits_free_header (&temp_header);
+  gfits_free_matrix (&temp_matrix);
+  
+  return (TRUE);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/write_vectors.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/write_vectors.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/write_vectors.c	(revision 11389)
@@ -0,0 +1,151 @@
+# include "data.h"
+
+int write_vectors (int argc, char **argv) {
+  
+  int append;
+  int i, j, Nvec, Ne, N;
+  FILE *f;
+  char **fmtlist, *fmttype;
+  char *p0, *p1, *p2, *format;
+  Vector **vec;
+
+  /* look for format option */
+  format = (char *) NULL;
+  if ((N = get_argument (argc, argv, "-f"))) {
+    remove_argument (N, &argc, argv);
+    format = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  append = FALSE;
+  if ((N = get_argument (argc, argv, "-append"))) {
+    remove_argument (N, &argc, argv);
+    append = TRUE;
+  }
+
+  if (argc < 3) {
+    gprint (GP_ERR, "USAGE: write [-append] [-f \"format\"] file vector vector ...\n");
+    return (FALSE);
+  }
+
+  /* open file for outuput */
+  if (append) {
+      f = fopen (argv[1], "a");
+  } else {
+      f = fopen (argv[1], "w");
+  }
+  if (f == (FILE *) NULL) {
+    gprint (GP_ERR, "can't open file for write\n");
+    return (FALSE);
+  }
+
+  /* find number of output vectors */
+  Nvec = (argc - 2);
+  if (Nvec < 1) {
+      gprint (GP_ERR, "USAGE: write (file) vector vector ...\n");
+      fclose (f);
+      return (FALSE);
+  }
+  ALLOCATE (vec, Vector *, Nvec);
+
+  /* select/check vectors from list */
+  for (i = 0; i < Nvec; i++) {
+    if ((vec[i] = SelectVector (argv[i + 2], OLDVECTOR, FALSE)) == NULL) {
+      gprint (GP_ERR, "unknown vector %s\n", argv[i+2]);
+      gprint (GP_ERR, "USAGE: write (file) vector vector ...\n");
+      free (vec);
+      fclose (f);
+      return (FALSE);    
+    }
+  }
+  
+  /* select vector lengths */
+  Ne = vec[0][0].Nelements;
+  for (i = 0; i < Nvec; i++) {
+    if (vec[0][0].Nelements != Ne) {
+      gprint (GP_ERR, "error: vectors must all be the same size\n");
+      free (vec);
+      fclose (f);
+      return (FALSE);    
+    }
+  }
+
+  /* default output format */
+  if (format == (char *) NULL) {
+    for (i = 0; i < vec[0][0].Nelements; i++) {
+      for (j = 0; j < Nvec; j++) {
+	fprintf (f, "%.10g ", vec[j][0].elements[i]);
+      }
+      fprintf (f, "\n");
+    } 
+    fclose (f);
+    free (vec);
+    return (TRUE);
+  }
+
+  /* construct an array of format strings */
+  ALLOCATE (fmttype, char, Nvec);
+  ALLOCATE (fmtlist, char *, Nvec);
+  for (i = 0; i < Nvec; i++) {
+    ALLOCATE (fmtlist[i], char, 1024);
+    bzero (fmtlist[i], 1024);
+  }
+
+  p0 = format;
+  for (j = 0; j < Nvec; j++) {
+    /* find this format character */
+    p1 = strchr (p0, '%');
+    if (p1 == (char *) NULL) {
+      gprint (GP_ERR, "mismatch between format and values\n");
+      free (fmttype);
+      for (i = 0; i < Nvec; i++) free (fmtlist[i]);
+      free (fmtlist);
+      free (format);
+      fclose (f);
+      return (FALSE);
+    }
+    
+    /* identify type (%NNNNd %NNNNf) */
+    for (p2 = p1 + 1; (*p2 == '.') || (*p2 == '-') || (*p2 == '+') || (*p2 == ' ') || isdigit(*p2); p2++);
+    strncpy (fmtlist[j], p0, p2 - p0 + 1);
+    switch (*p2) {
+      case 'e':
+      case 'f':
+	fmttype[j] = 'f';
+	break;
+      case 'd':
+      case 'c':
+      case 'x':
+	fmttype[j] = 'd';
+	break;
+      default:
+	gprint (GP_ERR, "syntax error in format (only e,f,d,c,x allowed)\n");
+	return (FALSE);
+    }
+    p0 = p2 + 1;
+  }
+  strcat (fmtlist[Nvec-1], p0);
+  
+  for (i = 0; i < vec[0][0].Nelements; i++) {
+    for (j = 0; j < Nvec; j++) {
+      if (fmttype[j] == 'd') {
+	fprintf (f, fmtlist[j], (int)(vec[j][0].elements[i]));
+      } 
+      if (fmttype[j] == 'f') {
+	fprintf (f, fmtlist[j], (float)(vec[j][0].elements[i]));
+      } 
+    }
+    fprintf (f, "\n");
+  }
+  fclose (f);
+
+  free (fmttype);
+  for (i = 0; i < Nvec; i++) free (fmtlist[i]);
+  free (fmtlist);
+  free (format);
+  
+  return (TRUE);
+
+}
+
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/zap.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/zap.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/zap.c	(revision 11389)
@@ -0,0 +1,43 @@
+# include "data.h"
+
+int zap (int argc, char **argv) {
+
+  int i, j, N;
+  int sx, sy, nx, ny;
+  float *V, value;
+  Buffer *buf;
+
+  value = 0;
+  if ((N = get_argument (argc, argv, "-v"))) {
+    remove_argument (N, &argc, argv);
+    value  = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 6) {
+    gprint (GP_ERR, "USAGE: zap <buffer> sx sy nx ny [-v value]\n");
+    return (FALSE);
+  }
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+
+  sx = atof (argv[2]);
+  sy = atof (argv[3]);
+  nx = atof (argv[4]);
+  ny = atof (argv[5]);
+
+  if (sx < 0) goto error;
+  if (sy < 0) goto error;
+  if (sx + nx > buf[0].matrix.Naxis[0]) goto error;
+  if (sy + ny > buf[0].matrix.Naxis[1]) goto error;
+
+  for (j = sy; j < sy + ny; j++) {
+    V = (float *)(buf[0].matrix.buffer) + j*buf[0].matrix.Naxis[0] + sx; 
+    for (i = 0; i < nx; i++, V++) *V = value;
+  }
+  return (TRUE);
+
+ error:
+  gprint (GP_ERR, "region out of range\n");
+  return (FALSE);
+}
+
Index: /branches/opihi-2-9/Ohana/src/opihi/cmd.data/zplot.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/cmd.data/zplot.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/cmd.data/zplot.c	(revision 11389)
@@ -0,0 +1,65 @@
+# include "data.h"
+
+int zplot (int argc, char **argv) {
+  
+  int i, N, Npts, Ngraph;
+  float *in, *out;
+  double min, range;
+  Graphdata graphmode;
+  Vector *xvec, *yvec, *zvec, Zvec;
+
+  Ngraph = -1;
+  if ((N = get_argument (argc, argv, "-n"))) {
+    remove_argument (N, &argc, argv);
+    Ngraph = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if (!GetGraph (&graphmode, NULL, &Ngraph)) return (FALSE);
+
+  if (argc != 6) {
+    gprint (GP_ERR, "USAGE: zplot <x> <y> <z> min max\n");
+    return (FALSE);
+  }
+
+  min = atof(argv[4]);
+  range = atof(argv[5]) - min;
+
+  /* find vectors */
+  if ((xvec = SelectVector (argv[1], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((yvec = SelectVector (argv[2], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((zvec = SelectVector (argv[3], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if (xvec[0].Nelements != yvec[0].Nelements) {
+    gprint (GP_ERR, "vectors %s and %s not the same length\n", argv[1], argv[2]);
+    return (FALSE);
+  }
+  if (xvec[0].Nelements != zvec[0].Nelements) {
+    gprint (GP_ERR, "vectors %s and %s not the same length\n", argv[1], argv[3]);
+    return (FALSE);
+  }
+  Zvec.Nelements = zvec[0].Nelements;
+  ALLOCATE (Zvec.elements, float, Zvec.Nelements);
+ 
+  in = zvec[0].elements;
+  out = Zvec.elements;
+  for (i = 0; i < Zvec.Nelements; i++, in++, out++) {
+    *out = MIN (1.0, MAX (0.01, (*in - min) / range));
+  }
+
+  /* point size determined by Zvec */
+  graphmode.style = 2; /* plot points */
+  graphmode.size = -1; /* point size determined by Zvec */
+  graphmode.etype = 0; /* no errorbars */
+  Npts = xvec[0].Nelements;
+  PrepPlotting (Npts, &graphmode);
+
+  PlotVector (Npts, xvec[0].elements);
+  PlotVector (Npts, yvec[0].elements);
+  PlotVector (Npts, Zvec.elements);
+
+  free (Zvec.elements);
+
+  return (TRUE);
+
+}
+
+
Index: /branches/opihi-2-9/Ohana/src/opihi/include/astro.h
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/include/astro.h	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/include/astro.h	(revision 11389)
@@ -0,0 +1,13 @@
+# include "external.h"
+# include "shell.h"
+# include "dvomath.h"
+# include "convert.h"
+# include "display.h"
+# include "data.h"
+
+# ifndef ASTRO_H
+# define ASTRO_H
+
+void InitAstro ();
+
+# endif
Index: /branches/opihi-2-9/Ohana/src/opihi/include/basic.h
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/include/basic.h	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/include/basic.h	(revision 11389)
@@ -0,0 +1,7 @@
+# include "external.h"
+# include "shell.h"
+# include "dvomath.h"
+
+void cleanup ();
+void InitBasic ();
+void InitBasic_PantasksClient ();
Index: /branches/opihi-2-9/Ohana/src/opihi/include/convert.h
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/include/convert.h	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/include/convert.h	(revision 11389)
@@ -0,0 +1,25 @@
+# include "external.h"
+
+# ifndef CONVERT_H
+# define CONVERT_H
+
+/*** time/coord conversion functions not supplied by libohana ***/
+time_t        TimeRef               PROTO((double time, time_t TimeReference, int TimeFormat));
+double        TimeValue             PROTO((time_t time, time_t TimeReference, int TimeFormat));
+
+int           hh_hms                PROTO((double hh, int *hr, int *mn, double *sc));
+int           dd_dms                PROTO((double dd, int *dg, int *mn, double *sc));
+int           hms_format            PROTO((char *line, double value));
+int           dms_format            PROTO((char *line, double value));
+int           hh_hm                 PROTO((double hh, int *hr, double *mn));
+int           day_to_sec            PROTO((char *string, time_t *second));
+int           hms_to_sec            PROTO((char *string, time_t *second));
+char         *sec_to_hms            PROTO((time_t second));
+char         *sec_to_day            PROTO((time_t second));
+
+char         *meade_deg_to_str      PROTO((double deg));
+char         *meade_ra_to_str       PROTO((double deg));
+char         *meade_dec_to_str      PROTO((double deg));
+char         *strptime              PROTO((const char *s, const char *format, struct tm *tm));
+
+# endif
Index: /branches/opihi-2-9/Ohana/src/opihi/include/data.h
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/include/data.h	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/include/data.h	(revision 11389)
@@ -0,0 +1,168 @@
+# include "external.h"
+# include "shell.h"
+# include "dvomath.h"
+# include "convert.h"
+# include "display.h"
+
+# ifndef DATA_H
+# define DATA_H
+
+/*** typedef structs used by math functions ***/
+typedef struct {
+  int   NLINES;
+  int   Nlines;
+  char **lines;
+  char  *name;
+} Queue;
+
+typedef struct {
+  char *name;
+  int NWORDS;
+  int Nwords;
+  char **words;
+  char **value;
+} Page;
+
+typedef struct {
+  char *name;
+  int NPAGES;
+  int Npages;
+  Page **pages;
+  int *index;
+  char **pageIDs;
+} Book;
+
+void InitData ();
+
+/* in book.c */
+void InitBooks ();
+void InitBook (Book *book, char *name);
+void FreeBook (Book *book);
+Book *FindBook (char *name);
+Book *GetBook (int where);
+Book *CreateBook (char *name);
+int DeleteBook (Book *book);
+void ListBooks ();
+
+/* in page.c */
+void InitPage (Page *page, char *name);
+void FreePage (Page *page);
+Page *FindPage (Book *book, char *name);
+Page *GetPage (Book *book, int where);
+Page *GetPageRestricted (Book *book, int where, char *keyName, char *keyValue);
+Page *CreatePage (Book *book, char *name);
+int DeletePage (Book *book, Page *page);
+void ListPages (Book *book);
+void ListWords (Page *page);
+int BookSetWord (Page *page, char *word, char *value);
+char *BookGetWord (Page *page, char *word);
+
+/* in queues.c */
+void InitQueues ();
+void ListQueues ();
+Queue *FindQueue (char *name);
+Queue *CreateQueue (char *name);
+void PushQueue (Queue *queue, char *line);
+void PushNamedQueue (char *name, char *line);
+char *PopQueue (Queue *queue);
+char *PopQueueMatch (Queue *queue, char *Key, char *value);
+void PushQueueUnique (Queue *queue, char *line, char *Key);
+void PushQueueReplace (Queue *queue, char *line, char *Key);
+int InitQueue (Queue *queue);
+int DeleteQueue (Queue *queue);
+int PrintQueue (Queue *queue);
+
+/* in sort.c */
+void sort (double *value, int N);
+void fsort (float *value, int N);
+void sortpair (double *value1, double *value2, int N);
+void fsortpair (float *X, float *Y, int N);
+void sortthree (float *X, float *Y, float *Z, int N);
+void sort_lists (float *X, float *Y, int *S, int N);
+void dsort_lists (double *X, double *Y, int *S, int N);
+void isort_pair (int *X, int *Y, int N);
+
+/* in fft.c */
+void fft (float *Data, int N, int isign);
+void fftold (float *Data, int N, int isign);
+void fftN (float *data, int *nn, int ndim, int isign);
+int IsBinary (int N);
+void fourn (float *data, int *nn, int ndim, int isign);
+
+/* in gaussj.c */
+int gaussj (double **a, int n, double **b, int m);
+int fgaussj (float **a, int n, float **b, int m);
+
+/* in svdcmp.c */
+int svdcmp (float *a, float *w, float *v, int Nx, int Ny);
+
+/* in spline.c */
+void spline (float *x, float *y, int N, float *y2);
+float splint (float *x, float *y, float *y2, int N, float X);
+
+/* mrqmin.c */
+float mrqcof (float *x, float *y, float *dy, int Npts, 
+	      float *par, int Npar, float **ta, float **tb, 
+	      float (funcs)(float, float *, int, float *));
+
+float mrqmin (float *x, float *y, float *dy, int Npts, 
+	      float *par, int Npar, 
+	      float (funcs)(float, float *, int, float *), int VERBOSE);
+
+float mrqinit (float *x, float *y, float *dy, int Npts, 
+	       float *par, int Npar, 
+	       float (funcs)(float, float *, int, float *), int VERBOSE);
+
+float **mrqcovar (int Npar);
+
+void mrqfree (int Npar);
+
+/* mrq2dmin.c */
+float mrq2dcof (float *x, float *t, float *y, float *dy, int Npts, 
+		float *par, int Npar, float **ta, float **tb, 
+		float (funcs)(float, float, float *, int, float *));
+
+float mrq2dmin (float *x, float *t, float *y, float *dy, int Npts, 
+		float *par, int Npar, 
+		float (funcs)(float, float, float *, int, float *), int VERBOSE);
+
+float mrq2dinit (float *x, float *t, float *y, float *dy, int Npts, 
+		 float *par, int Npar, 
+		 float (funcs)(float, float, float *, int, float *), int VERBOSE);
+
+float mrq2dchi (float *x, float *t, float *y, float *dy, int Npts, 
+		float *par, int Npar, 
+		float (funcs)(float, float, float *, int, float *));
+
+int mrq2dlimits (float *pmin, float *pmax, int Npar);
+
+float **mrq2dcovar (int Npar);
+
+void mrq2dfree (int Npar);
+
+/* powell.c */
+void powell (float *p, int Npar, float (func)() );
+
+/* gaussian.c */
+double gaussian (double x, double mean, double sigma);
+void gauss_init (int Nbin);
+double rnd_gauss (double mean, double sigma);
+
+/* starfuncs.c */
+double get_aperture_stats (Matrix *matrix, int X, int Y, int Npix, int Nborder, double max);
+int set_rough_radii (double Ra, double Ri, double Ro);
+int get_rough_star (float *data, int Nx, int Ny, int x, int y, float *xc, float *yc, float *sx, float *sy, float *sxy, float *zs, float *zp, float *sk);
+
+/* precess.c */
+double BtoJ (double in_epoch);
+double get_epoch (char *in_epoch, char mode);
+
+/* graphtools.c */
+void          SetLimits             PROTO((Vector *xvec, Vector *yvec, Graphdata *graphmode));
+void          SetLimitsRaw          PROTO((float *xvec, float *yvec, int Npts, Graphdata *graphmode));
+void          ApplyLimits           PROTO((int Xgraph, Graphdata *graphmode, int apply));
+int           style_args            PROTO((Graphdata *graphmode, int *argc, char **argv, int Nforce));
+
+int read_table_vectors (int argc, char **argv, char *extname);
+# endif
+
Index: /branches/opihi-2-9/Ohana/src/opihi/include/dimm.h
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/include/dimm.h	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/include/dimm.h	(revision 11389)
@@ -0,0 +1,71 @@
+# include "external.h"
+# include "shell.h"
+# include "dvomath.h"
+# include "convert.h"
+# include "display.h"
+# include "sbig.h"
+
+void InitDIMM ();
+
+/* telescope.c */
+double distSky (double r1, double r2, double d1, double d2);
+int getRD (double *r, double *d) ;
+int gotoRD (double r, double d);
+int offset (char *direction, double distance);
+int toffset (char *direction, char *rate, double duration);
+int getXY (double *x, double *y);
+int setRD (double r, double d);
+int setSite (char *sitename, double lon, double lat);
+int setTime (char *lst);
+int getSite (double *lon, double *lat, double *lst);
+int ParkScope();
+int SleepScope();
+int WakeScope();
+
+/* Serial.c */
+int SerialVerbose (int mode);
+int SerialInit (char *port);
+int SerialOpen (char *port);
+int SerialBaudRate (int fdesc, int rate);
+int SerialParity (int fdesc, int parity); 
+int SerialDataBits(int fdesc, int bits); 
+int SerialStopBit(int fdesc, int stpbit); 
+void SerialStop (int fdesc);
+int SerialCommand (char *in, char **out, int wait);
+
+/* camera.c */
+int InitCamera (int port);
+void DumpCameraInfo ();
+void CameraFullSize (int *x, int *y);
+int SetTemperature (double temp);
+double GetTemperature ();
+int DumpCameraStatus ();
+int Exposure (double exptime);
+static int readout_callback (float percent);
+int ReadOut (int x, int y, int dx, int dy, int binning, unsigned short *buffer);
+int OpenShutter ();
+int CloseShutter ();
+
+  /* this image structure stuff is considered for further development */ 
+# if (0)
+/** this Image is incompatible with the DVO Image struct */
+typedef struct {
+
+  /* image data area */
+  int Nx, Ny;
+  char *buffer;
+  int Nbytes;
+
+  /* image metadata */
+  double ccdtemp;
+  double airtemp;
+  double ra, dec, airmass;
+  double exptime;
+  int binning;
+} Image;
+
+/* analysis.c */
+int subtractImage (Image *a, Image *b);
+void statsImage (Image *image, Stats *stats);
+void findStars (Image *image, Stars **stars, int *Nstars, double threshold);
+# endif
Index: /branches/opihi-2-9/Ohana/src/opihi/include/display.h
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/include/display.h	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/include/display.h	(revision 11389)
@@ -0,0 +1,57 @@
+# include "external.h"
+# include "kapa.h"
+
+# ifndef DISPLAY_H
+# define DISPLAY_H
+
+# if (0)
+typedef struct {
+  double xmin, xmax, ymin, ymax;
+  int style, ptype, ltype, etype, ebar, color;
+  double lweight, size;
+  Coords coords;
+  int flipeast, flipnorth;
+  char axis[8], labels[8], ticks[8];
+} Graphdata;
+# endif
+
+/*** plotting functions ***/
+int           GetCurrentDevice      PROTO((void));
+int           PrepPlotting          PROTO((int Npts, Graphdata *graphmode));
+int           PlotVector            PROTO((int, float *));
+int           GetGraphData          PROTO((Graphdata *data, int *sock, int *N));
+int           GetGraph              PROTO((Graphdata *data, int *socket, int *N));
+void          InitGraph             PROTO((void));
+int           open_graph            PROTO((int N));
+int           close_graph           PROTO((int N));
+void          QuitGraph             PROTO((void));
+void          SetGraph              PROTO((Graphdata data));
+void          XGraphDead            PROTO((int input));
+int           GetColor              PROTO((char *name));
+
+/* image (tv) functions */
+int           GetImage              PROTO((int *socket, int *N));
+char         *GetImageName          PROTO((void));
+void          GetImageScale         PROTO((double *zero, double *range));
+void          InitImage             PROTO((void));
+int           open_image            PROTO((int N));
+int           close_image           PROTO((int N));
+void          QuitImage             PROTO((void));
+void          SetImageDevice        PROTO((int state));
+void          SetImageName          PROTO((char *name));
+void          SetImageScale         PROTO((double zero, double range));
+void          XImageDead            PROTO((int input));
+int           SelectOverlay         PROTO((char *name, int *number));
+
+/* calling program need to define a function 'get_variable' which
+ * returns the name of the executable for each of KAPA and KII
+ */
+char         *get_variable          PROTO((char *name));
+
+int SendLabel (char *string, int Xgraph, int mode);
+
+int SendGraphMessage (int device, char *format, ...);
+int SendGraphCommand (int device, int length, char *format, ...);
+int SendGraphCommandV (int device, int length, char *format, va_list argp);
+
+# endif
Index: /branches/opihi-2-9/Ohana/src/opihi/include/dvomath.h
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/include/dvomath.h	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/include/dvomath.h	(revision 11389)
@@ -0,0 +1,117 @@
+/*** dvomath.h ***/
+
+# ifndef DVOMATH_H
+# define DVOMATH_H
+
+# define NCHARS 256
+
+enum {ANYVECTOR, NEWVECTOR, OLDVECTOR};
+enum {ANYBUFFER, NEWBUFFER, OLDBUFFER};
+
+typedef struct {			/* representation of a variable (0-D) */
+  char     *name;
+  char     *value;
+} Variable;
+
+typedef struct {			/* representation of a vector (1-D) */
+  char name[1024];
+  float *elements;
+  int Nelements;
+} Vector;
+
+typedef struct {			/* representation of buffer (image) */
+  char name[1024];
+  char file[1024];
+  Header header;
+  Matrix matrix;
+  int  bitpix, unsign;
+  double bscale, bzero;
+} Buffer;
+
+typedef struct {			/* math stack structure */
+  char   *name;
+  char    type;
+  float  *ptr;
+  Buffer *buffer;
+  Vector *vector;
+  float   Float;
+} StackVar;
+
+/* math functions */
+char         *dvomath               PROTO((int argc, char **argv, int *size, int maxsize));
+char        **isolate_elements      PROTO((int argc, char **argv, int *nstack));
+StackVar     *convert_to_RPN        PROTO((int argc, char **argv, int *nstack));
+int           check_stack           PROTO((StackVar *stack, int Nstack, int validsize));
+int           evaluate_stack        PROTO((StackVar *stack, int *Nstack));
+void          init_stack            PROTO((StackVar *stack));
+void          copy_stack	    PROTO((StackVar *stack1, StackVar *stack2));
+void          move_stack	    PROTO((StackVar *stack1, StackVar *stack2));
+void          clean_stack	    PROTO((StackVar *stack, int Nstack));
+void          delete_stack	    PROTO((StackVar *stack, int Nstack));
+int           VV_binary             PROTO((StackVar *OUT, StackVar *V1, StackVar *V2, char *op));
+int           SV_binary             PROTO((StackVar *OUT, StackVar *V1, StackVar *V2, char *op));
+int           VS_binary             PROTO((StackVar *OUT, StackVar *V1, StackVar *V2, char *op));
+int           MV_binary             PROTO((StackVar *OUT, StackVar *V1, StackVar *V2, char *op));
+int           VM_binary             PROTO((StackVar *OUT, StackVar *V1, StackVar *V2, char *op));
+int           MM_binary             PROTO((StackVar *OUT, StackVar *V1, StackVar *V2, char *op));
+int           MS_binary             PROTO((StackVar *OUT, StackVar *V1, StackVar *V2, char *op));
+int           SM_binary             PROTO((StackVar *OUT, StackVar *V1, StackVar *V2, char *op));
+int           SS_binary             PROTO((StackVar *OUT, StackVar *V1, StackVar *V2, char *op));
+int           WW_binary             PROTO((StackVar *OUT, StackVar *V1, StackVar *V2, char *op));
+int           S_unary               PROTO((StackVar *OUT, StackVar *V1, char *op));
+int           V_unary               PROTO((StackVar *OUT, StackVar *V1, char *op));
+int           M_unary               PROTO((StackVar *OUT, StackVar *V1, char *op));
+
+/* variable handling */
+char         *get_variable          PROTO((char *name));
+char         *get_variable_ptr      PROTO((char *name));
+char         *get_local_variable_ptr PROTO((char *name));
+double        get_double_variable   PROTO((char *name, int *found));
+int           get_int_variable      PROTO((char *name, int *found));
+int           DeleteNamedScalar     PROTO((char *name));
+int           IsScalar              PROTO((char *name));
+int           set_variable          PROTO((char *name, double dvalue));
+int           set_int_variable      PROTO((char *name, int ivalue));
+int           set_str_variable      PROTO((char *name, char *value));
+int           set_local_variable    PROTO((char *name, char *value));
+void          InitVariables         PROTO((void));
+void          ListVariables         PROTO((void));
+float         get_variable_default  PROTO((char *name, float dvalue));
+int           SelectScalar          PROTO((char *string, double *value));
+
+/* vector handling */
+Vector       *InitVector            PROTO((void));
+void          InitVectors           PROTO((void));
+int           CopyVector            PROTO((Vector *out, Vector *in));
+int           MoveVector            PROTO((Vector *out, Vector *in));
+int           DeleteVector          PROTO((Vector *vec));
+int           CopyNamedVector       PROTO((char *out, char *in));
+int           MoveNamedVector       PROTO((char *out, char *in));
+int           DeleteNamedVector     PROTO((char *name));
+int           IsVector              PROTO((char *name));
+int           IsVectorPtr           PROTO((Vector *vec));
+int           ListVectors           PROTO((void));
+Vector       *SelectVector          PROTO((char *name, int mode, int verbose));
+
+/* buffer handling */
+Buffer       *InitBuffer            PROTO((void));
+void          InitBuffers           PROTO((void));
+int           CopyBuffer            PROTO((Buffer *out, Buffer *in));
+int           MoveBuffer            PROTO((Buffer *out, Buffer *in));
+int           DeleteBuffer          PROTO((Buffer *buf));
+int           CopyNamedBuffer       PROTO((char *out, char *in));
+int           MoveNamedBuffer       PROTO((char *out, char *in));
+int           DeleteNamedBuffer     PROTO((char *name));
+int           IsBuffer              PROTO((char *name));
+int           IsBufferPtr           PROTO((Buffer *buf));
+int           PrintBuffers          PROTO((int Long));
+int           CreateBuffer          PROTO((Buffer *buf, int Nx, int Ny, int bitpix, float bzero, float bscale));
+Buffer       *SelectBuffer          PROTO((char *name, int mode, int verbose));
+void          dump_buffers          PROTO((int n));  /* deprecated? */
+int           SelectOverlay         PROTO((char *name, int *number));
+
+/* why are these in here? */
+int           gfits_copy_matrix_info (Matrix *matrix1, Matrix *matrix2);
+int           GetTimeFormat         PROTO((time_t *TimeReference, int *TimeFormat));
+
+# endif
Index: /branches/opihi-2-9/Ohana/src/opihi/include/dvoshell.h
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/include/dvoshell.h	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/include/dvoshell.h	(revision 11389)
@@ -0,0 +1,98 @@
+# include "data.h"
+# include "basic.h"
+# include "astro.h"
+
+# ifndef DVOSHELL_H
+# define DVOSHELL_H
+
+/* magnitude types */
+enum {MAG_NONE, MAG_INST, MAG_CAT, MAG_SYS, MAG_REL, MAG_CAL, MAG_AVE, MAG_REF};
+
+/* measure params */
+enum {MEAS_ZERO, MEAS_RA, MEAS_DEC, MEAS_MAG, MEAS_dMAG, MEAS_MINST, MEAS_MCAT, 
+      MEAS_MSYS, MEAS_MREL, MEAS_MCAL, MEAS_PHOTCODE, MEAS_TIME, MEAS_dR, MEAS_dD, 
+      MEAS_FWHM, MEAS_DOPHOT, MEAS_XCCD, MEAS_YCCD, MEAS_XMOSAIC, MEAS_YMOSAIC, MEAS_FLAGS, MEAS_EXPTIME, MEAS_AIRMASS};
+
+/* average params */
+enum {AVE_ZERO, AVE_RA, AVE_DEC, AVE_RA_ERR, AVE_DEC_ERR, AVE_U_RA, AVE_U_DEC, 
+      AVE_U_RA_ERR, AVE_U_DEC_ERR, AVE_PAR, AVE_PAR_ERR, AVE_MAG, AVE_REF, AVE_dMAG, 
+      AVE_Xm, AVE_Xp, AVE_NMEAS, AVE_NMISS, AVE_TYPE, AVE_NPHOT, AVE_NCODE, AVE_NCRIT, 
+      AVE_FLAG, AVE_TYPEFRAC};
+
+typedef struct {
+  char name[64];
+  double RA0, RA1, DEC0, DEC1;
+} RegionFile;
+
+typedef struct {
+  double X;
+  double Y;
+  double R;
+  double D;
+  double M, dM;
+  char   dophot;
+  double sky;
+  double fx, fy, df;
+  double Mgal, Map;
+  int found;
+  short int code;
+  e_time t;
+} CMPstars;
+
+/*** dvo prototypes ***/
+int           DetermineTypeCode     PROTO((Average *average, Measure *measure, int code));
+double        DetermineTypefrac     PROTO((Average *average, Measure *measure, PhotCode *code));
+double        ExtractAverages       PROTO((PhotCode *code, int mode, Average *average, SecFilt *secfilt, Measure *measure, int param));
+double       *ExtractByDMag         PROTO((PhotCode **code, int *mode, Average *average, SecFilt *secfilt, Measure *measure, int *nlist, int param));
+double       *ExtractDMag           PROTO((PhotCode **code, int *mode, Average *average, SecFilt *secfilt, Measure *measure, int *nlist));
+double       *ExtractMagnitudes     PROTO((PhotCode *code, int mode, Average *average, SecFilt *secfilt, Measure *measure, int *n));
+double       *ExtractMeasures       PROTO((PhotCode *code, int mode, Average *average, SecFilt *secfilt, Measure *measure, int *nlist, int param));
+double       *ExtractMeasuresByDMag PROTO((PhotCode **code, int *mode, int use_first, Average *average, SecFilt *secfilt, Measure *measure, int *nlist, int param));
+double       *ExtractMeasuresDMag   PROTO((PhotCode **code, int *mode, Average *average, SecFilt *secfilt, Measure *measure, int *nlist));
+void          FreeImageSelection    PROTO(());
+void          FreeImageSelection    PROTO(());
+int           GetAverageParam       PROTO((char *parname));
+void          GetAverageParamHelp   PROTO(());
+int           GetMagMode            PROTO((char *string));
+double        GetMeasure            PROTO((int param, Average *average, Measure *measure, double mag));
+int           GetMeasureParam       PROTO((char *parname));
+int           GetMeasureTypeCode    PROTO((Measure *measure));
+int           GetPhotcodeInfo       PROTO((char *string, PhotCode **Code, int *Mode));
+int           GetSelectionParam     PROTO(());
+int           GetTimeSelection      PROTO((time_t *tz, time_t *te));
+void          InitDVO               PROTO(());
+int           InitPhotcodes         PROTO(());
+Image        *LoadImages            PROTO((int *Nimage));
+Image        *MatchImage            PROTO((unsigned int time, short int source));
+Image        *MatchImage            PROTO((unsigned int time, short int source));
+Coords       *MatchMosaic           PROTO((unsigned int time, short int source));
+int           Quality               PROTO((Measure *measure, int IsDophot));
+int           SelectMags            PROTO((int Nphot, int Tphot, int Ns, Average *average, Measure *measure, SecFilt *secfilt, int UL));
+
+SkyList      *SelectRegions         PROTO((char *RegionName, char *RegionList));
+SkyList      *SkyListLoadFile       PROTO((char *filename));
+int           SetCATDIR             PROTO((char *path, int verbose));
+char *        GetCATDIR             PROTO(());
+SkyTable     *GetSkyTable           PROTO(());
+SkyList      *SkyListFromFile       PROTO((char *filename));
+int           SetRegionSelection    PROTO((int *argc, char **argv, char **RegionName, char **RegionList));
+
+int           SetImageSelection     PROTO((int mode, int RegionSelect));
+int           SetPhotSelections     PROTO((int *argc, char **argv, int Nparams));
+int           SetSelectionParam     PROTO((int param));
+int           TestAverage           PROTO((PhotCode *code, Average *average, SecFilt *secfilt, Measure *measure));
+int           TestPhotSelections    PROTO((PhotCode **code, int *mode, int param));
+void          compare               PROTO((Catalog *catlog1, Catalog *catlog2, Vector *rvec,  Vector *dvec,  Vector *mvec, Vector *drvec, Vector *ddvec, Vector *dmvec, double radius));
+void          cprecess              PROTO((Average *average, int Naverage, double in_epoch, double out_epoch));
+void          image_subset          PROTO((Image *image, int Nimage, int **Subset, int *Nsubset, Graphdata *graph, int RegionSelect, unsigned long int tzero, double trange, int TimeSelect));
+int           match_image           PROTO((Image *image, int Nimage, unsigned int T, short int S));
+int           match_image_subset    PROTO((Image *image, int *subset, int Nsubset, unsigned int T, short int S));
+void          print_value           PROTO((double value, short int ival));
+void          sort_image_subset     PROTO((Image *image, int *subset, int N));
+void          sort_images           PROTO((Image *image, int N));
+void          sortave               PROTO((Average *ave, int N));
+CMPstars     *cmpReadFits           PROTO((FILE *f, int *nstars));
+CMPstars     *cmpReadText           PROTO((FILE *f, int *nstars));
+int           RD_to_XYpic           PROTO((double *x, double *y, double r, double d, Coords *coords, double Rmin, double Rmax, double Rmid, int *leftside));
+
+# endif
Index: /branches/opihi-2-9/Ohana/src/opihi/include/external.h
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/include/external.h	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/include/external.h	(revision 11389)
@@ -0,0 +1,30 @@
+# include <signal.h>
+# include <unistd.h>
+# include <sys/uio.h>
+# include <fcntl.h>
+# include <sys/types.h>
+# include <sys/wait.h>
+# include <sys/socket.h>
+# include <sys/un.h>
+# include <sys/time.h>
+# include <time.h>
+# include <errno.h>
+# include <pthread.h>
+
+# include <netinet/ip.h>
+# include <netdb.h>
+# include <arpa/inet.h>
+
+# include <ohana.h>
+# include <dvo.h>
+
+/* provide missing external defines */
+# ifdef MISSING_SOCKET_INFO
+#   define F_SETFL         4   
+#   define O_NONBLOCK       0200000  
+#   define AF_UNIX         1          
+#   define SOCK_STREAM     1          
+#   define ENOENT          2 
+# endif
+
+# define strlen(A) ((int)strlen(A))
Index: /branches/opihi-2-9/Ohana/src/opihi/include/hstgsc.h
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/include/hstgsc.h	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/include/hstgsc.h	(revision 11389)
@@ -0,0 +1,27 @@
+
+static double BigDecBounds[] = {0.0, 7.5, 15.0, 22.5, 30.0, 37.5, 45.0, 
+				52.5, 60.0, 67.5, 75.0, 82.5, 90.0,
+				0.0, -7.5, -15.0, -22.5, -30.0, -37.5, -45.0, 
+				-52.5, -60.0, -67.5, -75.0, -82.5, -90.0};
+static char *Dec2Sections[] = {"n0000", "n0730", "n1500", "n2230", "n3000", "n3730", "n4500", 
+			       "n5230", "n6000", "n6730", "n7500", "n8230", "weirdness", 
+			       "s0000", "s0730", "s1500", "s2230", "s3000", "s3730", "s4500", 
+			       "s5230", "s6000", "s6730", "s7500", "s8230", "weirdness"};
+
+static int NDecLines[] = {593, 584, 551, 530, 522, 465, 406, 362, 280, 198, 123, 24, 
+			  0, 597, 578, 574, 577, 534, 499, 442, 376, 294, 212, 144, 48};
+
+/** older data layout concepts 
+static char *DecSections[] = {"N0000", "N0730", "N1500", "N2230", "N3000", "N3730", "N4500", 
+			      "N5230", "N6000", "N6730", "N7500", "N8230", "weirdness", 
+			      "S0000", "S0730", "S1500", "S2230", "S3000", "S3730", "S4500", 
+			      "S5230", "S6000", "S6730", "S7500", "S8230", "weirdness"};
+
+static char *disk[] = {"disk 1", "disk 1", "disk 1", "disk 1", "disk 1", "disk 1", "disk 1", 
+		       "disk 1", "disk 1", "disk 1", "disk 1", "disk 1", "weirdness", 
+		       "disk 1", "disk 2", "disk 2", "disk 2", "disk 2", "disk 2", "disk 2", 
+		       "disk 2", "disk 2", "disk 2", "disk 2", "disk 2", "weirdness"};
+
+static int NBigRASections [] = {48, 47, 45, 43, 40, 36, 32, 28, 21, 15, 9, 3, 3, 48, 47, 45, 43, 40, 36, 32, 28, 21, 15, 9, 3, 3};
+
+**/
Index: /branches/opihi-2-9/Ohana/src/opihi/include/imfit.h
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/include/imfit.h	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/include/imfit.h	(revision 11389)
@@ -0,0 +1,20 @@
+# include "astro.h"
+
+int Npar;
+int Nfpar;
+float *par;
+float *fpar;
+float *sky;
+
+float (*fitfunc)(float, float, float *, int, float *);
+void (*imfit_cleanup)();
+
+void fgauss_setup (char *name);
+void pgauss_setup (char *name);
+void sgauss_setup (char *name);
+void qgauss_setup (char *name);
+void Pgauss_setup (char *name);
+void Sgauss_setup (char *name);
+void Qgauss_setup (char *name);
+void qfgauss_setup (char *name);
+void qrgauss_setup (char *name);
Index: /branches/opihi-2-9/Ohana/src/opihi/include/mana.h
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/include/mana.h	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/include/mana.h	(revision 11389)
@@ -0,0 +1,10 @@
+# include "data.h"
+# include "basic.h"
+# include "astro.h"
+
+# ifndef MANA_H
+
+void InitMana ();
+int *findrowpeaks (float *row, int Nrow, float threshold, int *npeaks);
+
+# endif
Index: /branches/opihi-2-9/Ohana/src/opihi/include/opihi.h
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/include/opihi.h	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/include/opihi.h	(revision 11389)
@@ -0,0 +1,5 @@
+# include "external.h"
+# include "shell.h"
+# include "dvomath.h"
+# include "convert.h"
+# include "display.h"
Index: /branches/opihi-2-9/Ohana/src/opihi/include/pantasks.h
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/include/pantasks.h	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/include/pantasks.h	(revision 11389)
@@ -0,0 +1,263 @@
+# include "data.h"
+# include "basic.h"
+# include "astro.h"
+
+# include <sys/time.h>
+# include <time.h>
+# include <zlib.h>
+
+typedef enum {
+  JOB_NONE,
+  JOB_BUSY, 
+  JOB_EXIT, 
+  JOB_HUNG,
+  JOB_CRASH,
+  JOB_PENDING,
+} JobStat;
+
+typedef enum {
+  JOB_LOCAL, 
+  JOB_CONTROLLER, 
+} JobMode;
+
+typedef enum {
+  CONTROLLER_HUNG = -1,
+  CONTROLLER_DOWN = 0,
+  CONTROLLER_GOOD = 1,
+} ControllerStat;
+
+enum {RANGE_ABS, RANGE_DAY, RANGE_WEEK};
+enum {TIMER_ALLJOBS, TIMER_SUCCESS, TIMER_FAILURE};
+
+enum {TASK_NONE, 
+      TASK_EMPTY, 
+      TASK_COMMENT, 
+      TASK_NMAX, 
+      TASK_ACTIVE, 
+      TASK_TRANGE, 
+      TASK_END, 
+      TASK_HOST, 
+      TASK_STDOUT, 
+      TASK_STDERR, 
+      TASK_COMMAND, 
+      TASK_OPTIONS, 
+      TASK_PERIODS, 
+      TASK_NPENDING, 
+      TASK_EXIT, 
+      TASK_EXEC
+} TaskHashResults;
+
+typedef struct {
+  time_t start;
+  time_t stop;
+  char type;
+  char include;
+  int Nmax;
+  int Nrun;
+} TimeRange;
+
+/* a task is a description of the wrapping of a job */
+typedef struct {
+  Macro  *exec;				/* name is 'exec' */
+  Macro  *crash;			/* name is 'crash' */
+  Macro  *timeout;
+  Macro  *defexit;
+
+  int     NEXIT;
+  int     Nexit;
+  Macro **exit;				/* name is exit status */
+
+  int     argc;
+  char  **argv;
+
+  int     optc;
+  char  **optv;
+
+  char   *host;
+  int     host_required;
+
+  char   *name;
+
+  char   *stdout_dump;
+  char   *stderr_dump;
+
+  int       Nranges;
+  TimeRange *ranges;
+
+  int     Nmax;  // only construct Ntotal jobs for this task
+  int     Njobs;
+
+  int     Npending;  // number of currently pending jobs
+  int     NpendingMax;  // max number of pending jobs allowed
+
+  float   poll_period;
+  float   exec_period;
+  float   timeout_period;
+
+  struct timeval last;
+
+  int Nsuccess;
+  int Nfailure;
+  int Ntimeout;
+
+  double dtimeAve_alljobs, dtimeMin_alljobs, dtimeMax_alljobs;
+  double dtimeAve_success, dtimeMin_success, dtimeMax_success;
+  double dtimeAve_failure, dtimeMin_failure, dtimeMax_failure;
+
+  int active;
+
+} Task;
+
+// time period include/exclude periods: 
+// date ranges (e_time - e_time) 
+// time ranges (e_time - e_time) (use e_time % 86400)
+// time-of-week ranges  (e_time - e_time
+// -trange Mon Fri (inclusive on days -- end defaults to Fri@23:59:59)
+// -trange 08:00 - 17:00
+// -trange 2005/12/24 2005/12/31
+// be careful of HST!
+// type: day, week, date
+// keep: TRUE: perform action within this time period
+// keep: FALSE: do not perform action within this time period
+  
+typedef struct {
+  int JobID;				/* internal ID for job */
+  int pid;				/* external ID for job */
+
+  struct timeval last;
+  struct timeval start;
+  int state;
+  int exit_status;
+
+  int     argc;
+  char  **argv;
+
+  int     optc;
+  char  **optv;
+
+  Task   *task;
+
+  IOBuffer    stdout;			/* stdout storage buffer */
+  IOBuffer    stderr;			/* stderr storage buffer */
+  JobMode     mode;			/* local or controller? */
+
+  char   *stdout_dump;
+  char   *stderr_dump;
+  char   *realhost;
+
+  int         stdout_size;		/* size of pending stdout buffer (controller) */
+  int         stderr_size;		/* size of pending stderr buffer (controller) */
+  int         stdout_fd;		/* stdout pipe (local only) */
+  int         stderr_fd;		/* stderr pipe (local only) */
+
+  double dtime;
+} Job;
+
+# define CONTROLLER_PROMPT "pcontrol:"
+
+/* scheduler prototypes */
+
+void InitPantasks ();
+void InitPantasksServer ();
+void InitPantasksClient ();
+void InitTasks ();
+Task *NextTask ();
+Task *FindTask (char *name);
+void ListTasks (int verbose);
+int ShowTask (char *name);
+int FreeTask (Task *task);
+Task *CreateTask (char *name);
+int ValidateTask (Task *task, int RequireStatic);
+int RegisterNewTask ();
+int DeleteNewTask ();
+Task *GetNewTask ();
+Task *GetActiveTask ();
+void SetTaskTimer (struct timeval *timer);
+double GetTaskTimer (struct timeval start);
+void InitTaskTimers ();
+int TaskHash (char *input);
+int RemoveTask (Task *task);
+Task *SetNewTask (Task *task);
+void ListTaskStats (char *regex);
+void UpdateTaskTimerStats (Task *task, int mode, double dtime);
+
+int NextJobID ();
+int InitJobIDs ();
+int FreeJobID (int ID);
+
+void InitJobs ();
+Job *NextJob ();
+Job *FindJob (int JobID);
+void ListJobs ();
+Job *CreateJob (Task *task);
+int SubmitJob (Job *job);
+int CheckJob (Job *job);
+int DeleteJob (Job *job);
+void FreeJob (Job *job);
+
+int CheckJobs ();
+int CheckTasks ();
+int CheckSystem ();
+int CheckController ();
+int CheckTimeRanges (TimeRange *ranges, int Nranges);
+int BumpTimeRanges (TimeRange *ranges, int Nranges);
+
+int GetJobOutput (char *channel, int pid, IOBuffer *buffer, int Nbytes);
+int CheckControllerJob (Job *job);
+int CheckControllerJobStatus (Job *job);
+int SubmitControllerJob (Job *job);
+int DeleteControllerJob (Job *job);
+Job *FindControllerJob (int JobID);
+int StartController ();
+int ControllerCommand (char *command, char *response, IOBuffer *buffer);
+int SubmitLocalJob (Job *job);
+int CheckLocalJob (Job *job);
+int CheckLocalJobStatus (Job *job);
+void InitTaskTimers ();
+CommandF *FindControllerCommand (char *cmd);
+int QuitController ();
+int StopController ();
+int VerboseMode ();
+int KillLocalJob (Job *job);
+int CheckControllerOutput ();
+int PrintControllerOutput ();
+
+int KillControllerJob (Job *job);
+int CheckControllerStatus ();
+int TestElapsedCheck ();
+void gotsignal (int signum);
+int client_shell (int argc, char **argv);
+
+void InitClients ();
+void AddNewClient (int client);
+int  DeleteClient (int client);
+void *ListenClients (void *data);
+
+// functions related to the server threads
+void CheckTasksSetState (int state);
+int CheckTasksGetState ();
+void *CheckTasksThread (void *data);
+
+void CheckJobsSetState (int state);
+int CheckJobsGetState ();
+void *CheckJobsThread (void *data);
+
+void CheckControllerSetState (int state);
+int CheckControllerGetState ();
+void *CheckControllerThread (void *data);
+
+void CheckInputsSetState (int state);
+int CheckInputsGetState ();
+void *CheckInputsThread (void *data);
+
+// functions related to the queue of input files
+void InitInputs ();
+void AddNewInput (char *input);
+int DeleteInput (char *input);
+void CheckInputs ();
+
+void SerialThreadLock ();
+void SerialThreadUnlock ();
+
+int InitPassword ();
+int CheckPassword (int BindSocket);
Index: /branches/opihi-2-9/Ohana/src/opihi/include/pclient.h
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/include/pclient.h	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/include/pclient.h	(revision 11389)
@@ -0,0 +1,53 @@
+# include "data.h"
+# include "basic.h"
+
+/** pclient global data **/
+
+/** child status values **/
+enum {
+  PCLIENT_NONE,
+  PCLIENT_BUSY,  
+  PCLIENT_EXIT,
+  PCLIENT_CRASH,
+};
+
+int ChildPID;				/** current child PID **/
+int ChildStatus;			/** current status of child **/
+int ChildExitStatus;			/** recent exit status of child **/
+
+/** child may be in the following states:
+    
+PCLIENT_NONE
+PCLIENT_BUSY
+PCLIENT_EXIT
+PCLIENT_CRASH
+
+allowed transitions:
+
+PCLIENT_NONE  ->    PCLIENT_BUSY  (start a job)
+
+PCLIENT_BUSY  ->    PCLIENT_EXIT  (job complete)
+PCLIENT_BUSY  ->    PCLIENT_CRASH (job crashed)
+
+PCLIENT_EXIT  ->    PCLIENT_NONE  (cleanup)
+PCLIENT_CRASH ->    PCLIENT_NONE  (cleanup)
+
+**/
+
+/** file descriptors for child I/O **/
+int child_stdin_fd[2];
+int child_stdout_fd[2];
+int child_stderr_fd[2];
+
+/** buffers for I/O storage **/
+IOBuffer child_stdout;
+IOBuffer child_stderr;
+
+int InitChild ();
+int CheckChild ();
+void CheckChildStatus ();
+
+void InitPclient ();
+void gotsignal (int signum);
+
+# define DTIME(A,B) ((A.tv_sec - B.tv_sec) + 1e-6*(A.tv_usec - B.tv_usec))
Index: /branches/opihi-2-9/Ohana/src/opihi/include/pcontrol.h
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/include/pcontrol.h	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/include/pcontrol.h	(revision 11389)
@@ -0,0 +1,222 @@
+# include "data.h"
+# include "basic.h"
+# define THREADED
+
+typedef struct timeval Ptime;
+typedef unsigned long long IDtype;
+
+/** job status values **/
+typedef enum {
+  PCONTROL_JOB_PENDING,
+  PCONTROL_JOB_BUSY,  
+  PCONTROL_JOB_HUNG,  
+  PCONTROL_JOB_DONE,  
+  PCONTROL_JOB_KILL,  
+  PCONTROL_JOB_EXIT,
+  PCONTROL_JOB_CRASH,
+} JobStat;
+
+/** job status values **/
+typedef enum {
+  PCONTROL_JOB_ANYHOST,
+  PCONTROL_JOB_WANTHOST,
+  PCONTROL_JOB_NEEDHOST,
+} JobMode;
+
+/** host status values **/
+typedef enum {
+  PCONTROL_HOST_IDLE,
+  PCONTROL_HOST_BUSY,  
+  PCONTROL_HOST_DOWN,
+  PCONTROL_HOST_DONE,
+  PCONTROL_HOST_OFF,
+} HostStat;
+
+typedef enum {
+  PCONTROL_RUN_UNKNOWN,
+  PCONTROL_RUN_NONE,
+  PCONTROL_RUN_HOSTS,
+  PCONTROL_RUN_REAP,
+  PCONTROL_RUN_ALL,
+} RunLevels;
+
+/* stack special positions */
+typedef enum {
+  STACK_TOP = 0,
+  STACK_BOTTOM = -1,
+} StackWhere;
+
+typedef enum {
+  PCLIENT_HUNG = -1,
+  PCLIENT_DOWN = 0,
+  PCLIENT_GOOD = 1,
+} PclientStat;
+
+typedef struct {
+  char *buffer;
+  int   Nalloc;
+  int   Nmaxread;
+  int   Nextra;
+  int   Nlast;
+  int   Nbuffer;
+} Fifo;
+
+/* data to define a job */
+typedef struct {
+  int          argc; 
+  char       **argv;
+  char        *hostname;
+  char        *realhost;
+  int          exit_status;
+  int          Reset;
+  int          stdout_size;
+  int          stderr_size;
+  JobMode      mode;
+  JobStat      state;
+  JobStat      stack;
+  IOBuffer     stdout;
+  IOBuffer     stderr;
+  Ptime        start;
+  Ptime        stop;
+  double       dtime;
+  int          pid;
+  IDtype       JobID;
+  struct Host *host;
+} Job;
+
+/* data to define a host machine */
+typedef struct {
+  char       *hostname;
+  int         stdin;
+  int         stdout;
+  int         stderr;
+  int         markoff;
+  int         pid;
+  HostStat    stack;
+  Ptime       lasttry;
+  Ptime       nexttry;
+  IDtype      HostID;
+  struct Job *job;
+} Host;
+
+typedef struct {
+  void **object;
+  char **name;
+  int   *id;
+  int    Nobject;
+  int    NOBJECT;
+# ifdef THREADED    
+  pthread_mutex_t mutex;
+# endif
+} Stack;
+
+/* XXX if this is hard-wired, we can't change shell name in StartHost */
+# define PCLIENT_PROMPT "pclient:"
+
+# define FREE(X) if (X != NULL) { free (X); }
+# define CLOSE(FD) { if (FD) close (FD); FD = 0; }
+# define DTIME(A,B) ((A.tv_sec - B.tv_sec) + 1e-6*(A.tv_usec - B.tv_usec))
+# define ZTIME(A) ((A.tv_sec == 0) && (A.tv_usec == 0))
+
+// # define ASSERT(TEST,STRING) { if (!(TEST)) { gprint (GP_ERR, "programming error: %s\n", STRING); abort (); }}
+// # define ABORT(STRING) { gprint (GP_ERR, "programming error: %s\n", STRING); abort (); }
+# define ASSERT(TEST,STRING) { if (!(TEST)) { gprint (GP_ERR, "programming error: %s\n", STRING); raise (SIGINT); exit (2); }}
+# define ABORT(STRING) { gprint (GP_ERR, "programming error: %s\n", STRING); raise (SIGINT); exit (2); }
+
+void InitPcontrol ();
+
+/*** StackOps.c ***/
+Stack *InitStack ();
+int    PushStack (Stack *stack, int where, void *object, int id, char *name);
+void  *PullStackByLocation (Stack *stack, int where);
+void  *PullStackByName (Stack *stack, char *name);
+void  *PullStackByID (Stack *stack, int id);
+int    RemoveStackEntry (Stack *stack, int where);
+void  *RemoveStackByID (Stack *stack, int id);
+void   LockStack (Stack *stack);
+void   UnlockStack (Stack *stack);
+
+// void  *FindStackByID (Stack *stack, int id);
+// void  *FindStackByName (Stack *stack, char *name);
+
+/*** CheckSystem.c ***/
+int   CheckSystem ();
+void *CheckSystem_Threaded (void *data);
+int   CheckBusyJobs (float delay);
+int   CheckDoneJobs (float delay);
+int   CheckKillJobs (float delay);
+int   CheckDoneHosts (float delay);
+int   CheckDownHosts (float delay);
+int   CheckIdleHosts (float delay);
+int   CheckLiveHosts (float delay);
+int   SetRunSystem (int state);
+
+/*** own files ***/
+int CheckHost (Host *host);
+int StartHost (Host *host);
+int CheckIdleHost (Host *host);
+int CheckDoneHost (Host *host);
+int CheckBusyJob (Job *job, Host *host);
+int CheckDoneJob (Job *job, Host *host);
+int KillJob (Job *job, Host *host);
+int StartJob (Job *job, Host *host);
+int ResetJob (Job *job);
+int GetJobOutput (char *command, Host *host, IOBuffer *buffer, int Nbytes);
+int PclientCommand (Host *host, char *command, char *response, IOBuffer *buffer);
+int rconnect (char *command, char *hostname, char *shell, int *stdio);
+
+/*** misc files ***/
+int    VerboseMode ();  // in verbose.c
+void   gotsignal (int signum); // in pcontrol.c
+
+/*** IDops.c ***/
+void InitIDs ();
+IDtype NextJobID ();
+IDtype NextHostID ();
+void PrintID (gpDest dest, IDtype ID);
+
+/*** CheckPoint.c ***/
+int SetCheckPoint ();
+int ClearCheckPoint ();
+int TestCheckPoint ();
+
+/*** HostOps.c ***/
+void   InitHostStacks ();
+Stack *GetHostStack (int StackID);
+char  *GetHostStackName (int StackID);
+Stack *GetHostStackByName (char *name);
+int    PutHost (Host *host, int StackID, int where);
+Host  *PullHostByID (IDtype HostID, int *StackID);
+Host  *PullHostByName (char *name, int *StackID);
+Host  *PullHostFromStackByID (int StackID, IDtype ID);
+Host  *PullHostFromStackByName (int StackID, char *name);
+IDtype AddHost (char *hostname);
+void   DelHost (Host *host);
+
+/*** StopHosts.c ***/
+void   DownHost (Host *host);
+void   OffHost (Host *host);
+int    DownHosts ();
+int    StopHost (Host *host);
+int    HarvestHost (int pid);
+
+/*** JobOps.c ***/
+void   InitJobStacks ();
+Stack *GetJobStack (int StackID);
+char  *GetJobStackName (int StackID);
+Stack *GetJobStackByName (char *name);
+int    PutJob (Job *job, int StackID, int where);
+int    PutJobSetState (Job *job, int StackID, int where, int state);
+Job   *PullJobByID (IDtype JobID, int *StackID);
+Job   *PullJobFromStackByID (int StackID, int ID);
+IDtype AddJob (char *hostname, JobMode mode, int timeout, int argc, char **argv);
+void   DelJob (Job *job);
+Host  *UnlinkJobAndHost (Job *job);
+void   LinkJobAndHost (Job *job, Host *host);
+
+// Job   *FindJobByID (IDtype JobID, int *StackID);
+// Job   *FindJobInStackByID (int StackID, int ID);
+// Host  *FindHostByID (IDtype HostID, int *StackID);
+// Host  *FindHostByName (char *name, int *StackID);
+// Host  *FindHostInStackByID (int StackID, IDtype ID);
+// Host  *FindHostInStackByName (int StackID, char *name);
Index: /branches/opihi-2-9/Ohana/src/opihi/include/shell.h
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/include/shell.h	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/include/shell.h	(revision 11389)
@@ -0,0 +1,166 @@
+/*** shell.h ***/
+# include "external.h"
+
+# ifndef SHELL_H
+# define SHELL_H
+
+# define ISVAR(a) (isalnum (a) || (a == ':') || (a == '_'))
+# define ISWORD(a,q) ((q) ? (a != '"') : (isalnum(a) || (a == '/') || (a == '.') || (a == '_') || (a == '-')))
+# define ISNUM(c) (isdigit(c) || (c == '-') || (c == '.'))
+
+# define MACRO_STRING(s) #s
+# define MACRO_NAME(s) MACRO_STRING(s)
+
+/* enums used by gprint functions */
+typedef enum {GP_FILE, GP_BUFF} gpMode;
+typedef enum {GP_LOG, GP_ERR} gpDest;
+
+typedef int CommandF ();
+
+typedef struct sockaddr_in SockAddress;
+
+/*** typedef structs used by shell functions ***/
+typedef struct {			/* basic opihi command structure */
+  char     *name;
+  CommandF *func;    
+  char     *help;
+} Command;
+
+typedef struct {			/* a macro (collection of commands) */
+  char   *name;
+  char  **line;
+  int     Nlines;
+} Macro;
+
+typedef struct {			/* a list (macro/loop currently being executed) */
+  char **line;
+  int    n;
+  int    Nlines;
+  int    Nalloc;
+} List;
+
+/* structure used to represent the gprint i/o stream */
+typedef struct {
+  FILE *file;
+  char *name;
+  IOBuffer *buffer;
+  gpMode mode;
+  gpDest dest;
+  pthread_t thread;
+} gpStream;
+
+/*** globals used to track the shell language concepts  ***/
+int 	     interrupt;			/* true if C-C has been pressed */
+int 	     auto_break;		/* if true, zero exit status forces macros to escape */
+int 	     loop_next; 		/* set to true when next (or continue) is called */
+int 	     loop_last; 		/* set to true when last (or return) is called */
+int 	     loop_break;		/* set to true when break is called */
+int          is_script;                 /* being run within a shell script */
+
+/*** basic opihi shell functions ***/
+void          general_init            	PROTO((int *argc, char **argv));
+void          program_init            	PROTO((int *argc, char **argv));
+void          startup               	PROTO((int *argc, char **argv));
+int           opihi                     PROTO((int argc, char **argv));
+int           multicommand          	PROTO((char *line));
+void          multicommand_InitServer   PROTO((void));
+int           command               	PROTO((char *line, char **outline, int VERBOSE));
+char         *expand_vars           	PROTO((char *line));
+char         *expand_vectors        	PROTO((char *line));
+char         *parse                 	PROTO((char *line));
+char        **parse_commands        	PROTO((char *, int *));
+void          welcome                   PROTO(());
+
+int           is_for_loop           	PROTO((char *line));
+int           is_if_block           	PROTO((char *line));
+int           is_list               	PROTO((char *line));
+int           is_loop               	PROTO((char *line));
+int           is_task               	PROTO((char *line));
+int           is_task_exit             	PROTO((char *line));
+int           is_task_exec             	PROTO((char *line));
+int           is_macro_create       	PROTO((char *line));
+void          InitLists                 PROTO(());
+int current_list_depth ();
+int increase_list_depth ();
+int decrease_list_depth ();
+char *get_next_listentry (int ThisList);
+
+void          InitCommands              PROTO(());
+void          AddCommand                PROTO((Command *new));
+int           DeleteCommand             PROTO((Command *command));
+Command      *MatchCommand              PROTO((char *name, int VERBOSE, int EXACT));
+void          sort_commands             PROTO((int *seq));
+
+void          SetCurrentMacroData	PROTO((char *name, int depth));
+Macro        *NewMacro			PROTO((char *name));
+int           DeleteMacro		PROTO((Macro *macro));
+Macro        *MatchMacro		PROTO((char *name, int VERBOSE, int EXACT));
+void          InitMacros                PROTO((void));
+char         *GetMacroName              PROTO((void));
+int           GetMacroDepth             PROTO((void));
+void          ListMacro                 PROTO((Macro *macro));
+void          ListMacros                PROTO(());
+void          FreeMacro                 PROTO((Macro *macro));
+CommandF     *find_macro_command        PROTO((char *name));
+
+int           exec_loop                 PROTO((Macro *loop));
+/* char         *get_next_listentry    	PROTO((int ThisList)); */
+/* char         *remove_listentry      	PROTO((int current)); */
+
+int           ConfigInit            	PROTO((int *argc, char **argv));
+char         *VarConfig             	PROTO((char *keyword, char *mode, void *ptr));
+char         *VarConfigEntry           	PROTO((char *keyword, char *mode, int entry, void *ptr));
+
+int           push_error                PROTO((char *line));
+int           print_error               PROTO((void));
+void          handle_interrupt      	PROTO((int));
+char        **command_completer     	PROTO((const char *, int, int));
+char         *command_generator     	PROTO((const char *text, int state));
+char        **completion_matches    	PROTO((char *, rl_compentry_func_t *));
+void          print_commands            PROTO((FILE *f));
+void          InitCommands              PROTO((void));
+
+/* command line parsing */
+char         *thisword              	PROTO((char *));
+char         *nextword              	PROTO((char *));
+char         *lastword              	PROTO((char *, char *));
+char         *thisvar               	PROTO((char *));
+char         *aftervar              	PROTO((char *));
+char         *lastvar               	PROTO((char *, char *));
+char         *thiscomm              	PROTO((char *));
+char         *nextcomm              	PROTO((char *));
+
+/* macro functions (mapped to commands) */
+int 	      macro_create 		PROTO((int, char **)); 
+int 	      macro_delete 		PROTO((int, char **)); 
+int 	      macro_edit   		PROTO((int, char **));
+int 	      macro_exec   		PROTO((int, char **));
+int 	      macro_list_f 		PROTO((int, char **));  /* "macro_list" is a readline func */
+int 	      macro_read   		PROTO((int, char **));
+int 	      macro_write   		PROTO((int, char **));
+
+char 	     *memstr        		PROTO((char *m1, char *m2, int n));
+int  	      write_fmt     		PROTO((int fd, char *format, ...));
+char 	     *opihi_version 		PROTO(());
+char 	     *strip_version 		PROTO((char *input));
+
+/* gprint functions */
+void          gprintInit      		PROTO(());
+gpStream     *gprintGetStream 		PROTO((gpDest dest));
+void          gprintSetBuffer 		PROTO((gpDest dest));
+IOBuffer     *gprintGetBuffer 		PROTO((gpDest dest));
+void          gprintSetFile   		PROTO((gpDest dest, char *filename));
+FILE         *gprintGetFile   		PROTO((gpDest dest));
+char         *gprintGetName   		PROTO((gpDest dest));
+int           gprint          		PROTO((gpDest dest, char *format, ...));
+int           gwrite          		PROTO((char *buffer, int size, int N, gpDest dest));
+
+/* socket functions */
+int InitServerSocket (SockAddress *Address);
+int WaitServerSocket (int InitSocket, SockAddress *Address);
+int GetClientSocket (char *hostname);
+int InitServerSocket_Named (char *hostname, SockAddress *Address);
+int DefineValidIP ();
+
+# endif
+
Index: /branches/opihi-2-9/Ohana/src/opihi/include/user.h
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/include/user.h	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/include/user.h	(revision 11389)
@@ -0,0 +1,260 @@
+int abszero         PROTO((int, char **));
+int applyfit        PROTO((int, char **));
+int applyfit2d      PROTO((int, char **));
+int badimages       PROTO((int, char **));
+int box             PROTO((int, char **));
+int calextract      PROTO((int, char **));
+int calmextract     PROTO((int, char **));
+int cals            PROTO((int, char **));
+int catlog          PROTO((int, char **));
+int ccd             PROTO((int, char **));
+int ccdextract      PROTO((int, char **));
+int center          PROTO((int, char **));
+int cgrid           PROTO((int, char **));
+int clear           PROTO((int, char **));
+int cmatch          PROTO((int, char **));
+int cmd             PROTO((int, char **));
+int cmdextract      PROTO((int, char **));
+int cmpread         PROTO((int, char **));
+int concat          PROTO((int, char **));
+int contour         PROTO((int, char **));
+int cplot           PROTO((int, char **));
+int create          PROTO((int, char **));
+int csystem         PROTO((int, char **));
+int ctimes          PROTO((int, char **));
+int cursor          PROTO((int, char **));
+int czplot          PROTO((int, char **));
+int datafile        PROTO((int, char **));
+int date            PROTO((int, char **));
+int ddmagextract    PROTO((int, char **));
+int ddmags          PROTO((int, char **));
+int delete          PROTO((int, char **));
+int device          PROTO((int, char **));
+int dmagaves        PROTO((int, char **));
+int dmagextract     PROTO((int, char **));
+int dmagmeas        PROTO((int, char **));
+int dmags           PROTO((int, char **));
+int dmt             PROTO((int, char **));
+int dumpmags        PROTO((int, char **));
+int elixir          PROTO((int, char **));
+int extract         PROTO((int, char **));
+int file            PROTO((int, char **));
+int fit             PROTO((int, char **));
+int fit2d           PROTO((int, char **));
+int gaussjordan     PROTO((int, char **));
+int gcat            PROTO((int, char **));
+int gimages         PROTO((int, char **));
+int grid            PROTO((int, char **));
+int gstar           PROTO((int, char **));
+int gtypes          PROTO((int, char **));
+int histogram       PROTO((int, char **));
+int images          PROTO((int, char **));
+int imbox           PROTO((int, char **));
+int imdata          PROTO((int, char **));
+int imdense         PROTO((int, char **)); 
+int imextract       PROTO((int, char **));
+int imlist          PROTO((int, char **));
+int imphot          PROTO((int, char **));
+int imrough         PROTO((int, char **));
+int imsearch        PROTO((int, char **));
+int imstats         PROTO((int, char **));
+int interpolate     PROTO((int, char **));
+int jpeg            PROTO((int, char **));
+int labels          PROTO((int, char **));
+int lcat            PROTO((int, char **));
+int lcurve          PROTO((int, char **));
+int limits          PROTO((int, char **));
+int list_buffers    PROTO((int, char **));
+int list_vectors    PROTO((int, char **));
+int mcreate         PROTO((int, char **));
+int mextract        PROTO((int, char **));
+int mget            PROTO((int, char **));
+int mset            PROTO((int, char **));
+int pcat            PROTO((int, char **));
+int photcodes       PROTO((int, char **));
+int photresid       PROTO((int, char **));
+int plot            PROTO((int, char **));
+int pmeasure        PROTO((int, char **));
+int precess         PROTO((int, char **));
+int print           PROTO((int, char **));
+int procks          PROTO((int, char **));
+int ps              PROTO((int, char **));
+int rd              PROTO((int, char **));
+int read_vectors    PROTO((int, char **));
+int region          PROTO((int, char **));
+int resid           PROTO((int, char **));
+int resize          PROTO((int, char **));
+int section         PROTO((int, char **));
+int set             PROTO((int, char **));
+int simage          PROTO((int, char **));
+int sort_vectors    PROTO((int, char **));
+int sprintf_opihi   PROTO((int, char **));
+int stats           PROTO((int, char **));
+int style           PROTO((int, char **));
+int subpix          PROTO((int, char **));
+int subraster       PROTO((int, char **));
+int subset          PROTO((int, char **));
+int textline        PROTO((int, char **));
+int tv              PROTO((int, char **));
+int uniq            PROTO((int, char **));
+int vectobuf        PROTO((int, char **));
+int vstat           PROTO((int, char **));
+int wd              PROTO((int, char **));
+int write_vectors   PROTO((int, char **));
+int zap             PROTO((int, char **));
+int zeropts         PROTO((int, char **));
+int zplot           PROTO((int, char **));
+
+static Command user[] = {  
+  {"abszero", 	   abszero,       "find filter zeropts"},
+  {"applyfit",     applyfit,      "apply fit to new vector"},
+  {"applyfit2d",   applyfit2d,    "apply 2-d fit to new vector"},
+  {"badimages",    badimages,     "look for images with anomalous astrometry"},
+  {"badimages",    badimages,     "look for images with anomalous astrometry"},
+  {"box",     	   box,           "draw a box on the plot"},
+  {"calextract",   calextract,    "extract dmags"},
+  {"calextract",   calextract,    "extract dmags"},
+  {"calmextract",  calmextract,   "extract dmags"},
+  {"cals",    	   cals,          "plot calibration data"},
+  {"catalog", 	   catlog,        "plot catalog stars"},
+  {"catalog", 	   catlog,        "plot catalog stars"},
+  {"ccd",     	   ccd,           "plot color-color diagram"},
+  {"ccd",     	   ccd,           "plot color-color diagram"},
+  {"ccdextract",   ccdextract,    "extract star coords from color-color diagram"},
+  {"center",       center,        "center image on coords"},
+  {"center",       center,        "center image on coords"},
+  {"cgrid",   	   cgrid,         "plot sky coordinate grid"},
+  {"cgrid",   	   cgrid,         "plot sky coordinate grid"},
+  {"clear",   	   clear,         "erase plot"},
+  {"cmatch",  	   cmatch,        "match two catalogs"},
+  {"cmatch",  	   cmatch,        "match two catalogs"},
+  {"cmd",     	   cmd,           "plot cmd of stars in current region"},
+  {"cmd",     	   cmd,           "plot cmd of stars in current region"},
+  {"cmdextract",   cmdextract,    "extract stars based on cmd regions"},
+  {"cmpread",      cmpread,       "read data from cmp format files"},
+  {"cmpread",      cmpread,       "read data from cmp format files"},
+  {"concat",  	   concat,        "reduce vector dimension"},
+  {"contour", 	   contour,       "create contour from image"},
+  {"cplot",   	   cplot,         "plot vectors in sky coordinates"},
+  {"cplot",   	   cplot,         "plot vectors in sky coordinates"},
+  {"create",  	   create,        "create a new vector"},
+  {"csystem", 	   csystem,       "convert between coordinate systems"},
+  {"csystem", 	   csystem,       "convert between coordinate systems"},
+  {"ctimes",  	   ctimes,        "convert between time formats"},
+  {"ctimes",  	   ctimes,        "convert between time formats"},
+  {"cursor",  	   cursor,        "get coords from cursor"},
+  {"czplot",  	   czplot,        "plot scaled vectors in sky coordinates"},
+  {"czplot",  	   czplot,        "plot scaled vectors in sky coordinates"},
+  {"datafile",     datafile,      "define file to read vectors"},
+  {"date",    	   date,          "get current date"},
+  {"ddmagextr",    ddmagextract,  "plot magnitude differences"},
+  {"ddmags",       ddmags,        "plot magnitude differences"},
+  {"ddmags",       ddmags,        "plot magnitude differences"},
+  {"delete",  	   delete,        "delete vectors or matrices"},
+  {"device",  	   device,        "set / get current graphics device"},
+  {"dmagaves",     dmagaves,      "plot differential magnitudes between filters"},
+  {"dmagextract",  dmagextract,   "extract stars based on differential magnitudes between filters"},
+  {"dmagmeas",     dmagmeas,      "plot differential magnitudes between filters"},
+  {"dmags",   	   dmags,         "plot differential magnitudes between filters"},
+  {"dmags",   	   dmags,         "plot differential magnitudes between filters"},
+  {"dmt",          dmt,           "plot mag scatter"},
+  {"dmt",          dmt,           "plot mag scatter"},
+  {"dumpmags",     dumpmags,      "custom dB dumping thingy"},
+  {"dumpmags",     dumpmags,      "custom dB dumping thingy"},
+  {"elixir",       elixir,        "get status info from elixir"},
+  {"elixir",       elixir,        "get status info from elixir"},
+  {"extract", 	   extract,       "extract vectors from catalogs"},
+  {"file",    	   file,          "test for a file"},
+  {"fit",     	   fit,           "fit polynomial to vector pair"},
+  {"fit2d",        fit2d,         "fit 2-d polynomial to vector triplet"},
+  {"gaussj",  	   gaussjordan,   "solve Ax = B (N-D)"},
+  {"gcat",         gcat,          "get catalog at location"},
+  {"gcat",         gcat,          "get catalog at location"},
+  {"gimages",      gimages,       "get images at location"},
+  {"gimages",      gimages,       "get images at location"},
+  {"grid",    	   grid,          "plot cartesian grid"},
+  {"gstar",   	   gstar,         "get star statistics"},
+  {"gstar",   	   gstar,         "get star statistics"},
+  {"gtypes",       gtypes,        "get type fractions"},
+  {"gtypes",       gtypes,        "get type fractions"},
+  {"histogram",    histogram,     "generate histogram from vector"},
+  {"images",  	   images,        "plot image boxes"},
+  {"images",  	   images,        "plot image boxes"},
+  {"imbox",   	   imbox,         "plot expected image box"},
+  {"imbox",   	   imbox,         "plot expected image box"},
+  {"imdata",  	   imdata,        "extract data for specific images"},
+  {"imdata",  	   imdata,        "extract data for specific images"},
+  {"imdense", 	   imdense,       "image density plot"},
+  {"imdense", 	   imdense,       "image density plot"},
+  {"imextract",    imextract,     "extract vectors from catalogs"},
+  {"imextract",    imextract,     "extract vectors from catalogs"},
+  {"imlist",  	   imlist,        "list image info"},
+  {"imlist",  	   imlist,        "list image info"},
+  {"imphot",  	   imphot,        "image photometry info"},
+  {"imphot",  	   imphot,        "image photometry info"},
+  {"imrough",      imrough,       "get info from imruf database"},
+  {"imrough",      imrough,       "get info from imruf database"},
+  {"imsearch",     imsearch,      "get info from imreg database"},
+  {"imsearch",     imsearch,      "get info from imreg database"},
+  {"imstats", 	   imstats,       "plot image statistics"},
+  {"imstats", 	   imstats,       "plot image statistics"},
+  {"interpolate",  interpolate,   "interpolate between vector pairs"},
+  {"jpeg",         jpeg,          "write text line on graph"},
+  {"labels",  	   labels,        "define labels for plot"},
+  {"lcat",    	   lcat,          "list catalogs in region"},
+  {"lcat",    	   lcat,          "list catalogs in region"},
+  {"lcurve",  	   lcurve,        "plot lightcurve for a star"},
+  {"lcurve",  	   lcurve,        "plot lightcurve for a star"},
+  {"limits",  	   limits,        "define plot limits"},
+  {"buffers",      list_buffers,  "list the currently allocated buffers"},
+  {"vectors", 	   list_vectors,  "list vectors"},
+  {"local",  	   local,         "define local variables"},
+  {"mcreate", 	   mcreate,       "create a matrix"},
+  {"mextract",	   mextract,      "extract vectors from catalogs"},
+  {"mextract",	   mextract,      "extract vectors from catalogs"},
+  {"mget",    	   mget,          "extract a vector from a matrix"},
+  {"mset",    	   mset,          "insert a vector in a matrix"},
+  {"pcat",    	   pcat,          "plot catalog boundaries"},
+  {"pcat",    	   pcat,          "plot catalog boundaries"},
+  {"photcodes",    photcodes,     "list photometry codes"},
+  {"photcodes",    photcodes,     "list photometry codes"},
+  {"photresid",    photresid,     "plot photometry residuals"},
+  {"plot",    	   plot,          "plot a pair of vectors"},
+  {"pmeasure",	   pmeasure,      "plot individual measurements"},
+  {"pmeasure",	   pmeasure,      "plot individual measurements"},
+  {"precess", 	   precess,       "precess coordinates"},
+  {"precess", 	   precess,       "precess coordinates"},
+  {"print",   	   print,         "write vectors to file"},
+  {"print",   	   print,         "write vectors to file"},
+  {"procks",  	   procks,        "plot rocks"},
+  {"procks",  	   procks,        "plot rocks"},
+  {"ps",      	   ps,            "define labels for plot"},
+  {"rd",           rd,            "load fits image"},
+  {"read",         read_vectors,  "read vectors from datafile"},
+  {"region",  	   region,        "define sky region for plot"},
+  {"region",  	   region,        "define sky region for plot"},
+  {"resid",   	   resid,         "plot residuals"},
+  {"resize",  	   resize,        "set graphics/image window size"},
+  {"section", 	   section,       "define section of graph"},
+  {"set",     	   set,           "vector math"},
+  {"simage",  	   simage,        "plot stars in an image"},
+  {"simage",  	   simage,        "plot stars in an image"},
+  {"sort",    	   sort_vectors,  "sort list of vectors"},
+  {"sprintf", 	   sprintf_opihi, "formated print to variable"},
+  {"stats",   	   stats,         "give statistics on a portion of a buffer"},
+  {"style",   	   style,         "set the style for graph plots"},
+  {"subpix",  	   subpix,        "get subpixel positions"},
+  {"subpix",  	   subpix,        "get subpixel positions"},
+  {"subraster",    subraster,     "subraster of fits image"},
+  {"subset",  	   subset,        "expand vector dimension"},
+  {"textline",     textline,      "write text line on graph"},
+  {"tv",      	   tv,            "display an image on the Kii window"},
+  {"uniq",    	   uniq,          "create a uniq vector subset from a vector"},
+  {"vectobuf",     vectobuf,      "convert vector triplet to buffer"},
+  {"vstat",        vstat,         "get info from imreg database"},
+  {"wd",      	   wd,            "write an image to a file"},
+  {"write",   	   write_vectors, "write vectors to datafile"},
+  {"zap",     	   zap,           "delete pixels"},
+  {"zeropts", 	   zeropts,       "show filter zeropts"},
+  {"zplot",   	   zplot,         "plot x y with size scaled by z"},
+}; 
Index: /branches/opihi-2-9/Ohana/src/opihi/lib.data/Makefile
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/lib.data/Makefile	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/lib.data/Makefile	(revision 11389)
@@ -0,0 +1,48 @@
+include ../../../Configure
+
+HOME    =       $(ROOT)/src/opihi
+BIN     =       $(HOME)/bin
+LIB     =       $(HOME)/lib
+INC     =       $(HOME)/include
+SDIR    =       $(HOME)/lib.data
+
+# general numerical functions (libdata) #####################
+srcs = \
+$(SDIR)/book.$(ARCH).o                  \
+$(SDIR)/page.$(ARCH).o                  \
+$(SDIR)/sort.$(ARCH).o                  \
+$(SDIR)/fft.$(ARCH).o			\
+$(SDIR)/svdcmp.$(ARCH).o		\
+$(SDIR)/convert.$(ARCH).o		\
+$(SDIR)/spline.$(ARCH).o		\
+$(SDIR)/mrqmin.$(ARCH).o		\
+$(SDIR)/mrq2dmin.$(ARCH).o		\
+$(SDIR)/precess.$(ARCH).o		\
+$(SDIR)/starfuncs.$(ARCH).o		\
+$(SDIR)/powell.$(ARCH).o		\
+$(SDIR)/gaussian.$(ARCH).o		\
+$(SDIR)/graphtools.$(ARCH).o            \
+$(SDIR)/open_graph.$(ARCH).o            \
+$(SDIR)/open_image.$(ARCH).o            \
+$(SDIR)/queues.$(ARCH).o		\
+$(SDIR)/PlotVectors.$(ARCH).o		\
+$(SDIR)/style_args.$(ARCH).o
+
+# dependancy rules for include files ########################
+incs = \
+$(INC)/opihi.h \
+$(INC)/external.h \
+$(INC)/shell.h \
+$(INC)/dvomath.h \
+$(INC)/convert.h \
+$(INC)/display.h 
+
+libdata: $(DESTLIB)/libdata.a
+$(DESTLIB)/libdata.a: $(LIB)/libdata.$(ARCH).a
+$(LIB)/libdata.$(ARCH).a: $(srcs)
+$(srcs): $(incs)
+
+uninstall:
+	rm -f $(DESTLIB)/libdata.a
+
+include ../Makefile.Common
Index: /branches/opihi-2-9/Ohana/src/opihi/lib.data/PlotVectors.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/lib.data/PlotVectors.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/lib.data/PlotVectors.c	(revision 11389)
@@ -0,0 +1,52 @@
+# include "display.h"
+
+static int Xgraph;
+
+int PrepPlotting (int Npts, Graphdata *graphmode) {
+
+  if (!GetGraph (NULL, &Xgraph, NULL)) return (FALSE);
+  
+  /* tell kapa to look for the incoming image */
+  KiiSendCommand (Xgraph, 4, "PLOT"); 
+  
+  /* send Xgraph the plot details */
+  KiiSendMessage (Xgraph, "%8d %8d %d %d %d %d %d %f %f", 
+		  Npts, graphmode[0].style, 
+		  graphmode[0].ptype, graphmode[0].ltype, 
+		  graphmode[0].etype, graphmode[0].ebar, graphmode[0].color, 
+		  graphmode[0].lweight, graphmode[0].size);
+  KiiSendMessage (Xgraph, "%g %g %g %g", 
+		  graphmode[0].xmin, graphmode[0].xmax, 
+		  graphmode[0].ymin, graphmode[0].ymax);
+  return (TRUE);
+}
+
+int PlotVector (int Npts, float *values) {
+
+  int Nbytes;
+
+  Nbytes = Npts * sizeof (float);
+  write (Xgraph, values, Nbytes);
+  return (TRUE);
+}
+
+int PlotVectorPair (int N, float *xValues, float *yValues, Graphdata *graphmode) {
+
+    PrepPlotting (N, graphmode);
+    PlotVector (N, xValues);
+    PlotVector (N, yValues);
+
+    return (TRUE);
+}
+
+int PlotVectorTriplet (int N, float *xValues, float *yValues, float *zValues, Graphdata *graphmode) {
+
+    PrepPlotting (N, graphmode);
+    PlotVector (N, xValues);
+    PlotVector (N, yValues);
+    PlotVector (N, zValues);
+
+    return (TRUE);
+}
+
+/* we don't use GetGraph in PlotVector because it flushes the connection */
Index: /branches/opihi-2-9/Ohana/src/opihi/lib.data/book.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/lib.data/book.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/lib.data/book.c	(revision 11389)
@@ -0,0 +1,118 @@
+# include "data.h"
+
+Book **books;   /* book to store the list of all books */
+int    Nbooks;   /* number of currently defined books */
+int    NBOOKS;   /* number of currently allocated books */
+
+void InitBooks () {
+  Nbooks = 0;
+  NBOOKS = 16;
+  ALLOCATE (books, Book *, NBOOKS); 
+}
+
+void InitBook (Book *book, char *name) {
+
+    book[0].name = strcreate (name);
+
+    book[0].Npages = 0;
+    book[0].NPAGES = 16;
+    ALLOCATE (book[0].pages, Page *, book[0].NPAGES);
+    ALLOCATE (book[0].pageIDs, char *, book[0].NPAGES);
+    ALLOCATE (book[0].index, int, book[0].NPAGES);
+}
+
+void FreeBook (Book *book) {
+
+    int i;
+
+    free (book[0].name);
+    for (i = 0; i < book[0].Npages; i++) {
+	FreePage (book[0].pages[i]);
+	free (book[0].pageIDs[i]);
+    }
+    free (book[0].pages);
+    free (book[0].pageIDs);
+    free (book[0].index);
+}
+
+/* return the given book */
+Book *GetBook (int where) {
+
+  int i;
+
+  if (where < 0) where += Nbooks;
+  if (where < 0) return NULL;
+  if (where >= Nbooks) return NULL;
+  return (books[where]);
+}
+
+/* return the given book */
+Book *FindBook (char *name) {
+
+  int i;
+
+  for (i = 0; i < Nbooks; i++) {
+    if (!strcmp (books[i][0].name, name)) {
+      return (books[i]);
+    }
+  }
+  return (NULL);
+}
+
+/* make a new named book */
+Book *CreateBook (char *name) {
+
+  int N;
+  Book *book;
+
+  book = FindBook (name);
+  if (book != NULL) return (book);
+
+  N = Nbooks;
+  Nbooks ++;
+  CHECK_REALLOCATE (books, Book *, NBOOKS, Nbooks, 16);
+  ALLOCATE (book, Book, 1);
+  InitBook (book, name);
+  books[N] = book;
+  return (book);
+}
+
+/* delete a book */
+int DeleteBook (Book *book) {
+
+  int i, N, NBOOKS_2;
+
+  /* find book in book list */
+  N = -1;
+  for (i = 0; i < Nbooks; i++) {
+    if (books[i] == book) {
+      N = i;
+      break;
+    }
+  }
+  if (N == -1) return (FALSE);
+
+  for (i = N; i < Nbooks - 1; i++) {
+    books[i] = books[i + 1];
+  }
+  Nbooks --;
+  NBOOKS_2 = MAX (16, NBOOKS / 2);
+  if (Nbooks < NBOOKS_2) {
+    NBOOKS = NBOOKS_2;
+    REALLOCATE (books, Book *, NBOOKS);
+  }
+
+  FreeBook (book);
+  return (TRUE);
+}
+
+/* list known books */
+void ListBooks () {
+
+  int i;
+
+  for (i = 0; i < Nbooks; i++) {
+    gprint (GP_ERR, "%-15s %3d\n", books[i][0].name, books[i][0].Npages);
+  }
+  return;
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/lib.data/convert.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/lib.data/convert.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/lib.data/convert.c	(revision 11389)
@@ -0,0 +1,295 @@
+# include "convert.h"
+# define _XOPEN_SOURCE /* glibc2 (strptime) needs this */
+# include <time.h>
+
+/** additional time / coordinate conversions not supplied by libohana **/
+
+int hh_hms (double hh, int *hr, int *mn, double *sc) {
+
+  int flag;
+
+  flag = SIGN(hh);
+  hh *= flag;
+  hh = 24.0*(hh/24.0 - (int)(hh/24.0));
+  *sc = 60.0*(60.0*hh - (int)(60.0*hh));
+  *mn = 60.0*(hh - (int)hh);
+  *hr = (int) hh;
+  *hr *= flag;
+  return (TRUE);
+}
+ 
+int dd_dms (double dd, int *dg, int *mn, double *sc) {
+
+  int flag;
+
+  flag = SIGN(dd);
+  dd = fabs (dd);
+  *dg = (int) dd;
+  *mn = (int) 60*(dd - *dg);
+  *sc = 3600.0*(dd - *dg - *mn/60.0);
+  if (*sc > 59.99) {
+    *sc = 0;
+    *mn += 1.0;
+  }
+  *dg *= flag;
+  return (TRUE);
+}
+ 
+int hms_format (char *line, double value) {
+
+  int hr, mn;
+  double sc;
+
+  hh_hms (value, &hr, &mn, &sc);
+  hr = (int) value;
+  if (isnan (value))
+    sprintf (line, "xx:xx:xx.xx");
+  else {
+    if (value < 0) {
+      sprintf (line, "-%02d:%02d:%05.2f", abs(hr), mn, sc);
+    } else {
+      sprintf (line, "%02d:%02d:%05.2f", hr, mn, sc);
+    }
+  }      
+  return (TRUE);
+}
+
+int dms_format (char *line, double value) {
+
+  int dg, mn;
+  double sc;
+
+  dd_dms (value, &dg, &mn, &sc);
+  if (value < 0) {
+    sprintf (line, "-%02d:%02d:%05.2f", abs(dg), mn, sc);
+  } else {
+    sprintf (line, "%02d:%02d:%05.2f", dg, mn, sc);
+  }
+  return (TRUE);
+}
+
+/***** convert 00:00:00 or 00:00 to 0 - 86400 ****/
+int hms_to_sec (char *string, time_t *second) {
+  
+  char *p;
+  struct tm time;
+
+  p = strptime (string, "%H:%M:%S", &time);
+  if (p != NULL) goto valid;
+
+  p = strptime (string, "%H:%M", &time);
+  if (p != NULL) goto valid;
+
+  return (FALSE);
+    
+valid:
+  if (*p) return (FALSE);
+  *second = time.tm_hour*3600 + time.tm_min*60 + time.tm_sec;
+  return (TRUE);
+}
+
+/***** convert Mon[@00:00:00] or 00:00 to 0 - 86400*7 ****/
+int day_to_sec (char *string, time_t *second) {
+  
+  char *p;
+  struct tm time;
+
+  bzero (&time, sizeof(time));
+  p = strptime (string, "%A@%H:%M:%S", &time);
+  if (p != NULL) goto valid;
+
+  p = strptime (string, "%A@%H:%M", &time);
+  if (p != NULL) goto valid;
+
+  p = strptime (string, "%A@%H", &time);
+  if (p != NULL) goto valid;
+
+  p = strptime (string, "%A", &time);
+  if (p != NULL) goto valid;
+
+  return (FALSE);
+
+valid:
+  if (*p) return (FALSE);
+  *second = time.tm_wday*86400 + time.tm_hour*3600 + time.tm_min*60 + time.tm_sec;
+  return (TRUE);
+}
+
+/***** convert seconds to HH:MM:SS ****/
+char *sec_to_hms (time_t second) {
+  
+  struct tm *gmt;
+  char *line;
+
+  ALLOCATE (line, char, 64);
+  gmt   = gmtime (&second);
+  sprintf (line, "%02d:%02d:%02d", gmt[0].tm_hour, gmt[0].tm_min, gmt[0].tm_sec); 
+  return (line);
+}
+
+/***** convert seconds to Day@HH:MM:SS ****/
+char *sec_to_day (time_t second) {
+  
+  struct tm *gmt;
+  char *line;
+
+  ALLOCATE (line, char, 64);
+  gmt   = gmtime (&second);
+  switch (gmt[0].tm_wday) {
+    case 0:
+      sprintf (line, "Sun@%02d:%02d:%02d", gmt[0].tm_hour, gmt[0].tm_min, gmt[0].tm_sec); 
+      break;
+    case 1:
+      sprintf (line, "Mon@%02d:%02d:%02d", gmt[0].tm_hour, gmt[0].tm_min, gmt[0].tm_sec); 
+      break;
+    case 2:
+      sprintf (line, "Tue@%02d:%02d:%02d", gmt[0].tm_hour, gmt[0].tm_min, gmt[0].tm_sec); 
+      break;
+    case 3:
+      sprintf (line, "Wed@%02d:%02d:%02d", gmt[0].tm_hour, gmt[0].tm_min, gmt[0].tm_sec); 
+      break;
+    case 4:
+      sprintf (line, "Thu@%02d:%02d:%02d", gmt[0].tm_hour, gmt[0].tm_min, gmt[0].tm_sec); 
+      break;
+    case 5:
+      sprintf (line, "Fri@%02d:%02d:%02d", gmt[0].tm_hour, gmt[0].tm_min, gmt[0].tm_sec); 
+      break;
+    case 6:
+      sprintf (line, "Sat@%02d:%02d:%02d", gmt[0].tm_hour, gmt[0].tm_min, gmt[0].tm_sec); 
+      break;
+  }
+  return (line);
+}
+
+int hh_hm (double hh, int *hr, double *mn) {
+
+  int flag;
+
+  flag = SIGN(hh);
+  hh = fabs (hh);
+
+  *mn = 60.0*(hh - (int)hh);
+  *hr = (int) hh;
+  *hr *= flag;
+  return (TRUE);
+}
+
+char *meade_deg_to_str (double deg) {
+
+  int hr;
+  double mn;
+  char *line;
+
+  ALLOCATE (line, char, 16);
+
+  hh_hm (deg, &hr, &mn);
+
+  sprintf (line, "%03d:%04.1f", abs(hr), mn);
+  return (line);
+}
+
+char *meade_ra_to_str (double deg) {
+
+  int hr;
+  double mn;
+  char *line;
+
+  ALLOCATE (line, char, 16);
+
+  hh_hm (deg/15.0, &hr, &mn);
+
+  sprintf (line, "%02d:%04.1f", abs(hr), mn);
+  return (line);
+}
+
+char *meade_dec_to_str (double deg) {
+
+  int hr;
+  double mn;
+  char *line;
+
+  ALLOCATE (line, char, 16);
+
+  hh_hm (deg, &hr, &mn);
+
+  if (deg < 0) {
+    sprintf (line, "-%02d:%04.1f", abs(hr), mn);
+  } else {
+    sprintf (line, "+%02d:%04.1f", hr, mn);
+  }      
+  return (line);
+}
+
+/* convert UNIX time to a value referenced to the TimeReference in the given unit */
+double TimeValue (time_t time, time_t TimeReference, int TimeFormat) {
+
+  double value, dt;
+
+  dt = (time > TimeReference) ? (time - TimeReference) : -1 * (double)(TimeReference - time);
+  switch (TimeFormat) {
+  case TIME_JD:
+    value = time / 86400.0 + 2440587.5;
+    break;
+  case TIME_MJD:
+    value = time / 86400.0 + 40587.0;
+    break;
+  case TIME_DAYS:
+    value = dt / 86400.0;
+    break;
+  case TIME_HOURS:
+    value = dt / 3600.0;
+    break;
+  case TIME_MINUTES:
+    value = dt / 60.0;
+    break;
+  case TIME_SECONDS:
+  default:
+    value = dt;
+    break;
+  }
+  return (value);
+}
+  
+/* convert time value referenced to the TimeReference in the given unit to UNIX time */
+time_t TimeRef (double value, time_t TimeReference, int TimeFormat) {
+
+  int dt;
+  time_t time;
+
+  switch (TimeFormat) {
+  case TIME_JD:
+    time = (value -  2440587.5) * 86400.0;
+    return (time);
+    break;
+  case TIME_MJD:
+    time = (value -  40587.0) * 86400.0;
+    return (time);
+    break;
+  case TIME_DAYS:
+    dt = value * 86400.0;
+    break;
+  case TIME_HOURS:
+    dt = value * 3600.0;
+    break;
+  case TIME_MINUTES:
+    dt = value * 60.0;
+    break;
+  case TIME_SECONDS:
+  default:
+    dt = value;
+    break;
+  }
+
+  time = TimeReference + dt;
+  return (time);
+}
+
+/* times may be in forms as:
+ * 20040200450s (N seconds since 1970.0)
+ * 2440900.232j (julian date)
+ * 99/02/23,03:22:18 (date string)
+ * (separators may be anything except space, +, -)
+ * 99:02:15:12:23:30
+ * 99:02:15:12h23m30s
+ */
+
Index: /branches/opihi-2-9/Ohana/src/opihi/lib.data/fft.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/lib.data/fft.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/lib.data/fft.c	(revision 11389)
@@ -0,0 +1,270 @@
+# include "data.h"
+
+#define FSWAP(a,b) tempr=(a);(a)=(b);(b)=tempr
+
+void fft (float *Data, int N, int isign) {
+
+  int n,mmax,m,j,istep,i;
+  double wtemp,wr,wpr,wpi,wi,theta;
+  float tempr,tempi, *data;
+
+  data = Data;
+  n = N << 1;
+  j = 0;
+
+  for (i = 0; i < n; i+=2) {
+    if (j > i) {
+      FSWAP (data[j], data[i]);
+      FSWAP (data[j+1], data[i+1]);
+    }
+    m = n >> 1;
+    while (m >= 2 && j >= m) {
+      j -= m;
+      m >>= 1;
+    }
+    j += m;
+  }
+  mmax = 2;
+  while (n > mmax) {
+    istep = 2*mmax;
+    theta = 6.28318530717959 / (isign*mmax);
+    wtemp = sin(0.5*theta);
+    wpr = -2.0*wtemp*wtemp;
+    wpi = sin(theta);
+    wr = 1.0;
+    wi = 0.0;
+    for (m = 0; m < mmax; m+=2) {
+      for (i = m; i < n; i+=istep) {
+	j = i + mmax;
+	tempr = wr*data[j] - wi*data[j+1];
+	tempi = wr*data[j+1] + wi*data[j];
+	data[j] = data[i] - tempr;
+	data[j+1] = data[i+1] - tempi;
+	data[i] += tempr;
+	data[i+1] += tempi;
+      }
+      wr = (wtemp = wr)*wpr - wi*wpi+wr;
+      wi = wi*wpr + wtemp*wpi + wi;
+    }
+    mmax = istep;
+  }
+}
+
+void fftold (float *Data, int N, int isign) {
+
+  int n,mmax,m,j,istep,i;
+  double wtemp,wr,wpr,wpi,wi,theta;
+  float tempr,tempi, *data;
+
+  data = Data - 1;
+  n = N << 1;
+  j = 1;
+
+  for (i = 1; i < n; i+=2) {
+    if (j > i) {
+      FSWAP (data[j], data[i]);
+      FSWAP (data[j+1], data[i+1]);
+    }
+    m = n >> 1;
+    while (m >= 2 && j > m) {
+      j -= m;
+      m >>= 1;
+    }
+    j += m;
+  }
+  mmax = 2;
+  while (n > mmax) {
+    istep = 2*mmax;
+    theta = 6.28318530717959 / (isign*mmax);
+    wtemp = sin(0.5*theta);
+    wpr = -2.0*wtemp*wtemp;
+    wpi = sin(theta);
+    wr = 1.0;
+    wi = 0.0;
+    for (m = 1; m < mmax; m+=2) {
+      for (i = m; i <= n; i+=istep) {
+	j = i + mmax;
+	tempr = wr*data[j] - wi*data[j+1];
+	tempi = wr*data[j+1] + wi*data[j];
+	data[j] = data[i] - tempr;
+	data[j+1] = data[i+1] - tempi;
+	data[i] += tempr;
+	data[i+1] += tempi;
+      }
+      wr = (wtemp = wr)*wpr - wi*wpi+wr;
+      wi = wi*wpr + wtemp*wpi + wi;
+    }
+    mmax = istep;
+  }
+}
+
+/* convert indices to zero reference */
+void fftN (float *data, int *nn, int ndim, int isign) {
+
+  int i1,i2,i3,i2rev,i3rev,ip1,ip2,ip3,ifp1,ifp2;
+  int ibit,idim,k1,k2,n,nprev,nrem,ntot;
+  float tempi,tempr;
+  double theta,wi,wpi,wpr,wr,wtemp;
+
+  ntot = 1;
+  for (idim = 0; idim < ndim; idim++) ntot *= nn[idim];
+
+  nprev = 1;
+  for (idim = ndim - 1; idim >= 0; idim--) {
+    n  =  nn[idim];
+    nrem = ntot / (n*nprev);
+    ip1 = nprev << 1;
+    ip2 = ip1*n;
+    ip3 = ip2*nrem;
+    i2rev = 0;
+    for (i2 = 0; i2 < ip2; i2+=ip1) {
+      if (i2 < i2rev) {
+	for (i1 = i2; i1 <= i2+ip1-2; i1+=2) {
+	  for (i3 = i1; i3 < ip3; i3+=ip2) {	
+	    i3rev = i2rev+i3-i2;
+	    FSWAP(data[i3],data[i3rev]);
+	    FSWAP(data[i3+1],data[i3rev+1]);
+	  }
+	}
+      }
+      ibit = ip2 >> 1;
+      while (ibit >= ip1 && i2rev >= ibit) {
+	i2rev -= ibit;
+	ibit >>= 1;
+      }
+      i2rev += ibit;
+    }
+    ifp1 = ip1;
+    while (ifp1 < ip2) {
+      ifp2 = ifp1 << 1;
+      theta = isign*6.28318530717959/(ifp2/ip1);
+      wtemp = sin(0.5*theta);
+      wpr = -2.0*wtemp*wtemp;
+      wpi = sin(theta);
+      wr = 1.0;
+      wi = 0.0;
+      for (i3 = 0; i3 < ifp1; i3+=ip1) {
+	for (i1 = i3; i1 <= i3+ip1-2; i1+=2) {
+	  for (i2 = i1; i2 < ip3; i2+=ifp2) {
+	    k1 = i2;
+	    k2 = k1+ifp1;
+	    tempr = wr*data[k2]-wi*data[k2+1];
+	    tempi = wr*data[k2+1]+wi*data[k2];
+	    data[k2] = data[k1]-tempr;
+	    data[k2+1] = data[k1+1]-tempi;
+	    data[k1] += tempr;
+	    data[k1+1] += tempi;
+	  }
+	}
+	wr = (wtemp = wr)*wpr-wi*wpi+wr;
+	wi = wi*wpr+wtemp*wpi+wi;
+      }
+      ifp1 = ifp2;
+    }
+    nprev *= n;
+  }
+}
+
+#undef FSWAP
+
+/* based on the PRESS routine, this fft takes an array from data[0] to data[2N-1] */
+/* this function takes Data = h(t) and replaces it in situ with H(F) or vice versa.
+   There are assumed to be 2*N input values with 
+   Data[0,2,4,...] the real and Data[1,3,5,...] the imaginary ones.
+   the output is ordered the same.  
+
+   for h(t), values are in time sequence order.
+   for H(F), values are in order F = 0, 1/N, ... 1/2 - 1/N, +/- 1/2, -1/2 + 1/N, ... -1/N 
+
+   no normalization is performed, so a signal of amplitude A sin (w_k * t) will be 
+      give an H(F) value of 0.5 * A * N, and the DC term will have H(0) = A * N.
+
+*/ 
+
+int IsBinary (int N) {
+
+  int i, nbit;
+
+  /* check if number is a binary number */
+  nbit = 0;
+  for (i = 0; i < 8*sizeof(N); i++) {
+    nbit += (N & 0x01);
+    N = (N >> 1);
+  }
+  if (nbit == 1) { 
+    return (1); 
+  } else { 
+    return (0); 
+  }
+
+}  
+
+#define FSWAP(a,b) tempr=(a);(a)=(b);(b)=tempr
+
+void fourn (float *data, int *nn, int ndim, int isign) {
+
+  int i1,i2,i3,i2rev,i3rev,ip1,ip2,ip3,ifp1,ifp2;
+  int ibit,idim,k1,k2,n,nprev,nrem,ntot;
+  float tempi,tempr;
+  double theta,wi,wpi,wpr,wr,wtemp;
+
+  ntot = 1;
+  for (idim = 1; idim <= ndim; idim++)
+    ntot *= nn[idim];
+  nprev = 1;
+  for (idim = ndim; idim >= 1; idim--) {
+    n = nn[idim];
+    nrem = ntot/(n*nprev);
+    ip1 = nprev << 1;
+    ip2 = ip1*n;
+    ip3 = ip2*nrem;
+    i2rev = 1;
+    for (i2 = 1; i2 <= ip2; i2+=ip1) {
+      if (i2 < i2rev) {
+	for (i1 = i2; i1 <= i2+ip1-2; i1+=2) {
+	  for (i3 = i1; i3 <= ip3;i3+=ip2) {
+	    i3rev = i2rev+i3-i2;
+	    FSWAP(data[i3],data[i3rev]);
+	    FSWAP(data[i3+1],data[i3rev+1]);
+	  }
+	}
+      }
+      ibit = ip2 >> 1;
+      while (ibit >= ip1 && i2rev > ibit) {
+	i2rev -=  ibit;
+	ibit >>= 1;
+      }
+      i2rev += ibit;
+    }
+    ifp1 = ip1;
+    while (ifp1 < ip2) {
+      ifp2 = ifp1 << 1;
+      theta = isign*6.28318530717959/(ifp2/ip1);
+      wtemp = sin(0.5*theta);
+      wpr  =  -2.0*wtemp*wtemp;
+      wpi = sin(theta);
+      wr = 1.0;
+      wi = 0.0;
+      for (i3 = 1;i3<=ifp1;i3+=ip1) {
+	for (i1 = i3;i1<=i3+ip1-2;i1+=2) {
+	  for (i2 = i1;i2<=ip3;i2+=ifp2) {
+	    k1 = i2;
+	    k2 = k1+ifp1;
+	    tempr = wr*data[k2]-wi*data[k2+1];
+	    tempi = wr*data[k2+1]+wi*data[k2];
+	    data[k2] = data[k1]-tempr;
+	    data[k2+1] = data[k1+1]-tempi;
+	    data[k1] += tempr;
+	    data[k1+1] += tempi;
+	  }
+	}
+	wr = (wtemp = wr)*wpr-wi*wpi+wr;
+	wi = wi*wpr+wtemp*wpi+wi;
+      }
+      ifp1 = ifp2;
+    }
+    nprev *= n;
+  }
+}
+
+#undef FSWAP
Index: /branches/opihi-2-9/Ohana/src/opihi/lib.data/gaussian.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/lib.data/gaussian.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/lib.data/gaussian.c	(revision 11389)
@@ -0,0 +1,75 @@
+# include "data.h"
+
+static int Ngaussint = 0;
+static double *gaussint;
+
+extern double drand48();
+
+double gaussian (double x, double mean, double sigma) {
+
+  double f;
+
+  f = exp (-0.5 * SQ(x - mean) / SQ(sigma)) / sqrt(2 * M_PI * SQ(sigma));
+
+  return (f);
+
+}
+
+/* integrate a gaussian from -5 sigma to +5 sigma */
+void gauss_init (int Nbin) {
+ 
+  int i;
+  long A, B;
+  double val, x, dx, dx1, dx2, dx3, df;
+  double mean, sigma;
+ 
+  /* no need to generate this if it already exists */
+  if (Ngaussint == Nbin) return;
+
+  A = time(NULL);
+  for (B = 0; A == time(NULL); B++);
+  srand48(B);
+ 
+  Ngaussint = Nbin;
+  ALLOCATE (gaussint, double, Ngaussint + 1);
+
+  val = 0;
+  dx = 1.0 / Ngaussint;
+  dx1 = dx / 3.0;
+  dx2 = 2.0*dx/3.0;
+  dx3 = dx;
+  mean = 0.0;
+  sigma = 1.0;
+ 
+  for (i = 0, x = -7.0; (i < Ngaussint) && (x < 7.0); x += dx)  {
+    df = (3.0*gaussian(x    , mean, sigma) + 
+          9.0*gaussian(x+dx1, mean, sigma) +
+          9.0*gaussian(x+dx2, mean, sigma) + 
+          3.0*gaussian(x+dx3, mean, sigma)) * (dx1/8.0);
+    val += df;
+    if (val > (i + 0.5) / (double) Ngaussint) {
+      gaussint[i] = x + dx / 2.0;
+      i++;
+    }
+  }
+}
+
+double rnd_gauss (double mean, double sigma) {
+ 
+  int i;
+  double y;
+ 
+  y = drand48();
+  i = Ngaussint*y;
+  y = gaussint[i]*sigma + mean;
+ 
+  return (y);
+ 
+}
+ 
+double int_gauss (int i) {
+  double y;
+  y = gaussint[i];
+  return (y);
+}
+ 
Index: /branches/opihi-2-9/Ohana/src/opihi/lib.data/graphtools.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/lib.data/graphtools.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/lib.data/graphtools.c	(revision 11389)
@@ -0,0 +1,81 @@
+# include "data.h"
+
+void SetLimits (Vector *xvec, Vector *yvec, Graphdata *graphmode) {
+
+  double maxX, minX, maxY, minY, range;
+  int i;
+
+  if (xvec != NULL) {
+    maxX = minX = xvec[0].elements[0];
+    for (i = 1; i < xvec[0].Nelements; i++) {
+      if (!finite(xvec[0].elements[i])) continue;
+      maxX = MAX (maxX, xvec[0].elements[i]);
+      minX = MIN (minX, xvec[0].elements[i]);
+    }
+    range = maxX - minX;
+    if (range == 0) range = 0.001 * maxX;
+    if (range == 0) range = 0.001;
+    graphmode[0].xmin = minX - 0.05*range;
+    graphmode[0].xmax = maxX + 0.05*range;
+  }
+
+  if (yvec != NULL) {
+    maxY = minY = yvec[0].elements[0];
+    for (i = 1; i < yvec[0].Nelements; i++) {
+      if (!finite(yvec[0].elements[i])) continue;
+      maxY = MAX (maxY, yvec[0].elements[i]);
+      minY = MIN (minY, yvec[0].elements[i]);
+    }
+    range = maxY - minY;
+    if (range == 0) range = 0.0011 * maxY;
+    if (range == 0) range = 0.0011;
+    graphmode[0].ymin = minY - 0.05*range;
+    graphmode[0].ymax = maxY + 0.05*range;
+  }
+  SetGraph (graphmode[0]);
+
+  set_variable ("XMIN", graphmode[0].xmin);
+  set_variable ("XMAX", graphmode[0].xmax);
+  set_variable ("YMIN", graphmode[0].ymin);
+  set_variable ("YMAX", graphmode[0].ymax);
+}
+
+void SetLimitsRaw (float *xvec, float *yvec, int Nelements, Graphdata *graphmode) {
+
+  double maxX, minX, maxY, minY, range;
+  int i;
+
+  if (xvec != NULL) {
+    maxX = minX = xvec[0];
+    for (i = 1; i < Nelements; i++) {
+      if (!finite(xvec[i])) continue;
+      maxX = MAX (maxX, xvec[i]);
+      minX = MIN (minX, xvec[i]);
+    }
+    range = maxX - minX;
+    if (range == 0) range = 0.001 * maxX;
+    if (range == 0) range = 0.001;
+    graphmode[0].xmin = minX - 0.05*range;
+    graphmode[0].xmax = maxX + 0.05*range;
+  }
+
+  if (yvec != NULL) {
+    maxY = minY = yvec[0];
+    for (i = 1; i < Nelements; i++) {
+      if (!finite(yvec[i])) continue;
+      maxY = MAX (maxY, yvec[i]);
+      minY = MIN (minY, yvec[i]);
+    }
+    range = maxY - minY;
+    if (range == 0) range = 0.0011 * maxY;
+    if (range == 0) range = 0.0011;
+    graphmode[0].ymin = minY - 0.05*range;
+    graphmode[0].ymax = maxY + 0.05*range;
+  }
+  SetGraph (graphmode[0]);
+
+  set_variable ("XMIN", graphmode[0].xmin);
+  set_variable ("XMAX", graphmode[0].xmax);
+  set_variable ("YMIN", graphmode[0].ymin);
+  set_variable ("YMAX", graphmode[0].ymax);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/lib.data/hashes.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/lib.data/hashes.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/lib.data/hashes.c	(revision 11389)
@@ -0,0 +1,49 @@
+
+/* I need a structure which will be appropriate to carry the psMetadataConfig data.  the main 
+   requirements are:
+
+   - name-based components
+   - string-indexing on columns
+
+   basic elements:
+
+   container->item->element->value
+
+   element: name, value (type?)
+   item->name, Nelement, elements
+   container->items, Nitems
+
+   user interactions
+
+   blob list
+   blob listitems (blob)
+   blob create (blob)
+   blob delete (blob)
+   blob listkeys (blob.item)
+
+   blob getvalue (blob.item.key) -var word
+   blob setvalue (blob.item.key) value
+
+   blob getitem (blob.item)  : list all key/value pairs
+   blob newitem (blob.item)
+   blob delitem (blob.item)
+   blob popitem (blob)
+
+   blob readqueue (queue)    : convert queue in MDC format to blob
+   *** this needs to be able to match by keys against existing items
+   
+   need equivalents to:
+   queuepush -uniq key
+   queuepop -
+   queuesize
+   
+
+   items should be sorted by name so we can lookup an item quickly
+
+
+
+   other related opihi data concepts
+   
+   $a = @function (output of function set to value?)
+
+*/
Index: /branches/opihi-2-9/Ohana/src/opihi/lib.data/mrq2dmin.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/lib.data/mrq2dmin.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/lib.data/mrq2dmin.c	(revision 11389)
@@ -0,0 +1,210 @@
+# include "data.h"  /* only needed for the ALLOCATE def */
+
+/* need to pass in a function of the form:
+   funcs (x, t, a, Npar, dy/da) 
+   returns y (x,t) for Npar parameters a along with dy/da at (x,t)
+   dy carries 1/sig^2 
+*/
+
+# define VERY_VERBOSE 0
+
+static float **alpha, **talpha;
+static float **beta, **tbeta;
+static float *partry, *dyda;
+static float ochisq, lambda;
+
+static float *parmin = NULL;
+static float *parmax = NULL;
+
+float mrq2dcof (float *x, float *t, float *y, float *dy, int Npts, 
+	      float *par, int Npar, float **ta, float **tb, 
+	      float (funcs)(float, float, float *, int, float *)) {
+
+  int k, j, i;
+  float ydiff, wt, chisq;
+
+  for (j = 0; j < Npar; j++) {
+    for (k = 0; k <= j; k++) ta[j][k] = 0.0;
+    tb[j][0] = 0.0;
+  }
+
+  chisq = 0.0;
+  for (i = 0; i < Npts; i++) {
+
+    ydiff = funcs (x[i], t[i], par, Npar, dyda) - y[i];
+    chisq += SQ(ydiff) * dy[i];
+    
+    for (j = 0; j < Npar; j++) {
+      wt = dyda[j] * dy[i];
+      for (k = 0; k <= j; k++) ta[j][k] += wt * dyda[k];
+      tb[j][0] += wt * ydiff;
+    }
+  }
+
+  for (j = 1; j < Npar; j++)
+    for (k = 0; k < j; k++)
+      ta[k][j] = ta[j][k];
+      
+# if (VERY_VERBOSE)
+  for (j = 0; j < Npar; j++) {
+    for (k = 0; k < Npar; k++) {
+      gprint (GP_ERR, "%9.3e  ", ta[j][k]);
+    }
+    gprint (GP_ERR, "    :   %9.3e  ", tb[j][0]);
+    gprint (GP_ERR, "\n");
+  }
+# endif
+
+  return (chisq);
+
+}
+
+float mrq2dchi (float *x, float *t, float *y, float *dy, int Npts, 
+		float *par, int Npar, 
+		float (funcs)(float, float, float *, int, float *)) {
+
+  int i;
+  float ydiff, chisq;
+
+  chisq = 0.0;
+  for (i = 0; i < Npts; i++) {
+    ydiff = funcs (x[i], t[i], par, Npar, dyda) - y[i];
+    chisq += SQ(ydiff) * dy[i];
+  }
+  return (chisq);
+}
+
+float mrq2dmin (float *x, float *t, float *y, float *dy, int Npts, 
+	      float *par, int Npar, 
+	      float (funcs)(float, float, float *, int, float *), int VERBOSE) {
+
+  int j, k;
+  float chisq;
+
+  /* set up test matrixes for this run */
+  for (j = 0; j < Npar; j++) {
+    for (k = 0; k < Npar; k++) talpha[j][k] = alpha[j][k];
+    talpha[j][j] = alpha[j][j] * (1.0 + lambda);
+    tbeta[j][0] = beta[j][0];
+  }
+
+  /* keep this test in here? */
+  if (!fgaussj (talpha, Npar, tbeta, 1)) {
+    lambda *= 10.0;
+    return (ochisq);
+  }
+
+  for (j = 0; j < Npar; j++) {
+    partry[j] = par[j] - tbeta[j][0];
+    /*
+    if (parmin != NULL) partry[j] = MAX (parmin[j], partry[j]);
+    if (parmax != NULL) partry[j] = MIN (parmax[j], partry[j]);
+    */
+  }
+
+  chisq = mrq2dcof (x, t, y, dy, Npts, partry, Npar, talpha, tbeta, funcs);
+  if (VERBOSE) { 
+    gprint (GP_ERR, "chisq: %f  ", chisq);
+    gprint (GP_ERR, "lambda: %f  ", lambda);
+    for (j = 0; j < Npar; j++) {
+      gprint (GP_ERR, "%f ", partry[j]);
+    }
+    gprint (GP_ERR, "\n");
+  }
+
+  /* if good, save temp values */
+  if (chisq < ochisq) {
+    lambda *= 0.1;
+    ochisq = chisq;
+    for (j = 0; j < Npar; j++) {
+      for (k = 0; k < Npar; k++) alpha[j][k] = talpha[j][k];
+      beta[j][0] = tbeta[j][0];
+      par[j] = partry[j];
+    }
+  } else {
+    lambda *= 10.0;
+    chisq = ochisq;
+  }
+
+  return (chisq);
+
+}
+
+int mrq2dlimits (float *pmin, float *pmax, int Npar) {
+
+  int i;
+
+  ALLOCATE (parmin, float, Npar);
+  ALLOCATE (parmax, float, Npar);
+  for (i = 0; i < Npar; i++) {
+    parmin[i] = pmin[i];
+    parmax[i] = pmax[i];
+  }
+  return (TRUE);
+}
+
+float mrq2dinit (float *x, float *t, float *y, float *dy, int Npts, 
+	      float *par, int Npar, 
+	      float (funcs)(float, float, float *, int, float *), int VERBOSE) {
+
+  int i;
+
+  ALLOCATE (dyda, float, Npar);
+  ALLOCATE (partry, float, Npar);
+  ALLOCATE (alpha, float *, Npar);
+  ALLOCATE (beta, float *, Npar);
+  ALLOCATE (talpha, float *, Npar);
+  ALLOCATE (tbeta, float *, Npar);
+  for (i = 0; i < Npar; i++) {
+    ALLOCATE (alpha[i], float, Npar);
+    ALLOCATE (beta[i], float, Npar);
+    ALLOCATE (talpha[i], float, Npar);
+    ALLOCATE (tbeta[i], float, Npar);
+  }
+
+  
+  lambda = 0.001;
+  
+  ochisq = mrq2dcof (x, t, y, dy, Npts, par, Npar, alpha, beta, funcs);
+  if (VERBOSE) {
+    gprint (GP_ERR, "chisq: %f  ", ochisq);
+    gprint (GP_ERR, "lambda: %f  ", lambda);
+    for (i = 0; i < Npar; i++) {
+      gprint (GP_ERR, "%f ", par[i]);
+    }
+    gprint (GP_ERR, "\n");
+  }
+
+  return (ochisq);
+
+}
+
+/* don't invoke this in the middle of a run, only near the end */ 
+float **mrq2dcovar (int Npar) {
+
+  fgaussj (alpha, Npar, beta, 1);
+  return (alpha);
+
+} 
+
+void mrq2dfree (int Npar) {
+
+  int i;
+
+  for (i = 0; i < Npar; i++) {
+    free (alpha[i]);
+    free (talpha[i]);
+    free (beta[i]);
+    free (tbeta[i]);
+  }
+  free (alpha);
+  free (talpha);
+  free (beta);
+  free (tbeta);
+  free (partry);
+  free (dyda);
+
+  if (parmin != NULL) free (parmin);
+  if (parmax != NULL) free (parmax);
+
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/lib.data/mrqmin.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/lib.data/mrqmin.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/lib.data/mrqmin.c	(revision 11389)
@@ -0,0 +1,159 @@
+# include "data.h"  /* only needed for the ALLOCATE def */
+
+/* need to pass in a function of the form:
+   funcs (x, a, Npar, dyda) 
+   returns f (x) for Npar parameters a, also df/da at x 
+   dy carries 1/sig^2 
+*/
+
+static float **alpha, **talpha;
+static float **beta, **tbeta;
+static float *partry, *dyda;
+static float ochisq, lambda;
+
+float mrqcof (float *x, float *y, float *dy, int Npts, 
+	      float *par, int Npar, float **ta, float **tb, 
+	      float (funcs)(float, float *, int, float *)) {
+
+  int k, j, i;
+  float ydiff, wt, chisq;
+
+  for (j = 0; j < Npar; j++) {
+    for (k = 0; k <= j; k++) ta[j][k] = 0.0;
+    tb[j][0] = 0.0;
+  }
+
+  chisq = 0.0;
+  for (i = 0; i < Npts; i++) {
+
+    ydiff = funcs (x[i], par, Npar, dyda) - y[i];
+    chisq += SQ(ydiff) * dy[i];
+
+    for (j = 0; j < Npar; j++) {
+      wt = dyda[j] * dy[i];
+      for (k = 0; k <= j; k++) ta[j][k] += wt * dyda[k];
+      tb[j][0] += wt * ydiff;
+    }
+  }
+
+  for (j = 1; j < Npar; j++)
+    for (k = 0; k < j; k++) 
+      ta[k][j] = ta[j][k];
+
+  return (chisq);
+
+}
+
+float mrqmin (float *x, float *y, float *dy, int Npts, 
+	      float *par, int Npar, 
+	      float (funcs)(float, float *, int, float *), int VERBOSE) {
+
+  int j, k;
+  float chisq;
+  float rho, dX, dL;
+
+  /* set up test matrixes for this run */
+  for (j = 0; j < Npar; j++) {
+    for (k = 0; k < Npar; k++) talpha[j][k] = alpha[j][k];
+    talpha[j][j] = alpha[j][j] * (1.0 + lambda);
+    tbeta[j][0] = beta[j][0];
+  }
+
+  fgaussj (talpha, Npar, tbeta, 1);
+
+  for (j = 0; j < Npar; j++) partry[j] = par[j] - tbeta[j][0];
+
+  /* get linear model prediction */
+  dL = 0;
+  for (j = 0; j < Npar; j++) {
+      dL += 0.5*lambda*SQ(tbeta[j][0]) + tbeta[j][0]*beta[j][0];
+  }
+
+  chisq = mrqcof (x, y, dy, Npts, partry, Npar, talpha, tbeta, funcs);
+  if (VERBOSE) { 
+    gprint (GP_ERR, "chisq: %f  ", chisq);
+    gprint (GP_ERR, "lambda: %f  ", lambda);
+    for (j = 0; j < Npar; j++) {
+      gprint (GP_ERR, "%f ", partry[j]);
+    }
+    gprint (GP_ERR, "\n");
+  }
+
+  /* compare linear model with actual */
+  dX = ochisq - chisq;
+  rho = dX / dL;
+
+  /* if good, save temp values */
+  if (rho > 0) {
+    lambda *= 0.1;
+    ochisq = chisq;
+    for (j = 0; j < Npar; j++) {
+      for (k = 0; k < Npar; k++) alpha[j][k] = talpha[j][k];
+      beta[j][0] = tbeta[j][0];
+      par[j] = partry[j];
+    }
+  } else {
+    lambda *= 10.0;
+    chisq = ochisq;
+  }
+
+  return (chisq);
+
+}
+
+float mrqinit (float *x, float *y, float *dy, int Npts, 
+	      float *par, int Npar, 
+	      float (funcs)(float, float *, int, float *), int VERBOSE) {
+
+  int i;
+
+  ALLOCATE (dyda, float, Npar);
+  ALLOCATE (partry, float, Npar);
+  ALLOCATE (alpha, float *, Npar);
+  ALLOCATE (beta, float *, Npar);
+  ALLOCATE (talpha, float *, Npar);
+  ALLOCATE (tbeta, float *, Npar);
+  for (i = 0; i < Npar; i++) {
+    ALLOCATE (alpha[i], float, Npar);
+    ALLOCATE (beta[i], float, Npar);
+    ALLOCATE (talpha[i], float, Npar);
+    ALLOCATE (tbeta[i], float, Npar);
+  }
+  
+  lambda = 0.01;
+  
+  ochisq = mrqcof (x, y, dy, Npts, par, Npar, alpha, beta, funcs);
+  if (VERBOSE) {
+    gprint (GP_ERR, "chisq: %f  ", ochisq);
+    gprint (GP_ERR, "lambda: %f  ", lambda);
+    for (i = 0; i < Npar; i++) {
+      gprint (GP_ERR, "%f ", par[i]);
+    }
+    gprint (GP_ERR, "\n");
+  }
+  return (ochisq);
+}
+
+/* don't invoke this in the middle of a run, only near the end */ 
+float **mrqcovar (int Npar) {
+  fgaussj (alpha, Npar, beta, 1);
+  return (alpha);
+} 
+
+void mrqfree (int Npar) {
+
+  int i;
+
+  for (i = 0; i < Npar; i++) {
+    free (alpha[i]);
+    free (talpha[i]);
+    free (beta[i]);
+    free (tbeta[i]);
+  }
+  free (alpha);
+  free (talpha);
+  free (beta);
+  free (tbeta);
+  free (partry);
+  free (dyda);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/lib.data/open_graph.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/lib.data/open_graph.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/lib.data/open_graph.c	(revision 11389)
@@ -0,0 +1,176 @@
+# include "display.h"
+# include "shell.h"
+# define DEBUG 0
+
+/* we have space for several kapa windows */
+# define NXGRAPH 5
+
+static int       Active;
+static int       Xgraph[NXGRAPH];  
+static Graphdata graphdata[NXGRAPH];
+
+void QuitGraph () {
+
+  int i;
+  
+  for (i = 0; i < NXGRAPH; i++) {
+    KiiClose (Xgraph[i]);
+  }
+}
+
+void InitGraph () {
+
+  int i;
+
+  Active = 0;
+  for (i = 0; i < NXGRAPH; i++) {
+    Xgraph[i] = -1;
+
+    graphdata[i].xmin = graphdata[i].ymin = 0.0;
+    graphdata[i].xmax = graphdata[i].ymax = 1.0;
+    graphdata[i].style = graphdata[i].ptype = 0;
+    graphdata[i].ltype = graphdata[i].color = 0;
+    graphdata[i].etype = graphdata[i].ebar = 0;
+    graphdata[i].lweight = graphdata[i].size = 1.0;
+    
+    graphdata[i].coords.pc1_1 = graphdata[i].coords.pc2_2 = 1.0;
+    graphdata[i].coords.pc1_2 = graphdata[i].coords.pc2_1 = 0.0;
+    strcpy (graphdata[i].coords.ctype, "RA---LIN");
+    graphdata[i].coords.crval1 = 0.0;
+    graphdata[i].coords.crval2 = 0.0;
+    graphdata[i].coords.crpix1 = 0.0;
+    graphdata[i].coords.crpix2 = 0.0;
+    graphdata[i].coords.cdelt1 = graphdata[i].coords.cdelt2 = 1.0;
+    graphdata[i].flipeast = TRUE;
+    graphdata[i].flipnorth = FALSE;
+    strcpy (graphdata[i].axis, "2222");
+    strcpy (graphdata[i].ticks, "2222");
+    strcpy (graphdata[i].labels, "2222");
+  }
+}
+
+/* set SIGPIPE to this function to close cleanly */ 
+void XGraphDead (int input) {
+  signal (SIGPIPE, XGraphDead);
+  gprint (GP_ERR, "kapa is dead, must restart\n");
+  Xgraph[Active] = -1;
+}
+
+/** start socketed connection */
+int open_graph (int N) {
+
+  int fd;
+  char *kapa_exec, name[16];
+  
+  kapa_exec = get_variable ("KAPA");
+  if (kapa_exec == (char *) NULL) {
+    gprint (GP_ERR, "variable KAPA not found\n");
+    return (FALSE);
+  }
+
+  snprintf (name, 16, "[%d]", N);
+  fd = KiiOpen (kapa_exec, name);
+  free (kapa_exec);
+
+  if (fd < 0) {
+    gprint (GP_ERR, "error starting kapa\n");
+    return (FALSE);
+  } 
+
+  Xgraph[N] = fd;
+  return (TRUE);
+}
+
+int close_graph (int N) {
+
+  if (N <  0) return (FALSE);
+  if (N >= NXGRAPH) return (FALSE);
+
+  KiiClose (Xgraph[N]); 
+  Xgraph[N] = -1;
+  return (TRUE);
+}
+
+/* return pointers for current Xgraph, set if desired, test, open if needed */
+int GetGraph (Graphdata *data, int *socket, int *N) {
+
+  int i, n;
+  char buffer[70];
+
+  SetImageDevice (FALSE);
+  if (N == (int *) NULL) {
+    n = Active;
+  } else {
+    if (*N >= NXGRAPH) {
+      gprint (GP_ERR, "invalid Xgraph window %d\n", *N); 
+      return (FALSE);
+    }
+    if (*N < 0) {
+      *N = n = Active;
+    } else {
+      Active = n = *N;
+    }
+  }
+  
+  /* test Xgraph[0], flush junk from pipe */
+  signal (SIGPIPE, XGraphDead);
+  fcntl (Xgraph[n], F_SETFL,  O_NONBLOCK); 
+  for (i = 0; (read (Xgraph[n], buffer, 64) > 0) && (i < 20); i++);
+  fcntl (Xgraph[n], F_SETFL, !O_NONBLOCK); 
+  
+  if (Xgraph[n] < 1) {
+    if (!open_graph(n)) {
+      return (FALSE);
+    }
+  }
+
+  if (data != (Graphdata *) NULL) *data  = graphdata[n];
+  if (socket != (int *) NULL) *socket = Xgraph[n];
+
+  return (TRUE);
+
+}
+
+/* return pointers for given Xgraph, don't set or open */
+int GetGraphData (Graphdata *data, int *sock, int *N) {
+
+  int n;
+
+  if (N == (int *) NULL) {
+    n = Active;
+  } else {
+    if (*N >= NXGRAPH) {
+      gprint (GP_ERR, "invalid Xgraph window %d\n", *N); 
+      return (FALSE);
+    }
+    if (*N < 0) {
+      n = Active;
+    } else {
+      n = *N;
+    }
+  }
+  
+  if (data != (Graphdata *) NULL) *data  = graphdata[n];
+  if (sock != (int *) NULL) *sock = Xgraph[n];
+
+  return (TRUE);
+
+}
+
+/* assign given values to current Xgraph */
+void SetGraph (Graphdata data) {
+  graphdata[Active] = data;
+}
+
+/** internal tracking of current active device type **/
+
+static int       IsImage = FALSE;
+
+int GetCurrentDevice () {
+  return (IsImage);
+}
+
+void SetImageDevice (int state) {
+  IsImage = state;
+}
+
Index: /branches/opihi-2-9/Ohana/src/opihi/lib.data/open_image.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/lib.data/open_image.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/lib.data/open_image.c	(revision 11389)
@@ -0,0 +1,132 @@
+# include "display.h"
+# include "shell.h"
+# define DEBUG 0
+
+/* we have space for several kii windows */
+# define NXIMAGE 5
+
+static int       Active;
+static int       Ximage[NXIMAGE];  
+static char      Ximbuffer[NXIMAGE][512];
+static double    Xzero[NXIMAGE];
+static double    Xrange[NXIMAGE];
+
+void QuitImage () {
+
+  int i;
+  
+  for (i = 0; i < NXIMAGE; i++) {
+    KiiClose (Ximage[i]);
+  }
+}
+
+void InitImage () {
+
+  int i;
+
+  Active = 0;
+  for (i = 0; i < NXIMAGE; i++) {
+    Ximage[i] = -1;
+    Xzero[i] = 0;
+    Xrange[i] = 1024;
+    strcpy (Ximbuffer[i], "none");
+  }
+}
+
+/* set SIGPIPE to this function to close cleanly */ 
+void XImageDead (int input) {
+  signal (SIGPIPE, XImageDead);
+  gprint (GP_ERR, "kii is dead, must restart\n");
+  Ximage[Active] = -1;
+}
+
+/** start socketed connection */
+int open_image (int N) {
+
+  int fd;
+  char *kii_exec, name[16];
+
+  kii_exec = get_variable ("KII");
+  if (kii_exec == (char *) NULL) {
+    gprint (GP_ERR, "variable KII not found\n");
+    return (FALSE);
+  }
+
+  snprintf (name, 16, "[%d]", N);
+  fd = KiiOpen (kii_exec, name);
+  free (kii_exec);
+
+  if (fd < 0) {
+    gprint (GP_ERR, "error starting kii\n");
+    return (FALSE);
+  } 
+
+  Ximage[N] = fd;
+  return (TRUE);
+}
+
+int close_image (int N) {
+
+  if (N <  0) return (FALSE);
+  if (N >= NXIMAGE) return (FALSE);
+
+  KiiClose (Ximage[N]); 
+  Ximage[N] = -1;
+  return (TRUE);
+}
+
+/* return pointers for current Ximage, set if desired, test, open if needed */
+int GetImage (int *socket, int *N) {
+
+  int i, n;
+  char buffer[70];
+
+  SetImageDevice (TRUE);
+  if (N == (int *) NULL) {
+    n = Active;
+  } else {
+    if (*N >= NXIMAGE) {
+      gprint (GP_ERR, "invalid Ximage window %d\n", *N); 
+      return (FALSE);
+    }
+    if (*N < 0) {
+      *N = n = Active;
+    } else {
+      Active = n = *N;
+    }
+  }
+  
+  /* test Ximage[0], flush junk from pipe */
+  signal (SIGPIPE, XImageDead);
+  fcntl (Ximage[n], F_SETFL,  O_NONBLOCK); 
+  for (i = 0; (read (Ximage[n], buffer, 64) > 0) && (i < 20); i++);
+  fcntl (Ximage[n], F_SETFL, !O_NONBLOCK); 
+  
+  if (Ximage[n] < 1) {
+    if (!open_image(n)) {
+      return (FALSE);
+    }
+  }
+
+  if (socket != (int *) NULL) *socket = Ximage[n];
+
+  return (TRUE);
+
+}
+
+void SetImageName (char *name) {
+  strcpy (Ximbuffer[Active], name);
+}
+
+char *GetImageName () {
+  return (Ximbuffer[Active]);
+}
+  
+void SetImageScale (double zero, double range) {
+  Xzero[Active] = zero;
+  Xrange[Active] = range;
+}
+void GetImageScale (double *zero, double *range) {
+  *zero = Xzero[Active];
+  *range = Xrange[Active];
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/lib.data/page.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/lib.data/page.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/lib.data/page.c	(revision 11389)
@@ -0,0 +1,210 @@
+# include "data.h"
+
+void InitPage (Page *page, char *name) {
+
+    page[0].name = strcreate (name);
+
+    page[0].Nwords = 0;
+    page[0].NWORDS = 16;
+    ALLOCATE (page[0].words, char *, page[0].NWORDS);
+    ALLOCATE (page[0].value, char *, page[0].NWORDS);
+}
+
+void FreePage (Page *page) {
+
+    int i;
+
+    free (page[0].name);
+    for (i = 0; i < page[0].Nwords; i++) {
+      free (page[0].words[i]);
+      free (page[0].value[i]);
+    }
+    free (page[0].words);
+    free (page[0].value);
+}
+
+/* return the given page */
+Page *GetPage (Book *book, int where) {
+
+  int i;
+
+  if (where < 0) where += book[0].Npages;
+  if (where < 0) return NULL;
+  if (where >= book[0].Npages) return NULL;
+  return (book[0].pages[where]);
+}
+
+/* return the given page with key restrictions */
+Page *GetPageRestricted (Book *book, int where, char *keyName, char *keyValue) {
+
+  int i;
+  int N, Nout;
+  char *value;
+
+  if (where < 0) where += book[0].Npages;
+  if (where < 0) return NULL;
+  if (where >= book[0].Npages) return NULL;
+
+  if (where >= 0) {
+    N = -1;
+    for (i = 0; (i < book[0].Npages) && (N < where); i++) {
+      value = BookGetWord (book[0].pages[i], keyName);
+      if ((value == NULL) && !strcmp (keyValue, "NULL")) {
+	N++;
+	Nout = i;
+      } 
+      if ((value != NULL) && !strcmp (keyValue, value)) {
+	N++;
+	Nout = i;
+      }
+    }
+  } else {
+    N = 0;
+    for (i = book[0].Npages - 1; (i >= 0) && (N > where); i--) {
+      value = BookGetWord (book[0].pages[i], keyName);
+      if ((value == NULL) && !strcmp (keyValue, "NULL")) {
+	N--;
+      } 
+      if ((value != NULL) && !strcmp (keyValue, value)) {
+	N--;
+      }
+    }
+  }
+
+  if (N != where) return NULL;
+
+  return (book[0].pages[Nout]);
+}
+
+/* return the given page */
+/* XXX use index to find more quickly */
+Page *FindPage (Book *book, char *name) {
+
+  int i;
+
+  for (i = 0; i < book[0].Npages; i++) {
+    if (!strcmp (book[0].pages[i][0].name, name)) {
+      return (book[0].pages[i]);
+    }
+  }
+  return (NULL);
+}
+
+/* make a new named page */
+Page *CreatePage (Book *book, char *name) {
+
+  int N;
+  Page *page;
+
+  page = FindPage (book, name);
+  if (page != NULL) return (page);
+
+  N = book[0].Npages;
+  book[0].Npages ++;
+  if (book[0].Npages >= book[0].NPAGES) {
+    book[0].NPAGES += 16;
+    REALLOCATE (book[0].pages, Page *, book[0].NPAGES);
+    REALLOCATE (book[0].pageIDs, char *, book[0].NPAGES);
+    REALLOCATE (book[0].index, int, book[0].NPAGES);
+  }
+  ALLOCATE (page, Page, 1);
+  InitPage (page, name);
+  book[0].pages[N] = page;
+  book[0].pageIDs[N] = strcreate(name);
+  book[0].index[N] = N;
+  
+  /* at this point, I should sort the index */
+
+  return (page);
+}
+
+/* delete a page in a book */
+int DeletePage (Book *book, Page *page) {
+
+  char *pageID;
+  int i, N, NPAGES_2;
+
+  /* find page in page list */
+  N = -1;
+  for (i = 0; i < book[0].Npages; i++) {
+    if (book[0].pages[i] == page) {
+      N = i;
+      break;
+    }
+  }
+  if (N == -1) return (FALSE);
+
+  pageID = book[0].pageIDs[i];
+
+  for (i = N; i < book[0].Npages - 1; i++) {
+    book[0].pages[i] = book[0].pages[i + 1];
+    book[0].pageIDs[i] = book[0].pageIDs[i + 1];
+    book[0].index[i] = book[0].index[i + 1];
+  }
+  book[0].Npages --;
+  NPAGES_2 = MAX (16, book[0].NPAGES / 2);
+  if (book[0].Npages < NPAGES_2) {
+    book[0].NPAGES = NPAGES_2;
+    REALLOCATE (book[0].pages, Page *, book[0].NPAGES);
+    REALLOCATE (book[0].pageIDs, char *, book[0].NPAGES);
+    REALLOCATE (book[0].index, int, book[0].NPAGES);
+  }
+
+  FreePage (page);
+  free (pageID);
+  return (TRUE);
+}
+
+void ListPages (Book *book) {
+
+  int i;
+
+  for (i = 0; i < book[0].Npages; i++) {
+    gprint (GP_ERR, "%-15s %3d\n", book[0].pages[i][0].name, book[0].pages[i][0].Nwords);
+  }
+  return;
+}
+
+void ListWords (Page *page) {
+
+  int i;
+
+  for (i = 0; i < page[0].Nwords; i++) {
+    gprint (GP_ERR, "%-15s %15s\n", page[0].words[i], page[0].value[i]);
+  }
+  return;
+}
+
+int BookSetWord (Page *page, char *word, char *value) {
+
+  int i;
+
+  for (i = 0; i < page[0].Nwords; i++) {
+    if (!strcmp (page[0].words[i], word)) {
+      free (page[0].value[i]);
+      page[0].value[i] = strcreate (value);
+      return TRUE;
+    }
+  }
+
+  page[0].Nwords ++;
+  if (page[0].Nwords >= page[0].NWORDS) {
+    page[0].NWORDS += 16;
+    REALLOCATE (page[0].words, char *, page[0].NWORDS);
+    REALLOCATE (page[0].value, char *, page[0].NWORDS);
+  }      
+  page[0].words[i] = strcreate (word);
+  page[0].value[i] = strcreate (value);
+  return (TRUE);
+}
+
+char *BookGetWord (Page *page, char *word) {
+  int i;
+
+  for (i = 0; i < page[0].Nwords; i++) {
+    if (!strcmp (page[0].words[i], word)) {
+      return (page[0].value[i]);
+    }
+  }
+  return NULL;
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/lib.data/powell.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/lib.data/powell.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/lib.data/powell.c	(revision 11389)
@@ -0,0 +1,126 @@
+# include "data.h"
+
+# define FTOL 0.001
+# define ITMAX 200
+
+void linmin (float *p, float *xi, int n, float *fret, float (*func)());
+
+/*** not well tested yet !! ***/
+
+void powell (float *p, int Npar, float (func)() ) {
+  
+  int i, ibig, j, Niter;
+  float t, fptt, fp, del;
+  float *pt, *ptt, *xit, **xi;
+  float ftemp;
+
+  ALLOCATE (pt, float, Npar);
+  ALLOCATE (ptt, float, Npar);
+
+  ALLOCATE (xi, float *, Npar);
+  for (i = 0; i < Npar; i++) {
+    ALLOCATE (xi[i], float, Npar);
+    bzero (xi[i], Npar * sizeof (float));
+    xi[i][i] = 1;
+  }
+  ALLOCATE (xit, float, Npar);
+  
+  ftemp = func (p);
+
+  for (j = 0; j < Npar; j++) pt[j] = p[j];
+
+  for (Niter = 0; Niter < ITMAX; Niter++) {
+    fp = ftemp;
+    ibig = 0;
+    del = 0.0;
+
+    for (i = 0; i < Npar; i++) {
+      for (j = 0; j < Npar; j++) xit[j] = xi[j][i];
+
+      fptt = ftemp;
+      linmin (p, xit, Npar, &ftemp, func);
+
+      if (fabs (fptt - ftemp) > del) {
+	del = fabs (fptt - ftemp);
+	ibig = i;
+      }
+    }
+
+    if (fabs (fp - ftemp) <= 0.5*FTOL*(fabs(fp) + fabs(ftemp))) {
+      free (xit);
+      free (ptt);
+      free (pt);
+      for (i = 0; i < Npar; i++) free (xi[i]);
+      free (xi);
+      return;
+    }
+
+    for (j = 0; j < Npar; j++) {
+      ptt[j] = 2.0*p[j] - pt[j];
+      xit[j] = p[j] - pt[j];
+      pt[j]  = p[j];
+    }
+
+    fptt = func (ptt);
+
+    if (fptt < fp) {
+      t = 2.0*(fp - 2.0*ftemp + fptt) * SQ(fp - ftemp - del) - del * SQ(fp - fptt);
+      if (t < 0.0) {
+	linmin (p, xit, Npar, &ftemp, func);
+	for (j = 0; j < Npar; j++) xi[j][ibig] = xit[j];
+      }
+    }
+  }
+
+  if (Niter == ITMAX) {
+    gprint (GP_ERR, "Too many iterations in routine POWELL\n");
+    return;
+  }
+
+}
+
+#undef ITMAX
+
+/* 
+   function has N parameters
+   p is the initial guess for the N parameters 
+   xi are the N unit vectors - x[i][j] = delta(i,j)
+   Npar = N parameters
+   
+   FTOL - ending tolerance
+*/
+   
+#define TOL 2.0e-4
+
+int ncom=0;	/* defining declarations */
+float *pcom=0,*xicom=0,(*nrfunc)();
+
+void linmin (float *p, float *xi, int n, float *fret, float (*func)()) {
+
+	int j;
+	float xx,xmin,fx,fb,fa,bx,ax;
+	float brent(),f1dim(),*vector();
+	void mnbrak(),free_vector();
+
+	ncom=n;
+	pcom=vector(1,n);
+	xicom=vector(1,n);
+	nrfunc=func;
+	for (j=1;j<=n;j++) {
+		pcom[j]=p[j];
+		xicom[j]=xi[j];
+	}
+	ax=0.0;
+	xx=1.0;
+	bx=2.0;
+	mnbrak(&ax,&xx,&bx,&fa,&fx,&fb,f1dim);
+	*fret=brent(ax,xx,bx,f1dim,TOL,&xmin);
+	for (j=1;j<=n;j++) {
+		xi[j] *= xmin;
+		p[j] += xi[j];
+	}
+	free_vector(xicom,1,n);
+	free_vector(pcom,1,n);
+}
+
+#undef TOL
Index: /branches/opihi-2-9/Ohana/src/opihi/lib.data/precess.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/lib.data/precess.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/lib.data/precess.c	(revision 11389)
@@ -0,0 +1,49 @@
+# include "data.h"
+    
+double get_epoch (char *in_epoch, char mode) {
+
+  int done;
+  double epoch;
+
+  epoch = 2000.0;
+  done = FALSE;
+  if (in_epoch[0] == 'B') {
+    epoch = BtoJ(atof(&in_epoch[1]));
+    done = TRUE;
+  }
+
+  if (in_epoch[0] == 'J') {
+    epoch = atof(&in_epoch[1]);
+    done = TRUE;
+  }
+
+  if (!done && (mode == 'B')) {
+    epoch = BtoJ(atof(in_epoch));
+    done = TRUE;
+  }
+    
+  if (!done && (mode == 'J')) {
+    epoch = atof(in_epoch);
+    done = TRUE;
+  }
+
+  if (!done) {
+    gprint (GP_ERR, "error finding epoch %s\n", in_epoch);
+    exit (0);
+  }
+  
+  return (epoch);
+
+}
+
+  
+double BtoJ (double in_epoch) {
+
+  double JD, out_epoch;
+
+  JD = (in_epoch - 1900.0)*365.242198781 + 2415020.31352;
+  out_epoch = 2000.0 + (JD - 2451545.0)/365.25;
+
+  return (out_epoch);
+}
+
Index: /branches/opihi-2-9/Ohana/src/opihi/lib.data/queues.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/lib.data/queues.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/lib.data/queues.c	(revision 11389)
@@ -0,0 +1,378 @@
+# include "data.h"
+
+Queue **queues;   /* queue to store the list of all queues */
+int    Nqueues;   /* number of currently defined queues */
+int    NQUEUES;   /* number of currently allocated queues */
+
+void InitQueues () {
+  Nqueues = 0;
+  NQUEUES = 16;
+  ALLOCATE (queues, Queue *, NQUEUES); 
+}
+
+/* list known queues */
+void ListQueues () {
+
+  int i;
+
+  for (i = 0; i < Nqueues; i++) {
+    gprint (GP_ERR, "%-15s %3d\n", queues[i][0].name, queues[i][0].Nlines);
+  }
+  return;
+}
+
+/* return the given queue */
+Queue *FindQueue (char *name) {
+
+  int i;
+
+  for (i = 0; i < Nqueues; i++) {
+    if (!strcmp (queues[i][0].name, name)) {
+      return (&queues[i][0]);
+    }
+  }
+  return (NULL);
+}
+
+/* make a new named queue */
+int InitQueue (Queue *queue) {
+
+  int i;
+
+  for (i = 0; i < queue[0].Nlines; i++) {
+    free (queue[0].lines[i]);
+  }
+  queue[0].Nlines = 0;
+  queue[0].NLINES = 16;
+  REALLOCATE (queue[0].lines, char *, queue[0].NLINES);
+  return (TRUE);
+}
+
+/* make a new named queue */
+Queue *CreateQueue (char *name) {
+
+  int N;
+  Queue *queue;
+
+  queue = FindQueue (name);
+  if (queue != NULL) return (queue);
+
+  N = Nqueues;
+  Nqueues ++;
+  CHECK_REALLOCATE (queues, Queue *, NQUEUES, Nqueues, 16);
+  ALLOCATE (queue, Queue, 1);
+  queue[0].Nlines = 0;
+  queue[0].NLINES = 16;
+  queue[0].name = strcreate (name);
+  ALLOCATE (queue[0].lines, char *, queue[0].NLINES);
+  queues[N] = queue;
+  return (queue);
+}
+
+/* delete a queue */
+int DeleteQueue (Queue *queue) {
+
+  int i, N, NQUEUES_2;
+
+  /* find queue in queue list */
+  N = -1;
+  for (i = 0; i < Nqueues; i++) {
+    if (queues[i] == queue) {
+      N = i;
+      break;
+    }
+  }
+  if (N == -1) return (FALSE);
+
+  for (i = N; i < Nqueues - 1; i++) {
+    queues[i] = queues[i + 1];
+  }
+  Nqueues --;
+  NQUEUES_2 = MAX (16, NQUEUES / 2);
+  if (Nqueues < NQUEUES_2) {
+    NQUEUES = NQUEUES_2;
+    REALLOCATE (queues, Queue *, NQUEUES);
+  }
+
+  free (queue[0].name);
+  for (i = 0; i < queue[0].Nlines; i++) {
+    free (queue[0].lines[i]);
+  }
+  free (queue[0].lines);
+  free (queue);
+  return (TRUE);
+}
+
+void PushNamedQueue (char *name, char *line) {
+
+  Queue *queue;
+  
+  queue = FindQueue (name);
+  if (queue == NULL) {
+    queue = CreateQueue (name);
+  }
+  PushQueue (queue, line);
+  return;
+}
+
+/* push line onto queue.  return chars create new lines */
+void PushQueue (Queue *queue, char *line) {
+
+  int N;
+  char *p, *q;
+
+  p = line;
+  q = strchr (line, '\n');
+  N = queue[0].Nlines;
+  while (q != NULL) {
+    queue[0].lines[N] = strncreate (p, q - p);
+    N++;
+    CHECK_REALLOCATE (queue[0].lines, char *, queue[0].NLINES, N, 16);
+    p = q + 1;
+    q = strchr (p, '\n');
+  }    
+  if (*p) {
+    queue[0].lines[N] = strcreate (p);
+    N++;
+    CHECK_REALLOCATE (queue[0].lines, char *, queue[0].NLINES, N, 16);
+  }
+  queue[0].Nlines = N;
+  return;
+}
+
+// return a newly allocated string containing the requested key value
+char *ChooseSingleKey (char *line, int Key) {
+
+  int i;
+  char *key, *p;
+
+  if (Key == -1) {
+    key = strcreate (line);
+    return (key);
+  }
+
+  key = line;
+  for (i = 0; (i < Key) && (key != NULL); i++) {
+    p = nextword (key);
+    key = p;
+  }
+  key = thisword (key);
+  return (key);
+}
+
+/* construct merged key given keylist of the form K:N:M */ 
+char *ChooseKey (char *line, char *keylist) {
+
+  char *output, *entry, *key, *p, *q;
+  int first, keynum;
+
+  if (line == NULL) return (NULL);
+  if (keylist == NULL) return (line);
+
+  ALLOCATE (output, char, strlen(line) + 1);
+  memset (output, 0, strlen(line) + 1);
+
+  first = TRUE;
+  p = q = keylist;
+  while (q != NULL) {
+    q = strchr (p, ':');
+    if (q == NULL) {
+      entry = strcreate (p);
+    } else {
+      entry = strncreate (p, q - p);
+    }
+    keynum = atoi (entry);
+    free (entry);
+
+    key = ChooseSingleKey (line, keynum);
+
+    if (!first) strcat (output, ":");
+    if (key) {
+	strcat (output, key);
+	free (key);
+    }
+
+    if (q != NULL) p = q + 1;
+    first = FALSE;
+  }
+  return (output);
+}
+
+/* push line onto queue, skipping existing matches (optionally by key) */
+void PushQueueUnique (Queue *queue, char *line, char *Key) {
+
+  int i, j, N, found;
+  char *p, *q, *key1, *key2;
+  Queue tmp;
+
+  /* init tmp queue */
+  tmp.Nlines = 0;
+  tmp.NLINES = 16;
+  ALLOCATE (tmp.lines, char *, tmp.NLINES);
+
+  /* push entries on tmp queue */
+  p = line;
+  q = strchr (line, '\n');
+  N = tmp.Nlines;
+  while (q != NULL) {
+    tmp.lines[N] = strncreate (p, q - p);
+    N++;
+    CHECK_REALLOCATE (tmp.lines, char *, tmp.NLINES, N, 16);
+    p = q + 1;
+    q = strchr (p, '\n');
+  }    
+  if (*p) {
+    tmp.lines[N] = strcreate (p);
+    N++;
+    CHECK_REALLOCATE (tmp.lines, char *, tmp.NLINES, N, 16);
+  }
+  tmp.Nlines = N;
+
+  /* add unique entries in tmp to queue */
+  for (i = 0; i < tmp.Nlines; i++) {
+    key1 = ChooseKey (tmp.lines[i], Key);
+    if (key1 == NULL) continue;
+    found = FALSE;
+    for (j = 0; !found && (j < queue[0].Nlines); j++) {
+      key2 = ChooseKey (queue[0].lines[j], Key);
+      if (key2 == NULL) continue;
+      found = !strcmp (key1, key2);
+      free (key2);
+    }      
+    if (!found) PushQueue (queue, tmp.lines[i]);
+    free (key1);
+  }
+  for (i = 0; i < tmp.Nlines; i++) {
+    free (tmp.lines[i]);
+  } 
+  free (tmp.lines);
+  return;
+}
+
+/* push line onto queue, replacing matches (optionally by Key) */
+void PushQueueReplace (Queue *queue, char *line, char *Key) {
+
+  int i, j, N, found;
+  char *p, *q, *key1, *key2;
+  Queue tmp;
+
+  /* init tmp queue */
+  tmp.Nlines = 0;
+  tmp.NLINES = 16;
+  ALLOCATE (tmp.lines, char *, tmp.NLINES);
+
+  /* push entries on tmp queue */
+  p = line;
+  q = strchr (line, '\n');
+  N = tmp.Nlines;
+  while (q != NULL) {
+    tmp.lines[N] = strncreate (p, q - p);
+    N++;
+    CHECK_REALLOCATE (tmp.lines, char *, tmp.NLINES, N, 16);
+    p = q + 1;
+    q = strchr (p, '\n');
+  }    
+  if (*p) {
+    tmp.lines[N] = strcreate (p);
+    N++;
+    CHECK_REALLOCATE (tmp.lines, char *, tmp.NLINES, N, 16);
+  }
+  tmp.Nlines = N;
+
+  /* add unique entries in tmp to queue */
+  for (i = 0; i < tmp.Nlines; i++) {
+    key1 = ChooseKey (tmp.lines[i], Key);
+    if (key1 == NULL) continue;
+    found = FALSE;
+    for (j = 0; !found && (j < queue[0].Nlines); j++) {
+      key2 = ChooseKey (queue[0].lines[j], Key);
+      if (key2 == NULL) continue;
+      found = !strcmp (key1, key2);
+      if (found) {
+	// XXX do I need to free queue[0].lines[j]??
+	queue[0].lines[j] = strcreate (tmp.lines[i]);
+      }
+      free (key2);
+    }      
+    if (!found) PushQueue (queue, tmp.lines[i]);
+    free (key1);
+  }
+  for (i = 0; i < tmp.Nlines; i++) {
+    free (tmp.lines[i]);
+  } 
+  free (tmp.lines);
+  return;
+}
+
+char *PopQueue (Queue *queue) {
+
+  int i, NLINES_2;
+  char *line;
+
+  if (queue[0].Nlines == 0) return (NULL);
+  line = queue[0].lines[0];
+
+  for (i = 0; i < queue[0].Nlines - 1; i++) {
+    queue[0].lines[i] = queue[0].lines[i+1];
+  }
+  queue[0].Nlines --;
+
+  /* shrink queue allocation if small enough */
+  NLINES_2 = MAX (16, queue[0].NLINES / 2);
+  if (queue[0].Nlines < NLINES_2) {
+    queue[0].NLINES = NLINES_2;
+    REALLOCATE (queue[0].lines, char *, queue[0].NLINES);
+  }    
+  return (line);
+}
+
+/* pop the first entry which for which the key matches */
+char *PopQueueMatch (Queue *queue, char *Key, char *value) {
+
+  int i, choice, NLINES_2;
+  char *line, *test;
+
+  if (queue[0].Nlines == 0) return (NULL);
+
+  /* find the matching key */
+  choice = -1;
+  for (i = 0; (i < queue[0].Nlines) && (choice == -1); i++) {
+      test = ChooseKey (queue[0].lines[i], Key);
+      if (test == NULL) continue;
+      if (strcmp (value, test)) { 
+	free (test);
+	continue;
+      }
+      free (test);
+      choice = i;
+  }
+  if (choice == -1) return NULL;
+
+  line = queue[0].lines[choice];
+
+  for (i = choice; i < queue[0].Nlines - 1; i++) {
+    queue[0].lines[i] = queue[0].lines[i+1];
+  }
+  queue[0].Nlines --;
+
+  /* shrink queue allocation if small enough */
+  NLINES_2 = MAX (16, queue[0].NLINES / 2);
+  if (queue[0].Nlines < NLINES_2) {
+    queue[0].NLINES = NLINES_2;
+    REALLOCATE (queue[0].lines, char *, queue[0].NLINES);
+  }    
+  return (line);
+}
+
+int PrintQueue (Queue *queue) {
+
+  int i;
+
+  if (queue[0].Nlines == 0) return (TRUE);
+
+  for (i = 0; i < queue[0].Nlines; i++) {
+    gprint (GP_LOG, "%s\n", queue[0].lines[i]);
+  }
+  return (TRUE);
+}
+
Index: /branches/opihi-2-9/Ohana/src/opihi/lib.data/sort.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/lib.data/sort.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/lib.data/sort.c	(revision 11389)
@@ -0,0 +1,334 @@
+# include "data.h"
+
+void sort (double *value, int N) {
+
+  int l,j,ir,i;
+  double temp;
+  
+  if (N < 2) return;
+  l = N >> 1;
+  ir = N - 1;
+  for (;;) {
+    if (l > 0) {
+      temp = value[--l];
+    }
+    else {
+      temp = value[ir];
+      value[ir] = value[0];
+      if (--ir == 0) {
+	value[0] = temp;
+	return;
+      }
+    }
+    i = l;
+    j = (l << 1) + 1;
+    while (j <= ir) {
+      if (j < ir && value[j] < value[j+1]) ++j;
+      if (temp < value[j]) {
+	value[i]=value[j];
+	j += (i=j) + 1;
+      }
+      else j = ir + 1;
+    }
+    value[i] = temp;
+  }
+}
+
+void fsort (float *value, int N) {
+
+  int l,j,ir,i;
+  float temp;
+  
+  if (N < 2) return;
+  l = N >> 1;
+  ir = N - 1;
+  for (;;) {
+    if (l > 0) {
+      temp = value[--l];
+    }
+    else {
+      temp = value[ir];
+      value[ir] = value[0];
+      if (--ir == 0) {
+	value[0] = temp;
+	return;
+      }
+    }
+    i = l;
+    j = (l << 1) + 1;
+    while (j <= ir) {
+      if (j < ir && value[j] < value[j+1]) ++j;
+      if (temp < value[j]) {
+	value[i]=value[j];
+	j += (i=j) + 1;
+      }
+      else j = ir + 1;
+    }
+    value[i] = temp;
+  }
+}
+
+void sortpair (double *value1, double *value2, int N) {
+
+  int l,j,ir,i;
+  double temp1, temp2;
+  
+  if (N < 2) return;
+  l = N >> 1;
+  ir = N - 1;
+  for (;;) {
+    if (l > 0) {
+      l--;
+      temp1 = value1[l];
+      temp2 = value2[l];
+    }
+    else {
+      temp1 = value1[ir];
+      temp2 = value2[ir];
+      value1[ir] = value1[0];
+      value2[ir] = value2[0];
+      if (--ir == 0) {
+	value1[0] = temp1;
+	value2[0] = temp2;
+	return;
+      }
+    }
+    i = l;
+    j = (l << 1) + 1;
+    while (j <= ir) {
+      if (j < ir && value1[j] < value1[j+1]) ++j;
+      if (temp1 < value1[j]) {
+	value1[i]=value1[j];
+	value2[i]=value2[j];
+	j += (i=j) + 1;
+      }
+      else j = ir + 1;
+    }
+    value1[i] = temp1;
+    value2[i] = temp2;
+  }
+}
+
+void fsortpair (float *X, float *Y, int N) {
+
+  int l,j,ir,i;
+  float tX, tY;
+  
+  if (N < 2) return;
+  l = N >> 1;
+  ir = N - 1;
+  for (;;) {
+    if (l > 0) {
+      l--;
+      tX = X[l];
+      tY = Y[l];
+    }
+    else {
+      tX = X[ir];
+      X[ir] = X[0];
+      tY = Y[ir];
+      Y[ir] = Y[0];
+      if (--ir == 0) {
+	X[0] = tX;
+	Y[0] = tY;
+	return;
+      }
+    }
+    i = l;
+    j = (l << 1) + 1;
+    while (j <= ir) {
+      if (j < ir && X[j] < X[j+1]) j++;
+      if (tX < X[j]) {
+	X[i] = X[j];
+	Y[i] = Y[j];
+	j += (i=j) + 1;
+      }
+      else j = ir + 1;
+    }
+    X[i] = tX;
+    Y[i] = tY;
+  }
+}
+
+void sortthree (float *X, float *Y, float *Z, int N) {
+
+  int l,j,ir,i;
+  float tX, tY, tZ;
+  
+  if (N < 2) return;
+  l = N >> 1;
+  ir = N - 1;
+  for (;;) {
+    if (l > 0) {
+      l--;
+      tX = X[l];
+      tY = Y[l];
+      tZ = Z[l];
+    }
+    else {
+      tX = X[ir];
+      X[ir] = X[0];
+      tY = Y[ir];
+      Y[ir] = Y[0];
+      tZ = Z[ir];
+      Z[ir] = Z[0];
+      if (--ir == 0) {
+	X[0] = tX;
+	Y[0] = tY;
+	Z[0] = tZ;
+	return;
+      }
+    }
+    i = l;
+    j = (l << 1) + 1;
+    while (j <= ir) {
+      if (j < ir && X[j] < X[j+1]) j++;
+      if (tX < X[j]) {
+	X[i] = X[j];
+	Y[i] = Y[j];
+	Z[i] = Z[j];
+	j += (i=j) + 1;
+      }
+      else j = ir + 1;
+    }
+    X[i] = tX;
+    Y[i] = tY;
+    Z[i] = tZ;
+  }
+}
+
+void sort_lists (float *X, float *Y, int *S, int N) {
+
+  int l,j,ir,i;
+  double tX, tY, tS;
+  
+  if (N < 2) return;
+  l = N >> 1;
+  ir = N - 1;
+  for (;;) {
+    if (l > 0) {
+      l--;
+      tX = X[l];
+      tY = Y[l];
+      tS = S[l];
+    }
+    else {
+      tX = X[ir];
+      X[ir] = X[0];
+      tY = Y[ir];
+      Y[ir] = Y[0];
+      tS = S[ir];
+      S[ir] = S[0];
+      if (--ir == 0) {
+	X[0] = tX;
+	Y[0] = tY;
+	S[0] = tS;
+	return;
+      }
+    }
+    i = l;
+    j = (l << 1) + 1;
+    while (j <= ir) {
+      if (j < ir && X[j] < X[j+1]) j++;
+      if (tX < X[j]) {
+	X[i] = X[j];
+	Y[i] = Y[j];
+	S[i] = S[j];
+	j += (i=j) + 1;
+      }
+      else j = ir + 1;
+    }
+    X[i] = tX;
+    Y[i] = tY;
+    S[i] = tS;
+  }
+}
+
+void dsort_lists (double *X, double *Y, int *S, int N) {
+
+  int l,j,ir,i;
+  double tX, tY, tS;
+  
+  if (N < 2) return;
+  l = N >> 1;
+  ir = N - 1;
+  for (;;) {
+    if (l > 0) {
+      l--;
+      tX = X[l];
+      tY = Y[l];
+      tS = S[l];
+    }
+    else {
+      tX = X[ir];
+      X[ir] = X[0];
+      tY = Y[ir];
+      Y[ir] = Y[0];
+      tS = S[ir];
+      S[ir] = S[0];
+      if (--ir == 0) {
+	X[0] = tX;
+	Y[0] = tY;
+	S[0] = tS;
+	return;
+      }
+    }
+    i = l;
+    j = (l << 1) + 1;
+    while (j <= ir) {
+      if (j < ir && X[j] < X[j+1]) j++;
+      if (tX < X[j]) {
+	X[i] = X[j];
+	Y[i] = Y[j];
+	S[i] = S[j];
+	j += (i=j) + 1;
+      }
+      else j = ir + 1;
+    }
+    X[i] = tX;
+    Y[i] = tY;
+    S[i] = tS;
+  }
+}
+
+// sort two int vectors by first vector
+void isort_pair (int *X, int *Y, int N) {
+
+  int l,j,ir,i;
+  int tX, tY;
+  
+  if (N < 2) return;
+  l = N >> 1;
+  ir = N - 1;
+  for (;;) {
+    if (l > 0) {
+      l--;
+      tX = X[l];
+      tY = Y[l];
+    }
+    else {
+      tX = X[ir];
+      X[ir] = X[0];
+      tY = Y[ir];
+      Y[ir] = Y[0];
+      if (--ir == 0) {
+	X[0] = tX;
+	Y[0] = tY;
+	return;
+      }
+    }
+    i = l;
+    j = (l << 1) + 1;
+    while (j <= ir) {
+      if (j < ir && X[j] < X[j+1]) j++;
+      if (tX < X[j]) {
+	X[i] = X[j];
+	Y[i] = Y[j];
+	j += (i=j) + 1;
+      }
+      else j = ir + 1;
+    }
+    X[i] = tX;
+    Y[i] = tY;
+  }
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/lib.data/spline.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/lib.data/spline.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/lib.data/spline.c	(revision 11389)
@@ -0,0 +1,58 @@
+# include "data.h"
+
+/* construct the natural spline for x, y in y2 */
+void spline (float *x, float *y, int N, float *y2) {
+
+  int i;
+  float dy, dx, *tmp;
+  
+  ALLOCATE (tmp, float, N);
+
+  y2[0] = tmp[0] = 0.0;
+  
+  for (i = 1; i < N-1; i++) {
+    dx = (x[i+0] - x[i-1]) / (x[i+1] - x[i-1]);
+    dy = dx * y2[i-1] + 2.0;
+    y2[i] = (dx - 1.0) / dy;
+    tmp[i] = (y[i+1] - y[i+0]) / (x[i+1] - x[i+0]) - (y[i+0] - y[i-1]) / (x[i+0] - x[i-1]);
+    tmp[i] = (6.0 * tmp[i] / (x[i+1] - x[i-1]) - dx*tmp[i-1]) / dy;
+  }
+  
+  y2[N-1] = 0;
+  for (i = N-2; i >= 1; i--)
+    y2[i] = y2[i]*y2[i+1] + tmp[i];
+
+  free (tmp);
+}
+
+/* evaluate spline for x, y, y2 at X */
+float splint (float *x, float *y, float *y2, int N, float X) {
+
+  int i, lo, hi;
+  float dx, a, b, value;
+  
+  /* find correct element in array (x must be sorted) */
+  lo = 0;
+  hi = N-1;
+  while (hi - lo > 1) {
+    i = (hi+lo) >> 1;
+    if (x[i] > X) 
+      hi = i;
+    else 
+      lo = i;
+  }
+
+  /* error condition: duplicate abssisca */
+  dx = x[hi] - x[lo];
+  if (dx == 0.0) {
+    return (HUGE_VAL);
+  }
+
+  /* evaluate spline */
+  a = (x[hi] - X) / dx;
+  b = (X - x[lo]) / dx;
+
+  value = a*y[lo] + b*y[hi] + ((a*a*a - a)*y2[lo] + (b*b*b - b)*y2[hi])*(dx*dx) / 6.0;
+  return (value);
+
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/lib.data/starfuncs.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/lib.data/starfuncs.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/lib.data/starfuncs.c	(revision 11389)
@@ -0,0 +1,251 @@
+# include "data.h"
+
+double get_aperture_stats (Matrix *matrix, int X, int Y, int Npix, int Nborder, double max) {
+
+  double *ring;
+  double x, y, x2, y2, xy, I, sky, FWHMx, FWHMy, value, mag, Sxy;
+  int i, j, n, Npix2, Nring, Nmax;
+  double Npts, gain, dsky2, dmag, peak, offset;
+  char *string;
+  
+  string = get_variable ("GAIN");
+  if (string == (char *) NULL) {
+    gprint (GP_ERR, "assuming a value of 1.0\n");
+    gain = 1.0;
+  } else {
+    gain = atof (string);
+  }
+  Nborder = MAX (1, Nborder);
+  Nborder = MIN (1000, Nborder);
+  
+  Npix2 = (int)(0.5*Npix);
+  Npix = 2 * Npix2 + 1;
+  Nring = 4*Nborder*(Nborder + Npix);
+  ALLOCATE (ring, double, Nring);
+  bzero (ring, sizeof(double)*Nring);
+
+  n = 0;  
+  for (j = 0; j < Nborder; j++) {
+    for (i = X - Npix2 - Nborder; i < X + Npix2 + Nborder + 1; i++, n+=2) {
+      ring[n]   = gfits_get_matrix_value (matrix, i, (int)(Y - Npix2 - j));
+      ring[n+1] = gfits_get_matrix_value (matrix, i, (int)(Y + Npix2 + j));
+    }
+    for (i = Y - Npix2; i < Y + Npix2 + 1; i++, n+=2) {
+      ring[n]   = gfits_get_matrix_value (matrix, (int)(X - Npix2 - j), i);
+      ring[n+1] = gfits_get_matrix_value (matrix, (int)(X + Npix2 + j), i);
+    }
+  }
+  sort (ring, Nring);
+  for (Npts = sky = dsky2 = 0, i = 0.25*Nring; i < 0.75*Nring; i++, Npts += 1.0) {
+    sky += ring[i];
+    dsky2 += ring[i]*ring[i];
+  }
+  sky = sky / Npts;
+  dsky2 = dsky2 / Npts - sky*sky;
+  free (ring);
+
+  peak = 0;
+  Npts = Nmax = 0;
+  x = y = x2 = y2 = xy = I = 0;
+  for (i = X - Npix2; i < X + Npix2 + 1; i++) {
+    for (j = Y - Npix2; j < Y + Npix2 + 1; j++) {
+      value = gfits_get_matrix_value (matrix, i, j);
+      offset = value - sky;
+      x  += i*offset;
+      y  += j*offset;
+      x2 += i*i*offset;
+      y2 += j*j*offset;
+      xy += i*j*offset;
+      I  += offset;
+      Npts ++;
+      if (value > max) {
+	Nmax ++;
+      }
+      if (value > peak) peak = value;
+    }
+  }
+
+  x = x / I;
+  y = y / I;
+  FWHMx = 2.355*sqrt (fabs(x2 / I - x*x));
+  FWHMy = 2.355*sqrt (fabs(y2 / I - y*y));
+  Sxy   = xy / I - x*y;
+  mag = -2.5*log10(I);
+  dmag = sqrt (fabs(1.0 / (gain*I) + Npts*dsky2 / (I*I)));
+  x = x + 1;
+  y = y + 1;
+  
+  set_variable ("Xg", x);
+  set_variable ("Yg", y);
+  set_variable ("SXg", FWHMx);
+  set_variable ("SYg", FWHMy);
+  set_variable ("SXYg", Sxy);
+  set_variable ("Sg", sky);
+  set_variable ("dSg", sqrt (fabs (dsky2)));
+  set_variable ("Zg", mag);
+  set_variable ("dZg", dmag);
+  set_variable ("Zcg", I);
+  set_variable ("Zpk", peak);
+  set_int_variable ("Nsat", Nmax);
+  
+  gprint (GP_LOG, "%f %f %f %f %f %f %f %f\n", x, y, FWHMx, FWHMy, sky, I, mag, dmag);
+
+  return (mag);
+
+}
+
+static double Raper  =  5;
+static double Rinner = 10;
+static double Router = 15;
+static double *sky = NULL;
+
+int set_rough_radii (double Ra, double Ri, double Ro) {
+
+  Raper = Ra;
+  Rinner = Ri;
+  Router = Ro;
+  if (sky == NULL) {
+    ALLOCATE (sky, double, SQ(2*Router + 1));
+  } else {
+    REALLOCATE (sky, double, SQ(2*Router + 1));
+  }
+  return (TRUE);
+}
+
+/* use a circular aperture */
+int get_rough_star (float *data, int Nx, int Ny, int x, int y,
+		    float *xc, float *yc, 
+		    float *sx, float *sy, float *sxy,
+		    float *zs, float *zp, float *sk) {
+
+  double Ra2, Ri2, Ro2, rad2;
+  int i, j, Npts, Nsky;
+  int Xs, Xe, Ys, Ye, off, Xc, Yc;
+  double peak, fsky, value;
+  double Sx, Sy, Sx2, Sy2, Sxy, Sum;
+  
+  /* define circular boundaries */
+  Ra2 = SQ(Raper);
+  Ri2 = SQ(Rinner);
+  Ro2 = SQ(Router);
+
+  /* measure the sky level */
+  /* boundaries for the outer sky region */
+  Xs = MAX (x - Router, 0);
+  Xe = MIN (x + Router + 1, Nx);
+  Ys = MAX (y - Router, 0);
+  Ye = MIN (y + Router + 1, Ny);
+
+/* this sample uses a circular aperture */
+# if (0)
+  Nsky = 0;  
+  for (j = Ys; j < Ye; j++) {
+    off = j*Nx;
+    for (i = Xs; i < Xe; i++) { 
+      rad2 = SQ(i - x) + SQ(j - y);
+      if (rad2 > Ro2) continue;
+      if (rad2 < Ri2) continue;
+      sky[Nsky] = data[i+off];
+      Nsky ++;
+    }
+  }
+  sort (sky, Nsky);
+  for (Npts = fsky = 0, i = 0.25*Nsky; i < 0.75*Nsky; i++, Npts += 1.0) {
+    fsky += sky[i];
+  }
+  fsky = fsky / Npts;
+# else
+
+/* this sample uses a square outer annulus, without loop if tests */
+  Nsky = 0;  
+  Xs = MAX (x - Router, 0);
+  Xe = MIN (x - Rinner + 1, Nx);
+  Ys = MAX (y - Rinner, 0);
+  Ye = MIN (y + Rinner + 1, Ny);
+  for (j = Ys; j < Ye; j++) {
+    off = j*Nx;
+    for (i = Xs; i < Xe; i++) { 
+      sky[Nsky] = data[i+off];
+      Nsky ++;
+    }
+  }
+  Xs = MAX (x + Rinner, 0);
+  Xe = MIN (x + Router + 1, Nx);
+  for (j = Ys; j < Ye; j++) {
+    off = j*Nx;
+    for (i = Xs; i < Xe; i++) { 
+      sky[Nsky] = data[i+off];
+      Nsky ++;
+    }
+  }
+  Xs = MAX (x - Rinner, 0);
+  Xe = MIN (x - Rinner + 1, Nx);
+  Ys = MAX (y - Router, 0);
+  Ye = MIN (y - Rinner + 1, Ny);
+  for (j = Ys; j < Ye; j++) {
+    off = j*Nx;
+    for (i = Xs; i < Xe; i++) { 
+      sky[Nsky] = data[i+off];
+      Nsky ++;
+    }
+  }
+  Ys = MAX (y + Rinner, 0);
+  Ye = MIN (y + Router + 1, Ny);
+  for (j = Ys; j < Ye; j++) {
+    off = j*Nx;
+    for (i = Xs; i < Xe; i++) { 
+      sky[Nsky] = data[i+off];
+      Nsky ++;
+    }
+  }
+  sort (sky, Nsky);
+  for (Npts = fsky = 0, i = 0.25*Nsky; i < 0.75*Nsky; i++, Npts += 1.0) {
+    fsky += sky[i];
+  }
+  fsky = fsky / Npts;
+# endif
+
+  /* boundaries for the star region */
+  Xs = MAX (x - Raper, 0);
+  Xe = MIN (x + Raper + 1, Nx);
+  Ys = MAX (y - Raper, 0);
+  Ye = MIN (y + Raper + 1, Ny);
+
+  /** note that this will fail on negative flux objects */
+  peak = Npts = 0;
+  Sx = Sy = Sx2 = Sy2 = Sxy = Sum = 0;
+  for (j = Ys; j < Ye; j++) {
+    off = j*Nx;
+    Yc = j - y;
+    for (i = Xs; i < Xe; i++) {
+      Xc = i - x;
+      rad2 = SQ(Xc) + SQ(Yc);
+      if (rad2 > Ro2) continue;
+      value = data[i+off] - fsky;
+      Sx  += Xc*value;
+      Sy  += Yc*value;
+      Sx2 += Xc*Xc*value;
+      Sy2 += Yc*Yc*value;
+      Sxy += Xc*Yc*value;
+      Sum += value;
+      Npts ++;
+      if (value > peak) peak = value;
+    }
+  }
+
+  *xc = Sx / Sum;
+  *yc = Sy / Sum;
+  *sx = sqrt (fabs (Sx2 / Sum - SQ(*xc)));
+  *sy = sqrt (fabs (Sy2 / Sum - SQ(*yc)));
+  *sxy = Sxy / Sum;
+  *xc += x;
+  *yc += y;
+  *zs = Sum;
+  *zp = peak;
+  *sk = fsky;
+  /* note sigma is rough: round-off errors can introduce errors */
+  /* using values relative to x,y should minimize this effect */
+
+  return (Npts);
+}
+
Index: /branches/opihi-2-9/Ohana/src/opihi/lib.data/style_args.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/lib.data/style_args.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/lib.data/style_args.c	(revision 11389)
@@ -0,0 +1,68 @@
+# include "data.h"
+# include "display.h"
+
+int style_args (Graphdata *graphmode, int *argc, char **argv, int Nforce) {
+  
+  int N, Ngraph;
+  char *name;
+
+  Ngraph = -1;
+  if ((N = get_argument (*argc, argv, "-n"))) {
+    remove_argument (N, argc, argv);
+    Ngraph = atof (argv[N]);
+    remove_argument (N, argc, argv);
+  }
+  if (Nforce != -1) Ngraph = Nforce;
+  if (!GetGraph (graphmode, NULL, &Ngraph)) return (FALSE);
+
+  if (*argc == 1) {
+    name = KapaColorName (graphmode[0].color);
+    gprint (GP_ERR, "current style (%d): -x %d -c %s -pt %d -lt %d -lw %f -sz %f\n", Ngraph,
+	     graphmode[0].style, name, graphmode[0].ptype, 
+	     graphmode[0].ltype, graphmode[0].lweight,
+	     graphmode[0].size);
+    return (TRUE);
+  }
+
+  if ((N = get_argument (*argc, argv, "-lt"))) {
+    remove_argument (N, argc, argv);
+    graphmode[0].ltype = atof(argv[N]);
+    remove_argument (N, argc, argv);
+  }
+  if ((N = get_argument (*argc, argv, "-lw"))) {
+    remove_argument (N, argc, argv);
+    graphmode[0].lweight = atof(argv[N]);
+    remove_argument (N, argc, argv);
+  }
+  if ((N = get_argument (*argc, argv, "-pt"))) {
+    remove_argument (N, argc, argv);
+    graphmode[0].ptype = atof(argv[N]);
+    remove_argument (N, argc, argv);
+  }
+  if ((N = get_argument (*argc, argv, "+eb"))) {
+    remove_argument (N, argc, argv);
+    graphmode[0].ebar = TRUE;
+  }
+  if ((N = get_argument (*argc, argv, "-eb"))) {
+    remove_argument (N, argc, argv);
+    graphmode[0].ebar = FALSE;
+  }
+  if ((N = get_argument (*argc, argv, "-sz"))) {
+    remove_argument (N, argc, argv);
+    graphmode[0].size = atof(argv[N]);
+    remove_argument (N, argc, argv);
+  }
+  if ((N = get_argument (*argc, argv, "-c"))) {
+    remove_argument (N, argc, argv);
+    graphmode[0].color = KapaColorByName (argv[N]);
+    if (graphmode[0].color == -1) return (FALSE);
+    remove_argument (N, argc, argv);
+  }
+  if ((N = get_argument (*argc, argv, "-x"))) {
+    remove_argument (N, argc, argv);
+    graphmode[0].style = atof(argv[N]);
+    remove_argument (N, argc, argv);
+  }
+
+  return (TRUE);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/lib.data/svdcmp.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/lib.data/svdcmp.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/lib.data/svdcmp.c	(revision 11389)
@@ -0,0 +1,211 @@
+# include "data.h"
+
+/*
+  static float at,bt,ct;
+  #define PYTHAG(a,b) ((at=fabs(a)) > (bt=fabs(b)) ? \
+  (ct=bt/at,at*sqrt(1.0+ct*ct)) : (bt ? (ct=at/bt,bt*sqrt(1.0+ct*ct)): 0.0))
+  pythag -> hypot (check on roundoff errors) 
+*/
+
+/* use simple max? */
+#define FSIGN(a,b) ((b) >= 0.0 ? fabs(a) : -fabs(a))
+
+/* n == Nx, m == Ny */
+int svdcmp (float *a, float *w, float *v, int Nx, int Ny) {
+
+  int flag, i, its, j, jj, k, l, nm, status;
+  float c, f, h, s, x, y, z;
+  float anorm=0.0, g = 0.0, scale = 0.0;
+  float *rv1;
+
+  if (Ny < Nx) return (0);
+
+  l = nm = 0;
+  ALLOCATE (rv1, float, Nx);
+  for (i = 0; i < Nx; i++) {
+    l = i + 1;
+    rv1[i] = scale*g;
+    g = s = scale = 0.0;
+    if (i < Ny) {
+      for (k = i; k < Ny; k++) scale += fabs(a[k*Nx + i]);
+      if (scale) {
+	for (k = i; k < Ny; k++) {
+	  a[k*Nx + i] /= scale;
+	  s += a[k*Nx + i]*a[k*Nx + i];
+	}
+	f = a[i*Nx + i];
+	g  = -FSIGN(sqrt(s), f);
+	h = f*g - s;
+	a[i*Nx + i] = f-g;
+	if (i != Nx - 1) {
+	  for (j = l; j < Nx; j++) {
+	    for (s = 0.0, k = i; k < Ny; k++) s += a[k*Nx + i]*a[k*Nx + j];
+	    f = s/h;
+	    for (k = i; k < Ny; k++) a[k*Nx + j] += f*a[k*Nx + i];
+	  }
+	}
+	for (k = i; k < Ny; k++) a[k*Nx + i] *= scale;
+      }
+    }
+    w[i] = scale*g;
+    g = s = scale = 0.0;
+    if ((i < Ny) && (i != (Nx - 1))) {
+      for (k = l; k < Nx; k++) scale += fabs(a[i*Nx + k]);
+      if (scale) {
+	for (k = l; k < Nx; k++) {
+	  a[i*Nx + k] /= scale;
+	  s += a[i*Nx + k]*a[i*Nx + k];
+	}
+	f = a[i*Nx + l];
+	g = -FSIGN(sqrt(s), f);
+	h = f*g - s;
+	a[i*Nx + l] = f-g;
+	for (k = l; k < Nx; k++) rv1[k] = a[i*Nx + k]/h;
+	if (i != Ny - 1) {
+	  for (j = l; j < Ny; j++) {
+	    for (s = 0.0, k = l; k < Nx; k++) s += a[j*Nx + k]*a[i*Nx + k];
+	    for (k = l; k < Nx; k++) a[j*Nx + k] += s*rv1[k];
+	  }
+	}
+	for (k = l; k < Nx; k++) a[i*Nx + k] *= scale;
+      }
+    }
+    anorm = MAX(anorm, (fabs(w[i]) + fabs(rv1[i])));
+  }
+
+  for (i = Nx - 1; i >= 0; i--) {
+    if (i < Nx - 1) {
+      if (g) {
+	/* isn't l == n to start?? */
+	for (j = l; j < Nx; j++) v[j*Nx + i] = (a[i*Nx + j]/a[i*Nx + l])/g;
+	for (j = l; j < Nx; j++) {
+	  for (s = 0.0, k = l; k < Nx; k++) s += a[i*Nx + k]*v[k*Nx + j];
+	  for (k = l; k < Nx; k++) v[k*Nx + j] += s*v[k*Nx + i];
+	}
+      }
+      for (j = l; j < Nx; j++) v[i*Nx + j] = v[j*Nx + i] = 0.0;
+    }
+    v[i*Nx + i] = 1.0;
+    g = rv1[i];
+    l = i;
+  }
+  for (i = Nx - 1; i >= 0; i--) {
+    l = i + 1;
+    g = w[i];
+    if (i < Nx - 1)
+      for (j = l; j < Nx; j++) a[i*Nx + j] = 0.0;
+    if (g) {
+      g = 1.0/g;
+      if (i != Nx - 1) {
+	for (j = l; j < Nx; j++) {
+	  for (s = 0.0, k = l; k < Ny; k++) s += a[k*Nx + i]*a[k*Nx + j];
+	  f = (s/a[i*Nx + i])*g;
+	  for (k = i; k < Ny; k++) a[k*Nx + j] += f*a[k*Nx + i];
+	}
+      }
+      for (j = i; j < Ny; j++) a[j*Nx + i] *= g;
+    } else {
+      for (j = i; j < Ny; j++) a[j*Nx + i] = 0.0;
+    }
+    ++a[i*Nx + i];
+  }
+
+  status = 1;
+  for (k = Nx - 1; k >= 0; k--) {
+    for (its = 0; its < 30; its++) {
+      flag = 1;
+      for (l = k; l >= 0; l--) {
+	nm = l - 1;
+	if (fabs(rv1[l])+anorm == anorm) {
+	  flag = 0;
+	  break;
+	}
+	if (fabs(w[nm])+anorm == anorm) break;
+      }
+      if (flag) {
+	c = 0.0;
+	s = 1.0;
+	for (i = l; i < k; i++) {
+	  f = s*rv1[i];
+	  if (fabs(f)+anorm != anorm) {
+	    g = w[i];
+	    h = hypot (f, g);
+	    w[i] = h;
+	    h = 1.0/h;
+	    c = g*h;
+	    s = (-f*h);
+	    for (j = 0; j < Ny; j++) {
+	      y = a[j*Nx + nm];
+	      z = a[j*Nx + i];
+	      a[j*Nx + nm] = y*c + z*s;
+	      a[j*Nx + i] = z*c - y*s;
+	    }
+	  }
+	}
+      }
+      z = w[k];
+      if (l == k) {
+	if (z < 0.0) {
+	  w[k] = -z;
+	  for (j = 0; j < Nx; j++) v[j*Nx + k] = (-v[j*Nx + k]);
+	}
+	break;
+      }
+      if (its == 29) status = 0;
+      x = w[l];
+      nm = k-1;
+      y = w[nm];
+      g = rv1[nm];
+      h = rv1[k];
+      f = ((y-z)*(y+z) + (g-h)*(g+h))/(2.0*h*y);
+      g = hypot (f, 1.0);
+      f = ((x-z)*(x+z) + h*((y/(f+FSIGN(g, f)))-h))/x;
+      c = s = 1.0;
+      for (j = l; j < nm; j++) {
+	i = j+1;
+	g = rv1[i];
+	y = w[i];
+	h = s*g;
+	g = c*g;
+	z = hypot (f, h);
+	rv1[j] = z;
+	c = f/z;
+	s = h/z;
+	f = x*c+g*s;
+	g = g*c-x*s;
+	h = y*s;
+	y = y*c;
+	for (jj = 0; jj < Nx; jj++) {
+	  x = v[jj*Nx + j];
+	  z = v[jj*Nx + i];
+	  v[jj*Nx + j] = x*c+z*s;
+	  v[jj*Nx + i] = z*c-x*s;
+	}
+	z = hypot(f, h);
+	w[j] = z;
+	if (z) {
+	  z = 1.0/z;
+	  c = f*z;
+	  s = h*z;
+	}
+	f = (c*g) + (s*y);
+	x = (c*y) - (s*g);
+	for (jj = 0; jj < Ny; jj++) {
+	  y = a[jj*Nx + j];
+	  z = a[jj*Nx + i];
+	  a[jj*Nx + j] = y*c+z*s;
+	  a[jj*Nx + i] = z*c-y*s;
+	}
+      }
+      rv1[l] = 0.0;
+      rv1[k] = f;
+      w[k] = x;
+    }
+  }
+  free(rv1);
+  return (1);
+}
+
+#undef FSIGN
+#undef MAX
+#undef PYTHAG
Index: /branches/opihi-2-9/Ohana/src/opihi/lib.shell/BufferOps.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/lib.shell/BufferOps.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/lib.shell/BufferOps.c	(revision 11389)
@@ -0,0 +1,262 @@
+# include "opihi.h"
+
+static Buffer **buffers;
+static int     Nbuffers;
+
+void InitBuffers () {
+  Nbuffers = 0;
+  ALLOCATE (buffers, Buffer *, 1);
+}
+
+Buffer *InitBuffer () {
+  Buffer *buf;
+
+  ALLOCATE (buf, Buffer, 1);
+  bzero (buf[0].name, 1024);
+  bzero (buf[0].file, 1024);
+  ALLOCATE (buf[0].matrix.buffer, char, 1);
+  ALLOCATE (buf[0].header.buffer, char, 1);
+  return (buf);
+}
+
+int IsBuffer (char *name) {
+ 
+  int i;
+
+  if (name == NULL) return (FALSE);
+
+  for (i = 0; (i < Nbuffers) && (strcmp(buffers[i][0].name, name)); i++);
+  if (i == Nbuffers) return (FALSE);
+  return (TRUE);
+}
+
+int IsBufferPtr (Buffer *buf) {
+ 
+  int i;
+
+  if (buf == NULL) return (FALSE);
+
+  for (i = 0; (i < Nbuffers) && (buffers[i] != buf); i++);
+  if (i == Nbuffers) return (FALSE);
+  return (TRUE);
+}
+
+Buffer *SelectBuffer (char *name, int mode, int verbose) {
+
+  int i;
+
+  if (name == NULL) goto error;
+  if (ISNUM(name[0])) goto error;
+  if (IsVector(name)) goto error;
+
+  for (i = 0; (i < Nbuffers) && (strcmp(buffers[i][0].name, name)); i++);
+  /* is a new buffer */
+  if (i == Nbuffers) { 
+    if (mode == OLDBUFFER) goto error;
+    Nbuffers += 1;
+    REALLOCATE (buffers, Buffer *, Nbuffers);
+    buffers[i] = InitBuffer ();
+    strcpy (buffers[i][0].name, name);
+    return (buffers[i]);
+  } 
+  /* is an old buffer */
+  if (mode == NEWBUFFER) goto error;
+  return (buffers[i]);
+
+ error:
+  if (verbose) gprint (GP_ERR, "invalid matrix %s\n", name);
+  return (NULL);
+}
+
+int CreateBuffer (Buffer *buf, int Nx, int Ny, int bitpix, float bzero, float bscale) {
+
+  /* store the default output values */
+  gfits_init_header (&buf[0].header);
+
+  /* assign the necessary internal values */
+  buf[0].header.bitpix   = -32;
+  buf[0].header.unsign   = FALSE;
+  buf[0].header.bzero    = 0;
+  buf[0].header.bscale   = 1;
+  
+  buf[0].header.Naxes = 2;
+  buf[0].header.Naxis[0] = Nx;
+  buf[0].header.Naxis[1] = Ny;
+
+  buf[0].bitpix = bitpix;
+  buf[0].unsign = FALSE;
+  buf[0].bzero  = bzero;
+  buf[0].bscale = bscale;
+  
+  /* make some test of the validity of the values */
+
+  /* create the appropriate header and matrix */
+  gfits_create_header (&buf[0].header);
+  gfits_create_matrix (&buf[0].header, &buf[0].matrix);
+
+  return (TRUE);
+}
+  
+/* copy data from in to out - new memory space */
+int CopyNamedBuffer (char *out, char *in) {
+  Buffer *In, *Out;
+  if ((In  = SelectBuffer (in,  OLDBUFFER, FALSE)) == NULL) return (FALSE);
+  if ((Out = SelectBuffer (out, ANYBUFFER, FALSE)) == NULL) return (FALSE);
+  CopyBuffer (Out, In);
+  return (TRUE);
+}
+
+int CopyBuffer (Buffer *out, Buffer *in) {
+  free (out[0].matrix.buffer);
+  free (out[0].header.buffer);
+  out[0].bitpix = in[0].bitpix;
+  out[0].unsign = in[0].unsign;
+  out[0].bscale = in[0].bscale;
+  out[0].bzero  = in[0].bzero;
+  strcpy (out[0].file, in[0].file);
+  gfits_copy_matrix (&in[0].matrix, &out[0].matrix);
+  gfits_copy_header (&in[0].header, &out[0].header);
+  return (TRUE);
+}
+
+/* move data from in to out - use old memory space */
+int MoveNamedBuffer (char *out, char *in) {
+  Buffer *In, *Out;
+  if ((In  = SelectBuffer (in,  OLDBUFFER, FALSE)) == NULL) return (FALSE);
+  if ((Out = SelectBuffer (out, ANYBUFFER, FALSE)) == NULL) return (FALSE);
+  MoveBuffer (Out, In);
+  return (TRUE);
+}
+int MoveBuffer (Buffer *out, Buffer *in) {
+  int i, j;
+
+  free (out[0].matrix.buffer);
+  free (out[0].header.buffer);
+  out[0].bitpix = in[0].bitpix;
+  out[0].unsign = in[0].unsign;
+  out[0].bscale = in[0].bscale;
+  out[0].bzero  = in[0].bzero;
+  out[0].matrix = in[0].matrix;
+  out[0].header = in[0].header;
+  strcpy (out[0].file, in[0].file);
+
+  /* delete buffer entry from buffer list, if it exists */
+  for (i = 0; (i < Nbuffers) && (in != buffers[i]); i++);
+  if (i == Nbuffers) {
+    free (in);
+    return (TRUE);
+  }
+
+  free (in);
+  for (j = i; j < Nbuffers - 1; j++) buffers[j] = buffers[j + 1];
+  Nbuffers -= 1;
+  REALLOCATE (buffers, Buffer *, MAX (Nbuffers, 1));
+  return (TRUE);
+}
+
+/* delete by ptr */
+int DeleteBuffer (Buffer *buf) {
+
+  int i, j;
+
+  if (buf == NULL) return (FALSE);
+  for (i = 0; (i < Nbuffers) && (buf != buffers[i]); i++);
+  if (i == Nbuffers) return (FALSE);
+
+  gfits_free_header (&buffers[i][0].header);
+  gfits_free_matrix (&buffers[i][0].matrix);
+  free (buffers[i]);
+
+  for (j = i; j < Nbuffers - 1; j++) buffers[j] = buffers[j + 1];
+
+  Nbuffers -= 1;
+  REALLOCATE (buffers, Buffer *, MAX (Nbuffers, 1));
+  return (TRUE);
+}
+  
+/* delete by name */
+int DeleteNamedBuffer (char *name) {
+
+  int i, j;
+
+  if (name == NULL) return (FALSE);
+  for (i = 0; (i < Nbuffers) && (strcmp(buffers[i][0].name, name)); i++);
+  if (i == Nbuffers) return (FALSE);
+
+  gfits_free_header (&buffers[i][0].header);
+  gfits_free_matrix (&buffers[i][0].matrix);
+  free (buffers[i]);
+
+  for (j = i; j < Nbuffers - 1; j++) buffers[j] = buffers[j + 1];
+
+  Nbuffers -= 1;
+  REALLOCATE (buffers, Buffer *, MAX (Nbuffers, 1));
+  return (TRUE);
+}
+
+int SelectOverlay (char *name, int *number) {
+
+  *number = -1;
+  if (!strcmp (name, "red") || !strcmp (name, "0"))
+    *number = 0;
+  if (!strcmp (name, "green") || !strcmp (name, "1"))
+    *number = 1;
+  if (!strcmp (name, "blue") || !strcmp (name, "2"))
+    *number = 2;
+  if (!strcmp (name, "yellow") || !strcmp (name, "3"))
+    *number = 3;
+
+  if (*number < 0) {
+    gprint (GP_ERR, "valid overlays may be: red (0), green (1), blue (2), yellow (3)\n");
+    return (FALSE);
+  }
+  else {
+    return (TRUE);
+  }
+}
+
+void dump_buffers (int n) {
+
+  int i;
+
+  gprint (GP_ERR, "try %d\n", n);
+  for (i = 0; i < Nbuffers; i++) {
+    gprint (GP_ERR, "%d  %lx\n", i, (long) buffers[i]);
+    gprint (GP_ERR, "%d  %lx  %s\n", i, (long) buffers[i][0].name, buffers[i][0].name);
+    gprint (GP_ERR, "%d  %lx  %s\n", i, (long) buffers[i][0].file, buffers[i][0].file);
+    gprint (GP_ERR, "%d  %lx  %lx\n", i, (long) &buffers[i][0].header, (long) buffers[i][0].header.buffer);
+    gprint (GP_ERR, "%d  %lx  %lx\n", i, (long) &buffers[i][0].matrix, (long) buffers[i][0].matrix.buffer);
+    gprint (GP_ERR, "%d  %d  %d  %f %f\n", i, buffers[i][0].bitpix, buffers[i][0].unsign, buffers[i][0].bscale, buffers[i][0].bzero);
+  }
+}
+
+int PrintBuffers (int Long) {
+
+  int i;
+
+  if (Nbuffers == 0) {
+    gprint (GP_ERR, "No allocated buffers\n");
+    return (TRUE);
+  }
+  
+  if (Long) {
+    gprint (GP_LOG, "    N       name                      file     X     Y    bytes BP  U   bzero     bscale  \n");
+    for (i = 0; i < Nbuffers; i++) {
+      gprint (GP_LOG, "%5d %10s %25s %5d %5d %10d %3d %1d %10.4e %10.4e\n",
+	       i, buffers[i][0].name, buffers[i][0].file, 
+	       buffers[i][0].header.Naxis[0], buffers[i][0].header.Naxis[1],
+	       buffers[i][0].header.size + buffers[i][0].matrix.size, buffers[i][0].bitpix, 
+	       buffers[i][0].unsign, buffers[i][0].bzero, buffers[i][0].bscale);
+    }
+    return (TRUE);
+  }
+
+  gprint (GP_LOG, "    N       name                      file     X     Y    bytes\n");
+  for (i = 0; i < Nbuffers; i++) {
+    gprint (GP_LOG, "%5d %10s %25s %5d %5d %10d\n",
+	     i, buffers[i][0].name, buffers[i][0].file, 
+	     buffers[i][0].header.Naxis[0], buffers[i][0].header.Naxis[1],
+	     buffers[i][0].header.size + buffers[i][0].matrix.size);
+  }
+  return (TRUE);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/lib.shell/CommandOps.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/lib.shell/CommandOps.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/lib.shell/CommandOps.c	(revision 11389)
@@ -0,0 +1,175 @@
+# include "opihi.h"
+
+static Command  *commands;
+static int      Ncommands;
+static int      NCOMMANDS;
+
+void InitCommands () {
+  NCOMMANDS = 20;
+  Ncommands = 0;
+  ALLOCATE (commands, Command, NCOMMANDS);
+}
+
+void AddCommand (Command *new) {
+  
+  commands[Ncommands] = *new;
+  Ncommands ++;
+  if (Ncommands == NCOMMANDS) {
+    NCOMMANDS += 20;
+    REALLOCATE (commands, Command, NCOMMANDS);
+  }
+}
+
+int DeleteCommand (Command *command) {
+
+  int i, Nc;
+
+  Nc = -1;
+  for (i = 0; i < Ncommands; i++) {
+    if (command == &commands[i]) {
+      Nc = i;
+      break;
+    }
+  }
+  if (Nc == -1) {
+    gprint (GP_ERR, "programming error: command not found\n");
+    return (FALSE);
+  }
+
+  free (commands[Nc].name);
+  for (i = Nc + 1; i < Ncommands; i++)
+    commands[i - 1] = commands[i];
+  Ncommands --;
+  REALLOCATE (commands, Command, Ncommands);
+  return (TRUE);
+}
+
+/* return command which unambiguously matches name */
+Command *MatchCommand (char *name, int VERBOSE, int EXACT) {
+
+  int i, match[10], Nmatch;
+
+  /* try for an exact match first */
+  for (i = 0; i < Ncommands; i++) {
+    if (!strcmp (commands[i].name, name)) {
+      return (&commands[i]);
+    }
+  }
+  if (EXACT) {
+    if (VERBOSE) gprint (GP_ERR, "no exact match to %s\n", name);
+    return (NULL);
+  }
+
+  /* not found as complete command, try partial */
+  Nmatch = 0;
+  for (i = 0; (Nmatch < 10) && (i < Ncommands); i++) {
+    if (!strncmp (commands[i].name, name, strlen(name))) {  /* found a command */
+      match[Nmatch] = i;
+      Nmatch ++;
+    }
+  }
+  if (Nmatch == 1) return (&commands[match[0]]);
+
+  if (Nmatch > 1) {
+    if (VERBOSE) {
+      gprint (GP_ERR, "ambiguous command: %s ( ", name);
+      for (i = 0; i < Nmatch; i++) {
+	gprint (GP_ERR, "%s ", commands[match[i]].name);
+      }
+      gprint (GP_ERR, ")\n");
+    }
+    return (NULL);
+  }
+  if (VERBOSE) gprint (GP_ERR, "%s: Command not found.\n", name);
+  return (NULL);
+}  
+
+/* generate a command completion list for readline */
+/**** these probably do not interact well with OHANA memory!!! ****/
+char *command_generator (const char *text, int state) {
+
+  /* i must be remembered from call to call */
+  static int i, len;
+
+  /* On first call, state is set to 0: initial the state */
+  if (!state) {
+    i = -1;  
+    len = strlen (text);
+  }
+
+  /* Return the next partial match from the command list */
+  for (i++; i < Ncommands; i++) {
+    if (!len) 
+      return (strcreate(commands[i].name));
+    if (!strncmp (commands[i].name, text, len)) {
+      return (strcreate(commands[i].name));
+    }
+  }
+
+  /* If no names matched, then return NULL. */
+  return ((char *)NULL);
+}
+
+/* tell readline to use out command_generator rather than basic completion */
+char **command_completer (const char *text, int start, int end) {
+  
+  char **matches;
+
+  matches = (char **) NULL;
+  
+  if (start == 0)
+    matches = rl_completion_matches (text, command_generator);
+
+  return (matches);
+}
+
+void print_commands (FILE *f) {
+
+  int i, *seq;
+
+  ALLOCATE (seq, int, Ncommands);
+  sort_commands (seq);
+  for (i = 0; i < Ncommands; i++) {
+    fprintf (f, "%-25s -- %s\n", commands[seq[i]].name, commands[seq[i]].help);
+  }
+  free (seq);
+
+  return;
+}
+
+void sort_commands (int *seq) {
+
+  int l,j,ir,i, N;
+  int temp;
+  
+  N = Ncommands;
+  for (i = 0; i < N; i++) 
+    seq[i] = i;
+  
+  l = N >> 1;
+  ir = N - 1;
+  for (;;) {
+    if (l > 0) {
+      temp = seq[--l];
+    }
+    else {
+      temp = seq[ir];
+      seq[ir] = seq[0];
+      if (--ir == 0) {
+        seq[0] = temp;
+        return;
+      }
+    }
+    i = l;
+    j = (l << 1) + 1;
+    while (j <= ir) {
+      if (j < ir && (strcmp (commands[seq[j]].name, commands[seq[j+1]].name) < 0)) ++j;
+      if (strcmp (commands[temp].name, commands[seq[j]].name) < 0) {
+        seq[i]=seq[j];
+        j += (i=j) + 1;
+      }
+      else j = ir + 1;
+    }
+    seq[i] = temp;
+  }
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/lib.shell/ConfigInit.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/lib.shell/ConfigInit.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/lib.shell/ConfigInit.c	(revision 11389)
@@ -0,0 +1,65 @@
+# include "opihi.h"
+
+static char *GlobalConfig;
+
+int ConfigInit (int *argc, char **argv) {
+
+  char *config, *file;
+
+  /*** load configuration info ***/
+  file = SelectConfigFile (argc, argv, "ptolemy");
+  config = LoadConfigFile (file);
+  if (config == (char *) NULL) {
+    if (file != (char *) NULL) free (file);
+    return (FALSE);
+  }
+
+  GlobalConfig = config;
+
+  free (file);
+  return (TRUE);
+}
+
+char *VarConfig (char *keyword, char *mode, void *ptr) {
+
+  char *answer;
+
+  answer = get_variable (keyword);
+  if (answer == (char *) NULL) {
+    answer = ScanConfig (GlobalConfig, keyword, mode, 0, ptr);
+    return (answer);
+  }
+
+  if (!strcmp (mode, "%s"))  strcpy ((char *) ptr, answer);
+  if (!strcmp (mode, "%d"))  *(int *) ptr       = atoi (answer);
+  if (!strcmp (mode, "%u"))  *(unsigned *) ptr  = atoi (answer);
+  if (!strcmp (mode, "%ld")) *(long *) ptr      = atoi (answer);
+  if (!strcmp (mode, "%hd")) *(short *) ptr     = atoi (answer);
+  if (!strcmp (mode, "%f"))  *(float *) ptr     = atof (answer);
+  if (!strcmp (mode, "%lf")) *(double *) ptr    = atof (answer);
+
+  free (answer);
+  return (ptr);
+}
+
+char *VarConfigEntry (char *keyword, char *mode, int entry, void *ptr) {
+
+  char *answer;
+
+  answer = get_variable (keyword);
+  if (answer == (char *) NULL) {
+    answer = ScanConfig (GlobalConfig, keyword, mode, entry, ptr);
+    return (answer);
+  }
+
+  if (!strcmp (mode, "%s"))  strcpy ((char *) ptr, answer);
+  if (!strcmp (mode, "%d"))  *(int *) ptr       = atoi (answer);
+  if (!strcmp (mode, "%u"))  *(unsigned *) ptr  = atoi (answer);
+  if (!strcmp (mode, "%ld")) *(long *) ptr      = atoi (answer);
+  if (!strcmp (mode, "%hd")) *(short *) ptr     = atoi (answer);
+  if (!strcmp (mode, "%f"))  *(float *) ptr     = atof (answer);
+  if (!strcmp (mode, "%lf")) *(double *) ptr    = atof (answer);
+
+  free (answer);
+  return (ptr);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/lib.shell/ListOps.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/lib.shell/ListOps.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/lib.shell/ListOps.c	(revision 11389)
@@ -0,0 +1,257 @@
+# include "opihi.h"
+# include "macro.h"
+
+/*** local static variables used to track the command lists  ***/
+static List *lists;			/* variable to store the list of all lists */
+static int  Nlists;			/* number of currently available lists */
+
+void InitLists () {
+  Nlists = 0;
+  ALLOCATE (lists, List, 1); 
+  return;
+}
+
+int current_list_depth () {
+  return Nlists;
+}
+
+int increase_list_depth () {
+  Nlists ++;
+  REALLOCATE (lists, List, MAX (Nlists + 1, 0) + 1);
+  ALLOCATE (lists[Nlists].line, char *, 16);
+  lists[Nlists].Nalloc = 16;
+  lists[Nlists].Nlines = 0;
+  lists[Nlists].n = 0;
+  return Nlists;
+}
+
+int decrease_list_depth () {
+  
+  int i;
+
+  for (i = 0; i < lists[Nlists].Nlines; i++) {
+    free (lists[Nlists].line[i]);
+  }
+  free (lists[Nlists].line);
+  Nlists --;
+  REALLOCATE (lists, List, MAX (Nlists + 1, 0) + 1);
+  return Nlists;
+}
+
+/* return a new string consisting of the next line in the current list */
+char *get_next_listentry (int ThisList) {
+
+  int Nline;
+  char *output;
+
+  Nline = lists[ThisList].n;
+
+  if (Nline >= lists[ThisList].Nlines) return (NULL);
+
+  output = strcreate (lists[ThisList].line[Nline]);
+  lists[ThisList].n ++;
+  
+  return (output);
+}
+
+# if (0)
+char *remove_listentry (int current) {
+
+  int i;
+  char *output;
+
+  if ((current + 1) >= lists[Nlists].Nlines) 
+    return ((char *) NULL);
+
+  output = lists[Nlists].line[current + 1];
+  
+  for (i = current + 1; i < lists[Nlists].Nlines - 1; i++) {
+    lists[Nlists].line[i] = lists[Nlists].line[i + 1];
+  }
+
+  lists[Nlists].Nlines --;
+  return (output);
+
+}
+# endif 
+
+int add_listentry (int ThisList, char *line) {
+
+  int Nlines;
+  char *output;
+
+  Nlines = lists[ThisList].Nlines;
+  lists[ThisList].line[Nlines] = strcreate (line);
+  lists[ThisList].Nlines ++;
+
+  if (lists[ThisList].Nlines == lists[ThisList].Nalloc) {
+    lists[ThisList].Nalloc += 16;
+    REALLOCATE (lists[ThisList].line, char *, lists[ThisList].Nalloc);
+  }
+    
+  return (lists[ThisList].Nlines);
+}
+
+int is_for_loop (char *line) {
+
+  int status;
+  char *comm;
+
+  comm = thisword (line);
+  if (comm == (char *) NULL) return (FALSE);
+  
+  status = !strcmp (comm, "for");
+  free (comm);
+  return (status);
+}
+
+int is_macro_create (char *line) {
+
+  int i, N, status;
+  char *comm;
+  char *this_macro;
+  CommandF *cmd;
+
+  comm = thisword (line);
+  if (comm == NULL) return (FALSE);
+
+  status = !strcmp (comm, "macro");
+  free (comm);
+  if (!status) return (FALSE);
+  
+  this_macro = thisword (nextword (line));
+  if (this_macro == NULL) return (FALSE);
+
+  cmd = find_macro_command (this_macro);
+  free (this_macro);
+
+  if (cmd == NULL) {
+    return (FALSE);
+  }
+
+  return (TRUE);
+}
+
+int is_if_block (char *line) {
+
+  char *comm, *temp;
+
+  temp = thisword (nextword (nextword (line)));
+  comm = thisword (line);
+
+  if (comm == NULL) goto escape;
+
+  if (strcmp (comm, "if")) goto escape;
+
+  /* if (cond) (command) does not define a complete block */
+  if (temp != NULL) goto escape;
+
+  if (temp != NULL) free (temp);
+  if (comm != NULL) free (comm);
+  return (TRUE);
+
+escape: 
+  if (comm != NULL) free (comm);
+  if (temp != NULL) free (temp);
+  return (FALSE);
+}
+
+// list (word) : nested list
+// list (word) -x : not nested list
+// list (word) -split : not nested list
+int is_list_data (char *line) {
+
+  char *comm, *temp;
+
+  temp = thisword (nextword (nextword (line)));
+  comm = thisword (line);
+
+  if (comm == NULL) goto escape;
+
+  if (strcmp (comm, "list")) goto escape;
+
+  /* if (cond) (command) does not define a complete block */
+  if (temp != NULL) {
+      if (!strcmp (temp, "-x")) goto escape;
+      if (!strcmp (temp, "-split")) goto escape;
+      if (!strcmp (temp, "-add")) goto escape;
+  }
+
+  if (temp != NULL) free (temp);
+  if (comm != NULL) free (comm);
+  return (TRUE);
+
+escape: 
+  if (comm != NULL) free (comm);
+  if (temp != NULL) free (temp);
+  return (FALSE);
+}
+
+int is_loop (char *line) {
+
+  int status;
+  char *comm;
+
+  comm = thisword (line);
+  if (comm == (char *) NULL) return (FALSE);
+
+  status = !strcmp (comm, "while");
+  free (comm);
+  return (status);
+}
+
+int is_task (char *line) {
+
+  int status;
+  char *comm;
+
+  comm = thisword (line);
+  if (comm == (char *) NULL) return (FALSE);
+
+  status = !strcmp (comm, "task");
+  free (comm);
+  return (status);
+}
+
+int is_task_exit (char *line) {
+
+  int status;
+  char *comm;
+
+  comm = thisword (line);
+  if (comm == (char *) NULL) return (FALSE);
+
+  status = !strcmp (comm, "task.exit");
+  free (comm);
+  return (status);
+}
+
+int is_task_exec (char *line) {
+
+  int status;
+  char *comm;
+
+  comm = thisword (line);
+  if (comm == (char *) NULL) return (FALSE);
+
+  status = !strcmp (comm, "task.exec");
+  free (comm);
+  return (status);
+}
+
+int is_list (char *line) {
+  
+  int status;
+
+  status = is_if_block (line);
+  status |= is_macro_create (line);
+  status |= is_for_loop (line);
+  status |= is_list_data (line);
+  status |= is_loop (line);
+  status |= is_task (line);
+  status |= is_task_exit (line);
+  status |= is_task_exec (line);
+
+  return (status);
+
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/lib.shell/MacroOps.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/lib.shell/MacroOps.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/lib.shell/MacroOps.c	(revision 11389)
@@ -0,0 +1,143 @@
+# include "opihi.h"
+
+static char dot[] = ".";
+
+static Macro *macros;
+static int   Nmacros;
+static int   NMACROS;
+
+static char *MacroName = dot;
+static int   MacroDepth = 0;
+
+void InitMacros () {
+  NMACROS = 20;
+  Nmacros = 0;
+  ALLOCATE (macros, Macro, NMACROS);
+  MacroName = dot;
+  MacroDepth = 0;
+}
+
+void SetCurrentMacroData (char *name, int depth) {
+  MacroName = name;
+  MacroDepth = depth;
+}
+
+char *GetMacroName () {
+  return (MacroName);
+}
+
+int GetMacroDepth () {
+  return (MacroDepth);
+}
+
+Macro *NewMacro (char *name) {
+  
+  macros[Nmacros].name = strcreate (name);;
+  macros[Nmacros].Nlines = 0;
+  ALLOCATE (macros[Nmacros].line, char *, 1);
+  Nmacros ++;
+  if (Nmacros == NMACROS) {
+    NMACROS += 20;
+    REALLOCATE (macros, Macro, NMACROS);
+  }
+  return (&macros[Nmacros-1]);
+}
+
+void ListMacro (Macro *macro) {
+
+  int i;
+
+  if ((macro == NULL) || (macro[0].Nlines == 0)) {
+    gprint (GP_ERR, "  macro not defined\n");
+    return;
+  }
+  for (i = 0; i < macro[0].Nlines; i++) {
+    gprint (GP_ERR, "  %s\n", macro[0].line[i]);
+  }
+  return;
+}
+
+void ListMacros () {
+  int i;
+  for (i = 0; i < Nmacros; i++) {
+    gprint (GP_ERR, "%s\n", macros[i].name);
+  }
+}
+
+void FreeMacro (Macro *macro) {
+  
+  int i;
+
+  if (macro == NULL) return;
+
+  for (i = 0; i < macro[0].Nlines; i++) {
+    free (macro[0].line[i]);
+  }
+  free (macro[0].line);
+  free (macro[0].name);
+  return;
+}
+
+int DeleteMacro (Macro *macro) {
+
+  int i, Nm;
+
+  Nm = -1;
+  for (i = 0; i < Nmacros; i++) {
+    if (macro == &macros[i]) {
+      Nm = i;
+      break;
+    }
+  }
+  if (Nm == -1) {
+    gprint (GP_ERR, "programming error: macro not found\n");
+    return (FALSE);
+  }
+
+  FreeMacro (&macros[Nm]);
+  for (i = Nm + 1; i < Nmacros; i++)
+    macros[i - 1] = macros[i];
+  Nmacros --;
+  return (TRUE);
+}
+
+/* return macro which unambiguously matches name */
+Macro *MatchMacro (char *name, int VERBOSE, int EXACT) {
+
+  int i, match[10], Nmatch;
+
+  /* try for an exact match first */
+  for (i = 0; i < Nmacros; i++) {
+    if (!strcmp (macros[i].name, name)) {
+      return (&macros[i]);
+    }
+  }
+  if (EXACT) {
+    if (VERBOSE) gprint (GP_ERR, "no exact match to %s\n", name);
+    return (NULL);
+  }
+      
+  /* not found as complete macro, try partial */
+  Nmatch = 0;
+  for (i = 0; (Nmatch < 10) && (i < Nmacros); i++) {
+    if (!strncmp (macros[i].name, name, strlen(name))) {  /* found a macro */
+      match[Nmatch] = i;
+      Nmatch ++;
+    }
+  }
+  if (Nmatch == 1) return (&macros[match[0]]);
+
+  if (Nmatch > 1) {
+    if (VERBOSE) {
+      gprint (GP_ERR, "ambiguous macro: %s ( ", name);
+      for (i = 0; i < Nmatch; i++) {
+	gprint (GP_ERR, "%s ", macros[match[i]].name);
+      }
+      gprint (GP_ERR, ")\n");
+    }
+    return (NULL);
+  }
+  if (VERBOSE) gprint (GP_ERR, "%s: Macro not found.\n", name);
+  return (NULL);
+}  
+
Index: /branches/opihi-2-9/Ohana/src/opihi/lib.shell/Makefile
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/lib.shell/Makefile	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/lib.shell/Makefile	(revision 11389)
@@ -0,0 +1,67 @@
+include ../../../Configure
+
+HOME    =       $(ROOT)/src/opihi
+BIN     =       $(HOME)/bin
+LIB     =       $(HOME)/lib
+INC     =       $(HOME)/include
+SDIR    =       $(HOME)/lib.shell
+
+# opihi shell functions (libopihi) ########################
+shell = \
+$(SDIR)/ConfigInit.$(ARCH).o		\
+$(SDIR)/ListOps.$(ARCH).o	   	\
+$(SDIR)/command.$(ARCH).o               \
+$(SDIR)/CommandOps.$(ARCH).o		\
+$(SDIR)/errors.$(ARCH).o		\
+$(SDIR)/expand_vars.$(ARCH).o           \
+$(SDIR)/expand_vectors.$(ARCH).o        \
+$(SDIR)/exec_loop.$(ARCH).o             \
+$(SDIR)/interrupt.$(ARCH).o	        \
+$(SDIR)/MacroOps.$(ARCH).o		\
+$(SDIR)/macro_create.$(ARCH).o          \
+$(SDIR)/macro_delete.$(ARCH).o          \
+$(SDIR)/macro_edit.$(ARCH).o            \
+$(SDIR)/macro_funcs.$(ARCH).o           \
+$(SDIR)/macro_exec.$(ARCH).o            \
+$(SDIR)/macro_list.$(ARCH).o            \
+$(SDIR)/macro_read.$(ARCH).o            \
+$(SDIR)/macro_write.$(ARCH).o		\
+$(SDIR)/memstr.$(ARCH).o                \
+$(SDIR)/multicommand.$(ARCH).o          \
+$(SDIR)/parse.$(ARCH).o                 \
+$(SDIR)/parse_commands.$(ARCH).o	\
+$(SDIR)/startup.$(ARCH).o		\
+$(SDIR)/string.$(ARCH).o                \
+$(SDIR)/timeformat.$(ARCH).o            \
+$(SDIR)/BufferOps.$(ARCH).o             \
+$(SDIR)/SocketOps.$(ARCH).o             \
+$(SDIR)/VectorOps.$(ARCH).o             \
+$(SDIR)/check_stack.$(ARCH).o           \
+$(SDIR)/convert_to_RPN.$(ARCH).o	\
+$(SDIR)/evaluate_stack.$(ARCH).o  	\
+$(SDIR)/isolate_elements.$(ARCH).o 	\
+$(SDIR)/dvomath.$(ARCH).o               \
+$(SDIR)/stack_math.$(ARCH).o		\
+$(SDIR)/variable.$(ARCH).o	   	\
+$(SDIR)/version.$(ARCH).o	   	\
+$(SDIR)/gprint.$(ARCH).o		\
+$(SDIR)/opihi.$(ARCH).o
+
+# dependancy rules for include files ########################
+incs = \
+$(INC)/opihi.h \
+$(INC)/external.h \
+$(INC)/shell.h \
+$(INC)/dvomath.h \
+$(INC)/convert.h \
+$(INC)/display.h 
+
+libshell: $(DESTLIB)/libshell.a 
+$(DESTLIB)/libshell.a: $(LIB)/libshell.$(ARCH).a
+$(LIB)/libshell.$(ARCH).a: $(shell)
+$(shell) : $(incs)
+
+uninstall:
+	rm -f $(DESTLIB)/libshell.a
+
+include ../Makefile.Common
Index: /branches/opihi-2-9/Ohana/src/opihi/lib.shell/SocketOps.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/lib.shell/SocketOps.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/lib.shell/SocketOps.c	(revision 11389)
@@ -0,0 +1,283 @@
+# include "shell.h"
+
+# define MY_PORT 2000
+# define MY_WAIT 500
+# define DEBUG 0
+
+static int NVALID;
+static int Nvalid;
+static int *VALID;
+
+int InitServerSocket (SockAddress *Address) {
+
+  int status, InitSocket, length;
+
+# if (0)
+  struct hostent  *host;
+  char tmpline[80], hostip[80];
+
+  host = gethostbyname (hostname);
+  bzero (hostip, 80);
+  for (i = 0; i < host[0].h_length; i++) {
+    sprintf (tmpline, "%u", (0xff & host[0].h_addr[i]));
+    strcat (hostip, tmpline);
+    if (i < host[0].h_length - 1) strcat (hostip, ".");
+  }
+# endif
+  
+  Address[0].sin_family = AF_INET;
+  Address[0].sin_port   = MY_PORT;
+  Address[0].sin_addr.s_addr = INADDR_ANY; // use this line to bind any address / port?
+
+retry_server:
+
+# if (0)  
+  status = inet_aton (hostip, &Address[0].sin_addr);
+  if (!status) {
+    gprint (GP_ERR, "invalid address\n");
+    exit (2);
+  }
+# endif
+
+  length = sizeof(Address[0]);
+
+  InitSocket = socket (PF_INET, SOCK_STREAM, 0);
+  if (InitSocket == -1) {
+    perror ("socket: ");
+    exit (2);
+  }
+
+  if (DEBUG) gprint (GP_ERR, "init sock: %d, len: %d\n", InitSocket, length);
+  status = bind (InitSocket, (struct sockaddr *) Address, length);
+  if (status == -1) {
+
+# if 0
+    fprintf (stderr, "errno: %d\n", errno);
+    fprintf (stderr, "EACCES: %d\n", EACCES);
+    fprintf (stderr, "EBADF: %d\n", EBADF);
+    fprintf (stderr, "EINVAL: %d\n", EINVAL);
+    fprintf (stderr, "ENOTSOCK: %d\n", ENOTSOCK);
+    fprintf (stderr, "EFAULT: %d\n", EFAULT);
+    fprintf (stderr, "ELOOP: %d\n", ELOOP);
+    fprintf (stderr, "ENAMETOOLONG: %d\n", ENAMETOOLONG);
+    fprintf (stderr, "ENOENT: %d\n", ENOENT);
+    fprintf (stderr, "ENOMEM: %d\n", ENOMEM);
+    fprintf (stderr, "ENOTDIR: %d\n", ENOTDIR);
+    fprintf (stderr, "EROFS: %d\n", EROFS);
+    fprintf (stderr, "EADDRNOTAVAIL: %d\n", EADDRNOTAVAIL);
+    fprintf (stderr, "EADDRINUSE: %d\n", EADDRINUSE);
+    fprintf (stderr, "ENOSR: %d\n", ENOSR);
+# endif
+
+    if (errno == EADDRINUSE) {
+	Address[0].sin_port ++;
+	if (Address[0].sin_port > MY_PORT + 10) exit (2);
+	goto retry_server;
+    }
+    perror ("bind: ");
+    exit (2);
+  }
+  /* repeated starts of the server are limited by xinetd or something:
+     requires 60sec timeout of the selected socket */
+
+  fprintf (stderr, "bound to port: %d\n", Address[0].sin_port);
+  status = listen (InitSocket, 10);
+  if (status == -1) {
+    perror ("listen: ");
+    exit (2);
+  }
+  return (InitSocket);
+}
+
+int WaitServerSocket (int InitSocket, SockAddress *Address) {
+
+  int i, BindSocket, length;
+  SockAddress Address_in;
+  u_int32_t addr;
+
+  Address_in = Address[0];
+
+  length = sizeof(Address_in);
+
+  /* this is a blocking wait; use in a separate thread */
+  fcntl (InitSocket, F_SETFL, !O_NONBLOCK); 
+
+  if (DEBUG) gprint (GP_ERR, "init sock: %d, len: %d\n", InitSocket, length);
+  BindSocket = accept (InitSocket, (struct sockaddr *) &Address_in, &length);
+  if (DEBUG) gprint (GP_ERR, "bind sock: %d\n", BindSocket);
+  if (BindSocket == -1) {
+    perror ("accept: ");
+    exit (2);
+  }
+
+  addr = Address_in.sin_addr.s_addr;
+  if (DEBUG) {
+    gprint (GP_ERR, "incoming connection from: ");
+    gprint (GP_ERR, " %u", (0xff & (addr >>  0)));
+    gprint (GP_ERR, ".%u", (0xff & (addr >>  8)));
+    gprint (GP_ERR, ".%u", (0xff & (addr >> 16)));
+    gprint (GP_ERR, ".%u", (0xff & (addr >> 24)));
+    gprint (GP_ERR, "\n");
+  }
+
+  if (Nvalid == 0) goto accepted;
+
+  for (i = 0; i < Nvalid; i++) {
+    /* valid IP addresses may be machines (120.90.121.142) or 
+       class C networks (120.90.121.0) */
+       
+    /* for machine, address must match */
+    if ((0xff & (VALID[i] >> 24)) != 0) {
+      if (addr == VALID[i]) goto accepted;
+    }
+
+    /* for network, lower three bytes of address must match */
+    if ((0xff & (VALID[i] >> 24)) == 0) {
+      if ((0x00ffffff & addr) == VALID[i]) goto accepted;
+    }
+  }
+
+  if (DEBUG) gprint (GP_ERR, "connection rejected\n");
+  close (BindSocket);
+  return (-1);
+
+accepted:
+  if (DEBUG) gprint (GP_ERR, "connection accepted\n");
+  fcntl (BindSocket, F_SETFL, O_NONBLOCK); 
+  return (BindSocket);
+}
+
+int GetClientSocket (char *hostname) {
+
+  int i, status, InitSocket, length;
+  SockAddress Address;
+  struct hostent  *host;
+  char tmpline[80], hostip[80];
+
+  host = gethostbyname (hostname);
+  bzero (hostip, 80);
+  for (i = 0; i < host[0].h_length; i++) {
+    sprintf (tmpline, "%u", (0xff & host[0].h_addr[i]));
+    strcat (hostip, tmpline);
+    if (i < host[0].h_length - 1) strcat (hostip, ".");
+  }
+
+  if (DEBUG) {
+    gprint (GP_ERR, "trying %s (%s:%d)...", host[0].h_name, hostip, MY_PORT);
+  }
+
+  Address.sin_family = AF_INET;
+  Address.sin_port   = MY_PORT;
+
+retry_client:
+  status = inet_aton (hostip, &Address.sin_addr);
+  if (!status) {
+    gprint (GP_ERR, "invalid address\n");
+    exit (2);
+  }
+
+  length = sizeof(Address);
+
+  InitSocket = socket (PF_INET, SOCK_STREAM, 0);
+  if (InitSocket == -1) {
+    perror ("socket: ");
+    exit (2);
+  }
+
+  status = connect (InitSocket, (struct sockaddr *) &Address, length);
+  if (status == -1) {
+    if (errno == ECONNREFUSED) {
+      Address.sin_port ++;
+      if (Address.sin_port > MY_PORT + 10) exit (2);
+      goto retry_client;
+    }
+    perror ("connect: ");
+    exit (2);
+  }
+
+  if (DEBUG) gprint (GP_ERR, "connected on port: %d\n", Address.sin_port);
+  if (DEBUG) gprint (GP_ERR, "connected\n");
+  fcntl (InitSocket, F_SETFL, O_NONBLOCK); 
+  return (InitSocket);
+}
+
+int InitServerSocket_Named (char *hostname, SockAddress *Address) {
+
+  int i, status, InitSocket, length;
+  struct hostent  *host;
+  char tmpline[80], hostip[80];
+
+  host = gethostbyname (hostname);
+  bzero (hostip, 80);
+  for (i = 0; i < host[0].h_length; i++) {
+    sprintf (tmpline, "%u", (0xff & host[0].h_addr[i]));
+    strcat (hostip, tmpline);
+    if (i < host[0].h_length - 1) strcat (hostip, ".");
+  }
+  
+  Address[0].sin_family = AF_INET;
+  Address[0].sin_port   = MY_PORT;
+  status = inet_aton (hostip, &Address[0].sin_addr);
+  if (!status) {
+    gprint (GP_ERR, "invalid address\n");
+    exit (2);
+  }
+
+  length = sizeof(Address[0]);
+
+  InitSocket = socket (PF_INET, SOCK_STREAM, 0);
+  if (InitSocket == -1) {
+    perror ("socket: ");
+    exit (2);
+  }
+
+  if (DEBUG) gprint (GP_ERR, "init sock: %d, len: %d\n", InitSocket, length);
+  status = bind (InitSocket, (struct sockaddr *) Address, length);
+  if (status == -1) {
+    perror ("bind: ");
+    exit (2);
+  }
+
+  status = listen (InitSocket, 10);
+  if (status == -1) {
+    perror ("listen: ");
+    exit (2);
+  }
+
+  if (DEBUG) gprint (GP_ERR, "socket listening on %s (%s:%d)\n", host[0].h_name, hostip, MY_PORT);
+  return (InitSocket);
+}
+
+/* load valid ip list */
+int DefineValidIP () {
+
+  int i, Nvalid, ip1, ip2, ip3, ip4, test, status;
+  char string[80];
+
+  Nvalid = 0;
+  NVALID = 10;
+  ALLOCATE (VALID, int, NVALID);
+  for (i = 0; VarConfigEntry ("VALID_IP", "%s", i, string) != NULL; i++) {
+    status = sscanf (string, "%d.%d.%d.%d", &ip1, &ip2, &ip3, &ip4);
+    test = TRUE;
+    test &= (status == 4);
+    test &= ((ip1 > 0) && (ip1 < 256)); 
+    test &= ((ip2 > 0) && (ip2 < 256)); 
+    test &= ((ip3 > 0) && (ip3 < 256)); 
+    test &= ((ip4 >=0) && (ip4 < 256)); 
+    if (!test) {
+      gprint (GP_ERR, "invalid IP address %s\n", string);
+      exit (2);
+    }
+    VALID[Nvalid] = ip1 | (ip2 << 8) | (ip3 << 16) | (ip4 << 24);
+    Nvalid ++;
+    CHECK_REALLOCATE (VALID, int, NVALID, Nvalid, 10);
+  }
+  NVALID = Nvalid;
+  REALLOCATE (VALID, int, NVALID);
+  if (NVALID == 0) {
+    free (VALID);
+    VALID = NULL;
+  }
+  return (TRUE);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/lib.shell/VectorOps.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/lib.shell/VectorOps.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/lib.shell/VectorOps.c	(revision 11389)
@@ -0,0 +1,168 @@
+# include "opihi.h"
+
+static Vector **vectors;
+static int     Nvectors;
+  
+void InitVectors () {
+  Nvectors = 0;
+  ALLOCATE (vectors, Vector *, 1);
+}
+
+Vector *InitVector () {
+  Vector *vec;
+
+  ALLOCATE (vec, Vector, 1);
+  ALLOCATE (vec[0].elements, float, 1);
+  bzero (vec[0].name, 1024);
+  vec[0].Nelements = 0;
+  return (vec);
+}
+
+int IsVector (char *name) {
+ 
+  int i;
+
+  if (name == NULL) return (FALSE);
+
+  for (i = 0; (i < Nvectors) && (strcmp(vectors[i][0].name, name)); i++);
+  if (i == Nvectors) return (FALSE);
+  return (TRUE);
+}
+
+int IsVectorPtr (Vector *vec) {
+ 
+  int i;
+
+  if (vec == NULL) return (FALSE);
+
+  for (i = 0; (i < Nvectors) && (vectors[i] != vec); i++);
+  if (i == Nvectors) return (FALSE);
+  return (TRUE);
+}
+
+Vector *SelectVector (char *name, int mode, int verbose) {
+
+  int i;
+
+  if (name == NULL) goto error;
+  if (ISNUM(name[0])) goto error;
+  if (IsBuffer(name)) goto error;
+
+  for (i = 0; (i < Nvectors) && (strcmp(vectors[i][0].name, name)); i++);
+  /* is a new vector */
+  if (i == Nvectors) { 
+    if (mode == OLDVECTOR) goto error;
+    Nvectors += 1;
+    REALLOCATE (vectors, Vector *, Nvectors);
+    vectors[i] = InitVector ();
+    strcpy (vectors[i][0].name, name);
+    return (vectors[i]);
+  } 
+  /* is an old vector */
+  if (mode == NEWVECTOR) goto error;
+  return (vectors[i]);
+
+ error:
+  if (verbose) gprint (GP_ERR, "invalid vector %s\n", name);
+  return (NULL);
+}
+  
+/* delete by pointer */
+int DeleteVector (Vector *vec) {
+
+  int i, j;
+
+  if (vec == NULL) return (FALSE);
+
+  for (i = 0; (i < Nvectors) && (vec != vectors[i]); i++);
+  if (i == Nvectors) return (FALSE);
+
+  free (vectors[i][0].elements);
+  free (vectors[i]);
+  for (j = i; j < Nvectors - 1; j++) vectors[j] = vectors[j + 1];
+
+  Nvectors -= 1;
+  REALLOCATE (vectors, Vector *, MAX (Nvectors, 1));
+  return (TRUE);
+}
+  
+/* delete by name */
+int DeleteNamedVector (char *name) {
+
+  int i, j;
+
+  if (name == NULL) return (FALSE);
+  for (i = 0; (i < Nvectors) && (strcmp(vectors[i][0].name, name)); i++);
+  if (i == Nvectors) return (FALSE);
+
+  free (vectors[i][0].elements);
+  free (vectors[i]);
+  for (j = i; j < Nvectors - 1; j++) vectors[j] = vectors[j + 1];
+
+  Nvectors -= 1;
+  REALLOCATE (vectors, Vector *, MAX (Nvectors, 1));
+  return (TRUE);
+}
+
+/* copy data from in to out - new memory space */
+int CopyNamedVector (char *out, char *in) {
+  Vector *In, *Out;
+  if ((In  = SelectVector (in,  OLDVECTOR, FALSE)) == NULL) return (FALSE);
+  if ((Out = SelectVector (out, ANYVECTOR, FALSE)) == NULL) return (FALSE);
+  CopyVector (Out, In);
+  return (TRUE);
+}
+int CopyVector (Vector *out, Vector *in) {
+  free (out[0].elements);
+  out[0].Nelements = in[0].Nelements;
+  ALLOCATE (out[0].elements, float, out[0].Nelements);
+  memcpy (out[0].elements, in[0].elements, out[0].Nelements*sizeof(float));
+  return (TRUE);
+}
+
+/* move data from in to out - use old memory space */
+int MoveNamedVector (char *out, char *in) {
+  Vector *In, *Out;
+  if ((In  = SelectVector (in,  OLDVECTOR, FALSE)) == NULL) return (FALSE);
+  if ((Out = SelectVector (out, ANYVECTOR, FALSE)) == NULL) return (FALSE);
+  MoveVector (Out, In);
+  return (TRUE);
+}
+int MoveVector (Vector *out, Vector *in) {
+  int i, j;
+
+  free (out[0].elements);
+  out[0].Nelements = in[0].Nelements;
+  out[0].elements =  in[0].elements;
+
+  /* delete vector entry from vector list, if it exists */
+  for (i = 0; (i < Nvectors) && (in != vectors[i]); i++);
+  if (i == Nvectors) {
+    free (in);
+    return (TRUE);
+  }
+
+  for (j = i; j < Nvectors - 1; j++) vectors[j] = vectors[j + 1];
+  Nvectors -= 1;
+  REALLOCATE (vectors, Vector *, MAX (Nvectors, 1));
+  free (in);
+  return (TRUE);
+}
+
+int ListVectors () {
+
+  int i;
+
+  if (Nvectors == 0) {
+    gprint (GP_ERR, "No defined vectors\n");
+    return (FALSE);
+  }
+
+  gprint (GP_LOG, "    N       name      size\n");
+  for (i = 0; i < Nvectors; i++) {
+    gprint (GP_LOG, "%5d %10s %10d\n",
+	     i, vectors[i][0].name, vectors[i][0].Nelements);
+  }
+  return (TRUE);
+}
+  
Index: /branches/opihi-2-9/Ohana/src/opihi/lib.shell/check_stack.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/lib.shell/check_stack.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/lib.shell/check_stack.c	(revision 11389)
@@ -0,0 +1,84 @@
+# include "opihi.h"
+
+int check_stack (StackVar *stack, int Nstack, int validsize) {
+
+  int i, Nx, Ny, Nv, size;
+  char *c;
+
+  Nv = Nx = Ny = -1;
+
+  for (i = 0; i < Nstack; i++) {
+    if (stack[i].type == 'X') {
+
+      /** if this is a number, put it on the list of scalers and move on **/
+      stack[i].Float = strtod (stack[i].name, &c);
+      if (c == stack[i].name + strlen (stack[i].name)) {
+	stack[i].ptr   = &(stack[i].Float);
+	stack[i].type  = 'S';
+	continue;
+      } 
+
+      /** if this is a matrix, find the dimensions and check with existing values **/
+      if (IsBuffer (stack[i].name)) {
+	stack[i].buffer = SelectBuffer (stack[i].name, OLDBUFFER, TRUE);
+	stack[i].ptr    = (float *) stack[i].buffer[0].matrix.buffer;
+	stack[i].type   = 'M';
+	if (Nx == -1) {
+	  Nx = stack[i].buffer[0].matrix.Naxis[0];
+	  Ny = stack[i].buffer[0].matrix.Naxis[1];
+	} 
+	if ((Nx != stack[i].buffer[0].matrix.Naxis[0]) && (Ny != stack[i].buffer[0].matrix.Naxis[1])) {
+	  push_error ("dimensions don't match");
+	  return (-1);
+	}	
+	if (Nv != -1) {
+	  if ((Nv != Nx) && (Nv != Ny)) {
+	    push_error ("dimensions don't match");
+	    return (-1);
+	  }
+	}	
+	continue;
+      }
+
+      /** if this is a vector, find the dimensions and check with existing values **/
+      if (IsVector (stack[i].name)) {
+	stack[i].vector = SelectVector (stack[i].name, OLDVECTOR, FALSE);
+	stack[i].ptr    = (float *) stack[i].vector[0].elements;
+	stack[i].type   = 'V';
+
+	if (Nv == -1) Nv = stack[i].vector[0].Nelements;
+	if (Nv != stack[i].vector[0].Nelements) {
+	  push_error ("dimensions don't match");
+	  return (-1);
+	}
+	if (Nx != -1) {
+	  if ((Nx != Nv) && (Ny != Nv)) {
+	    push_error ("dimensions don't match");
+	    return (-1);
+	  }
+	}	
+	continue;
+      }
+
+      /* this is not a scalar, vector, or matrix.  must be string */
+      stack[i].type  = 'W';
+    }
+  }
+
+  /* return object dimensions */
+  size = 0;
+  if (Nv != -1) size = 1;
+  if (Nx != -1) size = 2;
+  if (validsize == -1)   return (size);
+  if (validsize != size) return (-1);
+  return (size);
+}
+
+/* check stack identifies the data elements as scalar, vector, matrix, or word.
+   operators have already been identified.  
+   check stack returns the total stack dimensionality (0,1,2)
+   on error, check stack returns -1
+   possible errors:
+     - mismatch with requested dimensionality
+     - mismatch in data dimensions
+*/
Index: /branches/opihi-2-9/Ohana/src/opihi/lib.shell/command.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/lib.shell/command.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/lib.shell/command.c	(revision 11389)
@@ -0,0 +1,72 @@
+# include "opihi.h"
+# define DEBUG 0
+
+int command (char *line, char **outline, int VERBOSE) {
+
+  int i, status, argc;
+  char **argv, **targv;
+  Command *cmd;
+
+  /* force a space between ! and first word: !ls becomes ! ls */
+  if (line[0] == '!') {
+    REALLOCATE (line, char, strlen(line) + 5);
+    memmove (&line[2], &line[1], strlen(&line[1]) + 1);
+    line[1] = ' ';
+  }
+
+  /* expand anything of the form $fred or $fred$sam, etc */ 
+  line = expand_vars (line);     /* line is freed here, new one allocated */
+  /* expand anything of the form fred[N] */ 
+  line = expand_vectors (line);  /* line is freed here, new one allocated */
+  /* solve math expresions, assign variable, if needed */
+  line = parse (line);        /* line is freed here, new one allocated */
+  /* any entry in line of the form {foo} returns value or tmp vector / buffer */
+
+  /* we may have reallocated line, return new pointer */
+  *outline = line;
+  
+  # if (DEBUG) 
+  fprintf (stderr, "line: %s\n", line);
+  # endif
+
+  argv = parse_commands (line, &argc);
+  if (argc == 0) return (TRUE);  /* empty command or assignment */
+
+  /* save the original values of argv since command may modify the array */
+  ALLOCATE (targv, char *, argc);
+  for (i = 0; i < argc; i++) targv[i] = argv[i];
+
+  cmd = MatchCommand (argv[0], VERBOSE, FALSE);
+  if (cmd == NULL) {
+    status = -1;
+  } else {
+    free (argv[0]);
+    argv[0] = strcreate (cmd[0].name);
+    targv[0] = argv[0];
+    status = (*cmd[0].func) (argc, argv);
+  }
+  for (i = 0; i < argc; i++) free (targv[i]);
+  free (targv);
+  free (argv);
+
+  if (!status) {
+    char *msg;
+    msg = get_variable_ptr ("ERRORMSG");
+    if (msg != (char *) NULL) gprint (GP_ERR, "%s\n", msg);
+  }
+
+  set_int_variable ("STATUS", status);
+
+  # if (DEBUG) 
+  gprint (GP_ERR, "command: %s, status: %d\n", line, status);
+  # endif
+
+  return (status);
+}
+
+/* parse the input line, search for the corresponding command, and execute it
+   if no match is found, return -1; this is used above to distinguish between
+   a command error and an unknown command.  if VERBOSE is true, unknown commands
+   result in an error message.  The input line is freed and the resulting parsed
+   line is returned on 'outline'
+*/
Index: /branches/opihi-2-9/Ohana/src/opihi/lib.shell/convert_to_RPN.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/lib.shell/convert_to_RPN.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/lib.shell/convert_to_RPN.c	(revision 11389)
@@ -0,0 +1,211 @@
+# include "opihi.h"
+# define DUMPSTACK 0
+
+StackVar *convert_to_RPN (int argc, char **argv, int *nstack) {
+  
+  int type, Nx, Ny;
+  int i, j, Nstack, Nop_stack, NSTACK;
+  StackVar *stack, *op_stack;
+
+  /* max total stack size is argc, though should be less, this is safe */
+  NSTACK = argc + 5;
+  ALLOCATE (stack, StackVar, NSTACK);
+  ALLOCATE (op_stack, StackVar, NSTACK);
+  for (i = 0; i < NSTACK; i++) {
+    init_stack (&stack[i]);
+    init_stack (&op_stack[i]);
+  }
+  
+  Nx = Ny = Nstack = Nop_stack = 0;
+  for (i = 0; i < argc; i++) {
+    
+    /* decide on priority of object */
+    type = 0;
+    /* unary operations */
+    if (!strcmp (argv[i], "abs"))    { type = 9; goto gotit; }
+    if (!strcmp (argv[i], "int"))    { type = 9; goto gotit; }
+    if (!strcmp (argv[i], "exp"))    { type = 9; goto gotit; }
+    if (!strcmp (argv[i], "ten"))    { type = 9; goto gotit; }
+    if (!strcmp (argv[i], "log"))    { type = 9; goto gotit; }
+    if (!strcmp (argv[i], "ln"))     { type = 9; goto gotit; }
+    if (!strcmp (argv[i], "sqrt"))   { type = 9; goto gotit; }
+    if (!strcmp (argv[i], "erf"))    { type = 9; goto gotit; }
+
+    if (!strcmp (argv[i], "sinh"))   { type = 9; goto gotit; }
+    if (!strcmp (argv[i], "cosh"))   { type = 9; goto gotit; }
+    if (!strcmp (argv[i], "asinh"))  { type = 9; goto gotit; }
+    if (!strcmp (argv[i], "acosh"))  { type = 9; goto gotit; }
+
+    if (!strcmp (argv[i], "sin"))    { type = 9; goto gotit; }
+    if (!strcmp (argv[i], "cos"))    { type = 9; goto gotit; }
+    if (!strcmp (argv[i], "tan"))    { type = 9; goto gotit; }
+    if (!strcmp (argv[i], "dsin"))   { type = 9; goto gotit; }
+    if (!strcmp (argv[i], "dcos"))   { type = 9; goto gotit; }
+    if (!strcmp (argv[i], "dtan"))   { type = 9; goto gotit; }
+    if (!strcmp (argv[i], "asin"))   { type = 9; goto gotit; }
+    if (!strcmp (argv[i], "acos"))   { type = 9; goto gotit; }
+    if (!strcmp (argv[i], "atan"))   { type = 9; goto gotit; }
+    if (!strcmp (argv[i], "dasin"))  { type = 9; goto gotit; }
+    if (!strcmp (argv[i], "dacos"))  { type = 9; goto gotit; }
+    if (!strcmp (argv[i], "datan"))  { type = 9; goto gotit; }
+
+    if (!strcmp (argv[i], "lgamma")) { type = 9; goto gotit; }
+
+    if (!strcmp (argv[i], "rnd"))    { type = 9; goto gotit; }
+    if (!strcmp (argv[i], "xramp"))  { type = 9; goto gotit; }
+    if (!strcmp (argv[i], "yramp"))  { type = 9; goto gotit; }
+    if (!strcmp (argv[i], "ramp"))   { type = 9; goto gotit; }
+    if (!strcmp (argv[i], "zero"))   { type = 9; goto gotit; }
+    if (!strcmp (argv[i], "--"))     { type = 9; goto gotit; }
+    if (!strcmp (argv[i], "not"))    { type = 9; goto gotit; }
+    if (!strcmp (argv[i], "isinf"))  { type = 9; goto gotit; }
+    if (!strcmp (argv[i], "isnan"))  { type = 9; goto gotit; }
+
+    /* binary operations */
+    if (!strcmp (argv[i], "^"))      { type = 8; goto gotit; }
+
+    if (!strcmp (argv[i], "@"))      { type = 7; goto gotit; }
+    if (!strcmp (argv[i], "/"))      { type = 7; goto gotit; }
+    if (!strcmp (argv[i], "*"))      { type = 7; goto gotit; }
+    if (!strcmp (argv[i], "%"))      { type = 7; goto gotit; }
+
+    if (!strcmp (argv[i], "+"))      { type = 6; goto gotit; }
+    if (!strcmp (argv[i], "-"))      { type = 6; goto gotit; }
+	
+    if (!strcmp (argv[i], "&"))      { type = 5; goto gotit; }
+    if (!strcmp (argv[i], "|"))      { type = 5; goto gotit; }
+
+    if (!strcmp (argv[i], "<"))      { type = 4; goto gotit; }
+    if (!strcmp (argv[i], ">"))      { type = 4; goto gotit; }
+    if (!strcmp (argv[i], "=="))     { type = 4; strcpy (argv[i], "E"); goto gotit; }
+    if (!strcmp (argv[i], "!="))     { type = 4; strcpy (argv[i], "N"); goto gotit; }
+    if (!strcmp (argv[i], "<="))     { type = 4; strcpy (argv[i], "L"); goto gotit; }
+    if (!strcmp (argv[i], ">="))     { type = 4; strcpy (argv[i], "G"); goto gotit; }
+    if (!strcmp (argv[i], ">>"))     { type = 4; strcpy (argv[i], "U"); goto gotit; }
+    if (!strcmp (argv[i], "<<"))     { type = 4; strcpy (argv[i], "D"); goto gotit; }
+
+    if (!strcmp (argv[i], "&&"))     { type = 3; strcpy (argv[i], "A"); goto gotit; }
+    if (!strcmp (argv[i], "||"))     { type = 3; strcpy (argv[i], "O"); goto gotit; }
+
+    if (!strcmp (argv[i], "("))      { type = 2; goto gotit; }
+    if (!strcmp (argv[i], ")"))      { type = 1; goto gotit; }
+
+  gotit:
+    /* choose how to deal with object */
+    switch (type) {
+      case 8:  /* exponentiation: 2^2^3 = 64 != 256 (precedence is right-to-left, not left-to-right!) */
+	/* pop previous, higher operators from OP stack to stack */
+	for (j = Nop_stack - 1; (j >= 0) && (op_stack[j].type > type); j--) {
+	  strcpy (stack[Nstack].name, op_stack[j].name);
+	  stack[Nstack].type = op_stack[j].type;
+	  Nstack ++;
+	  Nop_stack --;
+	}
+	/* push operator on OP stack */
+	strcpy (op_stack[Nop_stack].name, argv[i]);
+	op_stack[Nop_stack].type = type;
+	Nop_stack ++;
+	break;
+      case 9: /* unary OPs */
+      case 7: /* binary OPs */
+      case 6:
+      case 5: 
+      case 4: 
+      case 3: 
+	/* pop previous, higher or equal operators from OP stack to stack */
+	for (j = Nop_stack - 1; (j >= 0) && (op_stack[j].type >= type); j--) {
+	  strcpy (stack[Nstack].name, op_stack[j].name);
+	  stack[Nstack].type = op_stack[j].type;
+	  Nstack ++;
+	  Nop_stack --;
+	}
+	/* push operator on OP stack */
+	strcpy (op_stack[Nop_stack].name, argv[i]);
+	op_stack[Nop_stack].type = type;
+	Nop_stack ++;
+	break;
+      case 2:  
+	/* push operator on OP stack */
+	strcpy (op_stack[Nop_stack].name, argv[i]);
+	op_stack[Nop_stack].type = type;
+	Nop_stack ++;
+	break;
+      case 1: 
+	/* pop rest of operators from OP stack to stack, looking for '(' */
+	for (j = Nop_stack - 1; (j >= 0) && (op_stack[j].type != 2); j--) {
+	  strcpy (stack[Nstack].name, op_stack[j].name);
+	  stack[Nstack].type = op_stack[j].type;
+	  Nstack ++;
+	  Nop_stack --;
+	}
+	if ((j == -1) || (op_stack[j].type != 2)) {
+	  push_error ("syntax error: mismatched parenthesis");
+	  Nstack = 0;
+	  goto cleanup;
+	}
+	Nop_stack --;
+	break;
+      case 0:
+	/* place the value (number or vector/matrix name) on stack */
+	/* value of 'X' is used as sentinel until we sort out values */
+	strcpy (stack[Nstack].name, argv[i]);
+	stack[Nstack].type = 'X';
+	Nstack ++;
+	break;
+    }
+  }
+
+  /* dump remaining operators on stack, checking for ')' */
+  for (j = Nop_stack - 1; j >= 0; j--) {
+    if (op_stack[j].type == 2) {
+      push_error ("syntax error: mismatched parenthesis");
+      Nstack = 0;
+      goto cleanup;
+    }
+    strcpy (stack[Nstack].name, op_stack[j].name);
+    stack[Nstack].type = op_stack[j].type;
+    Nstack ++;
+  }
+
+cleanup: 
+  /*** free up unused stack space ***/
+  clean_stack (op_stack, NSTACK);
+  free (op_stack);
+  clean_stack (&stack[Nstack], NSTACK - Nstack);
+  REALLOCATE (stack, StackVar, MAX (Nstack, 1));
+  *nstack = Nstack;
+
+  for (i = 0; i < argc; i++) {
+    free (argv[i]);
+  }
+  free (argv);
+
+# if (DUMPSTACK)
+  for (i = 0; i < Nstack; i++) {
+    gprint (GP_ERR, "%s ", stack[i].name);
+  }
+  if (Nstack > 0) gprint (GP_ERR, "\n");
+  for (i = 0; i < Nstack; i++) {
+    gprint (GP_ERR, "%d ", stack[i].type);
+  }
+  if (Nstack > 0) gprint (GP_ERR, "\n");
+# endif
+
+  return (stack);
+
+}
+
+/* here are the rules for parsing a math AOL line to RPN:
+
+1) if object is a number, push on stack
+2) if object is a third order operand (exp, sin, cos), push on op stack
+3) if object is an open paren, push on op stack,
+4) if object is a second order operand, push on stack
+5) if object is a first order operand, pop all second order operands from stack 
+until paren, push on stack
+6) if object is an end paren, pop all objects from stack until paren, 
+pop next stack, if third order op
+7) if end of line, pop all remaining objects, second order first, etc.
+   
+*/
+
Index: /branches/opihi-2-9/Ohana/src/opihi/lib.shell/dvomath.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/lib.shell/dvomath.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/lib.shell/dvomath.c	(revision 11389)
@@ -0,0 +1,94 @@
+# include "opihi.h"
+
+/* return value on success is temp vector/buffer name or scalar value return value on error is NULL, all
+   internals freed.  errors are sent to error stack.  may be printed by calling function */
+   
+char *dvomath (int argc, char **argv, int *size, int validsize) {
+  
+  int  i, Nstack, Ncstack;
+  char   **cstack, *outname;
+  StackVar *stack;
+  Buffer *buf;
+  Vector *vec;
+
+  buf = NULL;
+  vec = NULL;
+  ALLOCATE (outname, char, 256);
+
+  /* take char array with expression, convert to important elements */
+  cstack = isolate_elements (argc, argv, &Ncstack); 
+
+  /* generate RPN stack from cstack arguments */
+  stack = convert_to_RPN (Ncstack, cstack, &Nstack);
+  if (Nstack < 1) goto error;
+
+  /* distinguish scalar, vector, matrix, check dimensions */
+  *size = check_stack (stack, Nstack, validsize);
+  if (*size < 0) goto error;
+
+  switch (*size) {
+    case 0:
+      break;
+    case 1:  /* allocate temp vector */
+      vec = NULL;
+      for (i = 0; (i < 1000) && (vec == NULL); i++) {
+	sprintf (outname, "tmp%03d", i);
+	vec = SelectVector (outname, NEWVECTOR, FALSE);
+      }
+      if (vec == NULL) { 
+	push_error ("too many tmp vectors");
+	goto error;
+      }
+      break;
+    case 2:  /* allocate temp buffer */
+      buf = NULL;
+      for (i = 0; (i < 1000) && (buf == NULL); i++) {
+	sprintf (outname, "tmp%03d", i);
+	buf = SelectBuffer (outname, NEWBUFFER, FALSE);
+      }
+      if (buf == NULL) {
+	push_error ("too many tmp buffers");
+	goto error;
+      }
+      break;
+    default:
+      goto error;
+  }
+
+  /* evaluate operations, free stack on error */
+  Ncstack = Nstack;
+  if (!evaluate_stack (stack, &Nstack)) {
+    if (*size == 1) DeleteVector (vec);
+    if (*size == 2) DeleteBuffer (buf);
+    goto error;
+  }
+
+  switch (*size) {
+    case 0:
+      if (Ncstack == 1) {
+	  /* use exact input work */
+	  sprintf (outname, "%s", stack[0].name);
+      } else {
+	  sprintf (outname, "%.12g", stack[0].Float);
+      }
+      break;
+
+    case 1:
+      MoveVector (vec, stack[0].vector);
+      break;
+  
+    case 2:
+      MoveBuffer (buf, stack[0].buffer);
+      break;
+  }
+
+  clean_stack (stack, Nstack);
+  free (stack);
+  return (outname);
+
+error:  
+  clean_stack (stack, Nstack);
+  free (stack);
+  free (outname);
+  return (NULL);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/lib.shell/errors.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/lib.shell/errors.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/lib.shell/errors.c	(revision 11389)
@@ -0,0 +1,16 @@
+# include "opihi.h"
+
+static char errorline[1024];
+
+int push_error (char *line) {
+
+  bzero (errorline, 1024);
+  strncpy (errorline, line, 1023);
+  return (TRUE);
+}
+
+int print_error () {
+
+  gprint (GP_ERR, "%s\n", errorline);
+  return (TRUE);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/lib.shell/evaluate_stack.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/lib.shell/evaluate_stack.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/lib.shell/evaluate_stack.c	(revision 11389)
@@ -0,0 +1,195 @@
+# include "opihi.h"
+# define VERBOSE 0
+
+# define TWO_OP(A,B,FUNC) \
+  if (!strncasecmp (&stack[i - 2].type, A, 1) && !strncasecmp (&stack[i - 1].type, B, 1)) \
+    status = FUNC (&tmp_stack, &stack[i - 2], &stack[i - 1], stack[i].name); 
+
+# define ONE_OP(A,FUNC) \
+  if (!strncasecmp (&stack[i - 1].type, A, 1)) \
+    status = FUNC (&tmp_stack, &stack[i - 1], stack[i].name); 
+
+int evaluate_stack (StackVar *stack, int *Nstack) {
+  
+  int i, j, Nvar, Nout, status;
+  char line[512];
+  StackVar tmp_stack;
+  Nout = Nvar = 0;
+
+  status = TRUE;
+  init_stack (&tmp_stack);
+
+  if (*Nstack == 1) {
+    if (stack[0].type == 'S') {
+      free (tmp_stack.name);
+      return (TRUE);
+    }
+    if (stack[0].type == 'V') {
+      /* need to make a copy so we set output value? */
+      V_unary (&tmp_stack, &stack[0], "=");
+      move_stack (&stack[0], &tmp_stack);
+      return (TRUE);
+    }
+    if (stack[0].type == 'M') {
+      /* need to make a copy so we set output value? */
+      M_unary (&tmp_stack, &stack[0], "=");
+      move_stack (&stack[0], &tmp_stack);
+      return (TRUE);
+    }
+    push_error ("syntax error: not a math expression");
+    free (tmp_stack.name);
+    return (FALSE);
+  }      
+    
+  for (i = 0; i < *Nstack; i++) {
+
+    if (VERBOSE) {
+      gprint (GP_ERR, "%d: ", i);
+      for (j = 0; j < *Nstack; j++) {
+	gprint (GP_ERR, "%s ", stack[j].name);
+      }
+      if (*Nstack > 0) gprint (GP_ERR, "\n");
+      gprint (GP_ERR, "%d: ", i);
+      for (j = 0; j < *Nstack; j++) {
+	gprint (GP_ERR, "%d ", stack[j].type);
+      }
+      if (*Nstack > 0) gprint (GP_ERR, "\n");
+    }
+
+    /***** binary operators *****/
+    if ((stack[i].type >= 3) && (stack[i].type <= 8)) {
+
+      if (i < 2) {  /* need two variables to operate on */
+	sprintf (line, "syntax error: binary operator with one operand: %s\n", stack[i].name);
+	push_error (line);
+	free (tmp_stack.name); 
+	return (FALSE);
+      }
+
+      TWO_OP ("M","M",MM_binary);
+      TWO_OP ("M","V",MV_binary);
+      TWO_OP ("M","S",MS_binary);
+      TWO_OP ("V","M",VM_binary);
+      TWO_OP ("V","V",VV_binary);
+      TWO_OP ("V","S",VS_binary);
+      TWO_OP ("S","M",SM_binary);
+      TWO_OP ("S","V",SV_binary);
+      TWO_OP ("S","S",SS_binary);      
+      TWO_OP ("W","W",WW_binary);      
+      TWO_OP ("W","S",WW_binary);      
+      TWO_OP ("S","W",WW_binary);      
+      
+      if (!status) {
+	free (tmp_stack.name);
+	return (FALSE);
+      }
+      move_stack (&stack[i-2], &tmp_stack);
+      delete_stack (&stack[i-1], 2);
+      for (j = i + 1; j < *Nstack; j++) {
+	copy_stack (&stack[j - 2], &stack[j]);
+      }
+      *Nstack -= 2;
+      i -= 2;
+      init_stack (&tmp_stack);
+      continue;
+    }
+
+    /***** unary operators **/
+    if (stack[i].type == 9) {
+
+      if (i < 1) {  /* need one variable to operate on */
+	push_error ("syntax error: unary operator with no operand");
+	free (tmp_stack.name);
+	return (FALSE);
+      }
+      
+      ONE_OP ("M", M_unary);
+      ONE_OP ("V", V_unary);
+      ONE_OP ("S", S_unary);
+
+      /* there are no valid unary string operators */
+      if (!strncasecmp (&stack[i - 1].type, "W", 1)) {
+	push_error ("syntax error: no valid string unary ops");
+	free (tmp_stack.name);
+	return (FALSE);
+      }
+
+      move_stack (&stack[i-1], &tmp_stack);
+      delete_stack (&stack[i], 1);
+      for (j = i + 1; j < *Nstack; j++) {
+	copy_stack (&stack[j - 1], &stack[j]);
+      }
+      init_stack (&tmp_stack);
+      *Nstack -= 1;
+      i -= 1;
+      continue;
+    } 
+  }
+  free (tmp_stack.name);
+
+  if (*Nstack > 1) {
+    push_error ("syntax error in evaluation");
+    return (FALSE);
+  }
+  return (TRUE);
+}
+
+/* copy data to new stack variable */
+void copy_stack (StackVar *stack1, StackVar *stack2) {
+  stack1[0].name   = stack2[0].name  ;
+  stack1[0].type   = stack2[0].type  ;
+  stack1[0].ptr    = stack2[0].ptr   ;
+  stack1[0].buffer = stack2[0].buffer;
+  stack1[0].vector = stack2[0].vector;
+  stack1[0].Float  = stack2[0].Float ;
+  if (!strncasecmp (&stack1[0].type, "S", 1)) {
+    stack1[0].ptr    = &stack1[0].Float;
+  }
+}
+
+/* replace data with new stack variable */
+void move_stack (StackVar *stack1, StackVar *stack2) {
+  if (stack1[0].name != (char *) NULL) 
+    free (stack1[0].name);
+  copy_stack (stack1, stack2);
+}
+
+/* delete name and data */
+void clean_stack (StackVar *stack, int Nstack) {
+
+  int i;
+
+  for (i = 0; i < Nstack; i++) {
+    if (IsBufferPtr (stack[i].buffer) && (stack[i].type == 'm')) {
+      if (VERBOSE) gprint (GP_ERR, "free %s (buff) (%lx)\n", stack[i].name, (long) stack[i].buffer);
+      free (stack[i].buffer[0].header.buffer);
+      free (stack[i].buffer[0].matrix.buffer);
+      free (stack[i].buffer);
+      stack[i].buffer = NULL;
+    }	
+    if (IsVectorPtr (stack[i].vector) && (stack[i].type == 'v')) {
+      if (VERBOSE) gprint (GP_ERR, "free %s (vect) (%lx)\n", stack[i].name, (long) stack[i].vector);
+      free (stack[i].vector[0].elements);
+      free (stack[i].vector);
+      stack[i].vector = NULL;
+    }	
+    if (VERBOSE) gprint (GP_ERR, "free %s (name) (%d) (%lx)\n", stack[i].name, i, (long) stack[i].name);
+    free (stack[i].name);
+    stack[i].name = NULL;
+  }
+
+}
+
+/* delete name only, not data */
+void delete_stack (StackVar *stack, int Nstack) {
+  int i;
+  for (i = 0; i < Nstack; i++) {
+    free (stack[i].name);
+  }
+}
+
+void init_stack (StackVar *stack) {
+  stack[0].buffer = NULL;
+  stack[0].vector = NULL;
+  stack[0].name = strncreate ("tmp", NCHARS);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/lib.shell/exec_loop.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/lib.shell/exec_loop.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/lib.shell/exec_loop.c	(revision 11389)
@@ -0,0 +1,44 @@
+# include "opihi.h"
+
+int exec_loop (Macro *loop) {
+
+  void *Signal;
+  int n, Nlines, j, status, ThisList;
+  char *line;
+  
+  /* increase the shell level (Nlists) by one */
+  ThisList = increase_list_depth();
+  if (ThisList == 0) abort();
+
+  /* copy the macro to the current list */
+  for (j = 0; j < loop[0].Nlines; j++) {
+    add_listentry (ThisList, loop[0].line[j]);
+  }
+
+  /* set up interrupts */
+  Signal = signal (SIGINT, handle_interrupt);
+  interrupt = FALSE;
+
+  /* process the list */
+  loop_next = loop_break = loop_last = FALSE;
+  status = TRUE;
+
+  while (!interrupt) {
+    line = get_next_listentry (ThisList);
+    if (line == NULL) break;
+    status = multicommand (line);
+    free (line);
+    if (auto_break && !status) loop_break = TRUE;
+    if (loop_break || loop_last || loop_next) break;
+  }
+  signal (SIGINT, Signal);
+
+  /* free remaining lines on the list, free the list, decrement the shell level */
+  /*** can we free a list which is not the bottom lists? */
+  decrease_list_depth();
+
+  if (loop_break) return (FALSE);
+  return (TRUE);
+}
+
+/** note that the list number runs from 1 - Nlists+1 **/
Index: /branches/opihi-2-9/Ohana/src/opihi/lib.shell/expand_vars.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/lib.shell/expand_vars.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/lib.shell/expand_vars.c	(revision 11389)
@@ -0,0 +1,119 @@
+# include "opihi.h"
+
+char *expand_vars (char *line) {
+
+  char *L, *N, *V0, *V1, *Val, *newline, *c, found;
+  int done, MacroDepth;
+
+  if (line == NULL) return (NULL);
+  MacroDepth = GetMacroDepth ();
+
+  found = FALSE;
+  ALLOCATE (newline, char, 1024);  /* WARNING: this limits the length of the input line */
+
+  V0 = thiscomm (line);
+  if (V0 && !strncmp ("while", V0, strlen(V0))) {
+      // special case: don't expand variables in while () statement
+      strcpy (newline, line);
+      free (line);
+      return (newline);
+  }
+  free (V0);
+
+  /* look for form $a$b..$n and expand only the last ones */
+  for (L = line, N = newline; *L != 0; N++, L++) {  /* loop until end of line */
+    for (done = FALSE; !done;) {
+      if (*L == 0) done = TRUE;
+      if (*L == '$') {
+	V1 = aftervar(L);
+	if ((V1 != NULL) && (*V1 != '$')) done = TRUE;
+	if (V1 == NULL) done = TRUE;
+      }
+      if (!done) { 
+	*N = *L;
+	 L++; 
+	 N++;
+      }
+    }
+
+    if (*L == 0) break;
+
+    V1 = aftervar (L);           /* V1 points to the first non-WHITESPACE after the variable */
+    V0 = thisvar (L);            /* V0 points to the name of the var */
+    /* note: V1 points to a fraction of L, it does not need to be freed */
+
+    /* no variable name */
+    if (V0 == NULL) {
+      *N = *L;
+      continue;
+    }
+
+    /* variable assignment (skip these variables) */
+    if ((L == line) && (V1 != NULL)) {
+      if ((*V1 == '=') || !strcmp (V1, "++") || !strcmp (V1, "--")) {
+	*N = *L;
+	free (V0);
+	continue;
+      }
+    }
+
+    found = TRUE;
+    for (c = V0; isdigit(*c); c++); /* test if this is a macro argument variable (ie, $1.2) */
+    if (*c == 0) {  /* all digit var == macro parameter */
+      if (!MacroDepth) {
+	gprint (GP_ERR, "not in a macro\n");
+	goto error;
+      } else { /* if we are executing a macro, attach the list depth to the front, pass on down the line */
+	ALLOCATE (c, char, 1024);
+	sprintf (c, "%d.%s", MacroDepth, V0);
+	free (V0);
+	V0 = c;
+      }
+    }
+
+    Val = get_variable_ptr (V0);
+    if (Val == NULL) {   /* var was not found! */
+      gprint (GP_ERR, "variable %s not found\n", V0);
+      goto error;
+    }
+    for (; *Val != 0; N++, Val++)  {
+      *N = *Val; /* place the value of the variable in the newline */
+    }
+    N--; /* we overshoot on last loop */
+
+    /* skip past the variable in the source line */
+    /* L currently points at $ */
+    L++;
+    if (*L == '?') L++;  /* skip past ? in $?name */
+
+    while (ISVAR(*L)) L++;
+    L--; /* we overshoot */
+
+    if (V0 != NULL) free (V0);
+  }
+
+  *N = 0;
+  free (line);
+  REALLOCATE (newline, char, strlen (newline) + 1);
+  if (found) { /* try again for new variables */
+    newline = expand_vars (newline);
+  }
+  return (newline);
+
+error:
+  free (line);
+  free (V0);
+  free (newline);
+  return (NULL);
+}
+
+
+  /************************
+    we go through the line looking for the dollar signs ($) marking the 
+    variables.  We don't expand a variable if it is the first thing on the line 
+    AND it is followed by an equals sign.  
+    that is, don't expand if:
+    V0 = NULL ($ is last non-blank char on line -- no variable) or
+    V1[0] is = (assignment of variable value), AND L == line (ie, at beginning of line)
+    *************************/
+
Index: /branches/opihi-2-9/Ohana/src/opihi/lib.shell/expand_vectors.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/lib.shell/expand_vectors.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/lib.shell/expand_vectors.c	(revision 11389)
@@ -0,0 +1,97 @@
+# include "opihi.h"
+
+char *expand_vectors (char *line) {
+
+  char *newline, *tmpline, *val;
+  char *L, *N, *p, *q, *w;
+  int n, I, size;
+  double f1;
+  Vector *vec;
+
+  if (line == NULL) return (NULL);
+
+  ALLOCATE (newline, char, 1024);  /* WARNING: this limits the length of the input line */
+  ALLOCATE (tmpline, char, 1024);  /* WARNING: this limits the length of the input line */
+
+  /* look for form fred[stuff] */
+  /* skip first word (command) */
+  L = nextword (line);
+  if (L == NULL) {
+    free (newline);
+    free (tmpline);
+    return (line);
+  }
+
+  n = L - line;
+  strncpy (newline, line, n);
+  N = newline + n;
+  while (1) {
+    /* find vector subscript */
+    p = strchr (L, '[');
+    q = strchr (L, ']');
+    if ((p == NULL) && (q != NULL)) goto dumpline;
+    if ((p != NULL) && (q == NULL)) goto dumpline;
+    if ((p == NULL) && (q == NULL)) goto dumpline;
+    if (p > q) goto dumpline; /* odd state: unmatched pair: ][ */
+    n = (int) (q - p - 1);
+    if (n == 0) {
+      ALLOCATE (val, char, 64);
+      sprintf (val, "-1");
+      /* this choice of sentinel prevents us from using 
+	 x[-1], x[-2], and is not really needed */
+    } else {
+      strncpy (tmpline, p+1, n);
+      tmpline[n] = 0;
+      val = dvomath (1, &tmpline, &size, 0);
+      if (val == NULL) goto dumpline; /* not a valid vector subscript */
+    }
+    I = atoi (val);
+    free (val);
+
+    /* find vector name */
+    for (w = p - 1; (w >= line) && !OHANA_WHITESPACE(*w) && (isalnum(*w) || (*w == ':') || (*w == '_')); w--);
+    w ++;
+    n = (int)(p - w);
+    strncpy (tmpline, w, n);
+    tmpline[n] = 0;
+    if ((vec = SelectVector (tmpline, OLDVECTOR, TRUE)) == NULL) goto dumpline;
+
+    /* find vector element */
+    if (I >= vec[0].Nelements) {
+      gprint (GP_ERR, "vector subscript out of range\n"); 
+      goto escape;
+    }
+    if (I < 0) {
+      f1 = vec[0].Nelements;
+    } else {
+      f1 = vec[0].elements[I];
+    }
+    if ((int)f1 == f1) 
+      sprintf (tmpline, "%.0f", f1);
+    else
+      sprintf (tmpline, "%.9g", f1);
+    /* interpolate vector element */
+    n = (int) (w - L);
+    strncpy (N, L, n);
+    N += n;
+    n = strlen (tmpline);
+    strncpy (N, tmpline, n);
+    N += n;
+    L = q + 1;
+  }
+
+dumpline:
+  n = strlen (L);
+  strncpy (N, L, n);
+  N[n] = 0;
+  free (line);
+  free (tmpline);
+  return (newline);
+  
+escape:
+  free (line);
+  free (newline);
+  free (tmpline);
+  return (NULL);
+}
+
Index: /branches/opihi-2-9/Ohana/src/opihi/lib.shell/gprint.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/lib.shell/gprint.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/lib.shell/gprint.c	(revision 11389)
@@ -0,0 +1,244 @@
+# include "shell.h"
+
+/* we need to control the output destinations a bit carefully
+   in the pantasks_server mode.  The server needs to be able to 
+   send the output to a specific output device (eg, logging file)
+   of to save it within an internal buffer */
+
+/* further notes:
+   gprintf (int destination, char *format, ...);
+
+   the destination may be GP_LOG or GP_ERR.  by default, these go to stdout and
+   stderr.  either one may be redirected to another file or to a buffer.  as a
+   stand-along program, the outfile command redirects the GP_LOG output to an
+   alternate output file.  in the server mode, we redirect LOG to a standard log
+   file and ERR to a standard error file for server messages.  Commands executed
+   by the client have both streams returned to the client in turn, and are in
+   turn sent to stderr or the current stdout destination.
+
+   each thread has an independently set output destination.
+
+   option 1: NULL for invalid element:
+
+     a stream is either set to a FILE or an IOBuffer.  when it is set to a FILE,
+     the IOBuffer is freed and set to NULL.  when it is an IOBuffer, the file
+     pointer is closed and set to NULL.  setting a new FILE results in the 
+     IObuffer being freed and an already opened FILE to be flushed and closed.
+*/
+
+static gpStream *streams = NULL;
+static int Nstreams = 0;
+
+void gprintInit () {
+
+  int N;
+  pthread_t id;
+
+  /* need to use a mutex to prevent two threads from initing simultaneously */
+  if (streams == NULL) {
+    Nstreams = 2;
+    ALLOCATE (streams, gpStream, Nstreams);
+  } else {
+    Nstreams += 2;
+    REALLOCATE (streams, gpStream, Nstreams);
+  }
+
+  /* create two output streams for this thread: LOG and ERR */
+  id = pthread_self();
+
+  N = Nstreams - 2;
+  streams[N].dest = GP_LOG;
+  streams[N].file = stdout;
+  streams[N].name = strcreate ("stdout");
+
+  ALLOCATE (streams[N].buffer, IOBuffer, 1);
+  InitIOBuffer (streams[N].buffer, 64);
+  streams[N].mode = GP_FILE;
+  streams[N].thread = id;
+
+  N = Nstreams - 1;
+  streams[N].dest = GP_ERR;
+  streams[N].file = stderr;
+  streams[N].name = strcreate ("stderr");
+
+  ALLOCATE (streams[N].buffer, IOBuffer, 1);
+  InitIOBuffer (streams[N].buffer, 64);
+  streams[N].mode = GP_FILE;
+  streams[N].thread = id;
+}
+
+gpStream *gprintGetStream (gpDest dest) {
+
+  int i;
+  pthread_t id;
+
+  id = pthread_self();
+
+  /* find the existing output stream which matches */
+  for (i = 0; i < Nstreams; i++) {
+    if (streams[i].dest != dest) continue;
+    if (!pthread_equal (streams[i].thread, id)) continue;
+    return (&streams[i]);
+  }
+  fprintf (stderr, "programming error: gprintInit not called for thread\n");
+  abort ();
+}
+
+void gprintSetBuffer (gpDest dest) {
+
+  gpStream *stream;
+
+  stream = gprintGetStream (dest);
+
+  /* if we have an open file: flush it, close it, null it */
+  if (stream[0].file != NULL) {
+    fflush (stream[0].file);
+    if (stream[0].file == stdout) goto skip_close;
+    if (stream[0].file == stderr) goto skip_close;
+    fclose (stream[0].file);
+
+  skip_close:
+    stream[0].file = NULL;
+  }
+  
+  if (stream[0].buffer == NULL) {
+    ALLOCATE (stream[0].buffer, IOBuffer, 1);
+    InitIOBuffer (stream[0].buffer, 64);
+  } else {
+    FlushIOBuffer (stream[0].buffer);
+  }
+  
+  /* this element may be redundant with the NULL state of file and buffer */
+  stream[0].mode = GP_BUFF;
+}
+
+IOBuffer *gprintGetBuffer (gpDest dest) {
+
+  gpStream *stream;
+  stream = gprintGetStream (dest);
+  return (stream[0].buffer);
+}
+
+void gprintSetFile (gpDest dest, char *filename) {
+
+  gpStream *stream;
+  stream = gprintGetStream (dest);
+
+  /* if we have an open buffer, free it and null it */
+  if (stream[0].buffer != NULL) {
+    FreeIOBuffer (stream[0].buffer);
+    free (stream[0].buffer);
+    stream[0].buffer = NULL;
+  }
+
+  /* if we have an open file, flush it and close it */
+  if (stream[0].file != NULL) {
+    fflush (stream[0].file);
+    if (stream[0].file == stdout) goto skip_close;
+    if (stream[0].file == stderr) goto skip_close;
+    fclose (stream[0].file);
+  }
+skip_close:
+  
+  free (stream[0].name);
+
+  /* we allow the user to set stdout to ERR and stderr to LOG if they want */
+  if (!strcmp (filename, "stdout")) {
+    stream[0].file = stdout;
+    stream[0].name = strcreate (filename);
+    goto skip_open;
+  }
+  if (!strcmp (filename, "stderr")) {
+    stream[0].file = stderr;
+    stream[0].name = strcreate (filename);
+    goto skip_open;
+  }
+  
+  /* open the file */
+  stream[0].file = fopen (filename, "a");
+  if (stream[0].file == NULL) {
+    fprintf (stderr, "cannot open file %s\n", filename);
+    stream[0].file = (dest == GP_LOG) ? stdout : stderr;
+    stream[0].name = (dest == GP_LOG) ? strcreate ("stdout") : strcreate("stderr");
+  } else {
+    stream[0].name = strcreate (filename);
+  }
+
+skip_open:
+  stream[0].mode = GP_FILE;
+}
+
+FILE *gprintGetFile (gpDest dest) {
+
+  gpStream *stream;
+  stream = gprintGetStream (dest);
+  return (stream[0].file);
+}
+
+char *gprintGetName (gpDest dest) {
+
+  gpStream *stream;
+  stream = gprintGetStream (dest);
+  return (stream[0].name);
+}
+
+int gprint (gpDest dest, char *format, ...) {
+
+  int status;
+  gpStream *stream;
+  va_list argp;  
+
+  stream = gprintGetStream (dest);
+
+  va_start (argp, format);
+  
+  // gprint (GP_ERR, "GP_FILE: %d\n", GP_FILE);
+  // gprint (GP_ERR, "GP_BUFF: %d\n", GP_BUFF);
+  // gprint (GP_ERR, "mode: %d\n", stream[0].mode);
+
+  if (stream[0].mode == GP_FILE) {
+    // gprint (GP_ERR, "printing to FILE\n");
+    status = vfprintf (stream[0].file, format, argp);
+    if (status < 0) {
+      abort();
+    }
+  } else {
+    // gprint (GP_ERR, "printing to BUFFER\n");
+    vPrintIOBuffer (stream[0].buffer, format, argp);
+  }
+  va_end (argp);
+  return (TRUE);
+}
+
+int gwrite (char *buffer, int size, int N, gpDest dest) {
+
+  int Nbyte;
+  IOBuffer *outbuff;
+  gpStream *stream;
+
+  stream = gprintGetStream (dest);
+
+  if (stream[0].mode == GP_FILE) {
+    fwrite (buffer, size, N, stream[0].file);
+  } else {
+    outbuff = stream[0].buffer;
+    Nbyte = size * N;
+    if (outbuff[0].Nbuffer + Nbyte >= outbuff[0].Nalloc) {
+      outbuff[0].Nalloc = outbuff[0].Nbuffer + Nbyte + 64;
+      REALLOCATE (outbuff[0].buffer, char, outbuff[0].Nalloc);
+    }
+    memcpy (&outbuff[0].buffer[outbuff[0].Nbuffer], buffer, Nbyte);
+    outbuff[0].Nbuffer += Nbyte;
+  }
+  return (TRUE);
+}
+
+/* I'm going to need to have different output targets for different threads
+   we can do this with these functions:
+
+   pthread_t pthread_self(void);
+   int pthread_equal(pthread_t thread1, pthread_t thread2);
+   // returns TRUE if equal, FALSE if not
+   
+*/
+
Index: /branches/opihi-2-9/Ohana/src/opihi/lib.shell/interrupt.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/lib.shell/interrupt.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/lib.shell/interrupt.c	(revision 11389)
@@ -0,0 +1,51 @@
+# include "opihi.h"
+
+static int Nint = 0;
+
+/* return FALSE if we are called many times in a row 
+   without a valid answer or any answer */
+
+void handle_interrupt (int input) {
+  
+  char string[64];
+  int Nask;
+
+  signal (SIGINT, SIG_IGN);
+
+  Nask = 0;
+  Nint ++;
+  if (Nint > 10) { 
+    interrupt = TRUE;
+    return;
+  }
+  if (Nint > 100) { 
+    exit (3);
+  }
+  
+  while (1) {
+    gprint (GP_ERR, "operation halted, continue? (y/n) ");
+    fscanf (stdin, "%s", string);
+    
+    if ((string[0] == 'y') || (string[0] == 'Y')) {
+      interrupt = FALSE;
+      signal (SIGINT, handle_interrupt);
+      Nint = 0;
+      return;
+    }
+
+    if ((string[0] == 'n') || (string[0] == 'N')) {
+      interrupt = TRUE;
+      signal (SIGINT, handle_interrupt);
+      Nint = 0;
+      return;
+    }
+    Nask ++;
+    if (Nask > 10) {
+      interrupt = TRUE;
+      signal (SIGINT, handle_interrupt);
+      Nint = 0;
+      return;
+    }
+  }  
+
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/lib.shell/isolate_elements.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/lib.shell/isolate_elements.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/lib.shell/isolate_elements.c	(revision 11389)
@@ -0,0 +1,200 @@
+# include "opihi.h"
+
+/* local private functions */
+void InsertValue (char c);
+void EndOfString (void);
+int IsAnOp (char *c);
+int IsTwoOp (char *c);
+
+/* local private static variables */
+int Nchar, Nout, NOUT;
+char **out;
+
+char **isolate_elements (int Nin, char **in, int *nout) {
+  
+  int i, j, minus, negate, plus, posate, OpStat, SciNotation;
+
+  NOUT = Nin;
+  Nchar = Nout = 0;
+  ALLOCATE (out, char *, NOUT);
+  ALLOCATE (out[Nout], char, NCHARS);
+
+  for (i = 0; i < Nin; i++) {
+    for (j = 0; j < strlen(in[i]); j++) {
+      SciNotation = FALSE;
+      /* identify 'negate' or 'minus' ops */
+      negate = minus = FALSE;
+      if (in[i][j] == '-') { 
+	minus = TRUE;  
+	/* if - is first thing on line, must be a negator */
+	if ((Nout == 0) && (Nchar == 0)) {  
+	  minus = FALSE;
+	  negate = TRUE;
+	  goto skip1;
+	}
+	/* check previous entry on line */
+	if (Nchar) {
+	  OpStat = IsAnOp (out[Nout]);
+	  if (out[Nout][0] == ')') OpStat = FALSE;
+	} else {
+	  OpStat = IsAnOp (out[Nout-1]);
+	  if (out[Nout-1][0] == ')') OpStat = FALSE;
+	}
+	/* if - follows an operator, must be negator */
+	if (OpStat) {
+	  minus = FALSE;
+	  negate = TRUE;
+	  goto skip1;
+	}
+	/* if - follows 'e' is part of 1e-5 */
+	if (j == 0) goto skip1;
+	if ((in[i][j-1] == 'e') || (in[i][j-1] == 'E')) {
+	  SciNotation = TRUE;
+	  negate = minus = FALSE;
+	}
+      }
+    skip1:
+      /* idenfity 'posate' or 'plus' ops */
+      posate = plus = FALSE;
+      if (in[i][j] == '+') { 
+	plus = TRUE;  
+	/* if + is first thing on line, must be a posator */
+	if ((Nout == 0) && (Nchar == 0)) {  
+	  plus = FALSE;
+	  posate = TRUE;
+	  goto skip2;
+	}
+	/* check previous entry on line */
+	if (Nchar) {
+	  OpStat = IsAnOp (out[Nout]);
+	  if (out[Nout][0] == ')') OpStat = FALSE;
+	} else {
+	  OpStat = IsAnOp (out[Nout-1]);
+	  if (out[Nout-1][0] == ')') OpStat = FALSE;
+	}
+	/* if + follows an operator, must be posator */
+	if (OpStat) {
+	  plus = FALSE;
+	  posate = TRUE;
+	  goto skip2;
+	}
+	/* if + follows 'e' is part of 1e+5 */
+	if (j == 0) goto skip2;
+	if ((in[i][j-1] == 'e') || (in[i][j-1] == 'E')) {
+	  SciNotation = TRUE;
+	  posate = plus = FALSE;
+	}
+      }
+    skip2:
+      /* operators */
+      if (negate || minus || posate || plus || (IsAnOp (&in[i][j]) && !SciNotation)) {
+	if (posate) continue;
+	EndOfString ();
+	/* copy operator to out[Nout] */
+	InsertValue (in[i][j]);
+	if (negate) InsertValue ('-');
+
+	if (IsTwoOp (&in[i][j])) {
+	  InsertValue (in[i][j+1]);
+	  j++;
+	} 
+	EndOfString ();
+	continue;
+      }
+      /* quoted string */
+      if (in[i][j] == '"') {
+	InsertValue (in[i][j]);
+	j++;
+	while ((j < strlen(in[i])) && (in[i][j] != '"')) {
+	  InsertValue (in[i][j]);
+	  j++;
+	}
+	if (in[i][j] != '"') continue;
+	/* 
+	  gprint (GP_ERR, "mismatched quotes\n");
+	  return (FALSE);
+	}
+	*/
+	InsertValue (in[i][j]);
+	EndOfString ();
+	continue;
+      }
+      /* not an operator, not a quoted string */
+      if (!OHANA_WHITESPACE (in[i][j])) {
+	InsertValue (in[i][j]);
+      } else {
+	EndOfString ();
+      }
+    }
+    EndOfString ();
+  }
+
+  /* one extra entry is allocated, free here */
+  free (out[Nout]);
+  *nout = Nout;
+  return (out);
+
+}
+
+void InsertValue (char c) {
+  out[Nout][Nchar] = c;
+  Nchar ++;
+  out[Nout][Nchar] = 0;
+}
+
+void EndOfString () {
+  if (Nchar > 0) {
+    out[Nout][Nchar] = 0;
+    Nout ++;
+    Nchar = 0;
+    
+    if (Nout >= NOUT - 1) {
+      NOUT += 10; 
+      REALLOCATE (out, char *, NOUT); 
+    } 
+    ALLOCATE (out[Nout], char, NCHARS); 
+  }
+}
+
+int IsAnOp (char *c) {
+
+  if (!strncmp (c, "*",  1)) return (TRUE);
+  if (!strncmp (c, "/",  1)) return (TRUE);
+  if (!strncmp (c, "+",  1)) return (TRUE);
+  if (!strncmp (c, "-",  1)) return (TRUE);
+  if (!strncmp (c, "^",  1)) return (TRUE);
+  if (!strncmp (c, "@",  1)) return (TRUE);
+  if (!strncmp (c, "(",  1)) return (TRUE);
+  if (!strncmp (c, ")",  1)) return (TRUE);
+  if (!strncmp (c, "&",  1)) return (TRUE);
+  if (!strncmp (c, "|",  1)) return (TRUE);
+  if (!strncmp (c, ">",  1)) return (TRUE);
+  if (!strncmp (c, "<",  1)) return (TRUE);
+  if (!strncmp (c, "<",  1)) return (TRUE);
+  if (!strncmp (c, "<<", 2)) return (TRUE);
+  if (!strncmp (c, ">>", 2)) return (TRUE);
+  if (!strncmp (c, "&&", 2)) return (TRUE);
+  if (!strncmp (c, "||", 2)) return (TRUE);
+  if (!strncmp (c, "==", 2)) return (TRUE);
+  if (!strncmp (c, "!=", 2)) return (TRUE);
+  if (!strncmp (c, "<=", 2)) return (TRUE);
+  if (!strncmp (c, ">=", 2)) return (TRUE);
+
+  return (FALSE);
+
+}
+
+int IsTwoOp (char *c) {
+
+  if (!strncmp (c, "<<", 2)) return (TRUE);
+  if (!strncmp (c, ">>", 2)) return (TRUE);
+  if (!strncmp (c, "&&", 2)) return (TRUE);
+  if (!strncmp (c, "||", 2)) return (TRUE);
+  if (!strncmp (c, "==", 2)) return (TRUE);
+  if (!strncmp (c, "!=", 2)) return (TRUE);
+  if (!strncmp (c, "<=", 2)) return (TRUE);
+  if (!strncmp (c, ">=", 2)) return (TRUE);
+
+  return (FALSE);
+
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/lib.shell/macro_create.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/lib.shell/macro_create.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/lib.shell/macro_create.c	(revision 11389)
@@ -0,0 +1,114 @@
+# include "opihi.h"
+# define D_NLINES 100
+# define prompt "> "
+int macro_exec   PROTO((int, char **));
+
+static char helpline[] = "(macro)";
+
+int macro_create (int argc, char **argv) {
+
+  int ThisList, depth, i, done, NLINES, N;
+  char *input, *help;
+  Command *cmd;
+  Macro *macro;
+
+  help = helpline;
+  if ((N = get_argument (argc, argv, "-c"))) {
+    remove_argument (N, &argc, argv);
+    help = strcreate(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 2) {
+    gprint (GP_ERR, "USAGE: macro <name> [-c \"comment line\"]\n");
+    gprint (GP_ERR, "  (enter commands, end with the word 'END')\n");
+    return (FALSE);
+  }
+
+  /**** Check for existence of this macro ****/
+  cmd = MatchCommand (argv[1], FALSE, TRUE);
+  macro = MatchMacro (argv[1], FALSE, TRUE);
+  
+  if ((macro == NULL) && (cmd != NULL)) {
+    gprint (GP_ERR, "cannot redefine inherent command %s\n", argv[1]);
+    return (FALSE);
+  }
+  if ((macro != NULL) && (cmd == NULL)) {
+    gprint (GP_ERR, "programming error: macro not in command list (%s)\n", argv[1]);
+    return (FALSE);
+  }
+
+  if (macro == NULL) { /**** New Macro ****/
+    ALLOCATE (cmd, Command, 1);
+    cmd[0].name = strcreate (argv[1]);
+    cmd[0].help = help;
+    cmd[0].func = macro_exec;
+    AddCommand (cmd);
+    free (cmd);
+    macro = NewMacro (argv[1]);
+  } else { /**** Old Macro ****/
+    /* replace existing command help with new value */
+    if (cmd[0].help != helpline) 
+      free (cmd[0].help);
+    cmd[0].help = help;
+  }
+
+  /* reallocate space for macro lines */
+  NLINES = D_NLINES;
+  for (i = 0; i < macro[0].Nlines; i++) free (macro[0].line[i]);
+  REALLOCATE (macro[0].line, char *, NLINES);
+
+  /* read in macro
+     If we are entering at the keyboard (ThisList == 0), use readline.
+     Otherwise, read from the current list
+     End when we hit the final "END" (the true END -- we count macro defines!!) */
+     
+  depth = 0;
+  ThisList = current_list_depth();
+  for (i = 0, done = FALSE; !done; ) {
+
+    /* get the next line (from correct place) */
+    if (ThisList == 0) 
+      input = readline (prompt);
+    else 
+      input = get_next_listentry (ThisList);
+
+    if ((ThisList == 0) && (input == (char *) NULL)) {
+      gprint (GP_ERR, "end macro with 'END'\n");
+      continue;
+    }
+    if (ThisList == 0) ohana_memregister (input);
+
+    if ((ThisList > 0) && (input == (char *) NULL)) {
+      gprint (GP_ERR, "missing 'END' in macro definition\n");
+      input = strcreate ("end");
+    }
+
+    stripwhite (input);
+
+    /* test for new macro (or other list, in the future?) */
+    if (is_list (input)) depth ++;
+
+    /* test for end of nested list -- if not nested, END refers to this macro */
+    if (!strncasecmp (input, "END", 3)) {
+      depth --;
+      if (depth < 0) { /* we hit the last "END", macro is done */
+	free (input);
+	macro[0].Nlines = i;
+	if (macro[0].Nlines == 0) i = 1;
+	REALLOCATE (macro[0].line, char *, i);
+	return (TRUE);
+      }
+    }
+
+    if (*input) { 
+      macro[0].line[i] = input;
+      i++;
+      if (i == NLINES - 1) {
+	NLINES += D_NLINES;
+	REALLOCATE (macro[0].line, char *, NLINES);
+      }
+    }
+  }
+  return (TRUE);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/lib.shell/macro_delete.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/lib.shell/macro_delete.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/lib.shell/macro_delete.c	(revision 11389)
@@ -0,0 +1,28 @@
+# include "opihi.h"
+
+int macro_delete (int argc, char **argv) {
+
+  Command *cmd;
+  Macro *macro;
+
+  if (argc != 2) {
+    gprint (GP_ERR, "USAGE: macro delete <macro>\n");
+    return (FALSE);
+  }
+
+  macro = MatchMacro (argv[1], FALSE, TRUE);
+  if (macro == NULL) {
+    gprint (GP_ERR, "Macro %s not found\n", argv[1]);
+    return (FALSE);
+  }
+  cmd = MatchCommand (argv[1], FALSE, TRUE);
+  if (cmd == NULL) {
+    gprint (GP_ERR, "programming error: macro exists but not command\n");
+    return (FALSE);
+  }
+
+  DeleteMacro (macro);
+  DeleteCommand (cmd);
+  return (TRUE);
+}
+
Index: /branches/opihi-2-9/Ohana/src/opihi/lib.shell/macro_edit.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/lib.shell/macro_edit.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/lib.shell/macro_edit.c	(revision 11389)
@@ -0,0 +1,9 @@
+# include "opihi.h"
+
+int macro_edit (int argc, char **argv) {
+
+  gprint (GP_ERR, "this function is not implemented yet\n");
+  return (FALSE);
+
+}
+
Index: /branches/opihi-2-9/Ohana/src/opihi/lib.shell/macro_exec.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/lib.shell/macro_exec.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/lib.shell/macro_exec.c	(revision 11389)
@@ -0,0 +1,47 @@
+# include "opihi.h"
+
+int macro_exec (int argc, char **argv) {
+
+  int i, status, MacroDepth;
+  char *PreviousName, **params, tmp[1024];
+  Macro *macro;
+  
+  macro = MatchMacro (argv[0], FALSE, TRUE);
+  if (macro == NULL) {
+    gprint (GP_ERR, "%s: Command not found.\n", argv[0]);
+    return (FALSE);
+  }
+
+  /* increase MacroDepth by one - governs macro args */
+  PreviousName = GetMacroName ();
+  MacroDepth = GetMacroDepth ();
+  MacroDepth ++;
+  SetCurrentMacroData (macro[0].name, MacroDepth);
+
+  ALLOCATE (params, char *, argc);
+  sprintf (tmp, "%d.%d", MacroDepth, 0);
+  params[0] = strcreate (tmp);
+  sprintf (tmp, "%d", argc);
+  set_str_variable (params[0], tmp);
+  for (i = 1; i < argc; i++) {
+    sprintf (tmp, "%d.%d", MacroDepth, i);
+    params[i] = strcreate (tmp);
+    set_str_variable (params[i], argv[i]);
+  }
+
+  /* process this list */
+  status = exec_loop (&macro[0]);
+  loop_last = loop_next = FALSE; 
+  /* 'last' and 'next' should only affect one loop */
+
+  /* clear out the command line variables */
+  for (i = 0; i < argc; i++) {
+    DeleteNamedScalar (params[i]);
+    free (params[i]);
+  }
+  free (params);
+  
+  MacroDepth --;
+  SetCurrentMacroData (PreviousName, MacroDepth);
+  return (status);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/lib.shell/macro_funcs.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/lib.shell/macro_funcs.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/lib.shell/macro_funcs.c	(revision 11389)
@@ -0,0 +1,26 @@
+# include "basic.h"
+
+static Command macro_command[] = {
+  {"create", macro_create, "create a macro *"},
+  {"delete", macro_delete, "delete a macro *"},
+  {"list",   macro_list_f, "list a macro *"},
+  {"edit",   macro_edit,   "edit a macro <not working yet!> *"},
+  {"read",   macro_read,   "read a macro from a file <not working yet!> *"},
+  {"write",  macro_write,  "write a macro to a file <not working yet!> *"}
+};
+
+CommandF *find_macro_command (char *name) {
+
+  int i, N;
+
+  N = sizeof (macro_command) / sizeof (Command);
+
+  /* find the macro sub-command which matches from the list. */
+  for (i = 0; i < N; i++) {
+    if (!strcmp (macro_command[i].name, name)) {
+      return (macro_command[i].func);
+    }
+  }
+
+  return NULL;
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/lib.shell/macro_list.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/lib.shell/macro_list.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/lib.shell/macro_list.c	(revision 11389)
@@ -0,0 +1,23 @@
+# include "opihi.h"
+
+int macro_list_f (int argc, char **argv) {
+
+  int i;
+  Macro *macro;
+
+  if (argc != 2) {
+    gprint (GP_ERR, "USAGE: macro list <macro>\n");
+    return (FALSE);
+  }
+
+  macro = MatchMacro (argv[0], FALSE, TRUE);
+  if (macro == NULL) {
+    gprint (GP_ERR, "%s: Macro not found\n", argv[1]);
+    return (FALSE);
+  }
+
+  for (i = 0; i < macro[0].Nlines; i++) {
+    gprint (GP_ERR, "%s\n", macro[0].line[i]);
+  }
+  return (TRUE);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/lib.shell/macro_read.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/lib.shell/macro_read.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/lib.shell/macro_read.c	(revision 11389)
@@ -0,0 +1,9 @@
+# include "opihi.h"
+
+int macro_read (int argc, char **argv) {
+
+  gprint (GP_ERR, "this function is not implemented yet\n");
+  return (FALSE);
+
+}
+
Index: /branches/opihi-2-9/Ohana/src/opihi/lib.shell/macro_write.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/lib.shell/macro_write.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/lib.shell/macro_write.c	(revision 11389)
@@ -0,0 +1,9 @@
+# include "opihi.h"
+
+int macro_write (int argc, char **argv) {
+
+  gprint (GP_ERR, "this function is not implemented yet\n");
+  return (FALSE);
+
+}
+
Index: /branches/opihi-2-9/Ohana/src/opihi/lib.shell/memstr.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/lib.shell/memstr.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/lib.shell/memstr.c	(revision 11389)
@@ -0,0 +1,35 @@
+# include "shell.h"
+
+/* memstr returns a view, not an allocated string : don't free */
+/* returns pointer to start of m2 in m1, or NULL if failure */ 
+char *memstr (char *m1, char *m2, int n) {
+
+  int i, N;
+
+  N = strlen (m2);
+  for (i = 0; (i < n - N + 1) && memcmp (m1, m2, N); i++, m1++);
+  if (memcmp (m1, m2, N)) return (NULL);
+  return (m1);
+
+}
+
+/* formatted write statement, with intelligent allocation */
+int write_fmt (int fd, char *format, ...) {
+
+  int Nbyte, status;
+  char tmp, *line;
+  va_list argp;  
+
+  va_start (argp, format);
+  Nbyte = vsnprintf (&tmp, 0, format, argp);
+  va_end (argp);
+
+  va_start (argp, format);
+  ALLOCATE (line, char, Nbyte + 1);
+  vsnprintf (line, Nbyte + 1, format, argp);
+  status = write (fd, line, strlen(line));
+  va_end (argp);
+
+  free (line);
+  return (status);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/lib.shell/multicommand.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/lib.shell/multicommand.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/lib.shell/multicommand.c	(revision 11389)
@@ -0,0 +1,134 @@
+# include "opihi.h"
+
+static int server = 0;
+
+void multicommand_InitServer () {
+
+  char hostname[256], PASSWORD[256];
+
+  if (server != 0) {
+    /* check if down? */
+    fprintf (stderr, "error: server fd already defined\n");
+    exit (1);
+  }
+
+  /* find the defined server hostname */
+  if (VarConfig ("PANTASKS_SERVER", "%s", hostname) == NULL) {
+    gprint (GP_ERR, "pantasks server host undefined\n");
+    exit (2);
+  }
+
+  /* attempt to connect to the server */
+  server = GetClientSocket (hostname);
+
+  /* here we can perform the security handshaking */
+  VarConfig ("PASSWORD", "%s", PASSWORD);
+  SendCommand (server, strlen(PASSWORD), PASSWORD);
+  
+  return;
+}
+
+/* take input line and split into multiple lines
+   at the semi-colons.  send these to 'command' */
+
+int multicommand (char *line) {
+ 
+  int done, status, verbose;
+  char *p, *q, *tmpline, *outline;
+  IOBuffer message;
+
+  /* if no server is defined, use 'verbose' mode for 'command' */ 
+  verbose = (server == 0);
+
+  p = line; 
+  done = FALSE;
+  status = TRUE;
+  while (!done) {
+    q = strchr (p, ';');
+    if (q == NULL) {
+      q = p + strlen(p);
+      done = TRUE;
+    }
+    tmpline = strncreate (p, q - p);
+    stripwhite (tmpline);
+    if (*tmpline) {
+
+      status = command (tmpline, &outline, verbose);
+
+      if (status == -1) {
+	if (server) {
+	  // send the command to the server instead
+	  if (!SendMessage (server, outline)) {
+	    switch (errno) {
+	      case EPIPE:
+		gprint (GP_ERR, "server connection has died\n");
+		exit (1);
+	      default:
+		gprint (GP_ERR, "I/O error sending server message\n");
+		exit (2);
+	    }
+	  }
+
+	  // receive the command exit status
+	  if (ExpectMessage (server, 2.0, &message)) {
+	    switch (errno) {
+	      case EPIPE:
+		gprint (GP_ERR, "server connection has died\n");
+		exit (1);
+	      default:
+		gprint (GP_ERR, "I/O error sending server message\n");
+		exit (2);
+	    }
+	  } else {
+	    sscanf (message.buffer, "STATUS %d", &status);
+	  }
+
+	  // receive the resulting stderr
+	  if (ExpectMessage (server, 2.0, &message)) {
+	    switch (errno) {
+	      case EPIPE:
+		gprint (GP_ERR, "server connection has died\n");
+		exit (1);
+	      default:
+		gprint (GP_ERR, "I/O error sending server message\n");
+		exit (2);
+	    }
+	  } else {
+	    gwrite (message.buffer, 1, message.Nbuffer, GP_ERR);
+	  }
+
+	  // receive the resulting stdout
+	  if (ExpectMessage (server, 2.0, &message)) {
+	    switch (errno) {
+	      case EPIPE:
+		gprint (GP_ERR, "server connection has died\n");
+		exit (1);
+	      default:
+		gprint (GP_ERR, "I/O error sending server message\n");
+		exit (2);
+	    }
+	  } else {
+	    gwrite (message.buffer, 1, message.Nbuffer, GP_LOG);
+	  }
+	} else {
+	  // if no server is defined, we treat an unknown command as an error
+	  status = FALSE;
+	}	
+      }
+
+      if (outline != NULL) free (outline);
+      if (!status && auto_break) done = TRUE;
+    }
+    p = q + 1;
+  }
+  return (status);
+}
+
+/* should skip ; surrounded by "" */
+
+/* commands which are not found are sent to the server socket if 
+   defined. commands executed by the server return their stderr
+   and stdout streams.  server commands should probably not block
+   the server for very long or multiple clients will interfere
+   with each other.  
+*/
Index: /branches/opihi-2-9/Ohana/src/opihi/lib.shell/opihi.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/lib.shell/opihi.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/lib.shell/opihi.c	(revision 11389)
@@ -0,0 +1,59 @@
+# include "opihi.h"
+
+/******************/
+int opihi (int argc, char **argv) {
+
+  int Nbad, status;
+  char *line, *prompt, *history;
+  pid_t ppid;
+  FILE *log;
+
+  general_init (&argc, argv);
+  program_init (&argc, argv);
+  startup (&argc, argv);
+  prompt = get_variable("PROMPT");
+  history = get_variable("HISTORY");
+  welcome ();
+
+  Nbad = 0;
+  while (1) {  /** must exit with command "exit" or "quit" */
+    if (Nbad == 10) exit (3);
+
+    line = readline (prompt);
+
+    if (line == NULL) { 
+      
+      ppid = getppid();
+      if (ppid == 1) {
+	gprint (GP_ERR, "caught parent shutdown\n");
+	exit (2);
+      }
+      if (!isatty (STDIN_FILENO)) exit (2);
+      gprint (GP_LOG, "Use \"quit\" to exit\n");
+      Nbad ++;
+      continue;
+    }
+
+    Nbad = 0;
+    ohana_memregister (line);
+
+    stripwhite (line);
+    if (*line) {
+      status = multicommand (line);
+      add_history (line);
+      append_history (1, history);
+    }
+    free (line);
+    line = (char *) NULL;
+  }
+}
+
+/* 
+   startup sequence:
+
+   - general_init
+   - program_init
+   - startup (exit if non-interactive)
+   - welcome
+
+*/
Index: /branches/opihi-2-9/Ohana/src/opihi/lib.shell/parse.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/lib.shell/parse.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/lib.shell/parse.c	(revision 11389)
@@ -0,0 +1,271 @@
+# include "opihi.h"
+
+void interpolate_slash (char *line);
+
+char *parse (char *line) {
+
+  double fval;
+  char *newline, *N, *L, *val, *B, *V, *V0, *V1, *end, *c1, *c2;
+  int Nval, Nbytes, status, size;
+  FILE *f;
+  Vector *vec;
+
+  val = V0 = NULL;
+
+  if (line == (char *) NULL) goto error;
+
+  /* case 1: $var = expression */
+  if (line[0] == '$') {  
+    /* find the target variable name and the rest of the line */
+    interpolate_slash (line);
+    V0 = thisvar (line);
+    if (V0 == NULL) goto error;
+    V1 = aftervar (line);
+    if (V1 == NULL) goto error;
+ 
+    /* increment operator */
+    if (!strcmp (V1, "++")) {
+      val = get_variable (V0);
+      if (val == NULL) {
+	fval = 1.0;
+      } else {
+	fval = atof (val) + 1.0;
+      }
+      set_variable (V0, fval);
+      goto escape;
+    }
+
+    /* decrement operator */
+    if (!strcmp (V1, "--")) {
+      val = get_variable (V0);
+      if (val == NULL) {
+	fval = -1.0;
+      } else {
+	fval = atof (val) - 1.0;
+      }
+      set_variable (V0, fval);
+      goto escape;
+    }
+
+    /* not an assignement, syntax error */
+    if (*V1 != '=') goto error;
+
+    /* find first non-WHITESPACE character after = */
+    V1 ++;
+    while (isspace (*V1)) V1++;
+    if (*V1 == 0) goto error;
+
+    /* command replacement.  execute the line, place answer in val. */
+    if (*V1 == '`') {
+
+      /* look for end of line, must be ` */
+      B = V1 + strlen (V1) - 1;
+      if (*B != '`') goto error;
+
+      /* val will hold the result */
+      ALLOCATE (val, char, 1024);
+
+      /* B is the command to be executed */
+      B = strncreate (V1 + 1, strlen(V1) - 2);
+      f = popen (B, "r");
+      Nbytes = fread (val, 1, 1023, f);
+      val[Nbytes] = 0;
+      status = pclose (f);
+      free (B);
+
+      if (status) gprint (GP_ERR, "warning: exit status of command %d\n", status);
+
+      /* convert all but last return to ' '.  drop last return */
+      for (B = val; *B != 0; B++) {
+	if (*B == '\n') {
+	  if (B[1]) {
+	    *B = ' ';
+	  } else {
+	    *B = 0;
+	  }
+	}
+      }
+    } 
+
+    /* simple variable assignment */
+    if (*V1 != '`') {
+      /* dvomath returns a new string, or NULL, with the result of the expression */
+      val = dvomath (1, &V1, &size, 0);
+      if (val == NULL) { 
+	while (OHANA_WHITESPACE (*V1)) V1++;
+	val = strcreate (V1);
+      } 
+    }
+    /* both dvomath and command replacement create (char *) val */
+    set_str_variable (V0, val);
+    goto escape;  /* frees temp variables */
+  }
+
+  /* case 2: vect[N] = value */
+  V0 = thiscomm (line);
+  if (strchr(V0, '[') != (char *) NULL) { 
+    /* get vector name (left in V0) */
+    N = strchr (V0, '[');
+    if (N == V0) goto error;
+
+    /* get bracket contents (left in V) */
+    L = strchr (V0, ']');
+    if (L == (char *) NULL) goto error;
+    if (L != V0 + strlen (V0) - 1) goto error;
+
+    *N = 0;
+    V = strncreate (N+1, L - N - 1);
+
+    /* expand value in brackets */
+    val = dvomath (1, &V, &size, 0);
+    if (val == NULL) {
+      print_error ();
+      goto error;
+    }
+    Nval = atoi (val);
+    free (val); val = NULL;
+    free (V);
+
+    /* find vector */
+    if ((vec = SelectVector (V0, OLDVECTOR, TRUE)) == NULL) goto error;
+    free (V0); V0 = (char *) NULL;
+    if (Nval >= vec[0].Nelements) {
+      gprint (GP_ERR, "no element %d\n", Nval);
+      goto escape;
+    }
+
+    /* find value for assignment */
+    V1 = nextcomm (line);
+    if (V1 == (char *) NULL) goto error;
+    if (V1[0] != '=') goto error;
+    V1 ++;
+
+    /*** assign vector element to value ***/
+    val = dvomath (1, &V1, &size, 0); 
+    if (val == (char *) NULL) {
+      print_error ();
+      goto error;
+    }
+    vec[0].elements[Nval] = atof (val);
+    goto escape;
+  }
+  free (V0); V0 = (char *) NULL;
+
+  /* case 3: {expression} */
+  ALLOCATE (newline, char, 1024);
+  for (L = line, N = newline; *L != 0; L++, N++) { 
+
+    /* copy elements from L (line) to N (newline) until we hit a '{' */
+    for (; (*L != '{') && (*L != 0); L++, N++) *N = *L;
+    if (*L == 0) break;
+
+    if ((L != line) && (*(L-1) == 0x5c)) {
+      N--;
+      *N = *L;
+      continue;
+    }
+
+    /* check on the syntax of the line */
+    L++;
+    c1 = strchr (L, '}');
+    if (c1 == NULL) {
+      gprint (GP_ERR, "no close brackets!\n");
+      goto escape;
+    }
+    c2 = strchr (L, '{');
+    if ((c2 != NULL) && (c2 < c1)) {
+      gprint (GP_ERR, "can't nest brackets!\n");
+      goto escape;
+    }
+    end = c1;
+    *c1 = 0;
+
+    /* value in brackets must be a math expression of some sort.
+       isolated words are not valid here */
+    val = dvomath (1, &L, &size, -1);
+    if (val == NULL) {
+      print_error ();
+      goto escape;
+    } 
+    /* copy val to outline */
+    for (V = val; *V != 0; V++,N++) *N = *V;
+    L = end;
+    N--;
+    free (val); val = (char *) NULL;
+  }
+  
+  *N = 0;
+  free (line); line = (char *) NULL;
+
+  /* \ protects next character */
+  interpolate_slash (newline);
+  
+  REALLOCATE (newline, char, strlen (newline) + 1);
+  return (newline); 
+
+  error:
+  gprint (GP_ERR, "syntax error\n");
+
+  escape:
+  if (line != (char *) NULL) free (line);
+  if (val != (char *) NULL) free (val);
+  if (V0 != (char *) NULL) free (V0);
+  return (NULL);
+}
+
+/* replace all instances of \A with A in line */
+void interpolate_slash (char *line) {
+
+  char *in, *out;
+
+  for (in = out = line; *in != 0; in++, out++) {
+    if (*in == 0x5c) in++;
+    *out = *in;
+    if (*in == 0) return;
+  }
+  *out = *in;
+}
+
+  /* this routine looks for math and/or logic expressions that 
+     need to be evaluated and passes them on to "parenthesis",
+     which evaluates the expression */
+
+  /* There are two situations now which define an expression to 
+     be evaluated:
+     1) $var = expression   -- everything after the = must be a math expression or a string
+     2) {expression}        -- everything within the {} must be a math expression
+   */
+
+  /* case 1: $var = expression.  test that
+     a) there is a $ as the first character
+     b) the variable defined by that $ is not null
+     c) there is an = sign following the variable
+     d) there is something following the = sign
+     */
+  
+  /* case 2: vect[N] = expression. check syntax:
+     a) last char must be ]
+     b) word must contain [
+     c) between [ & ] must be an integer
+     d) vector must exist
+     e) there is an = sign following the first word
+     f) there is something following the = sign
+  */
+     
+
+  /* case 3: we hunt for '{', and then the first '}' and pass everything
+     inbetween.  no nested {{}}s are allowed! */
+  
+/* thisword ALLOCATES
+   thisvar  ALLOCATES
+   thiscomm ALLOCATES
+   
+   nextword !ALLOCATE
+   nextcomm !ALLOCATE
+   
+   lastword !ALLOCATE
+   lastvar !ALLOCATE
+   
+   aftervar !ALLOCATE
+*/   
+
Index: /branches/opihi-2-9/Ohana/src/opihi/lib.shell/parse_commands.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/lib.shell/parse_commands.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/lib.shell/parse_commands.c	(revision 11389)
@@ -0,0 +1,50 @@
+# include "opihi.h"
+# define D_NARG 10
+
+char **parse_commands (char *line, int *argc) {
+
+  int i, j, NARG;
+  char *c;
+  char **argv;
+
+  NARG = D_NARG;
+  ALLOCATE (argv, char *, NARG);
+
+  argv[0] = thisword (line);
+  if (argv[0] == (char *) NULL) {
+    free (argv);
+    *argc = 0;
+    return ((char **) NULL);
+  }
+
+  c = nextword (line);
+  for (i = 1; c != (char *) NULL; i++) {
+    argv[i] = thisword (c);
+    if (argv[i] == (char *) NULL) {
+      for (j = 0; j < i; j++) 
+	free (argv[i]);
+      free (argv);
+      *argc = 0;
+      return (argv);
+    }
+    c = nextword (c);
+    if (i == NARG - 1) {
+      NARG += D_NARG;
+      REALLOCATE (argv, char *, NARG);
+    }
+  }
+  REALLOCATE (argv, char *, i);
+  *argc = i;
+
+  return (argv);
+
+}
+
+  /* parse out the command line into (char **argv).  line looks like:
+     command word word word ... */
+
+  /* argv[0] and argv[1..argc-1] are handled differently because
+     the syntax of a valid command and a valid word are slighly 
+     different (not that this is obviously wanted...) */
+
+
Index: /branches/opihi-2-9/Ohana/src/opihi/lib.shell/stack_math.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/lib.shell/stack_math.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/lib.shell/stack_math.c	(revision 11389)
@@ -0,0 +1,1404 @@
+# include "opihi.h"
+
+/* the result of a matrix operation must go into a temp variable,
+   labeled by "m". if one of the input matrices is already a temp variable, we 
+   can continue using it this round 
+   */
+
+int VV_binary (StackVar *OUT, StackVar *V1, StackVar *V2, char *op) {
+
+  int i, Nx;
+  float *out, *M1, *M2;
+  char line[512];
+  
+  Nx = V1[0].vector[0].Nelements;
+  if (Nx != V2[0].vector[0].Nelements) {
+    return (FALSE);
+  }
+
+  if (V1[0].type == 'v') {  /** use V1 as temp buffer **/
+    OUT[0].vector = V1[0].vector;
+    V1[0].type = 'V'; /* prevent it from being freed below */
+  } else {
+    if (V2[0].type == 'v') { /** use V2 as temp buffer, but header of V1 **/
+      OUT[0].vector = V2[0].vector;
+      V2[0].type = 'V'; /* prevent it from being freed below */
+    } else {  /* no spare temp buffer */
+      OUT[0].vector = InitVector ();
+      CopyVector (OUT[0].vector, V1[0].vector);
+    }
+  }
+  OUT[0].type = 'v'; /*** <<--- says this is a temporary matrix ***/
+  strcpy (OUT[0].name, "tmp");
+  M1  = V1[0].ptr;
+  M2  = V2[0].ptr;
+  out = OUT[0].ptr = (float *)OUT[0].vector[0].elements;
+
+  switch (op[0]) { 
+  case '+': 
+    for (i = 0; i < Nx; i++, out++, M1++, M2++)
+      *out = *M1 + *M2;
+    break; 
+  case '-': 
+    for (i = 0; i < Nx; i++, out++, M1++, M2++)
+      *out = *M1 - *M2;
+    break; 
+  case '*': 
+    for (i = 0; i < Nx; i++, out++, M1++, M2++)
+      *out = *M1 * *M2;
+    break; 
+  case '/': 
+    for (i = 0; i < Nx; i++, out++, M1++, M2++)
+      *out = *M1 / *M2;
+    break; 
+  case '%': 
+    for (i = 0; i < Nx; i++, out++, M1++, M2++)
+      *out = (int) *M1 % (int) *M2;
+    break; 
+  case 0x5e: 
+    for (i = 0; i < Nx; i++, out++, M1++, M2++) 
+      *out = pow (*M1, *M2);
+    break; 
+  case '@': 
+    for (i = 0; i < Nx; i++, out++, M1++, M2++) 
+      *out = DEG_RAD*atan2 (*M1, *M2);
+    break; 
+  case 'D': 
+    for (i = 0; i < Nx; i++, out++, M1++, M2++) 
+      *out = MIN (*M1, *M2);
+    break; 
+  case 'U': 
+    for (i = 0; i < Nx; i++, out++, M1++, M2++) 
+      *out = MAX (*M1, *M2);
+    break; 
+  case '<': 
+    for (i = 0; i < Nx; i++, out++, M1++, M2++) 
+      *out = (*M1 < *M2) ? 1 : 0;
+    break; 
+  case '>': 
+    for (i = 0; i < Nx; i++, out++, M1++, M2++) 
+      *out = (*M1 > *M2) ? 1 : 0;
+    break; 
+  case '&': 
+    for (i = 0; i < Nx; i++, out++, M1++, M2++) 
+      *out = ((int)*M1 & (int)*M2);
+    break; 
+  case '|': 
+    for (i = 0; i < Nx; i++, out++, M1++, M2++) 
+      *out = ((int)*M1 | (int)*M2);
+    break; 
+  case 'E': 
+    for (i = 0; i < Nx; i++, out++, M1++, M2++) 
+      *out = (*M1 == *M2) ? 1 : 0;
+    break; 
+  case 'N': 
+    for (i = 0; i < Nx; i++, out++, M1++, M2++) 
+      *out = (*M1 != *M2) ? 1 : 0;
+    break; 
+  case 'L': 
+    for (i = 0; i < Nx; i++, out++, M1++, M2++) 
+      *out = (*M1 <= *M2) ? 1 : 0;
+    break; 
+  case 'G': 
+    for (i = 0; i < Nx; i++, out++, M1++, M2++) 
+      *out = (*M1 >= *M2) ? 1 : 0;
+    break; 
+  case 'A': 
+    for (i = 0; i < Nx; i++, out++, M1++, M2++) 
+      *out = (*M1 && *M2) ? 1 : 0;
+    break; 
+  case 'O': 
+    for (i = 0; i < Nx; i++, out++, M1++, M2++) 
+      *out = (*M1 || *M2) ? 1 : 0;
+    break; 
+  default:
+    sprintf (line, "error: op %c not defined!", op[0]);
+    push_error (line);
+    return (FALSE);
+  }
+
+  /** free up any temporary buffers: **/
+
+  if (V1[0].type == 'v') {
+    free (V1[0].vector[0].elements);
+    free (V1[0].vector);
+  }
+  if (V2[0].type == 'v') {
+    free (V2[0].vector[0].elements);
+    free (V2[0].vector);
+  }
+
+  /* at the end, V1 and V2 are deleted only if they were temporary */
+  return (TRUE);
+
+}
+
+int SV_binary (StackVar *OUT, StackVar *V1, StackVar *V2, char *op) {
+
+  int i, Nx;
+  float *out, *M1, *M2;
+  char line[512];
+  
+  Nx = V2[0].vector[0].Nelements;
+
+  if (V2[0].type == 'v') { /** use V2 as temp buffer, but header of V1 **/
+    OUT[0].vector = V2[0].vector;
+    V2[0].type = 'V'; /* prevent it from being freed below */
+  } else {  /* no spare temp buffer */
+    OUT[0].vector = InitVector ();
+    CopyVector (OUT[0].vector, V2[0].vector);
+  }
+  OUT[0].type = 'v';   /*** <<--- says this is a temporary matrix ***/
+  strcpy (OUT[0].name, "tmp");
+  M1  = V1[0].ptr;
+  M2  = V2[0].ptr;
+  out = OUT[0].ptr = (float *)OUT[0].vector[0].elements;
+
+  switch (op[0]) { 
+  case '+': 
+    for (i = 0; i < Nx; i++, out++, M2++)
+      *out = *M1 + *M2;
+    break; 
+  case '-': 
+    for (i = 0; i < Nx; i++, out++, M2++)
+      *out = *M1 - *M2;
+    break; 
+  case '*': 
+    for (i = 0; i < Nx; i++, out++, M2++)
+      *out = *M1 * *M2;
+    break; 
+  case '/': 
+    for (i = 0; i < Nx; i++, out++, M2++)
+      *out = *M1 / *M2;
+    break; 
+  case '%': 
+    for (i = 0; i < Nx; i++, out++, M2++)
+      *out = (int) *M1 % (int) *M2;
+    break; 
+  case 0x5e: 
+    for (i = 0; i < Nx; i++, out++, M2++) 
+      *out = pow (*M1, *M2);
+    break; 
+  case '@': 
+    for (i = 0; i < Nx; i++, out++, M2++) 
+      *out = DEG_RAD*atan2 (*M1, *M2);
+    break; 
+  case 'D': 
+    for (i = 0; i < Nx; i++, out++, M2++) 
+      *out = MIN (*M1, *M2);
+    break; 
+  case 'U': 
+    for (i = 0; i < Nx; i++, out++, M2++) 
+      *out = MAX (*M1, *M2);
+    break; 
+  case '<': 
+    for (i = 0; i < Nx; i++, out++, M2++) 
+      *out = (*M1 < *M2) ? 1 : 0;
+    break; 
+  case '>': 
+    for (i = 0; i < Nx; i++, out++, M2++) 
+      *out = (*M1 > *M2) ? 1 : 0;
+    break; 
+  case '&': 
+    for (i = 0; i < Nx; i++, out++, M2++) 
+      *out = ((int)*M1 & (int)*M2);
+    break; 
+  case '|': 
+    for (i = 0; i < Nx; i++, out++, M2++) 
+      *out = ((int)*M1 | (int)*M2);
+    break; 
+  case 'E': 
+    for (i = 0; i < Nx; i++, out++, M2++) 
+      *out = (*M1 == *M2) ? 1 : 0;
+    break; 
+  case 'N': 
+    for (i = 0; i < Nx; i++, out++, M2++) 
+      *out = (*M1 != *M2) ? 1 : 0;
+    break; 
+  case 'L': 
+    for (i = 0; i < Nx; i++, out++, M2++) 
+      *out = (*M1 <= *M2) ? 1 : 0;
+    break; 
+  case 'G': 
+    for (i = 0; i < Nx; i++, out++, M2++) 
+      *out = (*M1 >= *M2) ? 1 : 0;
+    break; 
+  case 'A': 
+    for (i = 0; i < Nx; i++, out++, M2++) 
+      *out = (*M1 && *M2) ? 1 : 0;
+    break; 
+  case 'O': 
+    for (i = 0; i < Nx; i++, out++, M2++) 
+      *out = (*M1 || *M2) ? 1 : 0;
+    break; 
+  default:
+    sprintf (line, "error: op %c not defined!", op[0]);
+    push_error (line);
+    return (FALSE);
+  }
+
+  /** free up any temporary buffers: **/
+  if (V2[0].type == 'v') {
+    free (V2[0].vector[0].elements);
+    free (V2[0].vector);
+  }
+
+  /* at the end, V1 and V2 are deleted only if they were temporary */
+  return (TRUE);
+
+}
+
+int VS_binary (StackVar *OUT, StackVar *V1, StackVar *V2, char *op) {
+
+  int i, Nx;
+  float *out, *M1, *M2;
+  char line[512];
+  
+  Nx = V1[0].vector[0].Nelements;
+
+  if (V1[0].type == 'v') { /** use V1 as temp buffer **/
+    OUT[0].vector = V1[0].vector;
+    V1[0].type = 'V'; /* prevent it from being freed below */
+  } else {  /* no spare temp buffer */
+    OUT[0].vector = InitVector ();
+    CopyVector (OUT[0].vector, V1[0].vector);
+  }
+  OUT[0].type = 'v';   /*** <<--- says this is a temporary matrix ***/
+  strcpy (OUT[0].name, "tmp");
+  M1  = V1[0].ptr;
+  M2  = V2[0].ptr;
+  out = OUT[0].ptr = (float *)OUT[0].vector[0].elements;
+
+  switch (op[0]) { 
+  case '+': 
+    for (i = 0; i < Nx; i++, out++, M1++)
+      *out = *M1 + *M2;
+    break; 
+  case '-': 
+    for (i = 0; i < Nx; i++, out++, M1++)
+      *out = *M1 - *M2;
+    break; 
+  case '*': 
+    for (i = 0; i < Nx; i++, out++, M1++)
+      *out = *M1 * *M2;
+    break; 
+  case '/': 
+    for (i = 0; i < Nx; i++, out++, M1++)
+      *out = *M1 / *M2;
+    break; 
+  case '%': 
+    for (i = 0; i < Nx; i++, out++, M1++)
+      *out = (int) *M1 % (int) *M2;
+    break; 
+  case 0x5e: 
+    for (i = 0; i < Nx; i++, out++, M1++) 
+      *out = pow (*M1, *M2);
+    break; 
+  case '@': 
+    for (i = 0; i < Nx; i++, out++, M1++) 
+      *out = DEG_RAD*atan2 (*M1, *M2);
+    break; 
+  case 'D': 
+    for (i = 0; i < Nx; i++, out++, M1++) 
+      *out = MIN (*M1, *M2);
+    break; 
+  case 'U': 
+    for (i = 0; i < Nx; i++, out++, M1++) 
+      *out = MAX (*M1, *M2);
+    break; 
+  case '<': 
+    for (i = 0; i < Nx; i++, out++, M1++) 
+      *out = (*M1 < *M2) ? 1 : 0;
+    break; 
+  case '>': 
+    for (i = 0; i < Nx; i++, out++, M1++) 
+      *out = (*M1 > *M2) ? 1 : 0;
+    break; 
+  case '&': 
+    for (i = 0; i < Nx; i++, out++, M1++) 
+      *out = ((int)*M1 & (int)*M2);
+    break; 
+  case '|': 
+    for (i = 0; i < Nx; i++, out++, M1++) 
+      *out = ((int)*M1 | (int)*M2);
+    break; 
+  case 'E': 
+    for (i = 0; i < Nx; i++, out++, M1++) 
+      *out = (*M1 == *M2) ? 1 : 0;
+    break; 
+  case 'N': 
+    for (i = 0; i < Nx; i++, out++, M1++) 
+      *out = (*M1 != *M2) ? 1 : 0;
+    break; 
+  case 'L': 
+    for (i = 0; i < Nx; i++, out++, M1++) 
+      *out = (*M1 <= *M2) ? 1 : 0;
+    break; 
+  case 'G': 
+    for (i = 0; i < Nx; i++, out++, M1++) 
+      *out = (*M1 >= *M2) ? 1 : 0;
+    break; 
+  case 'A': 
+    for (i = 0; i < Nx; i++, out++, M1++) 
+      *out = (*M1 && *M2) ? 1 : 0;
+    break; 
+  case 'O': 
+    for (i = 0; i < Nx; i++, out++, M1++) 
+      *out = (*M1 || *M2) ? 1 : 0;
+    break; 
+  default:
+    sprintf (line, "error: op %c not defined!", op[0]);
+    push_error (line);
+    return (FALSE);
+  }
+
+  /** free up any temporary buffers: **/
+
+  if (V1[0].type == 'v') {
+    free (V1[0].vector[0].elements);
+    free (V1[0].vector);
+  }
+  /* at the end, V1 and V2 are deleted only if they were temporary */
+  return (TRUE);
+
+}
+
+int MV_binary (StackVar *OUT, StackVar *V1, StackVar *V2, char *op) {
+
+  int i, j, Nx, Ny;
+  float *out, *M1, *M2;
+  char line[512];
+ 
+  Nx = V1[0].buffer[0].matrix.Naxis[0];
+  Ny = V1[0].buffer[0].matrix.Naxis[1];
+  if (Ny != V2[0].vector[0].Nelements) {
+    push_error ("dimension mismatch");
+    return (FALSE);
+  }
+
+  /* if possible, use V1 as temp buffer, otherwise create new one */
+  if (V1[0].type == 'm') {  
+    OUT[0].buffer = V1[0].buffer;
+    V1[0].type = 'M'; /* prevent it from being freed below */
+  } else {  
+    /* do buffer.matrix.buffer and buffer.header.buffer get correctly zeroed? */
+    OUT[0].buffer = InitBuffer ();
+    CopyBuffer (OUT[0].buffer, V1[0].buffer);
+  }
+  OUT[0].type = 'm'; /*** <<--- says this is a temporary matrix ***/
+  strcpy (OUT[0].name, "tmp");
+  M1  = V1[0].ptr;
+  M2  = V2[0].ptr;
+  out = OUT[0].ptr = (float *)OUT[0].buffer[0].matrix.buffer;
+
+  switch (op[0]) { 
+  case '+': 
+    for (i = 0; i < Ny; i++, M2++) {
+      for (j = 0; j < Nx; j++, out++, M1++)
+        *out = *M1 + *M2;
+    }
+    break; 
+  case '-': 
+    for (i = 0; i < Ny; i++, M2++) {
+      for (j = 0; j < Nx; j++, out++, M1++)
+        *out = *M1 - *M2;
+    }
+    break; 
+  case '*': 
+    for (i = 0; i < Ny; i++, M2++) {
+      for (j = 0; j < Nx; j++, out++, M1++)
+        *out = *M1 * *M2;
+    }
+    break; 
+  case '/': 
+    for (i = 0; i < Ny; i++, M2++) {
+      for (j = 0; j < Nx; j++, out++, M1++)
+        *out = *M1 / *M2;
+    }
+    break; 
+  case '%': 
+    for (i = 0; i < Ny; i++, M2++) {
+      for (j = 0; j < Nx; j++, out++, M1++)
+        *out = (int) *M1 % (int) *M2;
+    }
+    break; 
+  case 0x5e: 
+    for (i = 0; i < Ny; i++, M2++) {
+      for (j = 0; j < Nx; j++, out++, M1++) 
+        *out = pow (*M1, *M2);
+    }
+    break; 
+  case '@': 
+    for (i = 0; i < Ny; i++, M2++) {
+      for (j = 0; j < Nx; j++, out++, M1++) 
+        *out = DEG_RAD*atan2 (*M1, *M2);
+    }
+    break; 
+  case 'D': 
+    for (i = 0; i < Ny; i++, M2++) {
+      for (j = 0; j < Nx; j++, out++, M1++) 
+        *out = MIN (*M1, *M2);
+    }
+    break; 
+  case 'U': 
+    for (i = 0; i < Ny; i++, M2++) {
+      for (j = 0; j < Nx; j++, out++, M1++) 
+        *out = MAX (*M1, *M2);
+    }
+    break; 
+  case '<': 
+    for (i = 0; i < Ny; i++, M2++) {
+      for (j = 0; j < Nx; j++, out++, M1++) 
+        *out = (*M1 < *M2) ? 1 : 0;
+    }
+    break; 
+  case '>': 
+    for (i = 0; i < Ny; i++, M2++) {
+      for (j = 0; j < Nx; j++, out++, M1++) 
+        *out = (*M1 > *M2) ? 1 : 0;
+    }
+    break; 
+  case '&': 
+    for (i = 0; i < Ny; i++, M2++) {
+      for (j = 0; j < Nx; j++, out++, M1++) 
+        *out = ((int)*M1 & (int)*M2);
+    }
+    break; 
+  case '|': 
+    for (i = 0; i < Ny; i++, M2++) {
+      for (j = 0; j < Nx; j++, out++, M1++) 
+        *out = ((int)*M1 | (int)*M2);
+    }
+    break; 
+  case 'E': 
+    for (i = 0; i < Ny; i++, M2++) {
+      for (j = 0; j < Nx; j++, out++, M1++) 
+        *out = (*M1 == *M2) ? 1 : 0;
+    }
+    break; 
+  case 'N': 
+    for (i = 0; i < Ny; i++, M2++) {
+      for (j = 0; j < Nx; j++, out++, M1++) 
+        *out = (*M1 != *M2) ? 1 : 0;
+    }
+    break; 
+  case 'L': 
+    for (i = 0; i < Ny; i++, M2++) {
+      for (j = 0; j < Nx; j++, out++, M1++) 
+        *out = (*M1 <= *M2) ? 1 : 0;
+    }
+    break; 
+  case 'G': 
+    for (i = 0; i < Ny; i++, M2++) {
+      for (j = 0; j < Nx; j++, out++, M1++) 
+        *out = (*M1 >= *M2) ? 1 : 0;
+    }
+    break; 
+  case 'A': 
+    for (i = 0; i < Ny; i++, M2++) {
+      for (j = 0; j < Nx; j++, out++, M1++) 
+        *out = (*M1 && *M2) ? 1 : 0;
+    }
+    break; 
+  case 'O': 
+    for (i = 0; i < Ny; i++, M2++) {
+      for (j = 0; j < Nx; j++, out++, M1++) 
+        *out = (*M1 || *M2) ? 1 : 0;
+    }
+    break; 
+  default:
+    sprintf (line, "error: op %c not defined!", op[0]);
+    push_error (line);
+    return (FALSE);
+  }
+
+  /** free up any temporary buffers: **/
+
+  if (V1[0].type == 'm') {
+    free (V1[0].buffer[0].header.buffer);
+    free (V1[0].buffer[0].matrix.buffer);
+    free (V1[0].buffer);
+  }
+  if (V2[0].type == 'v') {
+    free (V2[0].vector[0].elements);
+    free (V2[0].vector);
+  }
+  /* at the end, V1 and V2 are deleted only if they were temporary */
+  return (TRUE);
+
+}
+
+
+int VM_binary (StackVar *OUT, StackVar *V1, StackVar *V2, char *op) {
+
+  int i, j, Nx, Ny;
+  float *out, *M1, *M2;
+  char line[512];
+  
+  Nx = V2[0].buffer[0].matrix.Naxis[0];
+  Ny = V2[0].buffer[0].matrix.Naxis[1];
+  if (Nx != V1[0].vector[0].Nelements) {
+    return (FALSE);
+  }
+
+  /* if possible, use V2 as temp buffer, otherwise create new one */
+  if (V2[0].type == 'm') {
+    OUT[0].buffer = V2[0].buffer;
+    V2[0].type = 'M'; /* prevent it from being freed below */
+  } else {  /* no spare temp buffer */
+    OUT[0].buffer = InitBuffer ();
+    CopyBuffer (OUT[0].buffer, V2[0].buffer);
+  }
+  OUT[0].type = 'm'; /*** <<--- says this is a temporary matrix ***/
+  strcpy (OUT[0].name, "tmp");
+  M1  = V1[0].ptr;
+  M2  = V2[0].ptr;
+  out = OUT[0].ptr = (float *)OUT[0].buffer[0].matrix.buffer;
+
+  switch (op[0]) { 
+  case '+': 
+    for (i = 0; i < Ny; i++) {
+      M1 = V1[0].ptr;
+      for (j = 0; j < Nx; j++, out++, M1++, M2++)
+        *out = *M1 + *M2;
+    }
+    break; 
+  case '-': 
+    for (i = 0; i < Ny; i++) {
+      M1 = V1[0].ptr;
+      for (j = 0; j < Nx; j++, out++, M1++, M2++)
+        *out = *M1 - *M2;
+    }
+    break; 
+  case '*': 
+    for (i = 0; i < Ny; i++) {
+      M1 = V1[0].ptr;
+      for (j = 0; j < Nx; j++, out++, M1++, M2++)
+        *out = *M1 * *M2;
+    }
+    break; 
+  case '/': 
+    for (i = 0; i < Ny; i++) {
+      M1 = V1[0].ptr;
+      for (j = 0; j < Nx; j++, out++, M1++, M2++)
+        *out = *M1 / *M2;
+    }
+    break; 
+  case '%': 
+    for (i = 0; i < Ny; i++) {
+      M1 = V1[0].ptr;
+      for (j = 0; j < Nx; j++, out++, M1++, M2++)
+        *out = (int) *M1 % (int) *M2;
+    }
+    break; 
+  case 0x5e: 
+    for (i = 0; i < Ny; i++) {
+      M1 = V1[0].ptr;
+      for (j = 0; j < Nx; j++, out++, M1++, M2++) 
+        *out = pow (*M1, *M2);
+    }
+    break; 
+  case '@': 
+    for (i = 0; i < Ny; i++) {
+      M1 = V1[0].ptr;
+      for (j = 0; j < Nx; j++, out++, M1++, M2++) 
+        *out = DEG_RAD*atan2 (*M1, *M2);
+    }
+    break; 
+  case 'D': 
+    for (i = 0; i < Ny; i++) {
+      M1 = V1[0].ptr;
+      for (j = 0; j < Nx; j++, out++, M1++, M2++) 
+        *out = MIN (*M1, *M2);
+    }
+    break; 
+  case 'U': 
+    for (i = 0; i < Ny; i++) {
+      M1 = V1[0].ptr;
+      for (j = 0; j < Nx; j++, out++, M1++, M2++) 
+        *out = MAX (*M1, *M2);
+    }
+    break; 
+  case '<': 
+    for (i = 0; i < Ny; i++) {
+      M1 = V1[0].ptr;
+      for (j = 0; j < Nx; j++, out++, M1++, M2++) 
+        *out = (*M1 < *M2) ? 1 : 0;
+    }
+    break; 
+  case '>': 
+    for (i = 0; i < Ny; i++) {
+      M1 = V1[0].ptr;
+      for (j = 0; j < Nx; j++, out++, M1++, M2++) 
+        *out = (*M1 > *M2) ? 1 : 0;
+    }
+    break; 
+  case '&': 
+    for (i = 0; i < Ny; i++) {
+      M1 = V1[0].ptr;
+      for (j = 0; j < Nx; j++, out++, M1++, M2++) 
+        *out = ((int)*M1 & (int)*M2);
+    }
+    break; 
+  case '|': 
+    for (i = 0; i < Ny; i++) {
+      M1 = V1[0].ptr;
+      for (j = 0; j < Nx; j++, out++, M1++, M2++) 
+        *out = ((int)*M1 | (int)*M2);
+    }
+    break; 
+  case 'E': 
+    for (i = 0; i < Ny; i++) {
+      M1 = V1[0].ptr;
+      for (j = 0; j < Nx; j++, out++, M1++, M2++) 
+        *out = (*M1 == *M2) ? 1 : 0;
+    }
+    break; 
+  case 'N': 
+    for (i = 0; i < Ny; i++) {
+      M1 = V1[0].ptr;
+      for (j = 0; j < Nx; j++, out++, M1++, M2++) 
+        *out = (*M1 != *M2) ? 1 : 0;
+    }
+    break; 
+  case 'L': 
+    for (i = 0; i < Ny; i++) {
+      M1 = V1[0].ptr;
+      for (j = 0; j < Nx; j++, out++, M1++, M2++) 
+        *out = (*M1 <= *M2) ? 1 : 0;
+    }
+    break; 
+  case 'G': 
+    for (i = 0; i < Ny; i++) {
+      M1 = V1[0].ptr;
+      for (j = 0; j < Nx; j++, out++, M1++, M2++) 
+        *out = (*M1 >= *M2) ? 1 : 0;
+    }
+    break; 
+  case 'A': 
+    for (i = 0; i < Ny; i++) {
+      M1 = V1[0].ptr;
+      for (j = 0; j < Nx; j++, out++, M1++, M2++) 
+        *out = (*M1 && *M2) ? 1 : 0;
+    }
+    break; 
+  case 'O': 
+    for (i = 0; i < Ny; i++) {
+      M1 = V1[0].ptr;
+      for (j = 0; j < Nx; j++, out++, M1++, M2++) 
+        *out = (*M1 || *M2) ? 1 : 0;
+    }
+    break; 
+  default:
+    sprintf (line, "error: op %c not defined!", op[0]);
+    push_error (line);
+    return (FALSE);
+  }
+
+  /** free up any temporary buffers: **/
+
+  if (V1[0].type == 'v') {
+    free (V1[0].vector[0].elements);
+    free (V1[0].vector);
+  }
+  if (V2[0].type == 'm') {
+    free (V2[0].buffer[0].header.buffer);
+    free (V2[0].buffer[0].matrix.buffer);
+    free (V2[0].buffer);
+  }
+  /* at the end, V1 and V2 are deleted only if they were temporary */
+  return (TRUE);
+
+}
+
+int MM_binary (StackVar *OUT, StackVar *V1, StackVar *V2, char *op) {
+
+  int i, Nx, Ny;
+  float *out, *M1, *M2;
+  char line[512];
+  
+  Nx = V1[0].buffer[0].matrix.Naxis[0];
+  Ny = V1[0].buffer[0].matrix.Naxis[1];
+
+  if (V1[0].type == 'm') {  /** use V1 as temp buffer **/
+    OUT[0].buffer = V1[0].buffer;
+    V1[0].type = 'M'; /* prevent it from being freed below */
+  } else {
+    if (V2[0].type == 'm') { /** use V2 as temp buffer, but header of V1 **/
+      OUT[0].buffer = V2[0].buffer;
+      V2[0].type = 'M'; /* prevent it from being freed below */
+    } else {  /* no spare temp buffer */
+      OUT[0].buffer = InitBuffer ();
+      CopyBuffer (OUT[0].buffer, V1[0].buffer);
+    }
+  }
+  OUT[0].type = 'm'; /*** <<--- says this is a temporary matrix ***/
+  strcpy (OUT[0].name, "tmp");
+  M1  = V1[0].ptr;
+  M2  = V2[0].ptr;
+  out = OUT[0].ptr = (float *)OUT[0].buffer[0].matrix.buffer;
+
+  switch (op[0]) { 
+  case '+': 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++, M2++)
+      *out = *M1 + *M2;
+    break; 
+  case '-': 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++, M2++)
+      *out = *M1 - *M2;
+    break; 
+  case '*': 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++, M2++)
+      *out = *M1 * *M2;
+    break; 
+  case '/': 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++, M2++)
+      *out = *M1 / *M2;
+    break; 
+  case '%': 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++, M2++)
+      *out = (int) *M1 % (int) *M2;
+    break; 
+  case 0x5e: 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++, M2++) 
+      *out = pow (*M1, *M2);
+    break; 
+  case '@': 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++, M2++) 
+      *out = DEG_RAD*atan2 (*M1, *M2);
+    break; 
+  case 'D': 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++, M2++) 
+      *out = MIN (*M1, *M2);
+    break; 
+  case 'U': 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++, M2++) 
+      *out = MAX (*M1, *M2);
+    break; 
+  case '<': 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++, M2++) 
+      *out = (*M1 < *M2) ? 1 : 0;
+    break; 
+  case '>': 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++, M2++) 
+      *out = (*M1 > *M2) ? 1 : 0;
+    break; 
+  case '&': 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++, M2++) 
+      *out = ((int)*M1 & (int)*M2);
+    break; 
+  case '|': 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++, M2++) 
+      *out = ((int)*M1 | (int)*M2);
+    break; 
+  case 'E': 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++, M2++) 
+      *out = (*M1 == *M2) ? 1 : 0;
+    break; 
+  case 'N': 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++, M2++) 
+      *out = (*M1 != *M2) ? 1 : 0;
+    break; 
+  case 'L': 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++, M2++) 
+      *out = (*M1 <= *M2) ? 1 : 0;
+    break; 
+  case 'G': 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++, M2++) 
+      *out = (*M1 >= *M2) ? 1 : 0;
+    break; 
+  case 'A': 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++, M2++) 
+      *out = (*M1 && *M2) ? 1 : 0;
+    break; 
+  case 'O': 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++, M2++) 
+      *out = (*M1 || *M2) ? 1 : 0;
+    break; 
+  default:
+    sprintf (line, "error: op %c not defined!", op[0]);
+    push_error (line);
+    return (FALSE);
+  }
+
+  /** free up any temporary buffers: **/
+
+  if (V1[0].type == 'm') {
+    free (V1[0].buffer[0].header.buffer);
+    free (V1[0].buffer[0].matrix.buffer);
+    free (V1[0].buffer);
+  }
+  if (V2[0].type == 'm') {
+    free (V2[0].buffer[0].header.buffer);
+    free (V2[0].buffer[0].matrix.buffer);
+    free (V2[0].buffer);
+  }
+  /* at the end, V1 and V2 are deleted only if they were temporary */
+  return (TRUE);
+
+}
+
+
+int MS_binary (StackVar *OUT, StackVar *V1, StackVar *V2, char *op) {
+
+  int i, Nx, Ny;
+  float *out, *M1, *M2;
+  char line[512];
+  
+  Nx = V1[0].buffer[0].matrix.Naxis[0];
+  Ny = V1[0].buffer[0].matrix.Naxis[1];
+
+  /* if possible, use V1 as temp buffer, otherwise create new one */
+  if (V1[0].type == 'm') {
+    OUT[0].buffer = V1[0].buffer;
+    V1[0].type = 'M'; /* prevent it from being freed below */
+  } else {
+    OUT[0].buffer = InitBuffer ();
+    CopyBuffer (OUT[0].buffer, V1[0].buffer);
+  }
+  OUT[0].type = 'm';      /*** <<--- says this is a temporary matrix ***/
+  strcpy (OUT[0].name, "tmp");
+  M1  = V1[0].ptr;
+  M2  = V2[0].ptr;
+  out = OUT[0].ptr = (float *)OUT[0].buffer[0].matrix.buffer;
+
+  switch (op[0]) { 
+  case '+': 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++)
+      *out = *M1 + *M2;
+    break; 
+  case '-': 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++)
+      *out = *M1 - *M2;
+    break; 
+  case '*': 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++)
+      *out = *M1 * *M2;
+    break; 
+  case '/': 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++)
+      *out = *M1 / *M2;
+    break; 
+  case '%': 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++)
+      *out = (int) *M1 % (int) *M2;
+    break; 
+  case 0x5e: 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++) 
+      *out = pow (*M1, *M2);
+    break; 
+  case '@': 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++) 
+      *out = DEG_RAD*atan2 (*M1, *M2);
+    break; 
+  case 'D': 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++) 
+      *out = MIN (*M1, *M2);
+    break; 
+  case 'U': 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++) 
+      *out = MAX (*M1, *M2);
+    break; 
+  case '<': 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++) 
+      *out = (*M1 < *M2) ? 1 : 0;
+    break; 
+  case '>': 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++) 
+      *out = (*M1 > *M2) ? 1 : 0;
+    break; 
+  case '&': 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++) 
+      *out = ((int)*M1 & (int)*M2);
+    break; 
+  case '|': 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++) 
+      *out = ((int)*M1 | (int)*M2);
+    break; 
+  case 'E': 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++) 
+      *out = (*M1 == *M2) ? 1 : 0;
+    break; 
+  case 'N': 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++) 
+      *out = (*M1 != *M2) ? 1 : 0;
+    break; 
+  case 'L': 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++) 
+      *out = (*M1 <= *M2) ? 1 : 0;
+    break; 
+  case 'G': 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++) 
+      *out = (*M1 >= *M2) ? 1 : 0;
+    break; 
+  case 'A': 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++) 
+      *out = (*M1 && *M2) ? 1 : 0;
+    break; 
+  case 'O': 
+    for (i = 0; i < Nx*Ny; i++, out++, M1++) 
+      *out = (*M1 || *M2) ? 1 : 0;
+    break; 
+  default:
+    sprintf (line, "error: op %c not defined!", op[0]);
+    push_error (line);
+    return (FALSE);
+  }
+
+  if (V1[0].type == 'm') {
+    free (V1[0].buffer[0].header.buffer);
+    free (V1[0].buffer[0].matrix.buffer);
+    free (V1[0].buffer);
+  }
+  return (TRUE);
+
+}
+
+
+int SM_binary (StackVar *OUT, StackVar *V1, StackVar *V2, char *op) {
+
+  int i, Nx, Ny;
+  float *out, *M1, *M2;
+  char line[512];
+  
+  Nx = V2[0].buffer[0].matrix.Naxis[0];
+  Ny = V2[0].buffer[0].matrix.Naxis[1];
+
+  if (V2[0].type == 'm') {  /* V2[0] is NOT temporary, we can't use it for storage */
+    OUT[0].buffer = V2[0].buffer;
+    V2[0].type = 'M'; /* prevent it from being freed below */
+  } else {
+    OUT[0].buffer = InitBuffer ();
+    CopyBuffer (OUT[0].buffer, V2[0].buffer);
+  }
+  OUT[0].type = 'm'; /*** <<--- says this is a temporary matrix ***/
+  strcpy (OUT[0].name, "tmp");
+  M1  = V1[0].ptr;
+  M2  = V2[0].ptr;
+  out = OUT[0].ptr = (float *)OUT[0].buffer[0].matrix.buffer;
+
+  switch (op[0]) { 
+  case '+': 
+    for (i = 0; i < Nx*Ny; i++, out++, M2++)
+      *out = *M1 + *M2;
+    break; 
+  case '-': 
+    for (i = 0; i < Nx*Ny; i++, out++, M2++)
+      *out = *M1 - *M2;
+    break; 
+  case '*': 
+    for (i = 0; i < Nx*Ny; i++, out++, M2++)
+      *out = *M1 * *M2;
+    break; 
+  case '/': 
+    for (i = 0; i < Nx*Ny; i++, out++, M2++)
+      *out = *M1 / *M2;
+    break; 
+  case '%': 
+    for (i = 0; i < Nx*Ny; i++, out++, M2++)
+      *out = (int) *M1 % (int) *M2;
+    break; 
+  case 0x5e: 
+    for (i = 0; i < Nx*Ny; i++, out++, M2++)
+      *out = pow (*M1, *M2);
+    break; 
+  case '@': 
+    for (i = 0; i < Nx*Ny; i++, out++, M2++) 
+      *out = DEG_RAD*atan2 (*M1, *M2);
+    break; 
+  case 'D': 
+    for (i = 0; i < Nx*Ny; i++, out++, M2++) 
+      *out = MIN (*M1, *M2);
+    break; 
+  case 'U': 
+    for (i = 0; i < Nx*Ny; i++, out++, M2++) 
+      *out = MAX (*M1, *M2);
+    break; 
+  case '<': 
+    for (i = 0; i < Nx*Ny; i++, out++, M2++) 
+      *out = (*M1 < *M2) ? 1 : 0;
+    break; 
+  case '>': 
+    for (i = 0; i < Nx*Ny; i++, out++, M2++) 
+      *out = (*M1 > *M2) ? 1 : 0;
+    break; 
+  case '&': 
+    for (i = 0; i < Nx*Ny; i++, out++, M2++) 
+      *out = ((int)*M1 & (int)*M2);
+    break; 
+  case '|': 
+    for (i = 0; i < Nx*Ny; i++, out++, M2++) 
+      *out = ((int)*M1 | (int)*M2);
+    break; 
+  case 'E': 
+    for (i = 0; i < Nx*Ny; i++, out++, M2++) 
+      *out = (*M1 == *M2) ? 1 : 0;
+    break; 
+  case 'N': 
+    for (i = 0; i < Nx*Ny; i++, out++, M2++) 
+      *out = (*M1 != *M2) ? 1 : 0;
+    break; 
+  case 'L': 
+    for (i = 0; i < Nx*Ny; i++, out++, M2++) 
+      *out = (*M1 <= *M2) ? 1 : 0;
+    break; 
+  case 'G': 
+    for (i = 0; i < Nx*Ny; i++, out++, M2++) 
+      *out = (*M1 >= *M2) ? 1 : 0;
+    break; 
+  case 'A': 
+    for (i = 0; i < Nx*Ny; i++, out++, M2++) 
+      *out = (*M1 && *M2) ? 1 : 0;
+    break; 
+  case 'O': 
+    for (i = 0; i < Nx*Ny; i++, out++, M2++) 
+      *out = (*M1 || *M2) ? 1 : 0;
+    break; 
+  default:
+    sprintf (line, "error: op %c not defined!", op[0]);
+    push_error (line);
+    return (FALSE);
+  }
+
+  if (V2[0].type == 'm') {
+    free (V2[0].buffer[0].header.buffer);
+    free (V2[0].buffer[0].matrix.buffer);
+    free (V2[0].buffer);
+  }
+  return (TRUE);
+
+}
+
+
+int SS_binary (StackVar *OUT, StackVar *V1, StackVar *V2, char *op) {
+
+  float *M1, *M2, *out;
+  char line[512];
+
+  M1  = V1[0].ptr;
+  M2  = V2[0].ptr;
+  OUT[0].ptr = V1[0].ptr;
+  out = OUT[0].ptr;
+  strcpy (OUT[0].name, "tmp");
+
+  switch (op[0]) { 
+  case '+': 
+    *out = *M1 + *M2;
+    break;    
+  case '-': 
+    *out = *M1 - *M2;
+    break;    
+  case '*': 
+    *out = *M1 * *M2;
+    break;    
+  case '/': 
+    *out = *M1 / *M2;
+    break; 
+  case '%': 
+    *out = (int) *M1 % (int) *M2;
+    break; 
+  case 0x5e: 
+    *out = pow (*M1, *M2);
+    break; 
+  case '@': 
+    *out = DEG_RAD*atan2 (*M1, *M2);
+    break; 
+  case 'D': 
+    *out = MIN (*M1, *M2);
+    break; 
+  case 'U': 
+    *out = MAX (*M1, *M2);
+    break; 
+  case '<': 
+    *out = (*M1 < *M2) ? 1 : 0;
+    break; 
+  case '>': 
+    *out = (*M1 > *M2) ? 1 : 0;
+    break; 
+  case '&': 
+    *out = ((int)*M1 & (int)*M2);
+    break; 
+  case '|': 
+    *out = ((int)*M1 | (int)*M2);
+    break; 
+  case 'E': 
+    *out = (*M1 == *M2) ? 1 : 0;
+    break; 
+  case 'N': 
+    *out = (*M1 != *M2) ? 1 : 0;
+    break; 
+  case 'L': 
+    *out = (*M1 <= *M2) ? 1 : 0;
+    break; 
+  case 'G': 
+    *out = (*M1 >= *M2) ? 1 : 0;
+    break; 
+  case 'A': 
+    *out = (*M1 && *M2) ? 1 : 0;
+    break; 
+  case 'O': 
+    *out = (*M1 || *M2) ? 1 : 0;
+    break; 
+  default:
+    sprintf (line, "error: op %c not defined!", op[0]);
+    push_error (line);
+    return (FALSE);
+  }
+  OUT[0].Float = *(OUT[0].ptr);
+  OUT[0].type = 'S';
+  return (TRUE);
+
+}
+
+int WW_binary (StackVar *OUT, StackVar *V1, StackVar *V2, char *op) {
+
+  int value;
+  char line[512];
+
+  /* evaluate stack will only call WW_binary with one numerical value,
+     and only in the case that the string did not parse to a number 
+     thus: string == number -> false */
+  if (!strncasecmp (&V1[0].type, "S", 1)) {
+    value = (op[0] == 'N');
+    goto escape;
+  }
+  if (!strncasecmp (&V2[0].type, "S", 1)) {
+    value = (op[0] == 'N');
+    goto escape;
+  }
+
+  switch (op[0]) { 
+  case 'E': 
+    value = strcmp (V1[0].name, V2[0].name) ? 0 : 1;
+    break; 
+  case 'N': 
+    value = strcmp (V1[0].name, V2[0].name) ? 1 : 0;
+    break; 
+  default:
+    sprintf (line, "error: op %c not defined for string operations!", op[0]);
+    push_error (line);
+    return (FALSE);
+  }
+
+escape:
+  strcpy (OUT[0].name, "tmp");
+  OUT[0].Float = value;
+  OUT[0].type = 'S';
+  OUT[0].ptr = &OUT[0].Float;
+  return (TRUE);
+
+}
+
+
+int S_unary (StackVar *OUT, StackVar *V1, char *op) {
+
+  float *out, *M1;
+  
+  out = OUT[0].ptr = V1[0].ptr;
+  M1  = V1[0].ptr;
+
+  if (!strcmp (op, "="))     {    }
+  if (!strcmp (op, "abs"))   {    *out = fabs(*M1);           }
+  if (!strcmp (op, "int"))   {    *out = (float)(int)(*M1);   }
+  if (!strcmp (op, "exp"))   {    *out = exp (*M1);           }
+  if (!strcmp (op, "ten"))   {    *out = pow (10.0,*M1);      }
+  if (!strcmp (op, "log"))   {    *out = log10 (*M1);         }
+  if (!strcmp (op, "ln"))    {    *out = log (*M1);           }
+  if (!strcmp (op, "sqrt"))  {    *out = sqrt (*M1);          }
+  if (!strcmp (op, "erf"))   {    *out = erf (*M1);           }
+
+  if (!strcmp (op, "sinh"))  {    *out = sinh (*M1);          }
+  if (!strcmp (op, "cosh"))  {    *out = cosh (*M1);          }
+  if (!strcmp (op, "asinh")) {    *out = asinh (*M1);         }
+  if (!strcmp (op, "acosh")) {    *out = acosh (*M1);         }
+  if (!strcmp (op, "lgamma")) {   *out = lgamma (*M1);        }
+
+  if (!strcmp (op, "sin"))   {    *out = sin (*M1);           }
+  if (!strcmp (op, "cos"))   {    *out = cos (*M1);           }
+  if (!strcmp (op, "tan"))   {    *out = tan (*M1);           }
+  if (!strcmp (op, "dsin"))  {    *out = sin (*M1*RAD_DEG);   }
+  if (!strcmp (op, "dcos"))  {    *out = cos (*M1*RAD_DEG);   }
+  if (!strcmp (op, "dtan"))  {    *out = tan (*M1*RAD_DEG);   }
+  if (!strcmp (op, "asin"))  {    *out = asin (*M1);          }
+  if (!strcmp (op, "acos"))  {    *out = acos (*M1);          }
+  if (!strcmp (op, "atan"))  {    *out = atan (*M1);          }
+  if (!strcmp (op, "dasin")) {    *out = asin (*M1)*DEG_RAD;  }
+  if (!strcmp (op, "dacos")) {    *out = acos (*M1)*DEG_RAD;  }
+  if (!strcmp (op, "datan")) {    *out = atan (*M1)*DEG_RAD;  }
+  if (!strcmp (op, "rnd"))   {    *out = drand48();           }
+  if (!strcmp (op, "not"))   {    *out = !(*M1);              }
+  if (!strcmp (op, "--"))    {    *out = - (*M1);             }
+  if (!strcmp (op, "isinf")) {    *out = !finite(*M1);        }
+  if (!strcmp (op, "isnan")) {    *out = isnan(*M1);          } 
+
+  OUT[0].Float = *out;
+  OUT[0].type = 'S';
+  return (TRUE);
+
+}
+
+int V_unary (StackVar *OUT, StackVar *V1, char *op) {
+
+  int i, Nx;
+  float *out, *M1;
+  
+  Nx = V1[0].vector[0].Nelements;
+ 
+  if (V1[0].type == 'v') {  /** use V1 as temp buffer **/
+    OUT[0].vector = V1[0].vector;
+    V1[0].type = 'V'; /* prevent it from being freed below */
+  } else {  /* no spare temp buffer */
+    OUT[0].vector = InitVector ();
+    CopyVector (OUT[0].vector, V1[0].vector);
+  }
+  OUT[0].type = 'v'; /*** <<--- says this is a temporary matrix ***/
+  M1  = V1[0].ptr;
+  out = OUT[0].ptr = (float *)OUT[0].vector[0].elements;
+
+  if (!strcmp (op, "="))     { } /* already set equal */
+  if (!strcmp (op, "abs"))   { for (i = 0; i < Nx; i++, out++, M1++) { *out = fabs(*M1);         }}
+  if (!strcmp (op, "int"))   { for (i = 0; i < Nx; i++, out++, M1++) { *out = (float)(int)(*M1); }}
+  if (!strcmp (op, "exp"))   { for (i = 0; i < Nx; i++, out++, M1++) { *out = exp(*M1);          }}
+  if (!strcmp (op, "ten"))   { for (i = 0; i < Nx; i++, out++, M1++) { *out = pow(10.0,*M1);     }}
+  if (!strcmp (op, "log"))   { for (i = 0; i < Nx; i++, out++, M1++) { *out = log10(*M1);        }}
+  if (!strcmp (op, "ln"))    { for (i = 0; i < Nx; i++, out++, M1++) { *out = log(*M1);          }}
+  if (!strcmp (op, "sqrt"))  { for (i = 0; i < Nx; i++, out++, M1++) { *out = sqrt(*M1);         }}
+  if (!strcmp (op, "erf"))   { for (i = 0; i < Nx; i++, out++, M1++) { *out = erf(*M1);          }}
+
+  if (!strcmp (op, "sinh"))   { for (i = 0; i < Nx; i++, out++, M1++) { *out = sinh(*M1);        }}
+  if (!strcmp (op, "cosh"))   { for (i = 0; i < Nx; i++, out++, M1++) { *out = cosh(*M1);        }}
+  if (!strcmp (op, "asinh"))  { for (i = 0; i < Nx; i++, out++, M1++) { *out = asinh(*M1);       }}
+  if (!strcmp (op, "acosh"))  { for (i = 0; i < Nx; i++, out++, M1++) { *out = acosh(*M1);       }}
+  if (!strcmp (op, "lgamma")) { for (i = 0; i < Nx; i++, out++, M1++) { *out = lgamma(*M1);      }}
+
+  if (!strcmp (op, "sin"))   { for (i = 0; i < Nx; i++, out++, M1++) { *out = sin(*M1);          }}
+  if (!strcmp (op, "cos"))   { for (i = 0; i < Nx; i++, out++, M1++) { *out = cos(*M1);          }}
+  if (!strcmp (op, "tan"))   { for (i = 0; i < Nx; i++, out++, M1++) { *out = tan(*M1);          }}
+  if (!strcmp (op, "dsin"))  { for (i = 0; i < Nx; i++, out++, M1++) { *out = sin(*M1*RAD_DEG);  }}
+  if (!strcmp (op, "dcos"))  { for (i = 0; i < Nx; i++, out++, M1++) { *out = cos(*M1*RAD_DEG);  }}
+  if (!strcmp (op, "dtan"))  { for (i = 0; i < Nx; i++, out++, M1++) { *out = tan(*M1*RAD_DEG);  }}
+  if (!strcmp (op, "asin"))  { for (i = 0; i < Nx; i++, out++, M1++) { *out = asin(*M1);         }}
+  if (!strcmp (op, "acos"))  { for (i = 0; i < Nx; i++, out++, M1++) { *out = acos(*M1);         }}
+  if (!strcmp (op, "atan"))  { for (i = 0; i < Nx; i++, out++, M1++) { *out = atan(*M1);         }}
+  if (!strcmp (op, "dasin")) { for (i = 0; i < Nx; i++, out++, M1++) { *out = asin(*M1)*DEG_RAD; }}
+  if (!strcmp (op, "dacos")) { for (i = 0; i < Nx; i++, out++, M1++) { *out = acos(*M1)*DEG_RAD; }}
+  if (!strcmp (op, "datan")) { for (i = 0; i < Nx; i++, out++, M1++) { *out = atan(*M1)*DEG_RAD; }}
+  if (!strcmp (op, "rnd"))   { for (i = 0; i < Nx; i++, out++, M1++) { *out = drand48();         }}
+  if (!strcmp (op, "ramp"))  { for (i = 0; i < Nx; i++, out++, M1++) { *out = i;                 }}
+  if (!strcmp (op, "zero"))  { for (i = 0; i < Nx; i++, out++, M1++) { *out = 0;                 }}
+  if (!strcmp (op, "not"))   { for (i = 0; i < Nx; i++, out++, M1++) { *out = !(*M1);            }}
+  if (!strcmp (op, "--"))    { for (i = 0; i < Nx; i++, out++, M1++) { *out = -(*M1);            }}
+  if (!strcmp (op, "isinf")) { for (i = 0; i < Nx; i++, out++, M1++) { *out = !finite(*M1);      }}
+  if (!strcmp (op, "isnan")) { for (i = 0; i < Nx; i++, out++, M1++) { *out = isnan(*M1);        }}
+
+  /* xramp and yramp only make sense in for matrices. for vectors, xramp = ramp, yramp = zero */
+  if (!strcmp (op, "xramp")) { for (i = 0; i < Nx; i++, out++, M1++) { *out = i;                 }}
+  if (!strcmp (op, "yramp")) { for (i = 0; i < Nx; i++, out++, M1++) { *out = 0;                 }}
+
+  if (V1[0].type == 'v') {
+    free (V1[0].vector[0].elements);
+    free (V1[0].vector);
+  }  
+  return (TRUE);
+
+}
+
+int M_unary (StackVar *OUT, StackVar *V1, char *op) {
+
+  int i, j, Nx, Ny;
+  float *out, *M1;
+  
+  Nx = V1[0].buffer[0].matrix.Naxis[0];
+  Ny = V1[0].buffer[0].matrix.Naxis[1];
+
+  if (V1[0].type == 'm') {
+    OUT[0].buffer = V1[0].buffer;
+    V1[0].type = 'M'; /* prevent it from being freed below */
+  } else {
+    OUT[0].buffer = InitBuffer ();
+    CopyBuffer (OUT[0].buffer, V1[0].buffer);
+  }
+  OUT[0].type = 'm';      /*** <<--- says this is a temporary matrix ***/
+  M1  = V1[0].ptr;
+  out = OUT[0].ptr = (float *)OUT[0].buffer[0].matrix.buffer;
+
+  if (!strcmp (op, "="))     { }
+  if (!strcmp (op, "abs"))   { for (i = 0; i < Nx*Ny; i++, out++, M1++) { *out = fabs(*M1);         }}
+  if (!strcmp (op, "int"))   { for (i = 0; i < Nx*Ny; i++, out++, M1++) { *out = (float)(int)(*M1); }}
+  if (!strcmp (op, "exp"))   { for (i = 0; i < Nx*Ny; i++, out++, M1++) { *out = exp(*M1);          }}
+  if (!strcmp (op, "ten"))   { for (i = 0; i < Nx*Ny; i++, out++, M1++) { *out = pow(10.0,*M1);     }}
+  if (!strcmp (op, "log"))   { for (i = 0; i < Nx*Ny; i++, out++, M1++) { *out = log10(*M1);        }}
+  if (!strcmp (op, "ln"))    { for (i = 0; i < Nx*Ny; i++, out++, M1++) { *out = log(*M1);          }}
+  if (!strcmp (op, "sqrt"))  { for (i = 0; i < Nx*Ny; i++, out++, M1++) { *out = sqrt(*M1);         }}
+  if (!strcmp (op, "erf"))   { for (i = 0; i < Nx*Ny; i++, out++, M1++) { *out = erf(*M1);          }}
+
+  if (!strcmp (op, "sinh"))  { for (i = 0; i < Nx*Ny; i++, out++, M1++) { *out = sinh(*M1);         }}
+  if (!strcmp (op, "cosh"))  { for (i = 0; i < Nx*Ny; i++, out++, M1++) { *out = cosh(*M1);         }}
+  if (!strcmp (op, "asinh")) { for (i = 0; i < Nx*Ny; i++, out++, M1++) { *out = asinh(*M1);        }}
+  if (!strcmp (op, "acosh")) { for (i = 0; i < Nx*Ny; i++, out++, M1++) { *out = acosh(*M1);        }}
+  if (!strcmp (op, "lgamma")) { for (i = 0; i < Nx*Ny; i++, out++, M1++) { *out = lgamma(*M1);      }}
+
+  if (!strcmp (op, "sin"))   { for (i = 0; i < Nx*Ny; i++, out++, M1++) { *out = sin(*M1);          }}
+  if (!strcmp (op, "cos"))   { for (i = 0; i < Nx*Ny; i++, out++, M1++) { *out = cos(*M1);          }}
+  if (!strcmp (op, "tan"))   { for (i = 0; i < Nx*Ny; i++, out++, M1++) { *out = tan(*M1);          }}
+  if (!strcmp (op, "dsin"))  { for (i = 0; i < Nx*Ny; i++, out++, M1++) { *out = sin(*M1*RAD_DEG);  }}
+  if (!strcmp (op, "dcos"))  { for (i = 0; i < Nx*Ny; i++, out++, M1++) { *out = cos(*M1*RAD_DEG);  }}
+  if (!strcmp (op, "dtan"))  { for (i = 0; i < Nx*Ny; i++, out++, M1++) { *out = tan(*M1*RAD_DEG);  }}
+  if (!strcmp (op, "asin"))  { for (i = 0; i < Nx*Ny; i++, out++, M1++) { *out = asin(*M1);         }}
+  if (!strcmp (op, "acos"))  { for (i = 0; i < Nx*Ny; i++, out++, M1++) { *out = acos(*M1);         }}
+  if (!strcmp (op, "atan"))  { for (i = 0; i < Nx*Ny; i++, out++, M1++) { *out = atan(*M1);         }}
+  if (!strcmp (op, "dasin")) { for (i = 0; i < Nx*Ny; i++, out++, M1++) { *out = asin(*M1)*DEG_RAD; }}
+  if (!strcmp (op, "dacos")) { for (i = 0; i < Nx*Ny; i++, out++, M1++) { *out = acos(*M1)*DEG_RAD; }}
+  if (!strcmp (op, "datan")) { for (i = 0; i < Nx*Ny; i++, out++, M1++) { *out = atan(*M1)*DEG_RAD; }}
+  if (!strcmp (op, "not"))   { for (i = 0; i < Nx*Ny; i++, out++, M1++) { *out = !(*M1);            }}
+  if (!strcmp (op, "--"))    { for (i = 0; i < Nx*Ny; i++, out++, M1++) { *out = -(*M1);            }}
+  if (!strcmp (op, "rnd"))   { for (i = 0; i < Nx*Ny; i++, out++, M1++) { *out = drand48();         }}
+  if (!strcmp (op, "ramp"))  { for (i = 0; i < Nx*Ny; i++, out++, M1++) { *out = i;                 }}
+  if (!strcmp (op, "zero"))  { for (i = 0; i < Nx*Ny; i++, out++, M1++) { *out = 0;                 }}
+  if (!strcmp (op, "isinf")) { for (i = 0; i < Nx*Ny; i++, out++, M1++) { *out = !finite(*M1);      }}
+  if (!strcmp (op, "isnan")) { for (i = 0; i < Nx*Ny; i++, out++, M1++) { *out = isnan(*M1);        }}
+
+  /* xrm and yrm only make sense in for matrices. see special meaning for vectors */
+  if (!strcmp (op, "xramp")) {
+    for (j = 0; j < Ny; j++) {
+      for (i = 0; i < Nx; i++, out++, M1++) {
+        *out = i;
+      }
+    }
+  }
+  if (!strcmp (op, "yramp")) {
+    for (j = 0; j < Ny; j++) {
+      for (i = 0; i < Nx; i++, out++, M1++) {
+        *out = j;
+      }
+    }
+  }
+  
+  if (V1[0].type == 'm') {
+    free (V1[0].buffer[0].header.buffer);
+    free (V1[0].buffer[0].matrix.buffer);
+    free (V1[0].buffer);
+  }
+  return (TRUE);
+
+}
+
+/*********************** fits copy header ***********************************/
+int gfits_copy_matrix_info (Matrix *matrix1, Matrix *matrix2) {
+
+  int i;
+
+  /* copy all but the matrix */
+
+  matrix2[0].unsign = matrix1[0].unsign;
+  matrix2[0].bitpix = matrix1[0].bitpix;
+  matrix2[0].size   = matrix1[0].size;
+  matrix2[0].bzero  = matrix1[0].bzero;
+  matrix2[0].bscale = matrix1[0].bscale;
+  matrix2[0].Naxes  = matrix1[0].Naxes;
+  for (i = 0; i < FT_MAX_NAXES; i++) 
+    matrix2[0].Naxis[i] = matrix1[0].Naxis[i];
+
+
+  return (TRUE);
+}       
Index: /branches/opihi-2-9/Ohana/src/opihi/lib.shell/startup.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/lib.shell/startup.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/lib.shell/startup.c	(revision 11389)
@@ -0,0 +1,161 @@
+# include "opihi.h"
+
+/* program-independent initialization
+ * these steps do not depend on the opihi implementation
+ * (ie, the supplied commands or data structures)
+ */
+
+void general_init (int *argc, char **argv) {
+
+  /* init srand for rnd numbers elsewhere */
+  long A, B;
+  A = time(NULL);
+  for (B = 0; A == time(NULL); B++);
+  srand48(B);
+ 
+  /* set signals */
+  signal (SIGINT, SIG_IGN);
+
+  /* init for main (or only) thread */
+  gprintInit ();
+
+  /* load config data (.ptolemyrc) */
+  if (!ConfigInit (argc, argv)) {
+    gprint (GP_ERR, "can't find config file. some functions will be unavailable\n");
+  }
+
+  return;
+}
+
+void startup (int *argc, char **argv) {
+    
+    int i, N, status, ONLY_INPUT, LOAD_RC;
+    char *line, *home, *outline, *varname;
+    char *rcfile, **list;
+    int Nlist, NLIST;
+   
+    /* load in interesting environment variables */
+    ALLOCATE (line, char, 1024);
+    
+    home = getenv ("HOME");
+    if (home == NULL) 
+      set_str_variable ("HOME", ".");
+    else 
+      set_str_variable ("HOME", home);
+    set_str_variable ("KII", "kii");
+    set_str_variable ("KAPA", "kapa");
+    set_variable ("PID", getpid());
+
+  /* keep these? 
+     set_int_variable ("UNSIGN", 0);
+     FT_UNSIGN_MODE = FALSE;
+  */
+
+
+
+  /* check history file permission */
+  {
+    FILE *f;
+    char *opihi_history;
+
+    opihi_history = get_variable ("HISTORY");
+    if (opihi_history && *opihi_history) {
+      f = fopen (opihi_history, "a");
+      if (f == NULL) /* no current history file here */
+	gprint (GP_ERR, "can't save history.\n");
+      else
+	fclose (f);
+      stifle_history (200);
+      read_history (opihi_history);
+    }
+  }
+
+  if (0) {
+    /* fix the history list to remove the timestamp */
+    char *c;
+    int i;
+    HIST_ENTRY **entry;
+    
+    entry = history_list ();
+    if (entry != (HIST_ENTRY **) NULL) {
+      for (i = 0; entry[i]; i++) {
+	if ((strlen (entry[i][0].line) > 19) &&
+	    (entry[i][0].line[2] == '/') && 
+	    (entry[i][0].line[5] == '/') && 
+	    (entry[i][0].line[11] == ':') && 
+	    (entry[i][0].line[14] == ':') && 
+	    (entry[i][0].line[17] == ':')) {
+	  c = entry[i][0].line + 19;
+	  memmove (entry[i][0].line, c, strlen(c) + 1);
+	}
+      }
+    }
+  }
+
+    LOAD_RC = TRUE;
+    if ((N = get_argument (*argc, argv, "--norc"))) {
+      remove_argument (N, argc, argv);
+      LOAD_RC = FALSE;
+    }
+    
+    ONLY_INPUT = FALSE;
+    if ((N = get_argument (*argc, argv, "--only"))) {
+      remove_argument (N, argc, argv);
+      ONLY_INPUT = TRUE;
+    }
+
+    /* load cmdline files */
+    Nlist = 0;
+    NLIST = 10;
+    ALLOCATE (list, char *, NLIST);
+    while ((N = get_argument (*argc, argv, "--load"))) {
+      remove_argument (N, argc, argv);
+      list[Nlist] = strcreate (argv[N]);
+      remove_argument (N, argc, argv);
+      Nlist++;
+      if (Nlist == NLIST) {
+	NLIST += 10;
+	REALLOCATE (list, char *, NLIST);
+      }
+    }
+
+    is_script = TRUE;
+    if (*argc == 1) is_script = FALSE;
+    set_int_variable ("SCRIPT", is_script);
+
+    if (LOAD_RC && !is_script) {
+      rcfile = get_variable ("RCFILE");
+      sprintf (line, "input %s/%s", home, rcfile);
+      status = command (line, &outline, TRUE);
+      if (outline != (char *) NULL) free (outline);
+    }
+      
+    set_int_variable ("argv:n", 0);
+    if (is_script) {
+      /* first argument in input script, rest are argv */
+      list[Nlist] = strcreate (argv[1]);
+      Nlist ++;
+      /* generate list argv:0 - argv:n from arguments */
+      ALLOCATE (varname, char, 256);
+      for (i = 2; i < *argc; i++) {
+	sprintf (varname, "argv:%d", i - 2);
+	set_str_variable (varname, argv[i]);
+      }
+      set_int_variable ("argv:n", i - 2);
+      free (varname);
+    }
+
+    /* execute command-line entries */
+    for (i = 0; i < Nlist; i++) {
+      ALLOCATE (line, char, 1024);
+      sprintf (line, "input %s", list[i]);
+      status = command (line, &outline, TRUE);
+      if (outline != (char *) NULL) free (outline);
+    }
+    free (list);
+
+    /* if this is not an interactive session, exit here */
+    if (ONLY_INPUT) exit (2);
+    if (is_script) exit (2);
+    return;
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/lib.shell/string.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/lib.shell/string.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/lib.shell/string.c	(revision 11389)
@@ -0,0 +1,250 @@
+# include "opihi.h"
+
+/**********************************************************************/
+/* returns a pointer to an isolated string containing the first word,
+   removing leading WHITESPACE.  A "word" is a contiguous set of 
+   characters from the set: alphanumerics, and any of: / . _ -
+   Any other single, non-WHITESPACE characters are considered to be 
+   complete words in themselves.  Any characters surrounded by quotes 
+   make a single word 
+*/
+
+char *thisword (char *string) {
+
+  int i, j, N;
+  char *word;
+
+  if (string == (char *) NULL) return ((char *) NULL);
+
+  for (i = 0; OHANA_WHITESPACE (string[i]); i++);
+  if (string[i] == 0) return ((char *)NULL);
+  if (string[i] == ';') {
+    word = strncreate (&string[i], 1);
+    return (word);
+  }
+
+  /* a string of characters contained within double quotes is 
+      a single entry.  check that there are pairs of quotes,
+      return only the string between the quotes */
+  if (string[i] == '"') { 
+    i++;
+    if (string[i] == 0) return ((char *) NULL);
+    for (j = i; (string[j] != 0) && (string[j] != '"'); j++);
+    if (string[j] == 0) {
+      gprint (GP_ERR, "misbalanced quotes\n");
+      return ((char *)NULL);
+    }
+    //    for (; (string[j] != 0) && (!OHANA_WHITESPACE(string[j])); j++);
+    word = strncreate (&string[i], j - i);
+    return (word);
+  } 
+
+  /* a string of characters contained within parentheses is 
+      a single entry.  check that there are matched pairs of
+      parentheses, return string, including exterior parentheses */
+  if (string[i] == '(') { 
+    i++;
+    N = 1;
+    if (string[i] == 0) return ((char *) NULL);
+    for (j = i; (string[j] != 0) && (N > 0); j++) {
+      if (string[j] == '(') {
+	N++;
+      }
+      if (string[j] == ')') {
+	N--;
+      }
+    }
+    if ((string[j] == 0) && (N != 0)) {
+      gprint (GP_ERR, "misbalanced parenthesis\n");
+      return ((char *)NULL);
+    }
+    word = strncreate (&string[i-1], j - i + 1);
+    return (word);
+  } 
+
+
+  for (j = i; (string[j] != 0) && (string[j] != ';') && !OHANA_WHITESPACE(string[j]); j++);
+  word = strncreate (&string[i], j - i);
+  return (word);
+
+}
+
+/* returns a pointer to an isolated string containing the first command,
+   removing leading WHITESPACE.  A command ends with the first non WHITESPACE */
+char *thiscomm (char *string) {
+
+  int i, j;
+  char *word;
+
+  if (string == (char *) NULL) return ((char *) NULL);
+
+  for (i = 0; OHANA_WHITESPACE (string[i]); i++);
+  if (string[i] == 0) return ((char *)NULL);
+
+  for (j = i; ((string[j] != 0) && !OHANA_WHITESPACE (string[j])); j++);
+  if (i == j) return ((char *) NULL);
+
+  word = strncreate (&string[i], j - i);
+  return (word);
+
+}
+
+/* take a pointer to the beginning of a variable (ie $foo)
+and extract only the variable name (eg, foo) */
+
+char *thisvar (char *string) {
+
+  int i, start;
+  char *word;
+
+  if (string == (char *) NULL) return ((char *) NULL);
+  if (string[0] != '$') return ((char *) NULL);
+
+  /* special case $?name : check that name is valid */
+  start = 1;
+  if (string[1] == '?') start = 2;
+
+  for (i = start; ISVAR(string[i]); i++);
+  if (i == start) return ((char *) NULL);
+
+  /* the ? is part of the variable */
+  word = strncreate (&string[1], i - 1);
+  return (word);
+
+}
+
+
+/**********************************************************************/
+/* returns a pointer to the next word, or (char *) NULL if there is not a next word */
+char *nextword (char *string) {
+
+  int i, j;
+
+  if (string == (char *) NULL) return ((char *) NULL);
+
+  for (i = 0; OHANA_WHITESPACE (string[i]); i++);
+  if (string[i] == 0) return ((char *)NULL);
+
+  if (string[i] == '"') { 
+    i++;
+    if (string[i] == 0) return ((char *) NULL);
+    for (; (string[i] != 0) && (string[i] != '"'); i++);
+    if (string[i] == 0) {
+      gprint (GP_ERR, "misbalanced quotes\n");
+      return ((char *)NULL);
+    }
+    i++;
+    for (; (string[i] != 0) && OHANA_WHITESPACE (string[i]); i++);
+    if (string[i] == 0) return ((char *) NULL);
+    return (&string[i]);
+  } 
+
+  if (string[i] == '(') { 
+    i++; 
+    j = 1;
+    if (string[i] == 0) return ((char *) NULL);
+    for (; (string[i] != 0) && (j > 0); i++) {
+      if (string[i] == '(') {
+	j++;
+      }
+      if (string[i] == ')') {
+	j--;
+      }
+    }
+    if ((string[i] == 0) && (j != 0)) {
+      gprint (GP_ERR, "misbalanced parenthesis\n");
+      return ((char *)NULL);
+    }
+    for (; (string[i] != 0) && OHANA_WHITESPACE (string[i]); i++);
+    if (string[i] == 0) return ((char *) NULL);
+    return (&string[i]);
+  } 
+
+  if (string[i] == ';') i++;
+  for (; (string[i] != 0) && (string[i] != ';') && !OHANA_WHITESPACE(string[i]); i++);
+  for (; (string[i] != 0) && OHANA_WHITESPACE (string[i]); i++);
+  if (string[i] == 0) return ((char *) NULL);
+
+  return (&string[i]);
+}
+
+/* returns a pointer to the next command, or (char *) NULL 
+   if there is not a next command.  A command is bounded by WHITESPACE */
+char *nextcomm (char *string) {
+
+  int i;
+
+  if (string == (char *) NULL) return ((char *) NULL);
+  
+  for (i = 0; (string[i] != 0) && !OHANA_WHITESPACE (string[i]); i++);
+  if (string[i] == 0) return ((char *) NULL);
+  
+  for (; OHANA_WHITESPACE (string[i]); i++);
+  if (string[i] == 0) return ((char *) NULL);
+
+  return (&string[i]);
+}
+
+/* returns a pointer to the previous word,
+   or (char *) NULL if there is not a previous word
+*/
+char *lastword (char *string, char *c) {
+
+  if (string == (char *) NULL) return ((char *) NULL);
+  if (c == (char *) NULL) return ((char *) NULL);
+
+  for (; !OHANA_WHITESPACE(*c) && (c >= string); c--);
+  if (c < string) return ((char *)NULL);
+
+  for (; OHANA_WHITESPACE(*c) && (c >= string); c--);
+  if (c < string)
+    return ((char *)NULL);
+  for (; !OHANA_WHITESPACE(*c) && (c >= string); c--);
+  c++;
+  return (c);
+}
+
+
+
+/* take a pointer to the beginning of a variable (ie $fred) and return
+   a pointer to the next thing (non WHITESPACE) which is not part of the
+   variable extract only the variable name */
+
+char *aftervar (char *string) {
+
+  int i, j, start;
+
+  if (string == (char *) NULL) return ((char *) NULL);
+  if (string[0] != '$') return ((char *) NULL);
+
+  /* special case: $?name : test only name */
+  start = 1;
+  if (string[1] == '?') start = 2;
+
+  for (i = start; ISVAR(string[i]); i++);
+  if (i == start) return ((char *) NULL);
+
+  for (j = i; OHANA_WHITESPACE (string[j]); j++);
+  if (string[j] == 0) return ((char *)NULL);
+
+  return (&string[j]);
+
+}
+
+
+/* returns a pointer to the previous var, 
+   or (char *) NULL if there is not a previous word
+*/
+char *lastvar (char *string, char *c) {
+
+  if (string == (char *) NULL) return ((char *) NULL);
+  if (c == (char *) NULL) return ((char *) NULL);
+
+  for (; (c >= string) && OHANA_WHITESPACE(*c); c--);
+  if (c < string) return ((char *)NULL);
+
+  for (; (c >= string) && ISVAR(*c) ; c--);
+  if ((c < string) || (*c != '$')) return ((char *)NULL);
+
+  return (c);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/lib.shell/timeformat.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/lib.shell/timeformat.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/lib.shell/timeformat.c	(revision 11389)
@@ -0,0 +1,30 @@
+# include "opihi.h"
+
+int GetTimeFormat (time_t *TimeReference, int *TimeFormat) {
+
+  char *p;
+
+  *TimeReference = 0;
+  if ((p = get_variable ("TIMEREF")) != (char *) NULL) {
+    if (!str_to_time (p, TimeReference)) {
+      gprint (GP_ERR, "error in TIME_REF format\n");
+      return (FALSE);
+    }
+    free (p);
+  }
+  *TimeFormat = FALSE;
+  if ((p = get_variable ("TIMEFORMAT")) != (char *) NULL) {
+    if (!strcasecmp (p, "JD")) *TimeFormat     = TIME_JD;
+    if (!strcasecmp (p, "MJD")) *TimeFormat    = TIME_MJD;
+    if (!strcasecmp (p, "date")) *TimeFormat   = TIME_DATE;
+    if (!strcasecmp (p, "days")) *TimeFormat   = TIME_DAYS;
+    if (!strcasecmp (p, "hours")) *TimeFormat  = TIME_HOURS;
+    if (!strcasecmp (p, "min")) *TimeFormat    = TIME_MINUTES;
+    if (!strcasecmp (p, "sec")) *TimeFormat    = TIME_SECONDS;
+    if (!*TimeFormat) gprint (GP_ERR, "unknown TIME_FORMAT\n");
+    free (p);
+    return (FALSE);
+  }
+  if (!*TimeFormat) *TimeFormat = TIME_SECONDS;
+  return (TRUE);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/lib.shell/variable.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/lib.shell/variable.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/lib.shell/variable.c	(revision 11389)
@@ -0,0 +1,359 @@
+# include "opihi.h"
+
+Variable *variables;   /* variable to store the list of all variables */
+int      Nvariables;   /* number of currently available variables */
+
+void InitVariables () {
+  Nvariables = 0;
+  ALLOCATE (variables, Variable, 1); 
+}
+
+int set_local_variable (char *name, char *value) {
+
+  int i;
+  char *local, *MacroName;
+
+  /* a local variable has the form (macroname).(varname) */
+  MacroName = GetMacroName ();
+
+  /* look for global variable (warning or error)
+  for (i = 0; i < Nvariables; i++) {
+    if (!strcmp (name, variables[i].name)) {
+      gprint (GP_ERR, "warning: local variable overrides global name\n");
+    }
+  } */
+
+  /* look for existing local variable */
+  ALLOCATE (local, char, strlen(name) + strlen(MacroName) + 2);
+  sprintf (local, "%s.%s", MacroName, name);
+  for (i = 0; i < Nvariables; i++) {
+    if (!strcmp (local, variables[i].name)) {
+      free (variables[i].value);
+      free (local);
+      variables[i].value = strcreate (value);
+      return (TRUE);
+    }
+  }
+  /* NEW variable */
+  Nvariables ++;
+  REALLOCATE (variables, Variable, Nvariables);
+  variables[Nvariables - 1].name = local;
+  variables[Nvariables - 1].value = strcreate (value);
+  return (TRUE);
+}
+
+int set_str_variable (char *name, char *value) {
+
+  int i;
+  char *local, *MacroName;
+
+  MacroName = GetMacroName ();
+
+  /* look for local variable first */
+  ALLOCATE (local, char, strlen(name) + strlen(MacroName) + 2);
+  sprintf (local, "%s.%s", MacroName, name);
+  for (i = 0; i < Nvariables; i++) {
+    if (!strcmp (local, variables[i].name)) {
+      free (variables[i].value);
+      free (local);
+      variables[i].value = strcreate (value);
+      return (TRUE);
+    }
+  }
+  free (local);
+
+  /* look for global variable */
+  for (i = 0; i < Nvariables; i++) {
+    if (!strcmp (name, variables[i].name)) {
+      free (variables[i].value);
+      variables[i].value = strcreate (value);
+      return (TRUE);
+    }
+  }
+  /* NEW variable */
+  Nvariables ++;
+  REALLOCATE (variables, Variable, Nvariables);
+  variables[Nvariables - 1].name = strcreate (name);
+  variables[Nvariables - 1].value = strcreate (value);
+  return (TRUE);
+}
+
+int set_variable (char *name, double dvalue) {
+
+  char value[1024];
+
+  sprintf (value, "%.12g", dvalue);
+  set_str_variable (name, value);
+  return (TRUE);
+}
+
+int set_int_variable (char *name, int ivalue) {
+
+  char value[1024];
+
+  sprintf (value, "%d", ivalue);
+  set_str_variable (name, value);
+  return (TRUE);
+}
+
+static char variable_true[] = "1";
+static char variable_false[] = "0";
+
+char *get_variable_ptr (char *name) {
+  
+  int i;
+  char *local, *MacroName, *value;
+
+  if (name == NULL) return (NULL);
+  if (*name == 0) return (NULL);
+
+  /* check for the existence of the given name (after ?) */
+  /* return a string which should not be freed */
+  if (*name == '?') {
+    value = get_variable_ptr (&name[1]);
+    if (value == NULL) {
+      return variable_false;
+    }
+    return variable_true;
+  }
+
+  MacroName = GetMacroName ();
+
+  /* look for local variable first */
+  ALLOCATE (local, char, strlen(name) + strlen(MacroName) + 2);
+  sprintf (local, "%s.%s", MacroName, name);
+  for (i = 0; i < Nvariables; i++) { /* find the variable mentioned */
+    if (!strcmp(local, variables[i].name)) {
+      free (local);
+      return (variables[i].value);
+    }
+  }
+  free (local);
+
+  /* look for global variable */
+  for (i = 0; i < Nvariables; i++) { /* find the variable mentioned */
+    if (!strcmp(name, variables[i].name)) {
+      return (variables[i].value);
+    }
+  }
+  return (NULL);
+}
+
+char *get_variable (char *name) {
+  
+  int i;
+  char *local, *MacroName;
+  char *value;
+
+  if (name == NULL) return (NULL);
+  if (*name == 0) return (NULL);
+
+  /* check for the existence of the given name (after ?) */
+  /* return a string which can be freed */
+  if (*name == '?') {
+    value = get_variable_ptr (&name[1]);
+    if (value == NULL) {
+      value = strcreate (variable_false);
+      return value;
+    }
+    value = strcreate (variable_true);
+    return value;
+  }
+
+  MacroName = GetMacroName ();
+
+  /* look for local variable first */
+  ALLOCATE (local, char, strlen(name) + strlen(MacroName) + 2);
+  sprintf (local, "%s.%s", MacroName, name);
+  for (i = 0; i < Nvariables; i++) { /* find the variable mentioned */
+    if (!strcmp(local, variables[i].name)) {
+      free (local);
+      return (strcreate (variables[i].value));
+    }
+  }
+  free (local);
+
+  /* look for global variable */
+  for (i = 0; i < Nvariables; i++) { /* find the variable mentioned */
+    if (!strcmp(name, variables[i].name)) {
+      return (strcreate (variables[i].value));
+    }
+  }
+  return (NULL);
+}
+
+/* return TRUE / FALSE if name is an existant variable */
+int get_variable_exists (char *name) {
+  
+  int i;
+  char *local, *MacroName;
+
+  MacroName = GetMacroName ();
+
+  /* look for local variable first */
+  ALLOCATE (local, char, strlen(name) + strlen(MacroName) + 2);
+  sprintf (local, "%s.%s", MacroName, name);
+  for (i = 0; i < Nvariables; i++) { /* find the variable mentioned */
+    if (!strcmp(local, variables[i].name)) {
+      free (local);
+      return (TRUE);
+    }
+  }
+  free (local);
+
+  /* look for global variable */
+  for (i = 0; i < Nvariables; i++) { /* find the variable mentioned */
+    if (!strcmp(name, variables[i].name)) {
+      return (TRUE);
+    }
+  }
+  return (FALSE);
+}
+
+char *get_local_variable_ptr (char *name) {
+  
+  int i;
+  char *local, *MacroName;
+
+  MacroName = GetMacroName ();
+
+  /* look for local variable first */
+  ALLOCATE (local, char, strlen(name) + strlen(MacroName) + 2);
+  sprintf (local, "%s.%s", MacroName, name);
+  for (i = 0; i < Nvariables; i++) { /* find the variable mentioned */
+    if (!strcmp(local, variables[i].name)) {
+      free (local);
+      return (variables[i].value);
+    }
+  }
+  free (local);
+  return (NULL);
+}
+
+float get_variable_default (char *name, float dvalue) {
+
+  char *value;
+  float fvalue;
+
+  value = get_variable (name);
+  if (value == NULL) {
+    return (dvalue);
+  }
+  fvalue = atof (value);
+  return (fvalue);
+}
+
+double get_double_variable (char *name, int *found) {
+  
+  int i;
+  char *local, *MacroName;
+
+  MacroName = GetMacroName ();
+
+  /* look for local variable first */
+  ALLOCATE (local, char, strlen(name) + strlen(MacroName) + 2);
+  sprintf (local, "%s.%s", MacroName, name);
+  for (i = 0; i < Nvariables; i++) { /* find the variable mentioned */
+    if (!strcmp(local, variables[i].name)) {
+      free (local);
+      *found = TRUE;
+      return (atof (variables[i].value));
+    }
+  }
+  free (local);
+
+  /* look for global variable */
+  for (i = 0; i < Nvariables; i++) { /* find the variable mentioned */
+    if (!strcmp(name, variables[i].name)) {
+      *found = TRUE;
+      return (atof (variables[i].value));
+    }
+  }
+  *found = FALSE;
+  return (0.0);
+}
+
+int get_int_variable (char *name, int *found) {
+  
+  int i;
+  char *local, *MacroName;
+
+  MacroName = GetMacroName ();
+
+  /* look for local variable first */
+  ALLOCATE (local, char, strlen(name) + strlen(MacroName) + 2);
+  sprintf (local, "%s.%s", MacroName, name);
+  for (i = 0; i < Nvariables; i++) { /* find the variable mentioned */
+    if (!strcmp(local, variables[i].name)) {
+      *found = TRUE;
+      free (local);
+      return (atof (variables[i].value));
+    }
+  }
+  free (local);
+
+  /* look for global variable */
+  for (i = 0; i < Nvariables; i++) { /* find the variable mentioned */
+    if (!strcmp(name, variables[i].name)) {
+      *found = TRUE;
+      return (atof (variables[i].value));
+    }
+  }
+  *found = FALSE;
+  return (0.0);
+}
+
+int DeleteNamedScalar (char *name) {
+
+  int i, j;
+
+  for (i = 0; i < Nvariables; i++) {
+    if (!strcmp (name, variables[i].name)) {
+      free (variables[i].name);
+      free (variables[i].value);
+      for (j = i; j < Nvariables - 1; j++) {
+	variables[j] = variables[j + 1];
+      }
+      Nvariables --;
+      REALLOCATE (variables, Variable, MAX (Nvariables, 1));
+      return (TRUE);
+    }
+  }
+  return (FALSE);
+}
+
+int IsScalar (char *name) { 
+
+  int i;
+
+  for (i = 0; i < Nvariables; i++) {
+    if (!strcmp (name, variables[i].name)) return (TRUE);
+  }
+  return (FALSE);
+}
+
+void ListVariables () {
+
+  int i;
+
+  if (Nvariables == 0) {
+    gprint (GP_ERR, "No defined variables\n");
+    return;
+  }
+
+  for (i = 0; i < Nvariables; i++) {
+    gprint (GP_ERR, "%s = %s\n", variables[i].name, variables[i].value);
+  }
+  return;
+}
+
+int SelectScalar (char *string, double *value) {
+
+  char *end;
+
+  /* if string is a number, return TRUE */
+  *value = strtod (string, &end);
+  if (end == string + strlen(string)) return (TRUE);
+
+  return (FALSE);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/lib.shell/version.c
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/lib.shell/version.c	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/lib.shell/version.c	(revision 11389)
@@ -0,0 +1,8 @@
+# include "shell.h"
+
+static char *unknown = "UNKNOWN";
+static char *name = "$Name: not supported by cvs2svn $";
+
+char *opihi_version () {
+  return (name);
+}
Index: /branches/opihi-2-9/Ohana/src/opihi/modules/dvo/navigate
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/modules/dvo/navigate	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/modules/dvo/navigate	(revision 11389)
@@ -0,0 +1,623 @@
+# -*- perl -*-
+
+macro navigate
+  style -n 0
+  limits
+  $DRAWSTARS  = -1
+  $DRAWIMAGES =  1
+  $DRAWGRID   = -1
+  $ZOOM = 180 / ($YMAX - $YMIN)
+  #this should be changed to a while loop, except 'while' is broken for some reason
+  $KEY = "none"
+  while ("$KEY" != "q")
+    cursor -g 1
+
+    # help list
+    if ("$KEY" == "h")
+     echo "Arrow Keys - pan in that direction"
+     echo "PgUp,PgDn - zoom in/out a factor of 1.2"
+     echo "Home,End  - zoom in/out a factor of 2"
+     echo "1 - zoom in factor of 2 at the cursor"
+     echo "2 - zoom in factor of 1.2 at the cursor"
+     echo "3 - recenter at cursor"
+     echo "4 - zoom out factor of 1.2 at the cursor"
+     echo "5 - zoom out factor of 2 at the cursor"
+     echo "6 - zoom out factor of 10 at the cursor"
+     echo "z - zoom to radius (requires 2nd keystroke)"
+     echo "f - show full sky"
+     echo ""
+     echo "q - quit"
+     echo "S - toggle auto-plotting of stars"
+     echo "A - toggle auto-plotting of image borders"
+     echo "g - toggle skygrid on/off"
+     echo "c - plot status catalog boundaries"
+     echo "C - list catalog at cursor location"
+     echo "i - list info about images touching cursor location" 
+     echo "I - list info about images, with pixel coords of cursor position"
+     echo "j - adjust mag scale, +0.5"
+     echo "k - adjust mag scale, -0.5"
+     echo "J - adjust dmag scale, /1.25"
+     echo "K - adjust dmag scale, *1.25"
+     echo "r - plot detected asteroids (rocks)"
+     echo "l - plot HST GSC"
+     echo "L - plot Landolt stars"
+     echo "m - list measurements for stars within 1 pixel of cursor"
+     echo "M - list measurements for stars within 1.8 arcsec of cursor"
+     echo "p - ****(don't know what this does)"
+     echo "s - ****(don't know what this does)"
+     echo "t - plot light curve for star within 2 arcsec of cursor position"
+     echo "T - plot 'galaxy' light curve for star within 2 arcsec of cursor position"
+     echo "u - ****(don't know what this does)"
+     echo "x - plot stars scaled by magnitude Chisq"
+     echo "X - plot stars by magnitude scatter"
+     echo "y - ****(don't know what this does)"
+     echo ""
+     echo "@ - execute macro `user_macro`"
+     echo ": - ****input a line and execute (not yet implemented)"
+    end
+
+    # quit from navigate
+    if ("$KEY" == "q") continue
+
+    #pan controls
+    if (("$KEY" == "Left") || ("$KEY" == "Right") || ("$KEY" == "Up") || ("$KEY" == "Down"))
+      $SHIFT = 0.2
+      $R$KEY  = $RMAX-$XMAX  
+      $D$KEY  = $DMAX-$YMAX
+      #assumes standard sky orientation!! (N up, E left)
+      if ("$KEY"=="Left")
+        $R$KEY = $R$KEY + $SHIFT*$XMAX
+      end
+      if ("$KEY"=="Right")
+        $R$KEY = $R$KEY + $SHIFT*$XMIN
+      end
+      if ("$KEY"=="Up")
+        $D$KEY = $D$KEY + $SHIFT*$YMAX
+      end
+      if ("$KEY"=="Down")
+        $D$KEY = $D$KEY + $SHIFT*$YMIN
+      end
+      #pretend like I hit '3' in the place to recenter it
+      nav_zoom 1      
+    end
+
+    # NEW zoom controls
+    if (("$KEY" == "Prior") || ("$KEY" == "Next") || ("$KEY" == "Home") || ("$KEY" == "End") || ("$KEY" == "Button4") || ("$KEY" == "Button5"))    
+      #move where key was hit to center      
+      $R$KEY  = $RMAX-$XMAX  
+      $D$KEY  = $DMAX-$YMAX
+      if ("$KEY" == "Prior")
+        $zfac=1.2
+      end
+      if ("$KEY" == "Next")
+        $zfac={1/1.2}
+      end
+      if ("$KEY" == "Home")
+        $zfac=2
+      end
+      if ("$KEY" == "End")
+        $zfac={1/2.}
+      end
+      if ("$KEY"=="Button4")
+        $zfac=1.6
+      end
+      if ("$KEY"=="Button5")
+        $zfac={1/1.6}
+      end
+      nav_zoom $zfac
+    end
+
+    if ("$KEY"=="Button1")
+      nav_zoom 1
+    end
+    if ("$KEY"=="Button2")
+      nav_zoom {1/2.}
+    end
+    if ("$KEY"=="Button3")
+      nav_zoom 2
+    end
+
+
+
+    # zoom controls
+    if ("$KEY" == "1")
+      nav_zoom 2
+    end
+    if ("$KEY" == "2")
+      nav_zoom 1.2
+    end
+    if ("$KEY" == "3")
+      nav_zoom 1
+    end
+    if ("$KEY" == "4")
+      nav_zoom {1/1.2}
+    end
+    if ("$KEY" == "5")
+      nav_zoom {1/2.}
+    end
+    if ("$KEY" == "6")
+      nav_zoom {1/20.}
+    end
+
+ 
+   # measure distance
+    if ("$KEY" == "d")
+      $r0 = $R$KEY
+      $d0 = $D$KEY
+      $ok = $KEY
+      echo "type 'd' again at endpoint"
+      cursor -g 1
+      $r1 = $R$KEY
+      $d1 = $D$KEY
+      $dr = 3600*((dcos($d0)*($r0-$r1))^2 + ($d0-$d1)^2)^0.5
+      echo "$dr arcsec"
+    end
+    # show ra, dec
+    if ("$KEY" == "w")
+      $tmp = $R$KEY
+      if ($tmp < 0) 
+        $tmp = $R$KEY + 360.0
+      end
+      echo "$tmp $D$KEY" 
+      exec echo $tmp $D$KEY | radec -hh
+    end
+    # zoom to radius
+    if ("$KEY" == "z")
+      $r0 = $R$KEY
+      $d0 = $D$KEY
+      $ok = $KEY
+      echo "type 'z' again at radius"
+      cursor -g 1
+      $r1 = $R$KEY
+      $d1 = $D$KEY
+      $dr = (($r0-$r1)^2 + ($d0-$d1)^2)^0.5
+      $ZOOM = $RAD / $dr
+      nav_recenter
+      nav_redraw
+      $KEY = $ok
+      $R$KEY = $r0
+      $D$KEY = $d0
+    end
+
+    # adjust mag scaling
+    if ("$KEY" == "J")
+      $MAG = $MAG - 0.5
+      nav_redraw
+    end
+    if ("$KEY" == "K")
+      $MAG = $MAG + 0.5
+      nav_redraw
+    end
+    if ("$KEY" == "j")
+      $dMAG = $dMAG * 0.8
+      nav_redraw
+    end
+    if ("$KEY" == "k")
+      $dMAG = $dMAG * 1.25
+      nav_redraw
+    end
+    echo "mag, dmag: $MAG, $dMAG"
+
+
+
+    # plot full sky
+    if ("$KEY" == "f") 
+      echo "full"
+      $ZOOM = 1
+      resize 1150 600		      
+      region 0 0 90 ait
+      $RMIN = 0
+      $RMAX = 360
+      $DMIN = -90
+      $DMAX = +90
+      style -c red; cgrid
+      style -c black
+      images
+    end
+
+    # plot rocks
+    if ("$KEY" == "r") 
+#      plot.rocks
+      style -c blue   -pt 1; procks -speed 0.0041 1
+      style -c red    -pt 1; procks -speed 0.00041 0.0041
+      style -c indigo -pt 1; procks -speed 0 0.00041
+      style -c black -lw 0;
+    end
+    # plot HST-GSC
+    if ("$KEY" == "l") 
+      style -c blue -pt 7; cat -all -g -m 9 16
+      style -c black
+    end
+    # plot Landolt
+    if ("$KEY" == "L") 
+#      style -c red  -lw 2 -pt 3; cat -a 1 2 3 /data/elixir/srcdir/refs/stetson/stetsonBn.txt -m 9 18
+#      style -c blue -lw 2 -pt 3; cat -a 25 26 8 /data/elixir/srcdir/refs/landolt/new/Landolt92.fix -m 9 18
+      style -c red -lw 2 -pt 7; cat -a 1 2 3 /data/elixir/srcdir/refs/sdss/g_SDSS.dat -m 9 14
+#      style -c red -lw 2 -pt 3; cat -a 25 26 8 /data/elixir/srcdir/refs/landolt/new/Landolt92.hq -m 9 18
+#      style -c red -lw 2 -pt 3; cat -a 22 23 8 /data/elixir/srcdir/refs/landolt/new/Landolt92.unfix -m 9 18
+#      style -c blue -lw 2 -pt 7; cat -a 1 2 4 /data/elixir/srcdir/refs/landolt/extreme/extreme.match -m 0 20
+#      style -x 2 -c red -pt 7 ; cplot RA DEC
+      style -c black -lw 0
+    end
+
+    # list star measurements
+    if ("$KEY" == "m") 
+        $dR = $RAD/$ZOOM/300
+        if ($dR < 0.0005)
+	 $dR = 0.0005
+        end
+	gstar $R$KEY $D$KEY $dR -m
+    end
+
+    # plot mag residuals
+    if ("$KEY" == "R") 
+      echo "filter: "
+      cursor 1
+      clear -n 1 -s; lim 10 22 -0.2 0.2; clear; box
+      dmags $KEY\:rel - $KEY : $KEY -type 0
+      plot -x 2 -pt 0 -sz 0.3 -c red yv xv
+      dmags $KEY\:rel - $KEY : $KEY -type 0 -flag 0 -nphot +3 -chisq 2.0
+      plot -x 2 -pt 2 -sz 0.5 -c black yv xv
+      $KEY = R
+      style -n 0
+    end
+
+    if ("$KEY" == "M") 
+	gstar $R$KEY $D$KEY 0.0005 -m
+    end
+    # list images
+    if ("$KEY" == "i") 
+	gimages $R$KEY $D$KEY
+    end
+    if ("$KEY" == "I") 
+	gimages $R$KEY $D$KEY -pix
+    end
+
+    #toggle images on / off
+    if ("$KEY" == "A")
+      $DRAWIMAGES = $DRAWIMAGES * -1
+      if ($DRAWIMAGES == 1)
+        images
+      end
+    end
+    # toggle stars on / off
+    if ("$KEY" == "S")
+      $DRAWSTARS = $DRAWSTARS * -1
+      if (($ZOOM > 20) && ($DRAWSTARS == 1))
+       style -pt 7
+       pmeasure -all -m $MAG {$MAG + $dMAG}
+      end
+    end
+    # turn grid on / off
+    if ("$KEY" == "g")
+      $DRAWGRID = $DRAWGRID * -1
+      if (($ZOOM > 20) && ($DRAWGRID==1))
+        style -c black; cgrid
+      end
+      if (($ZOOM > 20) && ($DRAWGRID==-1))
+        nav_redraw
+      end
+    end
+
+    # plot light-curve interactive
+    if ("$KEY" == "t")
+      style -n 1 -pt 2 -x 2
+      clear
+      if ($R$KEY < 0) 
+       $R$KEY = $R$KEY + 360
+      end
+      lcurve -l $R$KEY $D$KEY {30/3600} -d -v time mag
+      box
+      lcv
+      style -n 0
+    end
+    # plot light-curve 
+    if ("$KEY" == "T")
+      style -n 1 -pt 1 -c red -x 2
+      lcurve $R$KEY $D$KEY {30/3600} -d
+      style -c black
+      style -n 0 
+    end
+    # plot catalogs
+    if ("$KEY" == "c")
+      style -c blue; pcat; style -c black
+    end
+    # list catalogs
+    if ("$KEY" == "C")
+      gcat $R$KEY $D$KEY
+    end
+
+    # plot image chisqs
+    if ("$KEY" == "x") 
+       gcat $R$KEY $D$KEY
+       extract $CATNAME Xm -photcode R
+       extract $CATNAME ra
+       extract $CATNAME dec
+       style -x 2 -pt 7 -c blue
+       czplot ra dec Xm 3 30
+       style -c black -pt 1
+    end
+    # plot meas errors
+    if ("$KEY" == "X") 
+       gcat $R$KEY $D$KEY
+       extract $CATNAME dM -photcode R
+       extract $CATNAME ra
+       extract $CATNAME dec
+       style -x 2 -pt 7 -c red
+       czplot ra dec dM 0 30
+       style -c black -pt 1
+    end
+
+
+    # temp plot for skyprobe
+    if ("$KEY" == "u") 
+      imextract -region time
+      imextract -region mcal
+      imextract -region airmass
+      imextract -region nstar
+      vstat time
+      clear -n 1;
+      section a 0 0.00 1 0.33
+      lim {$MEDIAN-0.3} {$MEDIAN+0.3} -0.8 -0.5; box; plot time mcal
+      section b 0 0.33 1 0.33
+      lim {$MEDIAN-0.3} {$MEDIAN+0.3}  0.95 3.0; box; plot time airmass
+      section c 0 0.66 1 0.33
+      lim {$MEDIAN-0.3} {$MEDIAN+0.3} 0 3000; box; plot time nstar
+      style -n 0
+    end
+    if ("$KEY" == "s")
+      $tmp = $R$KEY
+      if ($tmp < 0) 
+        $tmp = $R$KEY + 360.0
+      end
+      $line = `echo $tmp $D$KEY | radec -hh`
+      imextract -region photcode
+      imextract -region time
+     
+      subset t = time if (int(photcode/100) == 1)
+      uniq t T
+      $Bn = t[]
+      $BN = T[]
+      
+      subset t = time if (int(photcode/100) == 2)
+      uniq t T
+      $Vn = t[]
+      $VN = T[]
+      
+      subset t = time if (int(photcode/100) == 3)
+      uniq t T
+      $Rn = t[]
+      $RN = T[]
+      
+      subset t = time if (int(photcode/100) == 4)
+      uniq t T
+      $In = t[]
+      $IN = T[]
+     
+      echo "$line  $Bn $BN  $Vn $VN  $Rn $RN  $In $IN"
+    end
+
+    if ("$KEY" == "p") 
+      echo "P - new coords; p - old coords"
+      cursor -g 1
+      exec echo $Rp $Dp $RP $DP >> fix.coords
+    end
+
+    if ("$KEY" == "y")
+      ccd I - 2MASS_J : 2MASS_J - 2MASS_K
+      lim -n 1 -1 10 -1 3; clear; box; plot -x 2 -pt 2 -sz 0.5 xv yv
+      dev -n 0 -g
+    end
+
+    #  User-defined macro
+    if ("$KEY" == "at")
+      user_macro
+    end
+
+    if ("$KEY" == "colon")
+      #make this work similar to ':' in vi or iraf
+      #does not work correctly now.
+      scan stdin line
+      $line
+    end
+
+  end
+end
+
+#define this so navigate doesn't crash if you try to call it.
+#If you define a user_macro, be sure to do so AFTER this in .dvorc.
+macro user_macro
+  #echo "success!"
+  $do_nothing=0
+end
+    
+
+macro nav_zoom
+  $ZOOM = $ZOOM * $1
+  nav_recenter
+  nav_redraw
+  $Rnum = $R$KEY		      
+  $Dnum = $D$KEY
+  $KEY = num
+end
+
+macro nav_recenter
+  region $R$KEY $D$KEY {$RAD/$ZOOM} sin
+  #assumes standard sky orientation!! (N up, E left)
+  $RMIN = $R$KEY + $XMIN
+  $RMAX = $R$KEY + $XMAX
+  $DMIN = $D$KEY + $YMIN
+  $DMAX = $D$KEY + $YMAX
+end
+
+macro nav_redraw
+  clear
+  if ($ZOOM <= 20) 
+    style -c red; cgrid
+  end
+  if (($ZOOM > 20) && ($DRAWGRID==1))
+    style -c black; cgrid
+  end
+  if (($ZOOM > 20) && ($DRAWSTARS == 1))
+    pmeasure -all -m $MAG {$MAG + $dMAG}
+  end    
+  style -c black
+  if ($DRAWIMAGES == 1)
+    images
+  end
+end
+
+
+
+#==================================================
+#=================   END BSNAV   ==================
+#==================================================
+
+
+macro sigclip
+  if ("$0" == "1")
+    echo ""
+    echo "sigclip <clipvector> <N_iterations> <N_sigma> [other vectors ..]"
+    echo ""
+  end
+
+  #required parameters
+  $CLIPVECT = $1
+  $NITERATE = $2
+  $NSIGCLIP = $3
+  
+  for i 0 $NITERATE
+    vstat -q $CLIPVECT
+    #clip boundaries
+    $top = $MEAN + ($NSIGCLIP*$SIGMA)
+    $bot = $MEAN - ($NSIGCLIP*$SIGMA)
+    
+    #clip it good.
+    subset temp = $CLIPVECT if (($CLIPVECT < $top) && ($CLIPVECT > $bot))
+    
+    #if you specify other vectors, clip the same elements from them too.
+    #they must all be the same length, of course!!
+    if ($0>4)
+      for j 4 $0
+        subset $$j = $$j if (($CLIPVECT < $top) && ($CLIPVECT > $bot))
+      end
+    end
+    
+    #copy temp back to $CLIPVECT and reiterate!
+    delete $CLIPVECT
+    concat temp $CLIPVECT  
+  end
+end
+
+
+macro binvec
+  if ("$0" == "1")
+    echo ""
+    echo "binvec <vec> <Nbins> [other vectors...]"
+    echo ""
+    echo "Bin the vector 'vec' into Nbin bins.  Listing other vectors will"
+    echo "put the corresponding elements of those into other vectors which"
+    echo "are the subset of the vector in that bin.  (That can probably be"
+    echo "stated better.)  This macro makes lots of new vectors.  Hooray!"
+    echo ""
+    echo "Creates"
+  end
+
+  #REQUIRED PARAMS
+  $binvect = $1
+  $NBINS   = $2
+
+  vstat -q $binvect
+  $step = ($MAX-$MIN)/$NBINS
+  $vmin = $MIN
+  $vmax = $MAX
+  delete -q $binvect\_bins
+  delete -q $binvect\_num
+  for i 1 {$NBINS+1}
+    $top = $vmin + ( $i   *$step)
+    $bot = $vmin + (($i-1)*$step)
+    #      sightly different behavior for last bin    -------v
+    if ($i != $NBINS)
+      subset temp = $binvect if (($binvect>=$bot)&&($binvect< $top))
+    else
+      subset temp = $binvect if (($binvect>=$bot)&&($binvect<=$top))
+    end
+    set $binvect\_bin$i = temp
+    set temp2 = temp
+    delete temp
+    #if you specify other vectors, grab the same elements from them too.
+    #they must all be the same length, of course!!
+
+    if ($0>3)
+      for j 3 $0
+        if ($i != $NBINS)
+          subset temp = $$j if (($binvect>=$bot)&&($binvect< $top))
+        else 
+          subset temp = $$j if (($binvect>=$bot)&&($binvect<=$top))
+        end
+        set $$j\_bin$i = temp
+        delete temp
+      end
+    end
+
+
+    concat {$bot+($step/2)} $binvect\_bins
+    concat temp2[] $binvect\_num
+    #dvo didn't like me saying 'concat $binvect\_bin$i[] $binvect\_num
+    delete temp2
+  end
+end
+
+macro binvec.2
+  if ("$0" == "1")
+    echo ""
+    echo "binvec.2 <vec> <min> <max> <binsize> [other vectors...]"
+    echo ""
+    echo ""
+    echo "see also 'binvec'"
+  end
+
+  #REQUIRED PARAMS
+  $binvect = $1
+  $vmin    = $2
+  $vmax    = $3
+  $step    = $4
+
+  $NBINS = ($MAX-$MIN)/$step
+
+  delete -q $binvect\_bins
+  delete -q $binvect\_num
+  for i 1 {$NBINS+1}
+    $top = $vmin + ( $i   *$step)
+    $bot = $vmin + (($i-1)*$step)
+    #      sightly different behavior for last bin    -------v
+    if ($i != $NBINS)
+      subset temp = $binvect if (($binvect>=$bot)&&($binvect< $top))
+    else
+      subset temp = $binvect if (($binvect>=$bot)&&($binvect<=$top))
+    end
+    set $binvect\_bin$i = temp
+    set temp2 = temp
+    delete temp
+    #if you specify other vectors, grab the same elements from them too.
+    #they must all be the same length, of course!!
+
+    if ($0>5)
+      for j 5 $0
+        if ($i != $NBINS)
+          subset temp = $$j if (($binvect>=$bot)&&($binvect< $top))
+        else 
+          subset temp = $$j if (($binvect>=$bot)&&($binvect<=$top))
+        end
+        set $$j\_bin$i = temp
+        delete temp
+      end
+    end
+
+
+    concat {$bot+($step/2)} $binvect\_bins
+    concat temp2[] $binvect\_num
+    #dvo didn't like me saying 'concat $binvect\_bin$i[] $binvect\_num
+    delete temp2
+  end
+end
Index: /branches/opihi-2-9/Ohana/src/opihi/modules/mana/plots
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/modules/mana/plots	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/modules/mana/plots	(revision 11389)
@@ -0,0 +1,41 @@
+
+macro cvplot 
+  if ($0 != 6)
+    echo "USAGE: cvplot r d ur ud scale"
+    break
+  end
+ 
+  local i
+  delete -q _tmpr _tmpd
+
+  for i 0 $1[]
+   concat $1[$i] _tmpr
+   concat $2[$i] _tmpd
+   concat {$1[$i]+$3[$i]*$5} _tmpr
+   concat {$2[$i]+$4[$i]*$5} _tmpd
+  end
+  style -pt 100
+  cplot _tmpr _tmpd
+  style -pt 7
+end
+
+macro vplot 
+  if ($0 != 6)
+    echo "USAGE: cvplot r d ur ud scale"
+    break
+  end
+ 
+  local i
+  delete -q _tmpr _tmpd
+
+  for i 0 $1[]
+   concat $1[$i] _tmpr
+   concat $2[$i] _tmpd
+   concat {$1[$i]+$3[$i]*$5} _tmpr
+   concat {$2[$i]+$4[$i]*$5} _tmpd
+  end
+  style -pt 100
+  plot _tmpr _tmpd
+  style -pt 7
+end
+
Index: /branches/opihi-2-9/Ohana/src/opihi/test/basic.sh
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/test/basic.sh	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/test/basic.sh	(revision 11389)
@@ -0,0 +1,9 @@
+
+list testdir
+  cmd.data/test
+  cmd.basic/test
+end
+
+input test/tests.sh
+
+fulltests
Index: /branches/opihi-2-9/Ohana/src/opihi/test/pclient.sh
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/test/pclient.sh	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/test/pclient.sh	(revision 11389)
@@ -0,0 +1,8 @@
+
+list testdir
+  pclient/test
+end
+
+input test/tests.sh
+
+fulltests
Index: /branches/opihi-2-9/Ohana/src/opihi/test/tests.sh
===================================================================
--- /branches/opihi-2-9/Ohana/src/opihi/test/tests.sh	(revision 11389)
+++ /branches/opihi-2-9/Ohana/src/opihi/test/tests.sh	(revision 11389)
@@ -0,0 +1,100 @@
+
+if ($?VERBOSE == 0)
+ $VERBOSE = 0
+end
+
+$failtest:n = 0
+$failfile:n = 0
+$faildirs:n = 0
+$currentdir = .
+
+macro fulltests
+  $Npass = 0
+  $Nfail = 0
+  $Ntest = 0
+  break -auto off
+
+  $failtest:n = 0
+  $failfile:n = 0
+  $faildirs:n = 0
+
+  for Ti 0 $testdir:n
+    if ($VERBOSE > 0)
+       echo "directory $testdir:$Ti"
+    end
+    runtestdir $testdir:$Ti
+  end
+
+  echo "completed $Ntest tests"
+  echo "$Npass tests passed"
+  echo "$Nfail tests failed"
+  echo "examined $testdir:n directories"
+
+  if ($Nfail > 0) 
+    echo " ** failed tests **"
+    for i 0 $Nfail
+      echo $faildirs:$i $failfile:$i $failtest:$i
+    end
+  end
+end
+
+macro runtestdir
+  if ($0 != 2)
+    echo "USAGE: runtestdir (testdir)"
+    break -auto on
+    break
+  end
+  
+  pwd -var startdir
+  cd -q $1
+  list testscripts -x "ls *.sh"
+
+  $currentdir = $1
+  for Tj 0 $testscripts:n
+    if ($VERBOSE > 1)
+      echo " running $testscripts:$Tj"
+    end
+    runtests $testscripts:$Tj      
+  end
+  
+  cd -q $startdir
+end
+
+macro runtests
+  if ($0 != 2)
+    echo "USAGE: runtests (script.sh)"
+    break -auto on
+    break
+  end
+  
+  local Tk
+
+  input $1
+  for Tk 0 $tests:n
+    if ($VERBOSE > 2)
+      echo "   running $tests:$Tk"
+    end
+    $PASS = 1
+    $tests:$Tk
+    if ($PASS == 0)
+      echo "   ** failed $tests:$Tk $1"
+      $Nfail ++
+      $n = $failtest:n
+      $failtest:$n = $tests:$Tk
+      $failfile:$n = $1
+      $faildirs:$n = $currentdir
+      $failtest:n ++
+      $failfile:n ++
+      $faildirs:n ++
+    else
+      $Npass ++
+    end
+    $Ntest ++
+    # echo "finished $tests:$Tk"
+  end
+end
+
+echo "USAGE:"
+echo "runtests (script.sh)"
+echo "runtestdir (testdir)"
+echo "set VERBOSE to 0 through 3"
