Index: /trunk/Ohana/src/opihi/cmd.astro/coords.c
===================================================================
--- /trunk/Ohana/src/opihi/cmd.astro/coords.c	(revision 29539)
+++ /trunk/Ohana/src/opihi/cmd.astro/coords.c	(revision 29540)
@@ -109,4 +109,5 @@
   gprint (GP_ERR, " -p : from pixels to ra/dec\n");
   gprint (GP_ERR, " -c : from ra/dec to pixels\n");
+  gprint (GP_ERR, " coordinates are in degrees\n");
  escape:
   if (MOSAIC != NULL) free (MOSAIC);
Index: /trunk/Ohana/src/opihi/cmd.basic/fprintf.c
===================================================================
--- /trunk/Ohana/src/opihi/cmd.basic/fprintf.c	(revision 29539)
+++ /trunk/Ohana/src/opihi/cmd.basic/fprintf.c	(revision 29540)
@@ -40,5 +40,9 @@
     switch (*p1) {
       case 'e':
+      case 'g':
       case 'f':
+      case 'E':
+      case 'F':
+      case 'G':
 	sprintf (tmp, fmt, atof(argv[i]));
 	break;
@@ -47,10 +51,14 @@
 	break;
       case 'd':
+      case 'o':
+      case 'i':
+      case 'u':
       case 'c':
       case 'x':
+      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");
+	gprint (GP_ERR, "syntax error in format (e,f,g,E,F,G,c,s,d,i,o,x,X conversions allowed)\n");
 	return (FALSE);
     }
Index: /trunk/Ohana/src/opihi/cmd.data/Makefile
===================================================================
--- /trunk/Ohana/src/opihi/cmd.data/Makefile	(revision 29539)
+++ /trunk/Ohana/src/opihi/cmd.data/Makefile	(revision 29540)
@@ -102,5 +102,6 @@
 $(SRC)/read_vectors.$(ARCH).o	\
 $(SRC)/rebin.$(ARCH).o		\
-$(SRC)/resize.$(ARCH).o	\
+$(SRC)/reindex.$(ARCH).o	\
+$(SRC)/resize.$(ARCH).o		\
 $(SRC)/relocate.$(ARCH).o	\
 $(SRC)/roll.$(ARCH).o		\
Index: /trunk/Ohana/src/opihi/cmd.data/center.c
===================================================================
--- /trunk/Ohana/src/opihi/cmd.data/center.c	(revision 29539)
+++ /trunk/Ohana/src/opihi/cmd.data/center.c	(revision 29540)
@@ -16,4 +16,6 @@
   if (!GetImage (NULL, &kapa, name)) return (FALSE);
   FREE (name);
+
+  // XXX need an option to center the image based on the current plot limits
 
   if ((argc != 3) && (argc != 4)) {
Index: /trunk/Ohana/src/opihi/cmd.data/init.c
===================================================================
--- /trunk/Ohana/src/opihi/cmd.data/init.c	(revision 29539)
+++ /trunk/Ohana/src/opihi/cmd.data/init.c	(revision 29540)
@@ -91,4 +91,5 @@
 int rebin            PROTO((int, char **));
 int resize           PROTO((int, char **));
+int reindex          PROTO((int, char **));
 int relocate         PROTO((int, char **));
 int roll             PROTO((int, char **));
@@ -232,4 +233,5 @@
   {1, "read",         read_vectors,     "read vectors from datafile"},
   {1, "rebin",        rebin,            "rebin image data by factor of N"},
+  {1, "reindex",      reindex,          "create new vector from old vector based on index vector"},
   {1, "resize",       resize,           "set graphics/image window size"},
   {1, "relocate",     relocate,         "set graphics/image window position"},
Index: /trunk/Ohana/src/opihi/cmd.data/limits.c
===================================================================
--- /trunk/Ohana/src/opihi/cmd.data/limits.c	(revision 29539)
+++ /trunk/Ohana/src/opihi/cmd.data/limits.c	(revision 29540)
@@ -24,4 +24,6 @@
   if (!GetGraph (&graphmode, &kapa, name)) return (FALSE);
   FREE (name);
+
+  // XXX need an option to set the limits based on the current image bounds
 
   if (argc == 1) {
Index: /trunk/Ohana/src/opihi/cmd.data/read_vectors.c
===================================================================
--- /trunk/Ohana/src/opihi/cmd.data/read_vectors.c	(revision 29539)
+++ /trunk/Ohana/src/opihi/cmd.data/read_vectors.c	(revision 29540)
@@ -216,5 +216,12 @@
 
     while (1) {
-      if (!gfits_load_header (f, &header)) ESCAPE ("extension not found in file");
+      if (!gfits_load_header (f, &header)) {
+	gprint (GP_ERR, "extension %s not found in file\n", extname);
+	if (CCDKeyword != NULL) free (CCDKeyword); 
+	gfits_free_table  (&table); 
+	gfits_free_header (&header); 
+	return (TRUE);  
+      }
+
       Nbytes = gfits_data_size (&header);
 
Index: /trunk/Ohana/src/opihi/cmd.data/reindex.c
===================================================================
--- /trunk/Ohana/src/opihi/cmd.data/reindex.c	(revision 29540)
+++ /trunk/Ohana/src/opihi/cmd.data/reindex.c	(revision 29540)
@@ -0,0 +1,66 @@
+# include "data.h"
+
+# define ESCAPE(MSG,...){ gprint (GP_ERR, MSG, __VA_ARGS__); goto error; } 
+
+int reindex (int argc, char **argv) {
+  
+  int  i, Npts, Nmax, valid;
+  Vector *ivec, *ovec, *xvec;
+
+  ivec = ovec = xvec = NULL;
+  Npts = 0;
+
+  valid = TRUE;
+  valid &= (argc >= 6);
+  valid &= !strcmp(argv[2], "=");
+  valid &= !strcmp(argv[4], "using");
+  if (!valid) {
+    gprint (GP_ERR, "USAGE: reindex (out) = (in) using (index)\n");
+    gprint (GP_ERR, "  creates a new vectors (out) from (in) based on sequence in (index)\n");
+    return (FALSE);
+  }
+
+  if ((ovec = SelectVector (argv[1], ANYVECTOR, TRUE)) == NULL) goto error;
+  if ((ivec = SelectVector (argv[3], OLDVECTOR, TRUE)) == NULL) goto error;
+  if ((xvec = SelectVector (argv[5], OLDVECTOR, TRUE)) == NULL) goto error;
+
+  if (xvec->type != OPIHI_INT) ESCAPE("%s\n", "index is not an integer?");
+
+  // ovec matches ivec in type and xvec in size (xvec need not have all ivec elements, and may have duplicates
+  ResetVector (ovec, ivec->type, MAX (xvec[0].Nelements, 1));
+
+  Nmax = ivec[0].Nelements - 1;
+
+  // we have two cases: (ivec == flt or int)
+  if (ivec->type == OPIHI_FLT) {
+    opihi_flt *vi = ivec[0].elements.Flt;
+    opihi_int *vx = xvec[0].elements.Int;
+    for (Npts = i = 0; i < xvec[0].Nelements; i++, vx++) {
+      if (*vx == -1) continue;
+      if (*vx < 0) ESCAPE("unexpected value in index: %d (%d)\n", *vx, i);
+      if (*vx > Nmax) ESCAPE("unexpected value in index: %d (%d)\n", *vx, i);
+      ovec[0].elements.Flt[Npts] = vi[*vx];
+      Npts++;
+    }
+  }
+  if (ivec->type == OPIHI_INT) {
+    opihi_int *vi = ivec[0].elements.Int;
+    opihi_int *vx = xvec[0].elements.Int;
+    for (Npts = i = 0; i < xvec[0].Nelements; i++, vx++) {
+      if (*vx == -1) continue;
+      if (*vx < 0) ESCAPE("unexpected value in index: %d (%d)\n", *vx, i);
+      if (*vx > Nmax) ESCAPE("unexpected value in index: %d (%d)\n", *vx, i);
+      ovec[0].elements.Int[Npts] = vi[*vx];
+      Npts++;
+    }
+  }
+
+  // free up unused memory
+  ResetVector (ovec, ivec->type, MAX (Npts, 1));
+  return (TRUE);
+
+error:
+  DeleteVector (ovec);
+  return (FALSE);
+}
+
Index: /trunk/Ohana/src/opihi/cmd.data/svd.c
===================================================================
--- /trunk/Ohana/src/opihi/cmd.data/svd.c	(revision 29539)
+++ /trunk/Ohana/src/opihi/cmd.data/svd.c	(revision 29540)
@@ -82,6 +82,6 @@
       }
 
-# if 0     
-      status = svdcmp_bond_raw (Ny, Nx, 1, 1, FLT_EPSILON, 1e-6, a, q, u, v);
+# if 1     
+      status = svdcmp_bond_new (Ny, Nx, 1, 1, FLT_EPSILON, 1e-6, a, q, u, v);
       fprintf (stderr, "status: %d\n", status);
 # else
Index: /trunk/Ohana/src/opihi/dvo/LoadImages.c
===================================================================
--- /trunk/Ohana/src/opihi/dvo/LoadImages.c	(revision 29539)
+++ /trunk/Ohana/src/opihi/dvo/LoadImages.c	(revision 29540)
@@ -75,4 +75,5 @@
     lastModified = getLastModified(filename);
   }
+
   return (image);
 }
Index: /trunk/Ohana/src/opihi/dvo/badimages.c
===================================================================
--- /trunk/Ohana/src/opihi/dvo/badimages.c	(revision 29539)
+++ /trunk/Ohana/src/opihi/dvo/badimages.c	(revision 29540)
@@ -70,5 +70,5 @@
   }
   
+  FreeImages(image);
   return (TRUE);
-
 }
Index: /trunk/Ohana/src/opihi/dvo/imdata.c
===================================================================
--- /trunk/Ohana/src/opihi/dvo/imdata.c	(revision 29539)
+++ /trunk/Ohana/src/opihi/dvo/imdata.c	(revision 29540)
@@ -222,4 +222,5 @@
   vec[0].Nelements = N;
   REALLOCATE (vec[0].elements.Flt, opihi_flt, MAX(1,N));
+  FreeImages(image);
   return (TRUE);
 }
Index: /trunk/Ohana/src/opihi/dvo/imlist.c
===================================================================
--- /trunk/Ohana/src/opihi/dvo/imlist.c	(revision 29539)
+++ /trunk/Ohana/src/opihi/dvo/imlist.c	(revision 29540)
@@ -108,6 +108,6 @@
   }
 
+  FreeImages(image);
   free (subset);
-  free (image);
   return (TRUE);
 }
Index: /trunk/Ohana/src/opihi/dvo/imphot.c
===================================================================
--- /trunk/Ohana/src/opihi/dvo/imphot.c	(revision 29539)
+++ /trunk/Ohana/src/opihi/dvo/imphot.c	(revision 29540)
@@ -92,5 +92,5 @@
   }
 
-  free (image);
+  FreeImages(image);
   free (subset);
   return (TRUE);
Index: /trunk/Ohana/src/opihi/dvo/imstats.c
===================================================================
--- /trunk/Ohana/src/opihi/dvo/imstats.c	(revision 29539)
+++ /trunk/Ohana/src/opihi/dvo/imstats.c	(revision 29540)
@@ -58,4 +58,5 @@
   free (Xvec.elements.Flt);
   free (Yvec.elements.Flt);
+  FreeImages (image);
   return (TRUE);
 }
Index: /trunk/Ohana/src/opihi/dvo/skycoverage.c
===================================================================
--- /trunk/Ohana/src/opihi/dvo/skycoverage.c	(revision 29539)
+++ /trunk/Ohana/src/opihi/dvo/skycoverage.c	(revision 29540)
@@ -179,5 +179,8 @@
   PutCoords (&coords, &buf[0].header);
 
-  if ((image = LoadImages (&Nimage)) == NULL) return (FALSE);
+  image = LoadImages(&Nimage);
+  if (image == NULL) {
+      return (FALSE);
+  }
   BuildChipMatch (image, Nimage);
 
@@ -251,6 +254,5 @@
     }
   }
-
-  free (image);
+  FreeImages(image);
   return (TRUE);
 }
Index: /trunk/Ohana/src/opihi/dvo/subpix.c
===================================================================
--- /trunk/Ohana/src/opihi/dvo/subpix.c	(revision 29539)
+++ /trunk/Ohana/src/opihi/dvo/subpix.c	(revision 29540)
@@ -147,8 +147,8 @@
 
   dvo_catalog_free (&catalog);
-  free (image);
   free (index);
   SkyListFree (skylist);
 
+  FreeImages(image);
   return (TRUE);
 }
Index: /trunk/Ohana/src/opihi/include/data.h
===================================================================
--- /trunk/Ohana/src/opihi/include/data.h	(revision 29539)
+++ /trunk/Ohana/src/opihi/include/data.h	(revision 29540)
@@ -92,4 +92,7 @@
 int svdcmp_bond_raw(int m, int n, int withu, int withv, double eps, double tol, double **a, double *q, double **u, double **v);
 
+/* in svdcmp_bond_new.c */
+int svdcmp_bond_new(int m, int n, int withu, int withv, double eps, double tol, double **a, double *q, double **u, double **v);
+
 /* mrqmin.c */
 opihi_flt mrqcof (opihi_flt *x, opihi_flt *y, opihi_flt *dy, int Npts, 
Index: /trunk/Ohana/src/opihi/include/pcontrol.h
===================================================================
--- /trunk/Ohana/src/opihi/include/pcontrol.h	(revision 29539)
+++ /trunk/Ohana/src/opihi/include/pcontrol.h	(revision 29540)
@@ -115,4 +115,6 @@
   char        *hostname;
   char        *realhost;
+  char       **xhosts;
+  int          Nxhosts;
   int          exit_status;
   int          Reset;
@@ -289,5 +291,5 @@
 Job   *PullJobByID (IDtype JobID, int *StackID);
 Job   *PullJobFromStackByID (int StackID, int ID);
-IDtype AddJob (char *hostname, JobMode mode, int timeout, int argc, char **argv);
+IDtype AddJob (char *hostname, JobMode mode, int timeout, int argc, char **argv, int Nxhosts, char **xhosts);
 void   DelJob (Job *job);
 Host  *UnlinkJobAndHost (Job *job);
Index: /trunk/Ohana/src/opihi/lib.data/Makefile
===================================================================
--- /trunk/Ohana/src/opihi/lib.data/Makefile	(revision 29539)
+++ /trunk/Ohana/src/opihi/lib.data/Makefile	(revision 29540)
@@ -20,4 +20,5 @@
 $(SDIR)/fft.$(ARCH).o			\
 $(SDIR)/svdcmp.$(ARCH).o		\
+$(SDIR)/svdcmp_bond_new.$(ARCH).o		\
 $(SDIR)/convert.$(ARCH).o		\
 $(SDIR)/bracket.$(ARCH).o		\
Index: /trunk/Ohana/src/opihi/lib.data/svdcmp_bond_new.c
===================================================================
--- /trunk/Ohana/src/opihi/lib.data/svdcmp_bond_new.c	(revision 29540)
+++ /trunk/Ohana/src/opihi/lib.data/svdcmp_bond_new.c	(revision 29540)
@@ -0,0 +1,246 @@
+# include "data.h"
+
+/*  svd.c -- Singular value decomposition. Translated to 'C' from the
+ *           original Algol code in "Handbook for Automatic Computation,
+ *           vol. II, Linear Algebra", Springer-Verlag.
+ *
+ *  (C) 2000, C. Bond. All rights reserved.
+ *
+ *  This is almost an exact translation from the original, except that
+ *  an iteration counter is added to prevent stalls. This corresponds
+ *  to similar changes in other translations.
+ *
+ *  Returns an error code = 0, if no errors and 'k' if a failure to
+ *  converge at the 'kth' singular value.
+ * 
+ */
+
+int svdcmp_bond_new(int m, int n, int withu, int withv, double eps, double tol, double **a, double *q, double **u, double **v)
+{
+	int i,j,k,l,l1,iter,retval;
+	double c,f,g,h,s,x,y,z;
+	double *e;
+
+	ALLOCATE (e, double, n);
+	memset (e, 0, n*sizeof(double));
+	retval = 0;
+
+/* Copy 'a' to 'u' */    
+	for (i=0;i<m;i++) {
+		for (j=0;j<n;j++)
+			u[i][j] = a[i][j];
+	}
+/* Householder's reduction to bidiagonal form. */
+	g = x = 0.0;    
+	l = 0;
+	for (i=0;i<n;i++) {
+		e[i] = g;
+		s = 0.0;
+		l = i+1;
+		for (j=i;j<m;j++)
+			s += (u[j][i]*u[j][i]);
+		if (s < tol)
+			g = 0.0;
+		else {
+			f = u[i][i];
+			g = (f < 0) ? sqrt(s) : -sqrt(s);
+			h = f * g - s;
+			u[i][i] = f - g;
+			for (j=l;j<n;j++) {
+				s = 0.0;
+				for (k=i;k<m;k++)
+					s += (u[k][i] * u[k][j]);
+				f = s / h;
+				for (k=i;k<m;k++)
+					u[k][j] += (f * u[k][i]);
+			} /* end j */
+		} /* end s */
+		q[i] = g;
+		s = 0.0;
+		for (j=l;j<n;j++)
+			s += (u[i][j] * u[i][j]);
+		if (s < tol)
+			g = 0.0;
+		else {
+			f = u[i][i+1];
+			g = (f < 0) ? sqrt(s) : -sqrt(s);
+			h = f * g - s;
+			u[i][i+1] = f - g;
+			for (j=l;j<n;j++) 
+				e[j] = u[i][j]/h;
+			for (j=l;j<m;j++) {
+				s = 0.0;
+				for (k=l;k<n;k++) 
+					s += (u[j][k] * u[i][k]);
+				for (k=l;k<n;k++)
+					u[j][k] += (s * e[k]);
+			} /* end j */
+		} /* end s */
+		y = fabs(q[i]) + fabs(e[i]);                         
+		if (y > x)
+			x = y;
+	} /* end i */
+
+/* accumulation of right-hand transformations */
+	if (withv) {
+		for (i=n-1;i>=0;i--) {
+			if (g != 0.0) {
+				h = u[i][i+1] * g;
+				for (j=l;j<n;j++)
+					v[j][i] = u[i][j]/h;
+				for (j=l;j<n;j++) {
+					s = 0.0;
+					for (k=l;k<n;k++) 
+						s += (u[i][k] * v[k][j]);
+					for (k=l;k<n;k++)
+						v[k][j] += (s * v[k][i]);
+
+				} /* end j */
+			} /* end g */
+			for (j=l;j<n;j++)
+				v[i][j] = v[j][i] = 0.0;
+			v[i][i] = 1.0;
+			g = e[i];
+			l = i;
+		} /* end i */
+ 
+	} /* end withv, parens added for clarity */
+
+/* accumulation of left-hand transformations */
+	if (withu) {
+		for (i=n;i<m;i++) {
+			for (j=n;j<m;j++)
+				u[i][j] = 0.0;
+			u[i][i] = 1.0;
+		}
+	}
+	if (withu) {
+		for (i=n-1;i>=0;i--) {
+			l = i + 1;
+			g = q[i];
+			for (j=l;j<m;j++)  /* upper limit was 'n' */
+				u[i][j] = 0.0;
+			if (g != 0.0) {
+				h = u[i][i] * g;
+				for (j=l;j<m;j++) { /* upper limit was 'n' */
+					s = 0.0;
+					for (k=l;k<m;k++)
+						s += (u[k][i] * u[k][j]);
+					f = s / h;
+					for (k=i;k<m;k++) 
+						u[k][j] += (f * u[k][i]);
+				} /* end j */
+				for (j=i;j<m;j++) 
+					u[j][i] /= g;
+			} /* end g */
+			else {
+				for (j=i;j<m;j++)
+					u[j][i] = 0.0;
+			}
+			u[i][i] += 1.0;
+		} /* end i*/
+	} /* end withu, parens added for clarity */
+
+/* diagonalization of the bidiagonal form */
+	eps *= x;
+	for (k=n-1;k>=0;k--) {
+		iter = 0;
+test_f_splitting:
+		for (l=k;l>=0;l--) {
+			if (fabs(e[l]) <= eps) goto test_f_convergence;
+			if (fabs(q[l-1]) <= eps) goto cancellation;
+		} /* end l */
+
+/* cancellation of e[l] if l > 0 */
+cancellation:
+		c = 0.0;
+		s = 1.0;
+		l1 = l - 1;
+		for (i=l;i<=k;i++) {
+			f = s * e[i];
+			e[i] *= c;
+			if (fabs(f) <= eps) goto test_f_convergence;
+			g = q[i];
+			h = q[i] = sqrt(f*f + g*g);
+			c = g / h;
+			s = -f / h;
+			if (withu) {
+				for (j=0;j<m;j++) {
+					y = u[j][l1];
+					z = u[j][i];
+					u[j][l1] = y * c + z * s;
+					u[j][i] = -y * s + z * c;
+				} /* end j */
+			} /* end withu, parens added for clarity */
+		} /* end i */
+test_f_convergence:
+		z = q[k];
+		if (l == k) goto convergence;
+
+/* shift from bottom 2x2 minor */
+		iter++;
+		if (iter > 30) {
+			retval = k;
+			break;
+		}
+		x = q[l];
+		y = q[k-1];
+		g = e[k-1];
+		h = e[k];
+		f = ((y-z)*(y+z) + (g-h)*(g+h)) / (2*h*y);
+		g = sqrt(f*f + 1.0);
+		f = ((x-z)*(x+z) + h*(y/((f<0)?(f-g):(f+g))-h))/x;
+/* next QR transformation */
+		c = s = 1.0;
+		for (i=l+1;i<=k;i++) {
+			g = e[i];
+			y = q[i];
+			h = s * g;
+			g *= c;
+			e[i-1] = z = sqrt(f*f+h*h);
+			c = f / z;
+			s = h / z;
+			f = x * c + g * s;
+			g = -x * s + g * c;
+			h = y * s;
+			y *= c;
+			if (withv) {
+				for (j=0;j<n;j++) {
+					x = v[j][i-1];
+					z = v[j][i];
+					v[j][i-1] = x * c + z * s;
+					v[j][i] = -x * s + z * c;
+				} /* end j */
+			} /* end withv, parens added for clarity */
+			q[i-1] = z = sqrt(f*f + h*h);
+			c = f/z;
+			s = h/z;
+			f = c * g + s * y;
+			x = -s * g + c * y;
+			if (withu) {
+				for (j=0;j<m;j++) {
+					y = u[j][i-1];
+					z = u[j][i];
+					u[j][i-1] = y * c + z * s;
+					u[j][i] = -y * s + z * c;
+				} /* end j */
+			} /* end withu, parens added for clarity */
+		} /* end i */
+		e[l] = 0.0;
+		e[k] = f;
+		q[k] = x;
+		goto test_f_splitting;
+convergence:
+		if (z < 0.0) {
+/* q[k] is made non-negative */
+			q[k] = - z;
+			if (withv) {
+				for (j=0;j<n;j++)
+					v[j][k] = -v[j][k];
+			} /* end withv, parens added for clarity */
+		} /* end z */
+	} /* end k */
+	
+	free(e);
+	return retval;
+}
Index: /trunk/Ohana/src/opihi/pcontrol/CheckIdleHost.c
===================================================================
--- /trunk/Ohana/src/opihi/pcontrol/CheckIdleHost.c	(revision 29539)
+++ /trunk/Ohana/src/opihi/pcontrol/CheckIdleHost.c	(revision 29540)
@@ -60,4 +60,6 @@
     if (strcasecmp (job[0].hostname, host[0].hostname)) continue;
 
+    if (!CheckMachineJobs (host, job)) continue;
+
     /* we have found an appropriate job; link it to the host and send to StartJob */
     job[0].host = (struct Host *) host;
@@ -80,4 +82,6 @@
     ASSERT (job[0].hostname != NULL, "WANTHOST hostname missing");
     if (strcasecmp (job[0].hostname, host[0].hostname)) continue;
+
+    if (!CheckMachineJobs (host, job)) continue;
 
     /* we have found an appropriate job; link it to the host and send to StartJob */
Index: /trunk/Ohana/src/opihi/pcontrol/JobOps.c
===================================================================
--- /trunk/Ohana/src/opihi/pcontrol/JobOps.c	(revision 29539)
+++ /trunk/Ohana/src/opihi/pcontrol/JobOps.c	(revision 29540)
@@ -195,5 +195,5 @@
 }
 
-IDtype AddJob (char *hostname, JobMode mode, int timeout, int argc, char **argv) {
+IDtype AddJob (char *hostname, JobMode mode, int timeout, int argc, char **argv, int Nxhosts, char **xhosts) {
 
   int JobID;
@@ -228,4 +228,7 @@
   job[0].host     = NULL;
 
+  job[0].xhosts = xhosts;
+  job[0].Nxhosts = Nxhosts;
+
   JobID = job[0].JobID;
 
@@ -257,4 +260,9 @@
   FREE (job[0].argv);
 
+  for (i = 0; i < job[0].Nxhosts; i++) {
+    FREE (job[0].xhosts[i]);
+  }
+  FREE (job[0].xhosts);
+
   FreeIOBuffer (&job[0].stdout_buf.buffer);
   FreeIOBuffer (&job[0].stderr_buf.buffer);
Index: /trunk/Ohana/src/opihi/pcontrol/MachineOps.c
===================================================================
--- /trunk/Ohana/src/opihi/pcontrol/MachineOps.c	(revision 29539)
+++ /trunk/Ohana/src/opihi/pcontrol/MachineOps.c	(revision 29540)
@@ -1,3 +1,4 @@
 # include "pcontrol.h"
+# define DEBUG 0
 
 static int MAX_UNWANTED_HOST_JOBS = 5;
@@ -107,4 +108,5 @@
 int AddMachineJob (Host *host, Job *job) {
 
+  int i;
   Machine *machine;
 
@@ -114,7 +116,14 @@
   machine[0].NjobsRealhost ++;
 
-  // skip jobs that do not have a targeted host
-  if (job[0].hostname == NULL) {
-    return (TRUE);
+  // skip jobs that do not have a targeted host or any xhosts
+  if (!job[0].hostname && !job[0].Nxhosts) {
+    return (TRUE);
+  }
+
+  for (i = 0; i < job[0].Nxhosts; i++) {
+    // find machine matching the xhost name (these count against the unwanted host total)
+    machine = FindMachineByName (job[0].xhosts[i]); // Can this fail?
+    if (!machine) continue;
+    machine[0].NjobsWanthost ++;
   }
 
@@ -134,4 +143,5 @@
 int DelMachineJob (Host *host, Job *job) {
 
+  int i;
   Machine *machine;
 
@@ -141,7 +151,14 @@
   machine[0].NjobsRealhost --;
 
-  // skip jobs that do not have a targeted host
-  if (job[0].hostname == NULL) {
-    return (TRUE);
+  // skip jobs that do not have a targeted host or any xhosts
+  if (!job[0].hostname && !job[0].Nxhosts) {
+    return (TRUE);
+  }
+
+  for (i = 0; i < job[0].Nxhosts; i++) {
+    // find machine matching the xhost name (these count against the unwanted host total)
+    machine = FindMachineByName (job[0].xhosts[i]); // Can this fail?
+    if (!machine) continue;
+    machine[0].NjobsWanthost --;
   }
 
@@ -175,21 +192,36 @@
 int CheckMachineJobs (Host *host, Job *job) {
 
+  int i;
   Machine *machine;
 
   machine = FindMachineByName (job[0].hostname);
-  if (machine == NULL) return (TRUE);
-  // fprintf (stderr, "wanthost: %s, Ntotal: %d, Nmax: %d\n", job[0].hostname, machine[0].NjobsWanthost + machine[0].NjobsRealhost, machine[0].Nhosts + MAX_UNWANTED_HOST_JOBS);
-  // if (machine[0].NjobsWanthost + machine[0].NjobsRealhost >= machine[0].Nhosts + MAX_UNWANTED_HOST_JOBS) {
-  if (machine[0].NjobsWanthost >= MAX_UNWANTED_HOST_JOBS) {
-    // fprintf (stderr, "too many outstanding jobs wanting host %s, delay job %s for now\n", job[0].hostname, job[0].argv[0]);
-    return (FALSE);
-  }
+  if (machine) {
+    if (DEBUG) fprintf (stderr, "wanthost: %s, Ntotal: %d, Nmax: %d\n", machine[0].name, machine[0].NjobsWanthost + machine[0].NjobsRealhost, machine[0].Nhosts + MAX_UNWANTED_HOST_JOBS);
+    if (machine[0].NjobsWanthost >= MAX_UNWANTED_HOST_JOBS) {
+      if (DEBUG) fprintf (stderr, "too many outstanding jobs wanting host %s, delay job %s for now\n", machine[0].name, job[0].argv[0]);
+      return (FALSE);
+    }
+  }
+
+  for (i = 0; i < job[0].Nxhosts; i++) {
+    machine = FindMachineByName (job[0].xhosts[i]);
+    if (machine) {
+      if (DEBUG) fprintf (stderr, "xhost: %s, Ntotal: %d, Nmax: %d\n", machine[0].name, machine[0].NjobsWanthost + machine[0].NjobsRealhost, machine[0].Nhosts + MAX_UNWANTED_HOST_JOBS);
+      if (machine[0].NjobsWanthost >= MAX_UNWANTED_HOST_JOBS) {
+	if (DEBUG) fprintf (stderr, "too many outstanding jobs wanting host %s, delay job %s for now\n", machine[0].name, job[0].argv[0]);
+	return (FALSE);
+      }
+    }
+  }    
 
   machine = FindMachineByName (host[0].hostname);
-  // fprintf (stderr, "realhost: %s, Ntotal: %d, Nmax: %d\n", host[0].hostname, machine[0].NjobsWanthost + machine[0].NjobsRealhost, machine[0].Nhosts + MAX_UNWANTED_HOST_JOBS);
-  if (machine[0].NjobsWanthost >= MAX_UNWANTED_HOST_JOBS) {
-    // fprintf (stderr, "too many outstanding jobs wanting host %s, delay job %s for now\n", job[0].hostname, job[0].argv[0]);
-    return (FALSE);
-  }
+  if (machine) {
+    if (DEBUG) fprintf (stderr, "realhost: %s, Ntotal: %d, Nmax: %d\n", machine[0].name, machine[0].NjobsWanthost + machine[0].NjobsRealhost, machine[0].Nhosts + MAX_UNWANTED_HOST_JOBS);
+    if (machine[0].NjobsWanthost >= MAX_UNWANTED_HOST_JOBS) {
+      if (DEBUG) fprintf (stderr, "too many outstanding jobs wanting host %s, delay job %s for now\n", machine[0].name, job[0].argv[0]);
+      return (FALSE);
+    }
+  }
+
   return (TRUE);
 }
Index: /trunk/Ohana/src/opihi/pcontrol/job.c
===================================================================
--- /trunk/Ohana/src/opihi/pcontrol/job.c	(revision 29539)
+++ /trunk/Ohana/src/opihi/pcontrol/job.c	(revision 29540)
@@ -6,4 +6,6 @@
   int i, N, Mode, targc, Timeout;
   IDtype JobID;
+  char **xhosts;
+  int Nxhosts, NXHOSTS;
 
   if (get_argument (argc, argv, "-host") && get_argument (argc, argv, "+host")) {
@@ -39,4 +41,21 @@
   }
 
+  xhosts = NULL;
+  Nxhosts = 0;
+  NXHOSTS = 10;
+  while ((N = get_argument (argc, argv, "-xhost"))) {
+    if (xhosts == NULL) {
+      ALLOCATE (xhosts, char *, NXHOSTS);
+    }
+    remove_argument (N, &argc, argv);
+    xhosts[Nxhosts] = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+    Nxhosts ++;
+    if (Nxhosts == NXHOSTS) {
+      NXHOSTS += 10;
+      REALLOCATE (xhosts, char *, NXHOSTS);
+    }
+  }
+
   if (argc < 2) {
     FREE (Host);
@@ -51,5 +70,5 @@
 
   // a JobID < 0 mean the job was not accepted
-  JobID = AddJob (Host, Mode, Timeout, targc, targv);
+  JobID = AddJob (Host, Mode, Timeout, targc, targv, Nxhosts, xhosts);
   gprint (GP_LOG, "JobID: %d\n", (int) JobID);
   return (TRUE);
@@ -57,6 +76,12 @@
  usage:
     gprint (GP_ERR, "USAGE: job [options] (arg0) (arg1) ... (argN)\n");
-    gprint (GP_ERR, "  options: -host, +host, -timeout\n");
+    gprint (GP_ERR, "  options: -host, +host, -timeout, -xhost (host)\n");
     gprint (GP_ERR, "  arguments of the form @MAX_THREADS@ will be replaced when the job is launched\n");
+
+    FREE (Host);
+    for (i = 0; i < Nxhosts; i++) {
+      FREE (xhosts[i]);
+    }
+    FREE (xhosts);
     return (FALSE);
 }
Index: /trunk/Ohana/src/opihi/pcontrol/test/machines.sh
===================================================================
--- /trunk/Ohana/src/opihi/pcontrol/test/machines.sh	(revision 29539)
+++ /trunk/Ohana/src/opihi/pcontrol/test/machines.sh	(revision 29540)
@@ -10,4 +10,6 @@
   host add ipp022
   host add ipp022
+  host add ipp002
+  host off ipp002
 
   machines
@@ -23,4 +25,26 @@
   job -host pikake sleep 10
   job -host pikake sleep 10
+end
+
+macro load.xhost
+  job -host pikake -xhost ipp002 sleep 10
+  job -host pikake -xhost ipp002 sleep 10
+  job -host ipp022 -xhost ipp002 sleep 10
+  job -host ipp022 -xhost ipp002 sleep 10
+  job -host pikake -xhost ipp002 sleep 10
+  job -host pikake -xhost ipp002 sleep 10
+  job -host ipp022 -xhost ipp002 sleep 10
+  job -host ipp022 -xhost ipp002 sleep 10
+end
+
+macro load.2xhost
+  job -host pikake -xhost ipp002 -xhost ipp022 sleep 10
+  job -host pikake -xhost ipp002 -xhost ipp022 sleep 10
+  job -host ipp022 -xhost ipp002 -xhost ipp022 sleep 10
+  job -host ipp022 -xhost ipp002 -xhost ipp022 sleep 10
+  job -host pikake -xhost ipp002 -xhost ipp022 sleep 10
+  job -host pikake -xhost ipp002 -xhost ipp022 sleep 10
+  job -host ipp022 -xhost ipp002 -xhost ipp022 sleep 10
+  job -host ipp022 -xhost ipp002 -xhost ipp022 sleep 10
 end
 
