Index: /branches/eam_branches/ipp-20101103/Ohana/src/tools/Makefile
===================================================================
--- /branches/eam_branches/ipp-20101103/Ohana/src/tools/Makefile	(revision 29869)
+++ /branches/eam_branches/ipp-20101103/Ohana/src/tools/Makefile	(revision 29870)
@@ -17,5 +17,5 @@
 PROGRAMS = gconfig fhead ftable fields list_astro glockfile \
 radec mktemp precess csystem fits_insert \
-medianfilter mefhead ckfits
+medianfilter mefhead ckfits roc
 
 all tools: $(PROGRAMS)
Index: /branches/eam_branches/ipp-20101103/Ohana/src/tools/src/roc.c
===================================================================
--- /branches/eam_branches/ipp-20101103/Ohana/src/tools/src/roc.c	(revision 29870)
+++ /branches/eam_branches/ipp-20101103/Ohana/src/tools/src/roc.c	(revision 29870)
@@ -0,0 +1,353 @@
+# include <ohana.h>
+# include <gfitsio.h>
+# include <sys/types.h>
+# include <regex.h>
+
+# define myAssert(LOGIC,MSG) { if (!(LOGIC)) { fprintf (stderr, "%s\n", MSG); abort(); } }
+
+# define ROC_HEADER_SIZE  0x1000
+# define ROC_HEADER_BLOCK 0x1000
+# define ROC_BLOCKSIZE    0x8000
+
+int roc_create (int argc, char **argv);
+int roc_repair (int argc, char **argv);
+int roc_insert (int argc, char **argv);
+int roc_delete (int argc, char **argv);
+int usage (void);
+int print_block (char *header, int *header_size, int *Noff, char *format,...);
+
+int main (int argc, char **argv) {
+
+  if (get_argument (argc, argv, "-h")) usage();
+  if (get_argument (argc, argv, "-help")) usage();
+  if (get_argument (argc, argv, "--help")) usage();
+  if (argc < 3) usage();
+
+  if (!strcasecmp(argv[1], "-create")) roc_create (argc, argv);
+  if (!strcasecmp(argv[1], "-repair")) roc_repair (argc, argv);
+  if (!strcasecmp(argv[1], "-insert")) roc_insert (argc, argv);
+  if (!strcasecmp(argv[1], "-delete")) roc_delete (argc, argv);
+
+  usage();
+  exit (1);
+}
+
+int roc_create (int argc, char **argv) {
+
+  int i, j, n, Ninput, result, Nblocks, header_size, size_off, Noff, Nbytes, Nread;
+  off_t maxSize, *sizes, *bytes_read;
+  char value;
+  char *header;
+  char **inputName, *base;
+  char **inputData;
+  char *outputData;
+  FILE **input, *target;
+  struct stat stats;
+
+  if (argc < 4) usage();
+
+  /* find the md5 sum for each input file (ADD LATER)
+   * find the size of the input files
+   * define the output file size = MAX(sizes)
+   * create the target file header
+   * open & read the input files, write the output
+   */
+
+  // the output file
+  char *targetName = argv[2];
+  Ninput = argc - 3;
+
+  // the input files
+  ALLOCATE (inputName, char *, Ninput);
+  for (i = 0; i < Ninput; i++) {
+    inputName[i] = strcreate (argv[i + 3]);
+  }
+
+  // check on the input files (validity & sizes)
+  maxSize = 0;
+  ALLOCATE (sizes, off_t, Ninput);
+  ALLOCATE (bytes_read, off_t, Ninput);
+  for (i = 0; i < Ninput; i++) {
+    result = stat (inputName[i], &stats);
+    if (result) {
+      perror("problem with input file");
+      exit (1);
+    }
+    if (!S_ISREG(stats.st_mode)) {
+      fprintf (stderr, "%s is not a regular file\n", inputName[i]);
+      exit (1);
+    }
+    sizes[i] = stats.st_size;
+    maxSize = MAX(maxSize, sizes[i]);
+    bytes_read[i] = 0;
+  }
+
+  ALLOCATE (input, FILE *, Ninput);
+  for (i = 0; i < Ninput; i++) {
+    input[i] = fopen(inputName[i], "r");
+    myAssert (input[i], "failed to open file");
+  }
+
+  Nblocks = maxSize / ROC_BLOCKSIZE;
+  if (maxSize % ROC_BLOCKSIZE) {
+    Nblocks = 1 + (int) (maxSize / ROC_BLOCKSIZE);
+  }
+
+  // create the output header
+  header_size = ROC_HEADER_SIZE;
+  ALLOCATE (header, char, header_size);
+
+  Noff = 0;
+  print_block (header, &header_size, &Noff, "ROC Version %d\n", 0);
+
+  size_off = Noff;
+  print_block (header, &header_size, &Noff, "HEADER SIZE 0x%08x\n", header_size); // this is a dummy: re-write below
+  print_block (header, &header_size, &Noff, "N_FILES %d\n", Ninput);
+  print_block (header, &header_size, &Noff, "N_BLOCKS %d\n", Nblocks);
+
+  // write the header information
+  for (i = 0; i < Ninput; i++) {
+    print_block (header, &header_size, &Noff, "FILE_%03d : %s\n", i, inputName[i]);
+    
+    base = filerootname(inputName[i]);
+    print_block (header, &header_size, &Noff, "BASE_%03d : %s\n", i, base);
+    print_block (header, &header_size, &Noff, "SIZE_%03d : %d\n", i, sizes[i]);
+    print_block (header, &header_size, &Noff, "MD5_%03d -- Not Yet Implemented\n", i);
+  }
+  print_block (header, &header_size, &size_off, "HEADER SIZE 0x%08x", header_size);
+  header[size_off] = '\n'; // kind of a hack: print_block writes a NULL char at the end of the string; replace with <RETURN>
+
+  target = fopen(targetName, "w");
+  myAssert (target, "failed to open output");
+
+  fwrite (header, 1, header_size, target);
+
+  ALLOCATE (inputData, char *, Ninput);
+  ALLOCATE (outputData, char, ROC_BLOCKSIZE);
+  for (i = 0; i < Ninput; i++) {
+    ALLOCATE (inputData[i], char, ROC_BLOCKSIZE);
+  }
+
+  for (n = 0; n < Nblocks; n++) {
+    for (i = 0; i < Ninput; i++) {
+      Nread = MIN (ROC_BLOCKSIZE, sizes[i] - bytes_read[i]);
+      Nbytes = fread (inputData[i], 1, Nread, input[i]);
+      myAssert (Nbytes == Nread, "failed to read data");
+      if (Nread < ROC_BLOCKSIZE) {
+	// if we have reached the end of the file, fill in the rest with NULLs
+	memset (&inputData[i][Nread], 0, ROC_BLOCKSIZE - Nread);
+      }
+      bytes_read[i] += Nread;
+    }
+    
+    for (j = 0; j < ROC_BLOCKSIZE; j++) {
+      value = 0;
+      for (i = 0; i < Ninput; i++) {
+	value = value ^ inputData[i][j];
+      }
+      outputData[j] = value;
+    }
+
+    fwrite (outputData, 1, ROC_BLOCKSIZE, target);
+  }
+
+  exit (0);
+}
+
+int roc_repair (int argc, char **argv) {
+
+  int i, j, n, Ninput, Nblocks, header_size, Nbytes, Nread, Nfile, Nwrite;
+  off_t *sizes, *bytes_read;
+  char value;
+  char *header, *line, *ptr;
+  char **inputName, *targetName, *outputName;
+  char **inputData;
+  char *targetData;
+  char *outputData;
+  FILE **input, *target, *output;
+
+  if (argc < 4) usage();
+
+  /* find the md5 sum for each input file (ADD LATER)
+   * find the size of the input files
+   * define the output file size = MAX(sizes)
+   * create the target file header
+   * open & read the input files, write the output
+   */
+
+  // the output file
+  targetName = argv[2];
+  Nfile = atoi(argv[3]);
+  outputName = argv[4];
+
+  if (Nfile < 0) {
+    fprintf (stderr, "invalid file number %d\n", Nfile);
+    exit (3);
+  }
+
+  target = fopen(targetName, "r");
+  myAssert (target, "failed to open output");
+  
+  ALLOCATE (line, char, 1024);
+
+  scan_line (target, line);
+  myAssert (!strncmp(line, "ROC Version 0", strlen("ROC Verion 0")), "invalid ROC file or format");
+
+  scan_line (target, line);
+  sscanf (line, "HEADER SIZE %x", &header_size);
+
+  ALLOCATE (header, char, header_size);
+
+  // read the full header
+  fseeko (target, 0, SEEK_SET);
+  fread (header, 1, header_size, target);
+
+  ptr = header;
+  ptr = strchr (ptr, '\n'); ptr ++; // ROC Version
+  ptr = strchr (ptr, '\n'); ptr ++; // HEADER SIZE
+  
+  sscanf (ptr, "N_FILES %d", &Ninput); ptr = strchr (ptr, '\n'); ptr ++; 
+  sscanf (ptr, "N_BLOCKS %d", &Nblocks); ptr = strchr (ptr, '\n'); ptr ++; 
+
+  if (Nfile >= Ninput) {
+    fprintf (stderr, "file number %d not in ROC\n", Nfile);
+    exit (3);
+  }
+
+  // the input files
+  ALLOCATE (inputName, char *, Ninput);
+  ALLOCATE (sizes, off_t, Ninput);
+  ALLOCATE (bytes_read, off_t, Ninput);
+  for (i = 0; i < Ninput; i++) {
+    ALLOCATE (inputName[i], char, 1024);
+    sscanf (ptr, "%*s : %s", inputName[i]); ptr = strchr (ptr, '\n'); ptr ++; 
+    ptr = strchr (ptr, '\n'); ptr ++; // BASE
+    sscanf (ptr, "%*s : "OFF_T_FMT, &sizes[i]); ptr = strchr (ptr, '\n'); ptr ++; 
+    ptr = strchr (ptr, '\n'); ptr ++; // MD5
+    bytes_read[i] = 0;
+  }
+
+  ALLOCATE (input, FILE *, Ninput);
+  for (i = 0; i < Ninput; i++) {
+    if (i == Nfile) continue;
+    input[i] = fopen(inputName[i], "r");
+    myAssert (input[i], "failed to open file");
+  }
+
+  output = fopen (outputName, "w");
+  myAssert (output, "failed to open output");
+
+  ALLOCATE (inputData, char *, Ninput);
+  ALLOCATE (targetData, char, ROC_BLOCKSIZE);
+  ALLOCATE (outputData, char, ROC_BLOCKSIZE);
+  for (i = 0; i < Ninput; i++) {
+    if (i == Nfile) continue;
+    ALLOCATE (inputData[i], char, ROC_BLOCKSIZE);
+  }
+
+  for (n = 0; n < Nblocks; n++) {
+    for (i = 0; i < Ninput; i++) {
+      if (i == Nfile) continue;
+      Nread = MIN (ROC_BLOCKSIZE, sizes[i] - bytes_read[i]);
+      Nbytes = fread (inputData[i], 1, Nread, input[i]);
+      myAssert (Nbytes == Nread, "failed to read data");
+      if (Nread < ROC_BLOCKSIZE) {
+	// if we have reached the end of the file, fill in the rest with NULLs
+	memset (&inputData[i][Nread], 0, ROC_BLOCKSIZE - Nread);
+      }
+      bytes_read[i] += Nread;
+    }
+    fread (targetData, 1, ROC_BLOCKSIZE, target);
+    
+    for (j = 0; j < ROC_BLOCKSIZE; j++) {
+      value = targetData[j];
+      for (i = 0; i < Ninput; i++) {
+	if (i == Nfile) continue;
+	value = value ^ inputData[i][j];
+      }
+      outputData[j] = value;
+    }
+
+    Nwrite = MIN (ROC_BLOCKSIZE, sizes[Nfile] - bytes_read[Nfile]);
+    if (Nwrite == 0) break;
+    Nbytes = fwrite (outputData, 1, Nwrite, output);
+    myAssert (Nbytes == Nwrite, "failed to write");
+    bytes_read[Nfile] += Nbytes;
+  }
+
+  for (i = 0; i < Ninput; i++) {
+    if (i == Nfile) continue;
+    fclose(input[i]);
+  }
+  fclose (output);
+  fclose (target);
+
+  exit (0);
+}
+
+int roc_insert (int argc, char **argv) {
+
+  exit (0);
+}
+
+int roc_delete (int argc, char **argv) {
+
+  exit (0);
+}
+
+/* roc file description:
+
+   header block + data block
+
+   header min length = ROC_HEADER_SIZE (padded with NULLs)
+
+   ROC Version %d
+   NFILES %d
+   FILE_NNN : full path
+   BASE_NNN : basename
+   SIZE_NNN : file size
+   MD5_NNN  : MD5 checksum of file
+   END
+
+   MAX(NNN) = 32?
+   32*1024
+*/
+
+int usage () {
+  fprintf (stderr, "USAGE: roc [mode]\n");
+  fprintf (stderr, " -create (target) (input) (input) (input) ... [options]\n");
+  fprintf (stderr, " -repair (target) (file #) (output\n");
+  fprintf (stderr, " -insert (target) (input)\n");
+  fprintf (stderr, " -delete (target) (file)\n");
+  exit (2);
+}
+
+int print_block (char *header, int *header_size, int *Noff, char *format,...) {
+
+  char tmp;
+  int Nbyte, Nleft;
+  va_list argp;  
+
+  va_start (argp, format);
+  Nbyte = vsnprintf (&tmp, 0, format, argp);
+  va_end (argp);
+
+  Nleft = *header_size - *Noff;
+
+  if (Nbyte >= Nleft) {
+    *header_size += ROC_HEADER_BLOCK + Nbyte;
+    REALLOCATE (header, char, *header_size);
+  }
+  
+  va_start (argp, format);
+  Nbyte = vsnprintf (&header[*Noff], Nleft, format, argp);
+  va_end (argp);
+
+  if (Nbyte >= Nleft) {
+    return (FALSE);
+  }
+
+  *Noff += Nbyte;
+  return (Nbyte);
+}
+
