Index: /branches/eam_branches/ohana.20190329/src/opihi/cmd.data/roll.c
===================================================================
--- /branches/eam_branches/ohana.20190329/src/opihi/cmd.data/roll.c	(revision 40820)
+++ /branches/eam_branches/ohana.20190329/src/opihi/cmd.data/roll.c	(revision 40821)
@@ -3,7 +3,9 @@
 int roll (int argc, char **argv) {
   
-  int Nbytes, Nextra;
-  int dX, dx, dy, nx, ny;
   Buffer *buf;
+
+  // this function is probably not needed
+  gprint (GP_ERR, "ERROR: use 'shift' instead of 'roll'\n");
+  return (FALSE);
 
   if (argc != 4) {
@@ -14,32 +16,71 @@
   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");
+  int dx = atoi (argv[2]);
+  int dy = atoi (argv[3]);
+
+  /* if (dx,dy < 0), we are moving the start position backwards,
+     if (dx,dy > 0), we are moving the start position forward */
+  
+  int Nx = buf[0].matrix.Naxis[0];
+  int Ny = buf[0].matrix.Naxis[1];
+
+  if (dy == 0) {
+    // moves in just dx can be done row-by-row
+
+    int dX = abs(dx);
+    int Nbytes = (Nx * Ny - dX) * sizeof (float);
+    int Nextra = dX * sizeof (float);
+
+    if (dx < 0) {
+      memmove (buf[0].matrix.buffer, &buf[0].matrix.buffer[dX*sizeof(float)], Nbytes);
+      memset (&buf[0].matrix.buffer[Nbytes], 0, Nextra);
+    } else {
+      memmove (&buf[0].matrix.buffer[dX*sizeof(float)], buf[0].matrix.buffer, Nbytes);
+      memset (buf[0].matrix.buffer, 0, Nextra);
+    }
+
+    return TRUE;
   }
 
-  /* 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];
+  if (dx == 0) {
+    // moves in just dy can be done row-by-row
 
-  dX = abs(dx);
-  Nbytes = nx * ny * sizeof (float);
-  Nextra = (nx * ny + dX) * sizeof (float);
+    ALLOCATE_PTR (output, float, Nx*Ny);
 
-  REALLOCATE (buf[0].matrix.buffer, char, Nextra);
+    float *input = (float *) buf[0].matrix.buffer;
 
-  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);
+    for (int iy = 0; iy < Ny; iy++) {
+      if (iy + dy < 0) continue;
+      if (iy + dy >= Ny) continue;
+      memcpy (&output[iy*Nx], &input[(iy + dy)*Nx], Nx);
+    }
+    if (dy > 0) {
+      memset (output, 0, dy*Nx*sizeof(float));
+    } else {
+      int Nbytes = Nx * (Ny - abs(dy)) * sizeof (float);
+      int Nextra = abs(dy) * Nx * sizeof (float);
+      memset (&output[Nbytes], 0, Nextra);
+    }
+    free (buf[0].matrix.buffer);
+    buf[0].matrix.buffer = (char *) output;
+    return TRUE;
   }
 
-  REALLOCATE (buf[0].matrix.buffer, char, Nbytes);
+  ALLOCATE_PTR (output, float, Nx*Ny);
+  float *input = (float *) buf[0].matrix.buffer;
 
-  return (TRUE);
-
+  for (int iy = 0; iy < Ny; iy++) {
+    if (iy + dy < 0) continue;
+    if (iy + dy >= Ny) continue;
+    for (int ix = 0; ix < Nx; ix++) {
+      if (ix + dx < 0) continue;
+      if (ix + dx >= Nx) continue;
+      output[ix + iy*Nx] = input[(ix + dx) + (iy + dy)*Nx];
+    }
+  }
+  free (buf[0].matrix.buffer);
+  buf[0].matrix.buffer = (char *) output;
+  return TRUE;
 }
 
+
