Index: trunk/Ohana/src/opihi/Makefile.Common
===================================================================
--- trunk/Ohana/src/opihi/Makefile.Common	(revision 42332)
+++ trunk/Ohana/src/opihi/Makefile.Common	(revision 42389)
@@ -42,5 +42,6 @@
 	@if [ ! -d $(LIB) ]; then mkdir -p $(LIB); fi
 	rm -f $@
-	gcc -shared -Wl,-soname,$*.so -o $@ $^ -lc
+#	gcc -shared -Wl,-soname,$*.so -o $@ $^ -lc
+	gcc -shared -Wl,-soname,$*.so -o $@ $^ -lc -Wl,--allow-multiple-definition
 
 $(DESTLIB)/%.so: $(LIB)/%.$(ARCH).so
Index: trunk/Ohana/src/opihi/cmd.basic/list.c
===================================================================
--- trunk/Ohana/src/opihi/cmd.basic/list.c	(revision 42332)
+++ trunk/Ohana/src/opihi/cmd.basic/list.c	(revision 42389)
@@ -111,5 +111,5 @@
       set_str_variable (line, argv[i+3]);
     }
-    snprintf (line, MAX_LINE_LENGTH, "%s:n", argv[1]);
+    snprintf_nowarn (line, MAX_LINE_LENGTH, "%s:n", argv[1]);
     set_int_variable (line, i);
 
@@ -133,5 +133,5 @@
     int isFound;
 
-    snprintf (line, MAX_LINE_LENGTH, "%s:n", argv[1]);
+    snprintf_nowarn (line, MAX_LINE_LENGTH, "%s:n", argv[1]);
     int nList = get_int_variable (line, &isFound);
     if (!isFound) {
@@ -145,11 +145,11 @@
 
     for (i = start; i < nList; i++) {
-      snprintf (line, MAX_LINE_LENGTH, "%s:%d", argv[1], i);
+      snprintf_nowarn (line, MAX_LINE_LENGTH, "%s:%d", argv[1], i);
       char *word = get_variable (line);
       if (!word) break;
       if (i > 0) {
-	snprintf (output, MAX_LINE_LENGTH, "%s %s", tmpline, word);
+	snprintf_nowarn (output, MAX_LINE_LENGTH, "%s %s", tmpline, word);
       } else {
-	snprintf (output, MAX_LINE_LENGTH, "%s", word);
+	snprintf_nowarn (output, MAX_LINE_LENGTH, "%s", word);
       }
       strcpy (tmpline, output);
@@ -179,5 +179,5 @@
     
     // old list must exist, or give an error
-    snprintf (line, MAX_LINE_LENGTH, "%s:n", argv[3]);
+    snprintf_nowarn (line, MAX_LINE_LENGTH, "%s:n", argv[3]);
     N = get_int_variable (line, &found);
     if (!found) {
@@ -188,10 +188,10 @@
       
 
-    snprintf (line, MAX_LINE_LENGTH, "%s:n", argv[1]);
+    snprintf_nowarn (line, MAX_LINE_LENGTH, "%s:n", argv[1]);
     set_int_variable (line, N);
     for (i = 0; i < N; i++) {
-      snprintf (line, MAX_LINE_LENGTH, "%s:%d", argv[3], i);
+      snprintf_nowarn (line, MAX_LINE_LENGTH, "%s:%d", argv[3], i);
       value = get_variable (line);
-      // snprintf (line, MAX_LINE_LENGTH, "%s:%d", argv[1], i);
+      // snprintf_nowarn (line, MAX_LINE_LENGTH, "%s:%d", argv[1], i);
       set_list_varname (line, argv[1], i, EXCEL_STYLE);
       set_str_variable (line, value);
@@ -207,12 +207,12 @@
     }
     
-    snprintf (line, MAX_LINE_LENGTH, "%s:n", argv[1]);
+    snprintf_nowarn (line, MAX_LINE_LENGTH, "%s:n", argv[1]);
     N = get_int_variable (line, &found);
     for (i = 0; i < argc - 3; i++) {
-      // snprintf (line, MAX_LINE_LENGTH, "%s:%d", argv[1], N + i);
+      // snprintf_nowarn (line, MAX_LINE_LENGTH, "%s:%d", argv[1], N + i);
       set_list_varname (line, argv[1], N + i, EXCEL_STYLE);
       set_str_variable (line, argv[i+3]);
     }
-    snprintf (line, MAX_LINE_LENGTH, "%s:n", argv[1]);
+    snprintf_nowarn (line, MAX_LINE_LENGTH, "%s:n", argv[1]);
     set_int_variable (line, N + i);
 
@@ -231,10 +231,10 @@
     char line2[MAX_LINE_LENGTH];
 
-    snprintf (line, MAX_LINE_LENGTH, "%s:n", argv[1]); // line = LIST:n
+    snprintf_nowarn (line, MAX_LINE_LENGTH, "%s:n", argv[1]); // line = LIST:n
     N = get_int_variable (line, &found);
 
     // loop over all list elements:
     for (i = 0; i < N; i++) {
-      // snprintf (line, MAX_LINE_LENGTH, "%s:%d", argv[1], i);
+      // snprintf_nowarn (line, MAX_LINE_LENGTH, "%s:%d", argv[1], i);
       set_list_varname (line, argv[1], i, EXCEL_STYLE); // line = LIST:i
       value = get_variable (line);
@@ -245,5 +245,5 @@
 	free (value);
 	for (j = i + 1; j < N; j++) {
-	  // snprintf (line, MAX_LINE_LENGTH, "%s:%d", argv[1], j);
+	  // snprintf_nowarn (line, MAX_LINE_LENGTH, "%s:%d", argv[1], j);
 	  set_list_varname (line2, argv[1], j, EXCEL_STYLE); // line2 = LIST:j
 	  next_value = get_variable (line2);
@@ -252,5 +252,5 @@
 	}
 	DeleteNamedScalar (line); // line = LIST:(N-1)
-	snprintf (line, MAX_LINE_LENGTH, "%s:n", argv[1]); // line = LIST:n (new value of n)
+	snprintf_nowarn (line, MAX_LINE_LENGTH, "%s:n", argv[1]); // line = LIST:n (new value of n)
 	set_int_variable (line, N - 1);
 	return (TRUE);
@@ -309,5 +309,5 @@
       depth --;
       if (depth < 0) { /* we hit the last "END", loop is done */
-	snprintf (line, MAX_LINE_LENGTH, "%s:n", argv[1]);
+	snprintf_nowarn (line, MAX_LINE_LENGTH, "%s:n", argv[1]);
 	set_int_variable (line, i);
 	free (input);
@@ -317,5 +317,5 @@
 
     if (*input) { 
-      // snprintf (line, MAX_LINE_LENGTH, "%s:%d", argv[1], i);
+      // snprintf_nowarn (line, MAX_LINE_LENGTH, "%s:%d", argv[1], i);
       set_list_varname (line, argv[1], i, EXCEL_STYLE);
       set_str_variable (line, input);
@@ -381,5 +381,5 @@
   free (val);
     
-  snprintf (line, MAX_LINE_LENGTH, "%s:n", listname);
+  snprintf_nowarn (line, MAX_LINE_LENGTH, "%s:n", listname);
   set_int_variable (line, i);
   return (TRUE);
@@ -399,5 +399,5 @@
   // otherwise save all glob matches
   if (globList.gl_pathc == 0) {
-    snprintf (line, MAX_LINE_LENGTH, "%s:n", listname);
+    snprintf_nowarn (line, MAX_LINE_LENGTH, "%s:n", listname);
     set_int_variable (line, 0);
     return TRUE;
@@ -409,5 +409,5 @@
     set_str_variable (line, globList.gl_pathv[i]);
   }
-  snprintf (line, MAX_LINE_LENGTH, "%s:n", listname);
+  snprintf_nowarn (line, MAX_LINE_LENGTH, "%s:n", listname);
   set_int_variable (line, Nfile);
   return (TRUE);
@@ -430,5 +430,5 @@
     Nline ++;
   }
-  snprintf (varname, MAX_LINE_LENGTH, "%s:n", listname);
+  snprintf_nowarn (varname, MAX_LINE_LENGTH, "%s:n", listname);
   set_int_variable (varname, Nline);
   return TRUE;
@@ -463,5 +463,5 @@
     FREE (new);
   }
-  snprintf (line, MAX_LINE_LENGTH, "%s:n", argv[1]);
+  snprintf_nowarn (line, MAX_LINE_LENGTH, "%s:n", argv[1]);
   set_int_variable (line, nWords);
 
Index: trunk/Ohana/src/opihi/cmd.basic/memory.c
===================================================================
--- trunk/Ohana/src/opihi/cmd.basic/memory.c	(revision 42332)
+++ trunk/Ohana/src/opihi/cmd.basic/memory.c	(revision 42389)
@@ -27,4 +27,12 @@
   if (!strcasecmp (argv[1], "checkfree")) {
     ohana_memcheck (1);
+    return (TRUE);
+  }
+  if (!strcasecmp (argv[1], "stats")) {
+    OhanaMemstats memstats = ohana_memstats (0);
+    set_variable ("memory:Ntotal", memstats.Ntotal);
+    set_variable ("memory:Nbytes", memstats.Nbytes);
+    set_variable ("memory:Ngood",  memstats.Ngood);
+    set_variable ("memory:Nbad",   memstats.Nbad);
     return (TRUE);
   }
Index: trunk/Ohana/src/opihi/cmd.basic/run_while.c
===================================================================
--- trunk/Ohana/src/opihi/cmd.basic/run_while.c	(revision 42332)
+++ trunk/Ohana/src/opihi/cmd.basic/run_while.c	(revision 42389)
@@ -72,5 +72,6 @@
   // test the logic once before running the loop
   logic_line = strcreate (argv[1]);
-  logic_line = expand_vars (logic_line);
+  logic_line = expand_vars (logic_line); // recalculates scalar elements
+  logic_line = expand_vectors (logic_line); // recalculates vector/matrix elements (e.g., vec[])
   val = dvomath (1, &logic_line, &size, 0);
   free (logic_line);
@@ -90,5 +91,6 @@
 
     logic_line = strcreate (argv[1]);
-    logic_line = expand_vars (logic_line);
+    logic_line = expand_vars (logic_line); // recalculates scalar elements
+    logic_line = expand_vectors (logic_line); // recalculates vector/matrix elements (e.g., vec[])
     val = dvomath (1, &logic_line, &size, 0);
     free (logic_line);
Index: trunk/Ohana/src/opihi/cmd.basic/test/stackmath.sh
===================================================================
--- trunk/Ohana/src/opihi/cmd.basic/test/stackmath.sh	(revision 42332)
+++ 	(revision )
@@ -1,128 +1,0 @@
-
-input tap.sh
-
-macro go
- plan {14 + 14}
- test1
- test2
- done
-end
-
-# test unary scalar ops
-macro test1
- $x = 5;                 ok ($x == 5) "scalar equality"
- $x = abs(-3);           ok ($x == 3) "scalar abs"
- $x = int(5.23);         ok ($x == 5) "scalar int"
- $x = floor(7.1234);     ok ($x == 7) "scalar floor"
- $x = floor(7.9876);     ok ($x == 7) "scalar floor"
- $x = ceil(7.1234);      ok ($x == 8) "scalar ceil"
- $x = ceil(7.9876);      ok ($x == 8) "scalar ceil"
-		         
- $x = exp(1.0);          ok ($x == 2.71828182846) "scalar exp"
- $x = ten(3.0);          ok ($x == 1000) "scalar ten"
- $x = log(10000);        ok ($x == 4) "scalar log"
- $x = ln(2.71828182846); ok ($x == 1) "scalar ln"
- $x = sqrt(9);           ok ($x == 3) "scalar sqrt"
- $x = dsin(30);          ok ($x == 0.5) "scalar dsin"
- $x = sin($M_PI/6);      ok ($x == 0.5) "scalar sin"
-end
-
-# test unary vector ops
-macro test2
- create x -3 3
-
- set y = x;                 ok (y[1] == -2) "vector equality"
- set y = abs(x);            ok (y[1] ==  2) "vector abs"
- 
- set y = ten(x);            ok (y[1] == 0.01) "vector ten"
-       	 		    ok (y[5] == 100) "vector ten"
- set z = log(y);            ok (z[5] == 2) "vector log"
-       	 		    ok (z[1] == -2) "vector ten"
-
- set y = exp(x);            ok (y[4] == 2.71828182846) "vector exp"
-       	 		    ok (y[2] == 0.367879441171) "vector exp"
- set z = ln(y);             ok (z[2] == -1) "vector ln"
-                            ok (z[4] == 1) "vector ln"
- create x 0 26
- set y = sqrt(x);           ok (y[4] == 2) "vector sqrt"
-       	 		    ok (y[9] == 3) "vector sqrt"
-
- create x 0 360 30
- set y = dsin(x);           ok (y[1] == 0.5) "vector dsin"
-                            ok (y[3] == 1.0) "vector dsin"
-end
-
-# here are all defined unary functions
-# SVM =
-# SVM abs    
-# SVM int    
-# SVM floor  
-#     round  
-# SVM ceil   
-#     rint   
-# SVM exp    
-# SVM ten    
-# SVM log    
-# SVM ln     
-# SVM sqrt   
-# SVM erf    
-# SVM sinh   
-# SVM cosh   
-# SVM asinh  
-# SVM acosh  
-# SVM sin    
-# SVM cos    
-# SVM tan    
-# SVM dsin   
-# SVM dcos   
-# SVM dtan   
-# SVM asin   
-# SVM acos   
-# SVM atan   
-# SVM dasin  
-# SVM dacos  
-# SVM datan  
-# SVM lgamma 
-# SVM rnd    
-# SVM drnd   
-# SVM lrnd   
-# SVM mrnd   
-# SVM not    
-# SVM negate
-# SVM isinf  
-# SVM isnan  
-#  VM ramp   
-#  VM xramp  
-#  VM yramp  
-#  VM zramp  
-#  VM zero   
-
-## tests are not reporting an error when using one of the unimplemented functions
-
-# here are all defined binary functions
-
-# V "^"
-# V max     "U"
-# V min     "D"
-# V atan2   "a"
-# V datan2  "d"
-# * <-      "l"
-# * ->      "r"
-# V @       
-# V /       
-# V *       
-# V %       
-# V +       
-# V -       
-# V &       
-# V |       
-# V <       
-# V >       
-# V ==      "E"
-# V !=      "N"
-# V <=      "L"
-# V >=      "G"
-# V >>      "U"
-# V <<      "D"
-# V &&      "A"
-# V ||      "O"
Index: trunk/Ohana/src/opihi/cmd.basic/test/stackmath.tp
===================================================================
--- trunk/Ohana/src/opihi/cmd.basic/test/stackmath.tp	(revision 42389)
+++ trunk/Ohana/src/opihi/cmd.basic/test/stackmath.tp	(revision 42389)
@@ -0,0 +1,128 @@
+
+input ../../test/tap.tp
+
+macro go
+ plan {14 + 14}
+ test1
+ test2
+ done
+end
+
+# test unary scalar ops
+macro test1
+ $x = 5;                 ok ($x == 5) "scalar equality"
+ $x = abs(-3);           ok ($x == 3) "scalar abs"
+ $x = int(5.23);         ok ($x == 5) "scalar int"
+ $x = floor(7.1234);     ok ($x == 7) "scalar floor"
+ $x = floor(7.9876);     ok ($x == 7) "scalar floor"
+ $x = ceil(7.1234);      ok ($x == 8) "scalar ceil"
+ $x = ceil(7.9876);      ok ($x == 8) "scalar ceil"
+		         
+ $x = exp(1.0);          ok ($x == 2.71828182846) "scalar exp"
+ $x = ten(3.0);          ok ($x == 1000) "scalar ten"
+ $x = log(10000);        ok ($x == 4) "scalar log"
+ $x = ln(2.71828182846); ok ($x == 1) "scalar ln"
+ $x = sqrt(9);           ok ($x == 3) "scalar sqrt"
+ $x = dsin(30);          ok ($x == 0.5) "scalar dsin"
+ $x = sin($M_PI/6);      ok ($x == 0.5) "scalar sin"
+end
+
+# test unary vector ops
+macro test2
+ create x -3 3
+
+ set y = x;                 ok (y[1] == -2) "vector equality"
+ set y = abs(x);            ok (y[1] ==  2) "vector abs"
+ 
+ set y = ten(x);            ok (y[1] == 0.01) "vector ten"
+       	 		    ok (y[5] == 100) "vector ten"
+ set z = log(y);            ok (z[5] == 2) "vector log"
+       	 		    ok (z[1] == -2) "vector ten"
+
+ set y = exp(x);            ok (y[4] == 2.71828182846) "vector exp"
+       	 		    ok (y[2] == 0.367879441171) "vector exp"
+ set z = ln(y);             ok (z[2] == -1) "vector ln"
+                            ok (z[4] == 1) "vector ln"
+ create x 0 26
+ set y = sqrt(x);           ok (y[4] == 2) "vector sqrt"
+       	 		    ok (y[9] == 3) "vector sqrt"
+
+ create x 0 360 30
+ set y = dsin(x);           ok (y[1] == 0.5) "vector dsin"
+                            ok (y[3] == 1.0) "vector dsin"
+end
+
+# here are all defined unary functions
+# SVM =
+# SVM abs    
+# SVM int    
+# SVM floor  
+#     round  
+# SVM ceil   
+#     rint   
+# SVM exp    
+# SVM ten    
+# SVM log    
+# SVM ln     
+# SVM sqrt   
+# SVM erf    
+# SVM sinh   
+# SVM cosh   
+# SVM asinh  
+# SVM acosh  
+# SVM sin    
+# SVM cos    
+# SVM tan    
+# SVM dsin   
+# SVM dcos   
+# SVM dtan   
+# SVM asin   
+# SVM acos   
+# SVM atan   
+# SVM dasin  
+# SVM dacos  
+# SVM datan  
+# SVM lgamma 
+# SVM rnd    
+# SVM drnd   
+# SVM lrnd   
+# SVM mrnd   
+# SVM not    
+# SVM negate
+# SVM isinf  
+# SVM isnan  
+#  VM ramp   
+#  VM xramp  
+#  VM yramp  
+#  VM zramp  
+#  VM zero   
+
+## tests are not reporting an error when using one of the unimplemented functions
+
+# here are all defined binary functions
+
+# V "^"
+# V max     "U"
+# V min     "D"
+# V atan2   "a"
+# V datan2  "d"
+# * <-      "l"
+# * ->      "r"
+# V @       
+# V /       
+# V *       
+# V %       
+# V +       
+# V -       
+# V &       
+# V |       
+# V <       
+# V >       
+# V ==      "E"
+# V !=      "N"
+# V <=      "L"
+# V >=      "G"
+# V >>      "U"
+# V <<      "D"
+# V &&      "A"
+# V ||      "O"
Index: trunk/Ohana/src/opihi/cmd.basic/test/tap.sh
===================================================================
--- trunk/Ohana/src/opihi/cmd.basic/test/tap.sh	(revision 42332)
+++ 	(revision )
@@ -1,61 +1,0 @@
-
-macro plan
- if ($0 != 2)
-  echo "USAGE: plan (Ntest)"
-  break
- end
-
- $tap_Nplan = $1
- $tap_Npass = 0
- $tap_Nfail = 0
- $tap_Ntest = 0
-end
-
-macro done
- if (not($?tap_Nplan))
-  echo "ERROR: tap tests not planned"
-  break
- end
-
- echo "planned $tap_Nplan tests, ran $tap_Ntest"
- echo "passed $tap_Npass tests, failed $tap_Nfail tests"
-
- if (($tap_Nfail == 0) && ($tap_Ntest == $tap_Nplan) && ($tap_Npass == $tap_Ntest))
-   echo "PASS: all tests run and passed"
-   return 1
- end
-
- if ($tap_Nfail > 0)
-   echo "FAIL: $tap_Nfail tests failed"
- end
-
- if ($tap_Ntest != $tap_Nplan)
-   echo "FAIL: not all tests run"
- end
-
- if ($tap_Ntest != $tap_Npass + $tap_Nfail)
-   echo "FAIL: inconsistent count: $tap_Ntest tests != $tap_Npass pass + $tap_Nfail fail"
- end
-end
-
-macro ok
- if ($0 != 3)
-  echo "USAGE (condition) (label)"
-  break
- end
- 
- if (not($?tap_Nplan))
-  echo "ERROR: tap tests not planned"
-  break
- end
- 
- if ($1)
-  echo "OK: $2"
-  $tap_Npass ++
- else     
-  echo "not OK: $2"
-  $tap_Nfail ++
- end
- $tap_Ntest ++
-end
-
Index: trunk/Ohana/src/opihi/cmd.data/Makefile
===================================================================
--- trunk/Ohana/src/opihi/cmd.data/Makefile	(revision 42332)
+++ trunk/Ohana/src/opihi/cmd.data/Makefile	(revision 42389)
@@ -140,4 +140,5 @@
 $(SRC)/radial.$(ARCH).o	\
 $(SRC)/rd.$(ARCH).o		\
+$(SRC)/rdjpg.$(ARCH).o		\
 $(SRC)/rdseg.$(ARCH).o		\
 $(SRC)/read_vectors.$(ARCH).o	\
@@ -154,4 +155,5 @@
 $(SRC)/set.$(ARCH).o		\
 $(SRC)/shift.$(ARCH).o		\
+$(SRC)/opihi_size.$(ARCH).o        \
 $(SRC)/sort.$(ARCH).o		\
 $(SRC)/spline.$(ARCH).o		\
Index: trunk/Ohana/src/opihi/cmd.data/cursor.c
===================================================================
--- trunk/Ohana/src/opihi/cmd.data/cursor.c	(revision 42332)
+++ trunk/Ohana/src/opihi/cmd.data/cursor.c	(revision 42389)
@@ -42,14 +42,9 @@
     KiiCursorRead (kapa, &X, &Y, &Z, &R, &D, key);
 
-    sprintf (string, "X%s", key);
-    set_variable (string, X);
-    sprintf (string, "Y%s", key);
-    set_variable (string, Y);
-    sprintf (string, "Z%s", key);
-    set_variable (string, Z);
-    sprintf (string, "R%s", key);
-    set_variable (string, R);
-    sprintf (string, "D%s", key);
-    set_variable (string, D);
+    snprintf_nowarn (string, 20, "X%s", key);    set_variable (string, X);
+    snprintf_nowarn (string, 20, "Y%s", key);    set_variable (string, Y);
+    snprintf_nowarn (string, 20, "Z%s", key);    set_variable (string, Z);
+    snprintf_nowarn (string, 20, "R%s", key);    set_variable (string, R);
+    snprintf_nowarn (string, 20, "D%s", key);    set_variable (string, D);
 
     set_str_variable ("KEY", key);
Index: trunk/Ohana/src/opihi/cmd.data/init.c
===================================================================
--- trunk/Ohana/src/opihi/cmd.data/init.c	(revision 42332)
+++ trunk/Ohana/src/opihi/cmd.data/init.c	(revision 42389)
@@ -126,4 +126,5 @@
 int queue2book       PROTO((int, char **));
 int rd               PROTO((int, char **));
+int rdjpg            PROTO((int, char **));
 int rdseg            PROTO((int, char **));
 int read_vectors     PROTO((int, char **));
@@ -160,4 +161,5 @@
 int tvgrid           PROTO((int, char **));
 int opihi_type       PROTO((int, char **));
+int opihi_size       PROTO((int, char **));
 int uniq             PROTO((int, char **));
 int uniqpair         PROTO((int, char **));
@@ -336,4 +338,5 @@
   {1, "ipptool2book", queue2book,       "convert queue with ipptool output to book"},
   {1, "rd",           rd,               "load fits image"},
+  {1, "rdjpg",        rdjpg,            "load jpeg image"},
   {1, "rdseg",        rdseg,            "read a segment of an image from a file"},
   {1, "read",         read_vectors,     "read vectors from datafile"},
@@ -350,4 +353,5 @@
   {1, "set",          set,              "image and vector math"},
   {1, "shift",        shift,            "shift data in an image"},
+  {1, "size",         opihi_size,       "get vector/matrix dimension/size information"},
   {1, "sort",         sort_vectors,     "sort list of vectors"},
   {1, "spline",       spline_command,   "shift data in an image"},
Index: trunk/Ohana/src/opihi/cmd.data/limits.c
===================================================================
--- trunk/Ohana/src/opihi/cmd.data/limits.c	(revision 42332)
+++ trunk/Ohana/src/opihi/cmd.data/limits.c	(revision 42389)
@@ -61,4 +61,5 @@
     APPLY = TRUE;
   }
+
   char *name = NULL;
   if ((N = get_argument (argc, argv, "-n"))) {
@@ -67,7 +68,16 @@
     remove_argument (N, &argc, argv);
   }
-
   if (!GetGraph (&graphmode, &kapa, name)) return (FALSE);
   FREE (name);
+
+  // this is not super intuitive
+  if ((N = get_argument (argc, argv, "-boxsize"))) {
+    remove_argument (N, &argc, argv);
+    float dx, dy;
+    // ask kapa for the size of the graph region in pixels
+    KapaGetLimits (kapa, &dx, &dy);
+    set_variable ("KAPA_XPIX", fabs(dx));
+    set_variable ("KAPA_YPIX", fabs(dy));
+  }
 
   // XXX need an option to set the limits based on the current image bounds
@@ -169,2 +179,15 @@
   return (TRUE);
 }
+
+/* -minX value : the minimum X axis value will be no higher than this value
+   -maxX value : the maximum X axis value will be no lower than this value
+   -delX value : the range of the X axis will be at least this value
+
+   These can be used to prevent the range from collapsing.  
+   These are only used if the -a option is supplied, otherwise the supplied or auto-calculated 
+   ranges are used (this seems like an poor choice)
+
+*/
+
+
+   
Index: trunk/Ohana/src/opihi/cmd.data/opihi_size.c
===================================================================
--- trunk/Ohana/src/opihi/cmd.data/opihi_size.c	(revision 42389)
+++ trunk/Ohana/src/opihi/cmd.data/opihi_size.c	(revision 42389)
@@ -0,0 +1,68 @@
+# include "data.h"
+
+int opihi_size (int argc, char **argv) {
+  
+  int N;
+
+  char *resultName = NULL;
+  Vector *resultVec = NULL;
+  if ((N = get_argument (argc, argv, "-result"))) {
+    remove_argument (N, &argc, argv);
+    resultName = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+    if ((resultVec = SelectVector (resultName, ANYVECTOR, FALSE)) == NULL)   {
+      gprint (GP_ERR, "invalid vector name %s for return result\n", resultName);
+      FREE (resultName);
+      return FALSE;
+    }
+  }
+
+  if (argc != 2) goto usage;
+
+  Vector *vec = NULL;
+  Buffer *buf = NULL;
+
+  // is it a Vector?
+  if ((vec = SelectVector (argv[1], OLDVECTOR, FALSE)) != NULL) {
+    if (resultVec) {
+      ResetVector (resultVec, OPIHI_INT, 1);
+      resultVec->elements.Int[0] = vec->Nelements;
+    } else {
+      gprint (GP_LOG, "%s vector size %d\n", argv[1], vec->Nelements);
+    }
+    goto got_result;
+  }
+
+  // is it a Matrix (Buffer)?
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, FALSE)) != NULL) {
+    if (resultVec) {
+      ResetVector (resultVec, OPIHI_INT, buf->header.Naxes);
+      for (int i = 0; i < buf->header.Naxes; i++) {
+	resultVec->elements.Int[i] = buf->header.Naxis[i];
+      }
+    } else {
+      gprint (GP_LOG, "%s matrix sizes ", argv[1]);
+      for (int i = 0; i < buf->header.Naxes; i++) {
+	gprint (GP_LOG, " %d", (int) buf->header.Naxis[i]);
+      }
+      gprint (GP_LOG, "\n");
+    }
+    goto got_result;
+  }
+  
+  if (resultVec) {
+    ResetVector (resultVec, OPIHI_INT, 0);
+  } else {
+    gprint (GP_LOG, "%s not defined\n", argv[1]);
+  }
+
+got_result:
+  FREE (resultName);
+  return TRUE;
+  
+usage:
+  gprint (GP_ERR, "SYNTAX: size (vector/buffer) [-result vector]\n");
+  gprint (GP_ERR, "  returns type (vector/matrix) and sizes\n");
+  gprint (GP_ERR, "  returns sizes in vector if -result is supplied\n");
+  return (FALSE);
+}
Index: trunk/Ohana/src/opihi/cmd.data/rdjpg.c
===================================================================
--- trunk/Ohana/src/opihi/cmd.data/rdjpg.c	(revision 42389)
+++ trunk/Ohana/src/opihi/cmd.data/rdjpg.c	(revision 42389)
@@ -0,0 +1,125 @@
+# include "data.h"
+# include "jpeglib.h"
+# include <setjmp.h>
+
+struct my_error_mgr {
+  struct jpeg_error_mgr pub;	/* "public" fields */
+  jmp_buf setjmp_buffer;	/* for return to caller */
+};
+
+typedef struct my_error_mgr * my_error_ptr;
+
+METHODDEF(void) my_error_exit (j_common_ptr cinfo)
+{
+  fprintf (stderr, "got an error\n");
+
+  /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */
+  my_error_ptr myerr = (my_error_ptr) cinfo->err;
+
+  /* Always display the message. */
+  /* We could postpone this until after returning, if we chose. */
+  (*cinfo->err->output_message) (cinfo);
+
+  /* Return control to the setjmp point */
+  longjmp(myerr->setjmp_buffer, 1);
+}
+
+int rdjpg (int argc, char **argv) {
+  
+  int N;
+  Buffer *buf;
+
+  struct jpeg_decompress_struct cinfo;
+  struct my_error_mgr jerr;
+
+  int VERBOSE = FALSE;
+  if ((N = get_argument (argc, argv, "-v"))) {
+    remove_argument (N, &argc, argv);
+    VERBOSE = TRUE;
+  }
+
+  if (argc != 3) {
+    gprint (GP_ERR, "USAGE: rdjpg <buffer> <filename>\n");
+    return (FALSE);
+  }
+
+  // open input file for read
+  FILE *f = fopen (argv[2], "r");
+  if (f == (FILE *) NULL) {
+    gprint (GP_ERR, "file %s not found\n", argv[2]);
+    return (FALSE);
+  }
+
+  // find matrix, free old data
+  if ((buf = SelectBuffer (argv[1], ANYBUFFER, TRUE)) == NULL) {
+    fclose (f);
+    return (FALSE);
+  }
+  gfits_free_matrix (&buf[0].matrix);
+  gfits_free_header (&buf[0].header);
+
+  // save file name in buffer info
+  char *filename = filebasename (argv[2]);
+  strcpy (buf[0].file, filename);
+  free (filename);
+
+  // the setup for the error handling seems a bit circular, but this
+  // example from the libjpeg example.c seems to work?
+  cinfo.err = jpeg_std_error(&jerr.pub);
+  jerr.pub.error_exit = my_error_exit;
+
+  // an error in the jpeg code will jump (goto) here:
+  if (setjmp(jerr.setjmp_buffer)) {
+    /* If we get here, the JPEG code has signaled an error.
+     * We need to clean up the JPEG object, close the input file, and return.
+     */
+    jpeg_destroy_decompress(&cinfo);
+    fclose(f);
+    return FALSE;
+  }
+
+  /* Now we can initialize the JPEG decompression object. */
+  jpeg_create_decompress(&cinfo);
+  jpeg_stdio_src(&cinfo, f);
+  jpeg_read_header(&cinfo, TRUE);
+  jpeg_start_decompress(&cinfo);
+
+  /* JSAMPLEs per row in output buffer */
+  int Nx = cinfo.output_width;
+  int Ny = cinfo.output_height;
+  int Npix_row = Nx * cinfo.output_components;
+
+  CreateBuffer (buf, Nx, Ny, -32, 0.0, 1.0);
+  float *Vout = (float *)buf[0].matrix.buffer;
+
+  /* Make a one-row-high sample array that will go away when done with image */
+  JSAMPARRAY buffer = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE, Npix_row, 1);
+
+  // read each of the scanlines
+  for (int iy = 0; iy < Ny; iy++) {
+    jpeg_read_scanlines(&cinfo, buffer, 1);
+
+    // for now just copy R + G + B as the total value:
+    for (int ix = 0; ix < Nx; ix ++) {
+      unsigned char Rpix = buffer[0][3*ix + 0];
+      unsigned char Gpix = buffer[0][3*ix + 1];
+      unsigned char Bpix = buffer[0][3*ix + 2];
+      float value = Rpix + Gpix + Bpix;
+      Vout[Nx*iy + ix] = value;
+    }
+  }
+    
+  jpeg_finish_decompress(&cinfo);
+  jpeg_destroy_decompress(&cinfo);
+  
+  fclose (f);
+  
+  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;
+
+  if (VERBOSE) gprint (GP_LOG, "read "OFF_T_FMT" bytes from %s into buffer %s\n", buf[0].header.datasize + buf[0].matrix.datasize, argv[2], argv[1]);
+
+  return (TRUE);
+}
Index: trunk/Ohana/src/opihi/cmd.data/read_vectors.c
===================================================================
--- trunk/Ohana/src/opihi/cmd.data/read_vectors.c	(revision 42332)
+++ trunk/Ohana/src/opihi/cmd.data/read_vectors.c	(revision 42389)
@@ -385,6 +385,5 @@
       if (!lineStatus && VERBOSE) {
 	char temp[32];
-	strncpy (temp, c0, 32);
-	temp[31] = 0;
+	strncpy_nowarn (temp, c0, 31);
 	gprint (GP_ERR, "skip line %s\n\n", temp);
       }
Index: trunk/Ohana/src/opihi/cmd.data/reindex.c
===================================================================
--- trunk/Ohana/src/opihi/cmd.data/reindex.c	(revision 42332)
+++ trunk/Ohana/src/opihi/cmd.data/reindex.c	(revision 42389)
@@ -72,4 +72,23 @@
     }
   }
+  if (ivec->type == OPIHI_STR) {
+    opihi_int *vx = xvec[0].elements.Int;
+    for (Npts = i = 0; i < xvec[0].Nelements; i++, vx++) {
+      if (Npts >= NPTS) {
+	NPTS += 2000;
+	REALLOCATE (ovec[0].elements.Str, char *, NPTS);
+      }
+      if (*vx < 0) {
+	if (KEEP_UNMATCH) {
+	  ovec[0].elements.Str[Npts] = strcreate(""); // XXX use a different or a specified value?
+	  Npts++;
+	} 
+	continue;
+      }
+      if (*vx > Nmax) ESCAPE("unexpected value in index: "OPIHI_INT_FMT" (%d)\n", *vx, i);
+      ovec[0].elements.Str[Npts] = strcreate(ivec->elements.Str[*vx]);
+      Npts++;
+    }
+  }
 
   // free up unused memory
Index: trunk/Ohana/src/opihi/cmd.data/subset.c
===================================================================
--- trunk/Ohana/src/opihi/cmd.data/subset.c	(revision 42332)
+++ trunk/Ohana/src/opihi/cmd.data/subset.c	(revision 42389)
@@ -44,5 +44,5 @@
   ResetVector (ovec, ivec->type, tvec[0].Nelements);
 
-  // we have four cases: (ivec == flt or int) and (tvec == flt or int)
+  // we have size cases: (ivec == flt, int, str) and (tvec == flt or int)
   if ((ivec->type == OPIHI_FLT) && (tvec->type == OPIHI_FLT)) {
     opihi_flt *vi = ivec[0].elements.Flt;
@@ -81,9 +81,12 @@
     }
   }
+  // XXX if ivec is an existing vector, this step will
+  // leak (existing elements need to be freed if they
+  // have been allocated).
   if ((ivec->type == OPIHI_STR) && (tvec->type == OPIHI_FLT)) {
     opihi_flt *vt = tvec[0].elements.Flt;
     for (Npts = i = 0; i < tvec[0].Nelements; i++, vt++) {
       if (!*vt) continue;
-      ovec[0].elements.Str[Npts] = strcreate (ivec[0].elements.Str[i]);
+      ovec[0].elements.Str[Npts] = strcreate(ivec[0].elements.Str[i]);
       Npts++;
     }
@@ -93,5 +96,5 @@
     for (Npts = i = 0; i < tvec[0].Nelements; i++, vt++) {
       if (!*vt) continue;
-      ovec[0].elements.Str[Npts] = strcreate (ivec[0].elements.Str[i]);
+      ovec[0].elements.Str[Npts] = strcreate(ivec[0].elements.Str[i]);
       Npts++;
     }
Index: trunk/Ohana/src/opihi/cmd.data/svd.c
===================================================================
--- trunk/Ohana/src/opihi/cmd.data/svd.c	(revision 42332)
+++ trunk/Ohana/src/opihi/cmd.data/svd.c	(revision 42389)
@@ -58,5 +58,5 @@
 
   // try C.R. Bond's version -- requires matrices in the form A[row][col] not A[row*Ncol + col]
-  if (1) { 
+  if (0) { 
       int j;
       double **a, **u, **v, *q;
Index: trunk/Ohana/src/opihi/cmd.data/test/histogram.sh
===================================================================
--- trunk/Ohana/src/opihi/cmd.data/test/histogram.sh	(revision 42332)
+++ trunk/Ohana/src/opihi/cmd.data/test/histogram.sh	(revision 42389)
@@ -35,6 +35,9 @@
  local i
 
- list word -x "ps -p $PID -o rss"
- $startmem = $word:1
+ create xhis 0 10 0.1
+ $i = 1
+
+ memory stats
+ $startmem = $memory:Ntotal
 
  for i 0 1000
@@ -42,6 +45,6 @@
  end
   
- list word -x "ps -p $PID -o rss"
- $endmem = $word:1
+ memory stats
+ $endmem = $memory:Ntotal
 
  $PASS = 1
Index: trunk/Ohana/src/opihi/cmd.data/test/join.sh
===================================================================
--- trunk/Ohana/src/opihi/cmd.data/test/join.sh	(revision 42332)
+++ trunk/Ohana/src/opihi/cmd.data/test/join.sh	(revision 42389)
@@ -21,65 +21,4 @@
 
  join ID1 ID2 
-
-mana: for i 0 index1[]
->> echo index1[$i] index2[$i]
->> end
-0 2
-2 1
-4 0
-5 3
-mana: join ID1 ID2 -outer
-mana: vectors 
-    N       name      size
-    0        ID1          6 (INT)
-    1       val1          6 (FLT)
-    2        ID2          4 (INT)
-    3        val          4 (FLT)
-    4     index1          6 (INT)
-    5     index2          4 (INT)
-mana: for i 0 index1[]
->> echo index1[$i]
->> end
-2
--1
-1
--1
-0
-3
-mana: echo ID1[2]
-3
-mana: echo ID1[0] ID2[2]
-1 1
-mana: for i 0 index1[]
->> if (index1[$i] == -1) continue
->> $N = index1[$i]
->> echo $i index1[$i] ID1[$i] ID2[$N]
->> end
-0 2 1 1
-2 1 3 3
-4 0 5 5
-5 3 6 6
-mana: for i 0 index2[]
->> if (index2[$i] == -1) continue
->> $N = index2[$i]
->> echo $i index2[$i] ID2[$i] ID1[$N]
->> end
-0 4 5 5
-1 2 3 3
-2 0 1 1
-3 5 6 6
-mana: 
-
- # if ((xvec[1024] != 17) || (yvec[1024] != 100))
- #  $PASS = 0
- #  echo "Value mismatch: xvec[1024] yvec[1024] (should be 17,100)"
- # end
- # 
- # imhist -q buff xvec yvec -region 40 0 25 10 -range 0 10
- # 
- # if ((xvec[1024] != 10) || (yvec[1024] != 100))
- #  $PASS = 0
- #  echo "Value mismatch: xvec[1024] yvec[1024] (should be 10,100)"
- # end
 
 end
Index: trunk/Ohana/src/opihi/cmd.data/threshold.c
===================================================================
--- trunk/Ohana/src/opihi/cmd.data/threshold.c	(revision 42332)
+++ trunk/Ohana/src/opihi/cmd.data/threshold.c	(revision 42389)
@@ -3,9 +3,10 @@
 int QUIET = FALSE;
 
-void _threshold_set_values (double value, int Nbin, double level) {
+void _threshold_set_values (double value, int Nbin, double level, int thresherr) {
 
   set_variable ("threshval", value);
   set_int_variable ("threshbin", Nbin);
   set_variable ("threshold", level);
+  set_int_variable ("thresherr", thresherr);
 
   if (!QUIET) gprint (GP_LOG, "theshold %f (bin %d is %f)\n", level, Nbin, value);
@@ -117,9 +118,9 @@
     if (vecy[0].elements.Flt[BinMin] > value) {
       if (SATURATE) {
-	_threshold_set_values (vecy[0].elements.Flt[BinMin], BinMin, vecx[0].elements.Flt[BinMin]);
+	_threshold_set_values (vecy[0].elements.Flt[BinMin], BinMin, vecx[0].elements.Flt[BinMin], 1);
 	return TRUE;
       } else {
 	gprint (GP_ERR, "ERROR: all values above threshold\n");
-	_threshold_set_values (NAN, -1, NAN);
+	_threshold_set_values (NAN, -1, NAN, 1);
 	return FALSE;
       }
@@ -127,9 +128,9 @@
     if (vecy[0].elements.Flt[BinMax] < value) {
       if (SATURATE) {
-	_threshold_set_values (vecy[0].elements.Flt[BinMax], BinMax, vecx[0].elements.Flt[BinMax]);
+	_threshold_set_values (vecy[0].elements.Flt[BinMax], BinMax, vecx[0].elements.Flt[BinMax], 1);
 	return TRUE;
       } else {
 	gprint (GP_ERR, "ERROR: all values below threshold\n");
-	_threshold_set_values (NAN, -1, NAN);
+	_threshold_set_values (NAN, -1, NAN, 1);
 	return FALSE;
       }
@@ -156,9 +157,9 @@
     if (vecy[0].elements.Flt[BinMin] < value) {
       if (SATURATE) {
-	_threshold_set_values (vecy[0].elements.Flt[BinMin], BinMin, vecx[0].elements.Flt[BinMin]);
+	_threshold_set_values (vecy[0].elements.Flt[BinMin], BinMin, vecx[0].elements.Flt[BinMin], 1);
 	return TRUE;
       } else {
 	gprint (GP_ERR, "ERROR: all values below threshold\n");
-	_threshold_set_values (NAN, -1, NAN);
+	_threshold_set_values (NAN, -1, NAN, 1);
 	return FALSE;
       }
@@ -166,9 +167,9 @@
     if (vecy[0].elements.Flt[BinMax] > value) {
       if (SATURATE) {
-	_threshold_set_values (vecy[0].elements.Flt[BinMax], BinMax, vecx[0].elements.Flt[BinMax]);
+	_threshold_set_values (vecy[0].elements.Flt[BinMax], BinMax, vecx[0].elements.Flt[BinMax], 1);
 	return TRUE;
       } else {
 	gprint (GP_ERR, "ERROR: all values above threshold\n");
-	_threshold_set_values (NAN, -1, NAN);
+	_threshold_set_values (NAN, -1, NAN, 1);
 	return FALSE;
       }
@@ -219,5 +220,5 @@
   }
 
-  _threshold_set_values (y1, Nhi, Xvalue);
+  _threshold_set_values (y1, Nhi, Xvalue, 0);
   return (TRUE);
 }
Index: trunk/Ohana/src/opihi/cmd.data/tvcolors.c
===================================================================
--- trunk/Ohana/src/opihi/cmd.data/tvcolors.c	(revision 42332)
+++ trunk/Ohana/src/opihi/cmd.data/tvcolors.c	(revision 42389)
@@ -41,4 +41,15 @@
     gprint (GP_ERR, "   f: 0 - 1 defines the scale value for the transition\n");
     gprint (GP_ERR, "   R,G,B: 0 - 1 define the value of the color at the transition point\n");
+
+    gprint (GP_ERR, "   There are 5 colormap file format options:\n");
+    gprint (GP_ERR, "   * file:filename : index Red Green Blue\n");
+    gprint (GP_ERR, "   * lgcy:filename : index Red Blue Green\n");
+    gprint (GP_ERR, "   * csvf:filename : index,Red,Green,Blue\n");
+    gprint (GP_ERR, "   * cetf:filename : fRed,fGreen,fBlue \n");
+    gprint (GP_ERR, "   * cetr:filename : fRed,fGreen,fBlue \n\n");
+    gprint (GP_ERR, "   The index value goes from 0.0 to 1.0 and sets transitions (must be monotonic).\n");
+    gprint (GP_ERR, "   In the CET cases, the index is implicit, with 256 entries expected.\n");
+    gprint (GP_ERR, "   For cetr: the index is reversed.\n");
+
     return (FALSE);
   }
Index: trunk/Ohana/src/opihi/cmd.data/wd.c
===================================================================
--- trunk/Ohana/src/opihi/cmd.data/wd.c	(revision 42332)
+++ trunk/Ohana/src/opihi/cmd.data/wd.c	(revision 42389)
@@ -115,5 +115,5 @@
       Ns = strlen (simple);
       No = 80 - Ns;
-      strncpy (temp_header.buffer, simple, Ns);
+      strncpy_nowarn (temp_header.buffer, simple, Ns);
       memset (&temp_header.buffer[Ns], ' ', No);
     }
@@ -275,25 +275,2 @@
   return (f);
 }
-
-
-///    /* 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 */
-///    fseeko (f, 0LL, SEEK_END);
-///    nbytes = fwrite (temp_header.buffer, 1, temp_header.datasize, f);
-///    fclose (f);
-///    if (nbytes != temp_header.datasize) {
-///      gprint (GP_ERR, "failed to write file\n");
-///      status = FALSE;
-///      goto done1;
-///    }
-///
-///  }
Index: trunk/Ohana/src/opihi/cmd.data/write_vectors.c
===================================================================
--- trunk/Ohana/src/opihi/cmd.data/write_vectors.c	(revision 42332)
+++ trunk/Ohana/src/opihi/cmd.data/write_vectors.c	(revision 42389)
@@ -214,5 +214,5 @@
     /* identify type (%NNNNd %NNNNf) */
     for (p2 = p1 + 1; (*p2 == '.') || (*p2 == '-') || (*p2 == '+') || (*p2 == ' ') || isdigit(*p2); p2++);
-    strncpy (fmtlist[j], p0, p2 - p0 + 1);
+    strncpy_nowarn (fmtlist[j], p0, p2 - p0 + 1);
     switch (*p2) {
       case 'e':
Index: trunk/Ohana/src/opihi/dvo/aregion.c
===================================================================
--- trunk/Ohana/src/opihi/dvo/aregion.c	(revision 42332)
+++ trunk/Ohana/src/opihi/dvo/aregion.c	(revision 42389)
@@ -49,6 +49,5 @@
   fread (buffer, 1, 48*NDecLines[NBigDec], f);
   for (i = 0; !done && (i < NDecLines[NBigDec]); i++) {
-    strncpy (temp, &buffer[i*48], 48);
-    temp[49] = 0;
+    strncpy_nowarn (temp, &buffer[i*48], 48);
     hstgsc_hms_to_deg (&RA0, &RA1, &DEC0, &DEC1, &temp[7]);
     if (RA1 < RA0) RA1 += 360.0;
Index: trunk/Ohana/src/opihi/dvo/coordmosaic.c
===================================================================
--- trunk/Ohana/src/opihi/dvo/coordmosaic.c	(revision 42332)
+++ trunk/Ohana/src/opihi/dvo/coordmosaic.c	(revision 42389)
@@ -311,10 +311,10 @@
       
       memset (segment, 0, 16); memcpy  (segment, &SEGMENT[i*Nsegment], 4);
-      snprintf (name, 16, "%s_L_CX%dY%d", segment, XORDER[i], YORDER[i]);
+      snprintf_nowarn (name, 16, "%s_L_CX%dY%d", segment, XORDER[i], YORDER[i]);
       double xvalue = get_double_variable (name, &found);
       xmask = !found;
       
       memset (segment, 0, 16); memcpy  (segment, &SEGMENT[i*Nsegment], 4);
-      snprintf (name, 16, "%s_M_CX%dY%d", segment, XORDER[i], YORDER[i]);
+      snprintf_nowarn (name, 16, "%s_M_CX%dY%d", segment, XORDER[i], YORDER[i]);
       double yvalue = get_double_variable (name, &found);
       ymask = !found;
@@ -437,9 +437,9 @@
 
 	int found, xmask, ymask;
-	snprintf (name, 16, "L_X%dY%d", ix, iy);
+	snprintf_nowarn (name, 16, "L_X%dY%d", ix, iy);
 	double xvalue = get_double_variable (name, &found);
 	xmask = !found;
 
-	snprintf (name, 16, "M_X%dY%d", ix, iy);
+	snprintf_nowarn (name, 16, "M_X%dY%d", ix, iy);
 	double yvalue = get_double_variable (name, &found);
 	ymask = !found;
Index: trunk/Ohana/src/opihi/dvo/elixir.c
===================================================================
--- trunk/Ohana/src/opihi/dvo/elixir.c	(revision 42332)
+++ trunk/Ohana/src/opihi/dvo/elixir.c	(revision 42389)
@@ -4,8 +4,10 @@
 int ReadMsg (char *fifo, char **message);
 
+# define MY_MAX_PATH 256
+
 int elixir (int argc, char **argv) {
   
-  char message[256], cmd[256], ElixirBase[256];
-  char fifo[256], fifodir[256], msgfile[256];
+  char message[MY_MAX_PATH], cmd[MY_MAX_PATH], ElixirBase[MY_MAX_PATH];
+  char fifo[MY_MAX_PATH], fifodir[MY_MAX_PATH], msgfile[MY_MAX_PATH];
   char *answer;
   int N;
@@ -38,17 +40,17 @@
     return (FALSE);
   }
-  sprintf (fifo, "%s.msg", ElixirBase);
+  snprintf_nowarn (fifo, MY_MAX_PATH, "%s.msg", ElixirBase);
   if (!VarConfig ("FIFOS", "%s", fifodir)) {
     gprint (GP_ERR, "FIFOS not in config, using local /tmp\n");
     strcpy (fifodir, "/tmp");
   }
-  sprintf (fifo, "%s.msg", ElixirBase);
+  snprintf_nowarn (fifo, MY_MAX_PATH, "%s.msg", ElixirBase);
 
-  sprintf (msgfile, "%s/EMsg.XXXXXX", fifodir);
+  snprintf_nowarn (msgfile, MY_MAX_PATH, "%s/EMsg.XXXXXX", fifodir);
   if (mkstemp (msgfile) == -1) {
     gprint (GP_ERR, "can't create fifo\n");
     return (FALSE);
   }
-  sprintf (message, "%s %s", cmd, msgfile);
+  snprintf_nowarn (message, MY_MAX_PATH, "%s %s", cmd, msgfile);
   unlink (msgfile);
 
Index: trunk/Ohana/src/opihi/dvo/find_regions.c
===================================================================
--- trunk/Ohana/src/opihi/dvo/find_regions.c	(revision 42332)
+++ trunk/Ohana/src/opihi/dvo/find_regions.c	(revision 42389)
@@ -100,6 +100,5 @@
     fread (buffer, 48*NDecLines[NBigDec + j], 1, f);
     for (i = 0; (i < NDecLines[NBigDec + j]); i++) {
-      strncpy (temp, &buffer[i*48], 48);
-      temp[49] = 0;
+      strncpy_nowarn (temp, &buffer[i*48], 48);
       hstgsc_hms_to_deg (&RA0, &RA1, &DEC0, &DEC1, &temp[7]);
       if (RA1 < RA0) RA1 += 360.0;
Index: trunk/Ohana/src/opihi/include/dvomath.h
===================================================================
--- trunk/Ohana/src/opihi/include/dvomath.h	(revision 42332)
+++ trunk/Ohana/src/opihi/include/dvomath.h	(revision 42389)
@@ -125,4 +125,5 @@
 int           M_unary               PROTO((StackVar *OUT, StackVar *V1, char *op));
 int           W_unary               PROTO((StackVar *OUT, StackVar *V1, char *op));
+int           L_unary               PROTO((StackVar *OUT, StackVar *V1, char *op));
 
 /* variable handling */
Index: trunk/Ohana/src/opihi/include/pcontrol.h
===================================================================
--- trunk/Ohana/src/opihi/include/pcontrol.h	(revision 42332)
+++ trunk/Ohana/src/opihi/include/pcontrol.h	(revision 42389)
@@ -341,4 +341,5 @@
 
 void pcontrol_exit (int n);
+void QuitCheckSystemThread (void);
 
 // Job   *FindJobByID (IDtype JobID, int *StackID);
Index: trunk/Ohana/src/opihi/lib.data/svdcmp.c
===================================================================
--- trunk/Ohana/src/opihi/lib.data/svdcmp.c	(revision 42332)
+++ trunk/Ohana/src/opihi/lib.data/svdcmp.c	(revision 42389)
@@ -23,4 +23,5 @@
   l = nm = 0;
   ALLOCATE (rv1, float, Nx);
+
   for (i = 0; i < Nx; i++) {
     l = i + 1;
@@ -29,5 +30,5 @@
     if (i < Ny) {
       for (k = i; k < Ny; k++) scale += fabs(a[k*Nx + i]);
-      if (scale) {
+      if (scale > 0.0) {
 	for (k = i; k < Ny; k++) {
 	  a[k*Nx + i] /= scale;
@@ -35,15 +36,17 @@
 	}
 	f = a[i*Nx + i];
-	g  = -FSIGN(sqrt(s), f);
+	g = sqrt(s);
+	if (f > 0.0) { g = -g; }
 	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];
+	    s = 0.0;
+	    for (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 + j] += f*a[k*Nx + i]; }
 	  }
 	}
-	for (k = i; k < Ny; k++) a[k*Nx + i] *= scale;
+	for (k = i; k < Ny; k++) { a[k*Nx + i] *= scale; }
       }
     }
@@ -51,6 +54,6 @@
     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++) { scale += fabs(a[i*Nx + k]); }
+      if (scale > 0.0) {
 	for (k = l; k < Nx; k++) {
 	  a[i*Nx + k] /= scale;
@@ -58,15 +61,17 @@
 	}
 	f = a[i*Nx + l];
-	g = -FSIGN(sqrt(s), f);
+	g = sqrt(s);
+	if (f > 0.0) { g = -g; }
 	h = f*g - s;
 	a[i*Nx + l] = f-g;
-	for (k = l; k < Nx; k++) rv1[k] = a[i*Nx + k]/h;
+	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];
+	    s = 0.0;
+	    for (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;
+	for (k = l; k < Nx; k++) { a[i*Nx + k] *= scale; }
       }
     }
@@ -76,13 +81,14 @@
   for (i = Nx - 1; i >= 0; i--) {
     if (i < Nx - 1) {
-      if (g) {
+      if (g != 0.0) {
 	/* 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];
+	  s = 0.0;
+	  for (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;
+      for (j = l; j < Nx; j++) { v[i*Nx + j] = v[j*Nx + i] = 0.0; }
     }
     v[i*Nx + i] = 1.0;
@@ -93,20 +99,20 @@
     l = i + 1;
     g = w[i];
-    if (i < Nx - 1)
-      for (j = l; j < Nx; j++) a[i*Nx + j] = 0.0;
-    if (g) {
+    if (i < Nx - 1) { for (j = l; j < Nx; j++) {a[i*Nx + j] = 0.0; }}
+    if (g != 0.0) {
       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];
+	  s = 0.0;
+	  for (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;
+	  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];
+      for (j = i; j < Ny; j++) { a[j*Nx + i] = 0.0; }
+    }
+    a[i*Nx + i] ++;
   }
 
@@ -126,5 +132,5 @@
 	c = 0.0;
 	s = 1.0;
-	for (i = l; i < k; i++) {
+	for (i = l; i <= k; i++) {
 	  f = s*rv1[i];
 	  if (fabs(f)+anorm != anorm) {
@@ -160,7 +166,12 @@
       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;
+      
+      float tmp = g;
+      if (f < 0.0) { tmp = - tmp; }
+
+      f = ((x-z)*(x+z) + h*((y/(f+tmp))-h))/x;
+
       c = s = 1.0;
-      for (j = l; j < nm; j++) {
+      for (j = l; j <= nm; j++) {
 	i = j+1;
 	g = rv1[i];
@@ -184,5 +195,5 @@
 	z = hypot(f, h);
 	w[j] = z;
-	if (z) {
+	if (z != 0.0) {
 	  z = 1.0/z;
 	  c = f*z;
Index: trunk/Ohana/src/opihi/lib.data/svdcmp_bond_new.c
===================================================================
--- trunk/Ohana/src/opihi/lib.data/svdcmp_bond_new.c	(revision 42332)
+++ trunk/Ohana/src/opihi/lib.data/svdcmp_bond_new.c	(revision 42389)
@@ -63,5 +63,5 @@
 			g = 0.0;
 		else {
-			f = u[i][i+1];
+		    f = u[i][i+1]; // XXXX this line will overrun the memory of u[][i+1] : i+1
 			g = (f < 0) ? sqrt(s) : -sqrt(s);
 			h = f * g - s;
Index: trunk/Ohana/src/opihi/lib.shell/VectorIO.c
===================================================================
--- trunk/Ohana/src/opihi/lib.shell/VectorIO.c	(revision 42332)
+++ trunk/Ohana/src/opihi/lib.shell/VectorIO.c	(revision 42389)
@@ -261,5 +261,5 @@
   memset (endptr, ' ', FT_LINE_LENGTH);
 
-  strncpy (endptr, newline, 80);
+  strncpy_nowarn (endptr, newline, 80);
   endptr += FT_LINE_LENGTH;
 
Index: trunk/Ohana/src/opihi/lib.shell/evaluate_stack.c
===================================================================
--- trunk/Ohana/src/opihi/lib.shell/evaluate_stack.c	(revision 42332)
+++ trunk/Ohana/src/opihi/lib.shell/evaluate_stack.c	(revision 42389)
@@ -67,5 +67,9 @@
     if (stack[0].type == ST_VECTOR) {
       /* need to make a copy so we set output value? */
-      V_unary (&tmp_stack, &stack[0], "=");
+      if (stack->vector->type == OPIHI_STR) {
+	L_unary (&tmp_stack, &stack[0], "=");
+      } else {
+	V_unary (&tmp_stack, &stack[0], "=");
+      }
       move_stack (&stack[0], &tmp_stack);
       return (TRUE);
Index: trunk/Ohana/src/opihi/lib.shell/expand_vectors.c
===================================================================
--- trunk/Ohana/src/opihi/lib.shell/expand_vectors.c	(revision 42332)
+++ trunk/Ohana/src/opihi/lib.shell/expand_vectors.c	(revision 42389)
@@ -28,7 +28,21 @@
   ALLOCATE (newline, char, NLINE);
 
+  // special case: don't expand vectors in while () statement
+  char *V0 = thiscomm (line);
+  if (V0 && !strncmp ("while", V0, strlen(V0))) {
+      strcpy (newline, line);
+      free (line);
+      return (newline);
+  }
+  free (V0);
+
   /* look for form fred[stuff] */
-  /* skip first word (command) */
-  L = nextword (line);
+  if (*line == '(') {
+    // if line is "(stuff)" then do not skip first word
+      L = line;
+  } else {
+    /* skip first word (command) */
+    L = nextword (line);
+  }
   if (L == NULL) {
     free (newline);
@@ -37,5 +51,5 @@
 
   n = L - line;
-  strncpy (newline, line, n);
+  strncpy_nowarn (newline, line, n);
   N = newline + n;
   J = 0;
@@ -242,8 +256,8 @@
 
     n = (int) (w - L);
-    strncpy (N, L, n);
+    strncpy_nowarn (N, L, n);
     N += n;
     n = strlen (strValue);
-    strncpy (N, strValue, n);
+    strncpy_nowarn (N, strValue, n);
     N += n;
     L = q + 1;
@@ -260,6 +274,5 @@
 
   n = strlen (L);
-  strncpy (N, L, n);
-  N[n] = 0;
+  strncpy_nowarn (N, L, n);
   free (line);
   return (newline);
Index: trunk/Ohana/src/opihi/lib.shell/stack_math.c
===================================================================
--- trunk/Ohana/src/opihi/lib.shell/stack_math.c	(revision 42332)
+++ trunk/Ohana/src/opihi/lib.shell/stack_math.c	(revision 42389)
@@ -1714,4 +1714,50 @@
   char line[512]; // this is only used to report an error 
   snprintf (line, 512, "error: op %s not defined as unary vector op!", op);
+  push_error (line);
+  return (FALSE);
+
+escape:
+
+  if (V1[0].type == ST_VECTOR_TMP) {
+    free (V1[0].vector[0].elements.Ptr);
+    free (V1[0].vector);
+    V1[0].vector = NULL;
+  }  
+
+  clear_stack (V1);
+  return (TRUE);
+
+}
+
+// vector string operations
+int L_unary (StackVar *OUT, StackVar *V1, char *op) {
+
+  int Nx = V1[0].vector[0].Nelements;
+
+  OUT[0].vector = InitVector ();
+  OUT[0].type = ST_VECTOR_TMP; /*** <<--- says this is a temporary matrix ***/
+
+  ResetVector (OUT[0].vector, OPIHI_STR, V1[0].vector[0].Nelements); 
+  char **Iv =  V1[0].vector[0].elements.Str; 
+  char **Ov = OUT[0].vector[0].elements.Str; 
+  if (!strcmp (op, "=")) {
+    for (int i = 0; i < Nx; i++) {			
+      Ov[i] = strcreate (Iv[i]);
+    }									
+    goto escape;							
+  }
+
+  // free the temp vector if needed
+  if (V1[0].type == ST_VECTOR_TMP) {
+    // XXX this probably does not free the strings
+    free (V1[0].vector[0].elements.Ptr);
+    free (V1[0].vector);
+    V1[0].vector = NULL;
+  }  
+
+  clear_stack (V1);
+
+  char line[512]; // this is only used to report an error 
+  snprintf (line, 512, "error: op %s not defined as unary string vector op!", op);
   push_error (line);
   return (FALSE);
Index: trunk/Ohana/src/opihi/pantasks/controller_status.c
===================================================================
--- trunk/Ohana/src/opihi/pantasks/controller_status.c	(revision 42332)
+++ trunk/Ohana/src/opihi/pantasks/controller_status.c	(revision 42389)
@@ -26,7 +26,7 @@
   }
 
-  snprintf (command, 1024, "status");
+  snprintf_nowarn (command, 1024, "status");
   for (i = 1; i < argc; i++) {
-    snprintf (tmpline, 1024, "%s %s", command, argv[i]);
+    snprintf_nowarn (tmpline, 1024, "%s %s", command, argv[i]);
     strcpy (command, tmpline);
   }
Index: trunk/Ohana/src/opihi/pantasks/pantasks_server.c.in
===================================================================
--- trunk/Ohana/src/opihi/pantasks/pantasks_server.c.in	(revision 42332)
+++ trunk/Ohana/src/opihi/pantasks/pantasks_server.c.in	(revision 42389)
@@ -138,4 +138,8 @@
   ConfigFree ();
 
+  // XXX this function is currently called by the thread running ListenClients, but
+  // it should be called by the main above.  have this function trigger the
+  // thread shutdown 
+
   QuitJobsAndTasksThread(); pthread_join (JobsAndTasksThread, NULL);
   QuitControllerThread();   pthread_join (controllerThread, NULL);
Index: trunk/Ohana/src/opihi/pcontrol/CheckSystem.c
===================================================================
--- trunk/Ohana/src/opihi/pcontrol/CheckSystem.c	(revision 42332)
+++ trunk/Ohana/src/opihi/pcontrol/CheckSystem.c	(revision 42389)
@@ -4,4 +4,11 @@
 static struct timeval lastlive = {0, 0};
 static RunLevels RunLevel = PCONTROL_RUN_NONE;
+
+static int CheckSystemThreadRuns = TRUE;
+
+void QuitCheckSystemThread (void) {
+  CheckSystemThreadRuns = FALSE;  
+}
+
 
 RunLevels SetRunLevel (RunLevels level) {
@@ -67,5 +74,5 @@
   gprintInit ();
 
-  while (1) {
+  while (CheckSystemThreadRuns) {
     // stop here if the user-thread requests (no objects in flight) 
     TestCheckPoint ();
Index: trunk/Ohana/src/opihi/pcontrol/pcontrol.c.in
===================================================================
--- trunk/Ohana/src/opihi/pcontrol/pcontrol.c.in	(revision 42332)
+++ trunk/Ohana/src/opihi/pcontrol/pcontrol.c.in	(revision 42389)
@@ -9,4 +9,8 @@
 # define opihi_rcfile ".pcontrolrc"
 
+# ifdef THREADED  
+  static pthread_t clientsThread;
+# endif
+
 /* program-dependent initialization */
 void program_init (int *argc, char **argv) {
@@ -14,8 +18,4 @@
   OHANA_UNUSED_PARAM(argv);
   
-# ifdef THREADED  
-  pthread_t clientsThread;
-# endif
-
   auto_break = TRUE;
 
@@ -83,6 +83,8 @@
   SetRunLevel (PCONTROL_RUN_HOSTS); 
   DownHosts ();
+
+  QuitCheckSystemThread(); pthread_join (clientsThread, NULL);
+
   ConfigFree ();
-
   FreeBasic ();
   FreePcontrol ();
Index: trunk/Ohana/src/opihi/pcontrol/test/linesize.sh
===================================================================
--- trunk/Ohana/src/opihi/pcontrol/test/linesize.sh	(revision 42332)
+++ trunk/Ohana/src/opihi/pcontrol/test/linesize.sh	(revision 42389)
@@ -27,5 +27,5 @@
 
   for i 1 10
-    job echo $inline7
+    job echo $inline6
   end
 
@@ -34,5 +34,5 @@
   for i 1 10
     stdout $i -var outline
-    strlen "$inline7" Nin
+    strlen "$inline6" Nin
     strlen "$outline" Nout
 
Index: trunk/Ohana/src/opihi/test/tap.tp
===================================================================
--- trunk/Ohana/src/opihi/test/tap.tp	(revision 42389)
+++ trunk/Ohana/src/opihi/test/tap.tp	(revision 42389)
@@ -0,0 +1,61 @@
+
+macro plan
+ if ($0 != 2)
+  echo "USAGE: plan (Ntest)"
+  break
+ end
+
+ $tap_Nplan = $1
+ $tap_Npass = 0
+ $tap_Nfail = 0
+ $tap_Ntest = 0
+end
+
+macro done
+ if (not($?tap_Nplan))
+  echo "ERROR: tap tests not planned"
+  break
+ end
+
+ echo "planned $tap_Nplan tests, ran $tap_Ntest"
+ echo "passed $tap_Npass tests, failed $tap_Nfail tests"
+
+ if (($tap_Nfail == 0) && ($tap_Ntest == $tap_Nplan) && ($tap_Npass == $tap_Ntest))
+   echo "PASS: all tests run and passed"
+   return 1
+ end
+
+ if ($tap_Nfail > 0)
+   echo "FAIL: $tap_Nfail tests failed"
+ end
+
+ if ($tap_Ntest != $tap_Nplan)
+   echo "FAIL: not all tests run"
+ end
+
+ if ($tap_Ntest != $tap_Npass + $tap_Nfail)
+   echo "FAIL: inconsistent count: $tap_Ntest tests != $tap_Npass pass + $tap_Nfail fail"
+ end
+end
+
+macro ok
+ if ($0 != 3)
+  echo "USAGE (condition) (label)"
+  break
+ end
+ 
+ if (not($?tap_Nplan))
+  echo "ERROR: tap tests not planned"
+  break
+ end
+ 
+ if ($1)
+  echo "OK: $2"
+  $tap_Npass ++
+ else     
+  echo "not OK: $2"
+  $tap_Nfail ++
+ end
+ $tap_Ntest ++
+end
+
Index: trunk/Ohana/src/opihi/test/tests.sh
===================================================================
--- trunk/Ohana/src/opihi/test/tests.sh	(revision 42332)
+++ trunk/Ohana/src/opihi/test/tests.sh	(revision 42389)
@@ -53,5 +53,5 @@
   for Tj 0 $testscripts:n
     if ($VERBOSE > 1)
-      echo " running $testscripts:$Tj"
+      echo " ----- running $testscripts:$Tj -----"
     end
     runtests $testscripts:$Tj      
