Index: /trunk/Ohana/src/imregister/base/ConfigCamera.c
===================================================================
--- /trunk/Ohana/src/imregister/base/ConfigCamera.c	(revision 3)
+++ /trunk/Ohana/src/imregister/base/ConfigCamera.c	(revision 3)
@@ -0,0 +1,50 @@
+# include "imregister.h"
+
+void ConfigCamera () { 
+
+  int i;
+  char *config, ID[64], field[128], line[128];
+
+  /* load camera config file */
+  config = LoadConfigFile (CameraConfig);
+  if (config == (char *) NULL) {
+    fprintf (stderr, "ERROR: can't find camera config file %s\n", CameraConfig);
+    exit (1);
+  }
+  
+  /* load data from config file */
+  ScanConfig (config, "NCCD", "%d", 1, &Nccd);
+  ALLOCATE (ccds, char *, Nccd);
+
+  for (i = 0; i < Nccd; i++) {
+    sprintf (field, "CCD.%d", i);
+    ScanConfig (config, field, "%s", 1, line);
+    sscanf (line, "%s", ID);
+    ccds[i] = strcreate (ID);
+  }
+}
+
+int MatchCCDName (Header *header) {
+
+  int i;
+  char ID[64];
+
+  ID[0] = 0;
+  
+  fits_scan (header, CCDnumKeyword,  "%s", 1, ID);
+  if (!ID[0]) { 
+    fprintf (stderr, "warning, ccd id not found in header\n");
+    return (-1);
+  }
+  
+  /* compare as number if ID is a complete number (ie, 00 equiv to 0, but 00b not equiv to 0b */
+  for (i = 0; i < Nccd; i++) {
+    if (strnumcmp (ccds[i], ID)) {
+      return (i);
+    }
+  }
+  
+  fprintf (stderr, "warning: ccd %s not found in camera config file\n", ID);
+  return (-1);
+}
+
Index: /trunk/Ohana/src/imregister/base/ConfigFilter.c
===================================================================
--- /trunk/Ohana/src/imregister/base/ConfigFilter.c	(revision 3)
+++ /trunk/Ohana/src/imregister/base/ConfigFilter.c	(revision 3)
@@ -0,0 +1,93 @@
+# include "imregister.h"
+
+void ConfigFilter () {
+
+  int i, N, code, NFILT, Nfilt, Nfield;
+  char *c, line[256], name[64];
+  FILE *f;
+
+  /* open filter list file */
+  f = fopen (FilterList, "r");
+  if (f == (FILE *) NULL) {
+    fprintf (stderr, "error reading photcodes\n");
+    exit (1);
+  }
+
+  /* allocate dataspace needed */
+  NFILT = 100;
+  Nfilt = 0;
+  ALLOCATE (filternum,  int,    NFILT);
+  ALLOCATE (filtername, char *, NFILT);
+  for (i = Nfilt; i < NFILT; i++) {
+    ALLOCATE (filtername[i], char, 64);
+  }
+
+  while (scan_line (f, line) != EOF) {
+    for (c = line; isspace (*c); c++);
+    if (*c == '#') continue;
+    Nfield = sscanf (c, "%d %s", &code, name);
+    if (Nfield != 2) { continue; }
+
+    filternum[Nfilt] = code;
+    strcpy (filtername[Nfilt], name);
+    Nfilt ++;
+
+    if (Nfilt == NFILT - 1) {
+      NFILT += 100;
+      REALLOCATE (filternum,  int,    NFILT);
+      REALLOCATE (filtername, char *, NFILT);
+      for (i = Nfilt; i < NFILT; i++) {
+	REALLOCATE (filtername[i], char, 64);
+      }
+    }
+  }
+  fclose (f);
+
+  /* make filter hash table (using first available entries) */
+  ALLOCATE (filterhash, char *, Nfilt);
+  for (i = 0; i < Nfilt; i++) {
+    filterhash[i] = (char *) NULL;
+  }
+
+  for (i = 0; i < Nfilt; i++) {
+    N = filternum[i];
+    if (filterhash[N] != (char *) NULL) continue;
+    filterhash[N] = filtername[i];
+  }
+
+  NFILTER = Nfilt;
+  /* we now have NFILTER set, and filternum & filtername arrays filled */
+
+}  
+
+/* convert filter string to fixed filter names (convert all spaces to .) */
+int MatchFilterList (char *line) {
+
+  char *p, tmp[31];
+  int i, blank;
+
+  blank = FALSE;
+  p = line;
+  for (i = 0; i < strlen (line); i++, p++) {
+    *p = line[i];
+    if (isblank(line[i])) { 
+      *p = '.';
+      if (blank) p--;
+      if (!blank) blank = TRUE;
+    } else {
+      blank = FALSE;
+    }
+  }
+  *p = 0;
+
+  for (i = 0; i < NFILTER; i++) {
+    if (!strcasecmp (line, filtername[i])) {
+      strcpy (line, filterhash[filternum[i]]);
+      return (TRUE);
+    }
+  }      
+  fprintf (stderr, "invalid filter %s\n", line);
+  snprintf (tmp, 30, "UKN:%s", line);
+  strcpy (line, tmp);
+  return (TRUE);
+}
Index: /trunk/Ohana/src/imregister/base/ConfigInit.c
===================================================================
--- /trunk/Ohana/src/imregister/base/ConfigInit.c	(revision 3)
+++ /trunk/Ohana/src/imregister/base/ConfigInit.c	(revision 3)
@@ -0,0 +1,85 @@
+# include "imregister.h"
+
+int success;
+
+void ConfigInit (int *argc, char **argv) {
+
+  char *config, *file, ElixirBase[80];
+
+  /*** load configuration info ***/
+  file = SelectConfigFile (argc, argv, "ptolemy");
+  config = LoadConfigFile (file);
+  if (config == (char *) NULL) {
+    fprintf (stderr, "ERROR: can't find configuration file %s\n", file);
+    if (file != (char *) NULL) free (file);
+    exit (0);
+  }
+
+  success = TRUE;
+
+  WarnConfig (config, "REGISTRATION_DATABASE",       "%s", 0, ImageDB);
+  WarnConfig (config, "DETREND_DATABASE",            "%s", 0, DetrendDB);
+  WarnConfig (config, "PHOT_DATABASE",               "%s", 0, PhotDB);
+  WarnConfig (config, "TRANS_DATABASE",              "%s", 0, TransDB);
+  WarnConfig (config, "IMAGE_CATALOG",               "%s", 0, ImPhotDB);
+
+  /* small text databases: filters, camera defs */ 
+  WarnConfig (config, "PHOTCODE_FILE",               "%s", 0, PhotCodeFile);
+  WarnConfig (config, "TEMPERATURE_LOG",             "%s", 0, TempLogFile);
+  WarnConfig (config, "FILTER_LIST",                 "%s", 0, FilterList);
+  WarnConfig (config, "CAMERA_CONFIG",               "%s", 0, CameraConfig);
+  WarnConfig (config, "DETREND_RECIPES",             "%s", 0, RecipeFile);
+						   
+  /* keyword abstractions for parse_time */	   
+  WarnConfig (config, "DATE-KEYWORD",                "%s", 0, DateKeyword);
+  WarnConfig (config, "DATE-MODE",                   "%s", 0, DateMode);
+  WarnConfig (config, "UT-KEYWORD",                  "%s", 0, UTKeyword);
+  WarnConfig (config, "MJD-KEYWORD",                 "%s", 0, MJDKeyword);
+  WarnConfig (config, "JD-KEYWORD",                  "%s", 0, JDKeyword);
+						   
+  /* keyword abstractions for iminfo */		   
+  WarnConfig (config, "EXPTIME-KEYWORD",             "%s", 0, ExptimeKeyword);
+  WarnConfig (config, "IMAGETYPE-KEYWORD",           "%s", 0, ImagetypeKeyword);
+  WarnConfig (config, "CCDNUM-KEYWORD",              "%s", 0, CCDnumKeyword);
+  WarnConfig (config, "FILTER-KEYWORD",              "%s", 0, FilterKeyword);
+  WarnConfig (config, "AIRMASS-KEYWORD",             "%s", 0, AirmassKeyword);
+  WarnConfig (config, "FOCUS-KEYWORD",               "%s", 0, FocusKeyword);
+  WarnConfig (config, "ROTATION-KEYWORD",            "%s", 0, RotationKeyword);
+  WarnConfig (config, "DETTEMP-KEYWORD",             "%s", 0, DettempKeyword);
+  WarnConfig (config, "TELDATA1-KEYWORD",            "%s", 0, Teldata1Keyword);
+  WarnConfig (config, "TELDATA2-KEYWORD",            "%s", 0, Teldata2Keyword);
+  WarnConfig (config, "TELDATA3-KEYWORD",            "%s", 0, Teldata3Keyword);
+  WarnConfig (config, "CAMERA-KEYWORD",              "%s", 0, CameraKeyword);
+
+  /* optional values */
+  ScanConfig (config, "RA-DDD-KEYWORD",              "%s", 0, RADecDegKeyword);
+  ScanConfig (config, "DEC-DDD-KEYWORD",             "%s", 0, DECDecDegKeyword);
+  ScanConfig (config, "RA-HMS-KEYWORD",              "%s", 0, RASexigKeyword);
+  ScanConfig (config, "DEC-DMS-KEYWORD",             "%s", 0, DECSexigKeyword);
+
+  if (!RADecDegKeyword[0] & !DECDecDegKeyword[0] && !RASexigKeyword[0] && !DECSexigKeyword[0]) {
+    fprintf (stderr, "missing astrometry configuration information\n");
+    success = FALSE;
+  }
+						   
+  WarnConfig (config, "imstats",                     "%s", 0, ElixirBase);
+  sprintf (ImstatFifo, "%s.source", ElixirBase);   
+  WarnConfig (config, "ptolemy",                     "%s", 0, ElixirBase);
+  sprintf (PtolemyFifo, "%s.source", ElixirBase);
+
+  if (! success) {
+    fprintf (stderr, "ERROR: problem with elixir configuration\n");
+    exit (1);
+  }
+
+  free (config);
+  free (file);
+
+}
+
+void WarnConfig (char *config, char *key, char * mode, int N, char *var) {
+  if (!ScanConfig (config, key, mode, N, var)) {
+    fprintf (stderr, "missing config variable %s\n", key);
+    success = FALSE;
+  }
+}
Index: /trunk/Ohana/src/imregister/base/WriteFIFO.c
===================================================================
--- /trunk/Ohana/src/imregister/base/WriteFIFO.c	(revision 3)
+++ /trunk/Ohana/src/imregister/base/WriteFIFO.c	(revision 3)
@@ -0,0 +1,26 @@
+# include "imregister.h"
+
+static char retchar[] = "\n";
+
+int WriteFIFO (char *filename, char *line) {
+
+  int state, mode;
+  int fd;
+
+  fd = setlockfile2 (filename, 20.0, LCK_XCLD, &state);
+  if (fd == -1) {
+      fprintf (stderr, "ERROR: can't lock fifo %s\n", filename);
+      return (FALSE);
+  }
+
+  lseek (fd, 0, SEEK_END);
+  write (fd, line, strlen (line));
+  write (fd, retchar, 1);
+
+  mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
+  fchmod (fd, mode);
+  clearlockfile2 (filename, fd, LCK_XCLD, &state);
+
+  return (TRUE);
+
+}
Index: /trunk/Ohana/src/imregister/base/get_fwhm.c
===================================================================
--- /trunk/Ohana/src/imregister/base/get_fwhm.c	(revision 3)
+++ /trunk/Ohana/src/imregister/base/get_fwhm.c	(revision 3)
@@ -0,0 +1,130 @@
+# include "imregister.h"
+
+/* see note at end of file */
+double get_fwhm (char *filename) {
+
+  FILE *f;
+  char line[1024];
+  double *fwhm, *mag, *Mag, *FWHM, *Nfwhm, flags;
+  double F, value, Mlim, Vmode, Fmin, Fmax;
+  int i, N, n, Nwant, bin, mode, Nmode;
+
+  /* get sextract file (has fwhm info) */
+  f = fopen (filename, "r");
+  if (f == (FILE *) NULL) {
+    fprintf (stderr, "ERROR: can't open file.sdat\n");
+    return (-1.0);
+  }
+
+  n = 0;
+  N = 1000;
+  ALLOCATE (fwhm, double, N);
+  ALLOCATE (mag, double, N);
+  
+  /* load in data from file */
+  while (scan_line (f, line) != EOF) {
+    dparse (&flags, 2, line);
+    if (flags > 0) continue;
+    dparse (&mag[n], 4, line);
+    if (mag[n] > 0) continue;
+    dparse (&fwhm[n], 1, line);
+    n++;
+    if (n == N) {
+      N += 1000;
+      REALLOCATE (fwhm, double, N);
+      REALLOCATE (mag, double, N);
+    }
+  }    
+  if (n == 0) { return (-1.0); }
+
+  /* find the mag threshold */
+  ALLOCATE (Mag, double, n);
+  memcpy (Mag, mag, n*sizeof(double));
+  dsort (Mag, n);
+  Nwant = MIN (MAX (0.25*n, 10), n-1);
+  Mlim = Mag[Nwant];
+
+  /* create subset of fwhm with mag < Mlim */
+  ALLOCATE (FWHM, double, n);
+  ALLOCATE (Nfwhm, double, 1024);
+  bzero (FWHM, n*sizeof(double));
+  bzero (Nfwhm, 1024*sizeof(double));
+  
+  N = 0;
+  for (i = 0; i < n; i++) {
+    if (mag[i] > Mlim) continue;
+    FWHM[N] = fwhm[i];
+    N++;
+
+    /* accumulate mag histogram */
+    bin = fwhm[i]*10.0;
+    if (bin < 0) continue;
+    if (bin > 999) continue;
+    Nfwhm[bin] ++;
+  }
+
+  /* find the mode (bin size = 0.1 pixels) */
+  mode = 0; 
+  Nmode = Nfwhm[mode];
+  for (i = 0; i < 1000; i++) {
+    if (Nfwhm[i] > Nmode) {
+      mode = i;
+      Nmode = Nfwhm[i];
+    }
+  }
+  Vmode = mode * 0.1;
+  Fmin = Vmode - 0.2;
+  Fmax = Vmode + 0.2;
+
+  /* average bins within 0.2 of mode */
+  F = 0;
+  n = 0;
+  for (i = 0; i < N; i++) {
+    if (FWHM[i] < Fmin) continue;
+    if (FWHM[i] > Fmax) continue;
+    n++;
+    F+=FWHM[i];
+  }
+  if (n > 3) {
+    value = F / n;
+    return (value);
+  }
+
+  /* if we don't get the answer from the above, resort to median */
+  dsort (FWHM, N);
+  F = 0;
+  n = 0;
+  for (i = 0.25*N; i < 0.75*N; i++) {
+    n++;
+    F+=FWHM[i];
+  }
+  if (n > 0) {
+    value = F / n;
+  } else {
+    value = -1;
+  }
+  return (value);
+
+}
+
+/* 
+
+   calculate the fwhm from the data in the given file.
+   The file contains output from sextractor (or other program, perhaps).
+   The columns that matter are: 
+     1) fwhm (pixels)
+     2) flags
+     4) mag
+
+   this function determines the magnitude range for the file,
+   selects stars in the upper 25% of that magnitude range (by number),
+   rejecting bad stars (flags > 0) along the way
+   
+   the resulting list of fwhms are examined for the mode, in 0.1 pixel bins.
+   stars with fwhm within 0.2 pix of that mode are averaged to find the
+   best fwhm value.
+
+   in the database, a value of 0 means the measurement has not been tried.
+   a value of -1 means the measurement failed
+
+*/
Index: /trunk/Ohana/src/imregister/base/misc.c
===================================================================
--- /trunk/Ohana/src/imregister/base/misc.c	(revision 3)
+++ /trunk/Ohana/src/imregister/base/misc.c	(revision 3)
@@ -0,0 +1,462 @@
+# include "imregister.h"
+
+/***** convert [-]00:00:00 to 0.0000 ****/
+int dms_to_ddd (double *Value, char *string) {
+  
+  int valid, neg, status;
+  double tmp, value;
+  char *p1, *p2, *px;
+
+  valid = FALSE; 
+  neg = FALSE;
+  stripwhite (string);
+  p1 = string;
+  px = string + strlen(string);
+
+  if (string[0] == '-') { 
+    valid = TRUE; 
+    neg = TRUE;
+    p1 = &string[1];
+  }
+  if (string[0] == '+') { 
+    valid = TRUE; 
+    neg = FALSE;
+    p1 = &string[1];
+  }
+  if (isdigit(string[0])) { 
+    valid = TRUE;
+    p1 = &string[0];
+  }
+  if (!valid) { return (FALSE); }
+
+  status = 1;
+  tmp = strtod (p1, &p2);
+  if (p2 == p1) return (FALSE); /* entry not a number: +fred */
+  value = tmp;
+  if (p2 == px) goto escape;    /* entry only number: +1.0 */ 
+  p1 = p2 + 1;
+
+  tmp = strtod (p1, &p2);
+  if (p2 == p1) goto escape;    /* entry not a number: +1:fred */
+  status = 2;
+  value += tmp / 60.0;
+  if (p2 == px) goto escape;    /* entry only number: +1:1 */
+  p1 = p2 + 1;
+
+  tmp = strtod (p1, &p2);
+  if (p2 == p1) goto escape;    /* entry not a number: +1:1:fred */
+  value += tmp / 3600.0;
+
+ escape:
+  if (neg) {
+    value *= -1;
+  }
+  *Value = value;
+
+  return (status);
+}
+
+/**********/
+int str_to_radec (double *ra, double *dec, char *str1, char *str2) {
+
+  double Ra, Dec;
+
+  *ra = *dec = 0;
+  switch (dms_to_ddd (&Ra, str1)) {
+  case 0:
+    fprintf (stderr, "syntax error in RA\n");
+    return (FALSE);
+  case 1:
+    break;
+  case 2:
+    Ra = Ra * 15;
+    break;
+  }
+  switch (dms_to_ddd (&Dec, str2)) {
+  case 0:
+    fprintf (stderr, "syntax error in DEC\n");
+    return (FALSE);
+  case 1:
+  case 2:
+    break;
+  }
+  *ra = Ra;
+  *dec = Dec;
+  return (TRUE);
+}
+
+# define FORMAT_DAYS    1
+# define FORMAT_HOURS   2
+# define FORMAT_MINUTES 3
+# define FORMAT_SECONDS 4
+# define FORMAT_JD      5
+# define FORMAT_DATE    6
+
+/**********/
+int chk_time (char *line) {
+
+  char *p1, *p2;
+  double tmp;
+  int mode;
+
+  p1 = line;
+  tmp = strtod (p1, &p2);
+  if (p2 == p1 + strlen (p1) - 1) {
+    if (*p2 == 'd') {
+      mode = FORMAT_DAYS;
+    }
+    if (*p2 == 'h') {
+      mode = FORMAT_HOURS;
+    }
+    if (*p2 == 'm') {
+      mode = FORMAT_MINUTES;
+    }
+    if (*p2 == 's') {
+      mode = FORMAT_SECONDS;
+    }
+    if (*p2 == 'j') {
+      mode = FORMAT_JD;
+    }
+  } else { 
+    mode = FORMAT_DATE;
+  }
+  return (mode);
+}
+
+/**********/
+int str_to_time (char *line, unsigned long *second) {
+  
+  struct timeval now;
+  double jd;
+
+  if (!strcasecmp (line, "NOW")) {
+    gettimeofday (&now, (struct timezone *) NULL);
+    *second = now.tv_sec;
+    return (TRUE);
+  }
+    
+  if (!strcasecmp (line, "TODAY")) {
+    gettimeofday (&now, (struct timezone *) NULL);
+    *second = 86400 * ((int)(now.tv_sec / 86400));
+    return (TRUE);
+  }
+    
+  switch (chk_time (line)) {
+  case 0:
+    return (FALSE);
+  case FORMAT_DAYS:
+    *second = strtod (line, 0) * 86400.0;
+    return (TRUE);
+  case FORMAT_HOURS:
+    *second = strtod (line, 0) * 3600.0;
+    return (TRUE);
+  case FORMAT_MINUTES:
+    *second = strtod (line, 0) * 60.0;
+    return (TRUE);
+  case FORMAT_SECONDS:
+    *second = strtod (line, 0);
+    return (TRUE);
+  case FORMAT_JD:
+    jd = strtod (line, 0);
+    *second = jd_to_sec (jd);
+    return (TRUE);
+  case FORMAT_DATE:
+    *second = date_to_sec (line);
+    return (TRUE);
+  }
+  return (FALSE);
+}
+
+/**********/
+int str_to_dtime (char *line, double *second) {
+  
+  switch (chk_time (line)) {
+  case 0:
+  case FORMAT_JD:
+  case FORMAT_DATE:
+    return (FALSE);
+  case FORMAT_DAYS:
+    *second = strtod (line, 0) * 86400.0;
+    return (TRUE);
+  case FORMAT_HOURS:
+    *second = strtod (line, 0) * 3600.0;
+    return (TRUE);
+  case FORMAT_MINUTES:
+    *second = strtod (line, 0) * 60.0;
+    return (TRUE);
+  case FORMAT_SECONDS:
+    *second = strtod (line, 0);
+    return (TRUE);
+  }
+  return (FALSE);
+}
+
+/**********/
+double sec_to_jd (unsigned long second) {
+
+  double jd;
+  
+  jd = second/86400.0 + 2440587.5;
+  return (jd);
+}
+
+/**********/
+unsigned long int jd_to_sec (double jd) {
+
+  unsigned long int second;
+
+  second = (jd - 2440587.5)*86400;
+  return (second);
+}
+
+/**********/
+char *sec_to_date (unsigned long second) {
+  
+  struct tm *gmt;
+  char *line;
+  
+  ALLOCATE (line, char, 64);
+  gmt   = gmtime (&second);
+  sprintf (line, "%4d/%02d/%02d,%02d:%02d:%02d", 1900+gmt[0].tm_year, gmt[0].tm_mon+1, gmt[0].tm_mday, gmt[0].tm_hour, gmt[0].tm_min, gmt[0].tm_sec); 
+  return (line);
+
+}
+
+/***** date in format yyyy/mm/dd,hh:mm:ss *****/
+unsigned long date_to_sec (char *date) {
+  
+  unsigned long second;
+  double tmp, jd;
+  struct tm now;
+  char *p1, *p2, *px;
+  
+  p1 = date;
+  px = date + strlen(date);
+  bzero (&now, sizeof(now));
+
+  tmp = strtod (p1, &p2);
+  if (p2 == p1) goto escape;
+  now.tm_year = tmp;
+  if (now.tm_year > 1000) now.tm_year -= 1900;
+  if (now.tm_year <   50) now.tm_year += 100;
+  if (p2 == px) goto escape;  
+  p1 = p2 + 1;
+
+  tmp = strtod (p1, &p2);
+  if (p2 == p1) goto escape;
+  now.tm_mon = tmp - 1; /* mon runs from 0 - 11 */
+  if (p2 == px) goto escape;  
+  p1 = p2 + 1;
+
+  tmp = strtod (p1, &p2);
+  if (p2 == p1) goto escape;
+  now.tm_mday = tmp;
+  if (p2 == px) goto escape;  
+  p1 = p2 + 1;
+
+  tmp = strtod (p1, &p2);
+  if (p2 == p1) goto escape;
+  p1 = p2 + 1;
+  now.tm_hour = tmp;
+  if (p2 == px) goto escape;  
+
+  tmp = strtod (p1, &p2);
+  if (p2 == p1) goto escape;
+  now.tm_min = tmp;
+  if (p2 == px) goto escape;  
+  p1 = p2 + 1;
+
+  tmp = strtod (p1, &p2);
+  if (p2 == p1) goto escape;
+  now.tm_sec = tmp;
+  if (p2 == px) goto escape;  
+  p1 = p2 + 1;
+
+ escape:
+  jd = now.tm_mday - 32075 + (int)(1461*(1900 + now.tm_year + 4800 + (int)(((now.tm_mon+1)-14)/12))/4)
+    + (int)(367*((now.tm_mon+1) - 2 - (int)(((now.tm_mon+1) - 14)/12)*12)/12)
+    - (int)(3*(int)((1900 + now.tm_year + 4900 + (int)(((now.tm_mon+1) - 14)/12))/100)/4) - 0.5;
+  
+  second = (jd - 2440587.5)*86400 + 3600.0*now.tm_hour + now.tm_min*60.0 + now.tm_sec;
+
+  return (second);
+}
+
+
+/* times may be in forms as:
+   20040200450s (N seconds since 1970.0)
+   2440900.232j (julian date)
+   99/02/23,03:22:18 (date string)
+   (separators may be anything except space, +, -)
+   99:02:15:12:23:30
+   99:02:15:12h23m30s
+   */
+
+
+/* fseek with timeout - 0.5 sec */
+int Fseek (FILE *f, long offset, int whence) {
+
+  int status, k;
+
+  status = fseek (f, offset, whence);
+  if (status == -1) {
+    for (k = 0; (k < 10) && ((status = fseek (f, 0, SEEK_SET)) == -1); k++) usleep (50000);
+    if (status == -1) {
+      return (0);
+    }
+  }
+  return (1);
+}
+
+/* return values:
+   0 - no trange arguments
+   1 - arguments ok
+   2 - arguments bad
+*/
+int get_trange_arguments (int *argc, char **argv, unsigned long **Tstart, unsigned long **Tstop, int *ntimes) {
+
+  int Na, N, Ntimes;
+  double trange;
+  unsigned long tmp, *tstart, *tstop;
+
+  /* allocate space for returned lists */
+  Ntimes = 10;
+  ALLOCATE (tstart, unsigned long, Ntimes);
+  ALLOCATE (tstop,  unsigned long, Ntimes);
+
+  for (N = 0; ; N++) {
+
+    /* find next -trange arg */
+    Na = get_argument (*argc, argv, "-trange");
+    if (Na == 0) {
+      *ntimes = N;
+      *Tstart = tstart;
+      *Tstop  = tstop;
+      return (TRUE);
+    }
+    remove_argument (Na, argc, argv);
+    
+    /* tstart */
+    if (!str_to_time (argv[Na], &tstart[N])) { 
+      return (FALSE);
+    }
+
+    /* interpret second value */
+    remove_argument (Na, argc, argv);
+    if (str_to_dtime (argv[Na], &trange)) { 
+      if (trange < 0) {
+	tstop[N]  = tstart[N];
+	tstart[N] = tstop[N] - trange;
+      } else {
+	tstop[N]  = tstart[N] + trange;
+      }
+      remove_argument (Na, argc, argv);
+      goto goodvalue;
+    }
+    if (str_to_time (argv[Na], &tstop[N])) { 
+      if (tstart[N] > tstop[N]) {
+	tmp     = tstart[N];
+	tstart[N] = tstop[N];
+	tstop[N]  = tmp;
+      }
+      remove_argument (Na, argc, argv);
+      goto goodvalue;
+    }
+    return (FALSE); /* syntax error in 2nd value */
+
+  goodvalue:
+    if (N == Ntimes - 1) {
+      Ntimes += 10;
+      REALLOCATE (tstart, unsigned long, Ntimes);
+      REALLOCATE (tstop,  unsigned long, Ntimes);
+    }
+  }
+}
+  
+void make_backup (char *filename) {
+
+  int status, cmode;
+  struct stat filestat;
+  char line [256];
+
+  status = stat (filename, &filestat);
+  if (status == 0) { /* file exists, make backup copy */
+    sprintf (line, "cp %s %s~", filename, filename);
+    status = system (line);
+    if (status) {
+      fprintf (stderr, "ERROR: unable to create %s~, exiting\n", filename);
+      exit (0);
+    }
+    cmode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
+    sprintf (line, "%s~", filename);
+    chmod (line, cmode);
+  }
+}
+
+
+int get_filter_arguments (int *argc, char **argv, int **Filt, int *Nfilt) {
+
+  int i, N, Na, NF;
+  int *filt;
+
+  /* allocate space for returned lists */
+  NF = 10;
+  ALLOCATE (filt, int, NF);
+
+  for (N = 0; ; N++) {
+
+    /* find next -trange arg */
+    Na = get_argument (*argc, argv, "-filter");
+    if (Na == 0) {
+      *Nfilt = N;
+      *Filt = filt;
+      return (TRUE);
+    }
+    remove_argument (Na, argc, argv);
+    
+    for (i = 0; i < strlen (argv[Na]); i++) { if (isspace (argv[Na][i])) argv[Na][i] = '.'; }
+    for (i = 0; i < NFILTER; i++) {
+      if (!strcasecmp (argv[Na], filtername[i])) {
+	filt[N] = filternum[i];
+      }
+    }
+    if (filt[N] == FILTER_NONE) return (FALSE);
+    remove_argument (Na, argc, argv);
+
+    if (N == NF - 1) {
+      NF += 10;
+      REALLOCATE (filt, int, NF);
+    }
+  }
+}
+  
+   
+int get_version (int argc, char **argv, char *version) {
+
+  int N;
+  char *p, *q, *line;
+
+  if (get_argument (argc, argv, "-version")) {
+
+    N = strlen (version) + 2;
+    line = (char *) malloc (N);
+    bzero (line, N);
+
+    p = strstr (version, "$Revision: ");
+    if (p != (char *) NULL) 
+      p += strlen ("$Revision: ");
+    else
+      p = version;
+
+    q = strstr (p, "$");
+    if (q != (char *) NULL) 
+      N = q - p; 
+    else
+      N = strlen (p);
+
+    strncpy (line, p, N);
+
+    fprintf (stderr, "%s\n", line);
+    exit (2);
+  }
+}  
Index: /trunk/Ohana/src/imregister/base/parse_time.c
===================================================================
--- /trunk/Ohana/src/imregister/base/parse_time.c	(revision 3)
+++ /trunk/Ohana/src/imregister/base/parse_time.c	(revision 3)
@@ -0,0 +1,126 @@
+# include "imregister.h"
+
+int parse_time (Header *header) {
+
+  double jd;
+  int Ny, Nf, mode;
+  int Nsec, hour, min, sec, year, month, day;
+  char *py, *pm, *pd, *c;
+  char line[256];
+
+  /* we want to find JD or MJD to get Nsec (seconds since 01/01/1970) */
+
+  /* try JD first */
+  if (strcasecmp (JDKeyword, "NONE")) {
+    uppercase (JDKeyword);
+    fits_scan (header, JDKeyword, "%lf", 1, &jd);
+    Nsec = (jd - 2440587.5)*86400;
+    return (Nsec);
+  }
+
+  /* try MJD next */
+  if (strcasecmp (MJDKeyword, "NONE")) {
+    uppercase (MJDKeyword);
+    fits_scan (header, MJDKeyword, "%lf", 1, &jd);
+    Nsec = (jd - 40587.0)*86400;
+    return (Nsec);
+  }
+    
+  /* get UT and DATE */
+  uppercase (UTKeyword);
+  fits_scan (header, UTKeyword, "%s", 1, line);
+  /* remove ':' characters */
+  for (c = strchr (line, 0x3a); c != (char *) NULL; c = strchr (line, 0x3a)) { *c = ' '; }
+  sscanf (line, "%d %d %d", &hour, &min, &sec);
+
+  /* parse mode line */
+  uppercase (DateMode);
+  for (Ny = 0, c = strchr (DateMode, 'Y'); c != (char ) NULL; c = strchr (c + 1, 'Y'), Ny++);
+  if ((Ny != 2) && (Ny != 4)) {
+    fprintf (stderr, "error in DATE-MODE format: %s\n", DateMode);
+    exit (0);
+  }
+  py = strchr (DateMode, 'Y');
+  pm = strchr (DateMode, 'M');
+  pd = strchr (DateMode, 'D');
+  if ((py == (char *) NULL) || (pm == (char *) NULL) || (pd == (char *) NULL)) {
+    fprintf (stderr, "error in DATE-MODE format: %s\n", DateMode);
+    exit (0);
+  }
+  if ((py > pm) && (py < pd)) {
+    fprintf (stderr, "error in DATE-MODE format: %s\n", DateMode);
+    exit (0);
+  }
+  if ((py > pd) && (py < pm)) {
+    fprintf (stderr, "error in DATE-MODE format: %s\n", DateMode);
+    exit (0);
+  }
+  mode = 0;
+  if ((py < pm) && (pm < pd)) { mode = 1; }  /* yyyy-mm-dd */
+  if ((py < pm) && (pm > pd)) { mode = 2; }  /* yyyy-dd-mm */
+  if ((py > pm) && (pm < pd)) { mode = 3; }  /* mm-dd-yyyy */
+  if ((py > pm) && (pm > pd)) { mode = 4; }  /* dd-mm-yyyy */
+  if (!mode) {
+    fprintf (stderr, "error in DATE-MODE format: %s\n", DateMode);
+    exit (0);
+  }
+
+  /* parse date entry */
+  uppercase (DateKeyword);
+  fits_scan (header, DateKeyword, "%s",  1, line);
+  /* remove possible separators: ':', '/' '.', '-' */
+  for (c = strchr (line, 0x3a); c != (char *) NULL; c = strchr (line, 0x3a)) { *c = ' '; }
+  for (c = strchr (line, 0x2f); c != (char *) NULL; c = strchr (line, 0x2f)) { *c = ' '; }
+  for (c = strchr (line, 0x2e); c != (char *) NULL; c = strchr (line, 0x2e)) { *c = ' '; }
+  for (c = strchr (line, 0x2d); c != (char *) NULL; c = strchr (line, 0x2d)) { *c = ' '; }
+
+  switch (mode) {
+  case 1:
+    Nf = sscanf (line, "%d %d %d", &year, &month, &day);
+    break;
+  case 2:
+    Nf = sscanf (line, "%d %d %d", &year, &day, &month);
+    break;
+  case 3:
+    Nf = sscanf (line, "%d %d %d", &month, &day, &year);
+    break;
+  case 4:
+    Nf = sscanf (line, "%d %d %d", &day, &month, &year);
+    break;
+  }
+  if (Nf != 3) {
+    fprintf (stderr, "error in date entry (%s) or DATE-MODE format (%s)\n", line, DateMode);
+    exit (0);
+  }
+
+  if (year > 1000) {
+    if (Ny == 2) {
+      fprintf (stderr, "warning: mode line claims 2 digit year, but 4 digit year found\n");
+    }
+  } else {
+    if (Ny == 4) {
+      fprintf (stderr, "warning: mode line claims 4 digit year, but 2 digit year found\n");
+    }
+    if (year < 50) year += 100;
+    year += 1900;
+  }    
+
+  /* convert yy.mm.dd hh.mm.ss to Nsec since 1970 (jd = 2440587.5) */
+  /* note that in this section, tm_mon has range 1-12, unlike for gmtime () */
+  jd = day - 32075 + (int)(1461*(year + 4800 + (int)(((month)-14)/12))/4)
+    + (int)(367*((month) - 2 - (int)(((month) - 14)/12)*12)/12)
+    - (int)(3*(int)((year + 4900 + (int)(((month) - 14)/12))/100)/4) - 0.5;
+  /* jd is the julian day of the whole day only not the time */
+  Nsec = (jd - 2440587.5)*86400 + 3600.0*hour + min*60.0 + sec;
+  
+  return (Nsec);
+
+}
+
+void uppercase (char *string) {
+
+  int i;
+    
+  for (i = 0; i < strlen (string); i++) string[i] = toupper (string[i]);
+
+}
Index: /trunk/Ohana/src/imregister/base/sort.c
===================================================================
--- /trunk/Ohana/src/imregister/base/sort.c	(revision 3)
+++ /trunk/Ohana/src/imregister/base/sort.c	(revision 3)
@@ -0,0 +1,68 @@
+
+void sort (float *value, int N) {
+
+  int l,j,ir,i;
+  float temp;
+  
+  if (N < 2) return;
+  l = N >> 1;
+  ir = N - 1;
+  for (;;) {
+    if (l > 0) {
+      temp = value[--l];
+    }
+    else {
+      temp = value[ir];
+      value[ir] = value[0];
+      if (--ir == 0) {
+	value[0] = temp;
+	return;
+      }
+    }
+    i = l;
+    j = (l << 1) + 1;
+    while (j <= ir) {
+      if (j < ir && value[j] < value[j+1]) ++j;
+      if (temp < value[j]) {
+	value[i]=value[j];
+	j += (i=j) + 1;
+      }
+      else j = ir + 1;
+    }
+    value[i] = temp;
+  }
+}
+
+void dsort (double *value, int N) {
+
+  int l,j,ir,i;
+  double temp;
+  
+  if (N < 2) return;
+  l = N >> 1;
+  ir = N - 1;
+  for (;;) {
+    if (l > 0) {
+      temp = value[--l];
+    }
+    else {
+      temp = value[ir];
+      value[ir] = value[0];
+      if (--ir == 0) {
+	value[0] = temp;
+	return;
+      }
+    }
+    i = l;
+    j = (l << 1) + 1;
+    while (j <= ir) {
+      if (j < ir && value[j] < value[j+1]) ++j;
+      if (temp < value[j]) {
+	value[i]=value[j];
+	j += (i=j) + 1;
+      }
+      else j = ir + 1;
+    }
+    value[i] = temp;
+  }
+}
Index: /trunk/Ohana/src/imregister/detrend/args.detregister.c
===================================================================
--- /trunk/Ohana/src/imregister/detrend/args.detregister.c	(revision 3)
+++ /trunk/Ohana/src/imregister/detrend/args.detregister.c	(revision 3)
@@ -0,0 +1,125 @@
+# include "imregister.h" 
+# include "detrend.h"
+
+/* criteria struct is global */
+int regargs (int argc, char **argv, Descriptor *descriptor) {
+
+  int N, i;
+
+  ConfigInit (&argc, argv);
+  ConfigCamera ();
+  ConfigFilter ();
+
+  output.Modify = TRUE;
+
+  /* these command line arguments will override image header info */
+  /* define time range */
+  descriptor[0].TimeSelect = FALSE;
+  if (N = get_argument (argc, argv, "-time")) {
+    remove_argument (N, &argc, argv);
+    if (!str_to_time (argv[N], &descriptor[0].tstart)) { 
+      fprintf (stderr, "syntax error\n");
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+    if (!str_to_time (argv[N], &descriptor[0].tstop)) { 
+      fprintf (stderr, "syntax error\n");
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+    descriptor[0].TimeSelect = TRUE;
+  }
+
+  /* set optional label */
+  descriptor[0].label = strcreate ("detrend");
+  if (N = get_argument (argc, argv, "-label")) {
+    remove_argument (N, &argc, argv);
+    descriptor[0].label = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+ 
+  /* set optional label */
+  descriptor[0].imageID = strcreate ("test");
+  if (N = get_argument (argc, argv, "-ID")) {
+    remove_argument (N, &argc, argv);
+    descriptor[0].imageID = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+ 
+  /* set optional order */
+  descriptor[0].order = 0;
+  if (N = get_argument (argc, argv, "-order")) {
+    remove_argument (N, &argc, argv);
+    descriptor[0].order = atoi (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+ 
+  /* define image type */
+  descriptor[0].type = T_NONE;
+  if (N = get_argument (argc, argv, "-type")) {
+    remove_argument (N, &argc, argv);
+    for (i = 0; i < NTYPE; i++) {
+      if (!strncasecmp (argv[N], typename[i], strlen(typename[i]))) {
+	descriptor[0].type = i;
+      }
+    }
+    if (descriptor[0].type == T_NONE) {
+      fprintf (stderr, "ERROR: invalid image type %s\n", argv[N]);
+      exit (1);
+    }
+    remove_argument (N, &argc, argv);
+  }
+ 
+  /* define ccd number */
+  descriptor[0].CCDSelect = FALSE;
+  if (N = get_argument (argc, argv, "-ccd")) {
+    remove_argument (N, &argc, argv);
+    descriptor[0].CCD = -1;
+    for (i = 0; (i < Nccd) && (descriptor[0].CCD == -1); i++) {
+      if (strnumcmp (ccds[i], argv[N])) {
+	descriptor[0].CCD = i;
+      }
+    }
+    if (descriptor[0].CCD == -1) {
+      fprintf (stderr, "ERROR: ccd %s choice out not found in camera config\n", argv[N]);
+      exit (1);
+    }
+    remove_argument (N, &argc, argv);
+    descriptor[0].CCDSelect = TRUE;
+  }
+ 
+  /* define exposure time */
+  descriptor[0].Exptime = 0.0;
+  descriptor[0].ExptimeSelect = FALSE;
+  if (N = get_argument (argc, argv, "-exptime")) {
+    remove_argument (N, &argc, argv);
+    descriptor[0].Exptime = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+    descriptor[0].ExptimeSelect = TRUE;
+  }
+ 
+  /* define filter */
+  descriptor[0].filter = FILTER_NONE;
+  if (N = get_argument (argc, argv, "-filter")) {
+    remove_argument (N, &argc, argv);
+    for (i = 0; (i < NFILTER) && (descriptor[0].filter == FILTER_NONE); i++) {
+      if (!strcasecmp (argv[N], filtername[i])) {
+	descriptor[0].filter = filternum[i];
+      }
+    }      
+    if (descriptor[0].filter == FILTER_NONE) {
+      fprintf (stderr, "ERROR: invalid filter %s\n", argv[N]);
+      exit (1);
+    }
+    remove_argument (N, &argc, argv);
+  }
+
+  /*** this program will only register SPLIT images ***/
+
+  if (argc != 2) {
+    fprintf (stderr, "USAGE: detregister (filename) [config ops] -time start stop] [-type type] [-ccd N] [-filter name]\n");
+    fprintf (stderr, "ERROR - detregister not run\n");
+    exit (1);
+  }
+  
+}
Index: /trunk/Ohana/src/imregister/detrend/args.detsearch.c
===================================================================
--- /trunk/Ohana/src/imregister/detrend/args.detsearch.c	(revision 3)
+++ /trunk/Ohana/src/imregister/detrend/args.detsearch.c	(revision 3)
@@ -0,0 +1,337 @@
+# include "imregister.h"
+# include "detrend.h"
+
+/********* decipher all of the possible command-line options ***********/
+int args (int argc, char **argv) {
+
+  int i, N;
+  int MosaicSelect, ImageSelect, RangeSelect, bad, Recipe, Ncrit;
+  char *ImageFile, *ImageMode, *ImageExtend;
+  Header header;
+  char line[256];
+  Criteria base, *crit;
+  int Ntimes, Nfilt, *filt;
+  unsigned long *tstart, *tstop;
+
+  if (N = get_argument (argc, argv, "-h")) { usage (); }
+  if (N = get_argument (argc, argv, "--help")) { usage (); }
+  bzero (&base, sizeof (Criteria));
+
+  /* check config & command-line args */
+  ConfigInit (&argc, argv);
+  ConfigCamera ();
+  ConfigFilter ();
+
+  /* mosaic-based selection */
+  MosaicSelect = FALSE;
+  if (N = get_argument (argc, argv, "-mosaic")) {
+    remove_argument (N, &argc, argv);
+    ImageFile = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+    MosaicSelect = TRUE;
+    /* check for incompatible arguments: -exptime, -filter, -time, -ccd */
+    bad = get_argument (argc, argv, "-exptime");
+    bad &= get_argument (argc, argv, "-image");
+    bad &= get_argument (argc, argv, "-filter");
+    bad &= get_argument (argc, argv, "-trange");
+    bad &= get_argument (argc, argv, "-time");
+    bad &= get_argument (argc, argv, "-ccd");
+    if (bad) { 
+      fprintf (stderr, "ERROR: syntax error: conflict with -mosaic\n");
+      exit (1);
+    }
+  }
+
+  /* image-based selection */
+  ImageSelect = FALSE;
+  if (N = get_argument (argc, argv, "-image")) {
+    remove_argument (N, &argc, argv);
+    ImageFile = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+    ImageExtend = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+    ImageMode = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+    ImageSelect = TRUE;
+    /* check for incompatible arguments: -exptime, -filter, -time, -ccd */
+    bad = get_argument (argc, argv, "-exptime");
+    bad &= get_argument (argc, argv, "-filter");
+    bad &= get_argument (argc, argv, "-trange");
+    bad &= get_argument (argc, argv, "-time");
+    bad &= get_argument (argc, argv, "-ccd");
+    if (bad) { 
+      fprintf (stderr, "ERROR: syntax error: conflict with -image\n");
+      exit (1);
+    }
+  }
+
+  /* define image type */
+  base.TypeSelect = FALSE;
+  base.Type = T_NONE;
+  if (N = get_argument (argc, argv, "-type")) {
+    remove_argument (N, &argc, argv);
+    for (i = 0; (i < NTYPE) && (base.Type == T_NONE); i++) {
+      if (!strncasecmp (argv[N], typename[i], strlen(typename[i]))) {
+	base.Type = i;
+      }
+    }
+    if (base.Type == T_NONE) {
+      fprintf (stderr, "ERROR: invalid image type %s\n", argv[N]);
+      exit (1);
+    }
+    remove_argument (N, &argc, argv);
+    base.TypeSelect = TRUE;
+    if (base.Type == T_ANY) base.TypeSelect = FALSE;
+  }
+ 
+  /* define time / ranges */
+  tstart = tstop = (unsigned long *) NULL;
+  base.TimeSelect = base.tstart = base.tstop = 0;
+  if (N = get_argument (argc, argv, "-time")) {
+    remove_argument (N, &argc, argv);
+    bad  = get_argument (argc, argv, "-trange");
+    bad &= str_to_time (argv[N], &base.tstart);
+    if (bad) {
+      fprintf (stderr, "ERROR: syntax error in -time\n");
+      exit (1);
+    }
+    base.tstop = base.tstart;  /* no need for dtime > 0 ? */
+    remove_argument (N, &argc, argv);
+    base.TimeSelect = 1;
+  } else {
+    if (!get_trange_arguments (&argc, argv, &tstart, &tstop, &base.TimeSelect)) {
+      fprintf (stderr, "ERROR: syntax error in -trange\n");
+      exit (1);
+    }
+  }
+
+  /* define filters */
+  base.FilterSelect = FALSE;
+  if (!get_filter_arguments (&argc, argv, &filt, &base.FilterSelect)) {
+    fprintf (stderr, "ERROR: syntax error in -filter\n");
+    exit (1);
+  }
+
+  /* define ccd number */
+  base.CCDSelect = FALSE;
+  if (N = get_argument (argc, argv, "-ccd")) {
+    base.CCD = -1;
+    remove_argument (N, &argc, argv);
+    for (i = 0; (i < Nccd) && (base.CCD == -1); i++) {
+      if (strnumcmp (ccds[i], argv[N])) {
+	base.CCD = i;
+      }
+    }
+    if (base.CCD == -1) {
+      fprintf (stderr, "ERROR: ccd %s choice out not found in camera config\n", argv[N]);
+      exit (1);
+    }
+    remove_argument (N, &argc, argv);
+    base.CCDSelect = TRUE;
+  }
+ 
+  /* define exposure time */
+  base.ExptimeSelect = FALSE;
+  if (N = get_argument (argc, argv, "-exptime")) {
+    remove_argument (N, &argc, argv);
+    base.Exptime = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+    base.ExptimeSelect = TRUE;
+  }
+ 
+  /* varients on the standard selection */
+  base.EntrySelect = FALSE;
+  if (N = get_argument (argc, argv, "-entry")) {
+    remove_argument (N, &argc, argv);
+    base.Entry = atoi (argv[N]);
+    remove_argument (N, &argc, argv);
+    base.EntrySelect = TRUE;
+  }
+  base.MatchNumber = -1;
+  if (N = get_argument (argc, argv, "-match")) {
+    remove_argument (N, &argc, argv);
+    base.MatchNumber = atoi (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  base.LabelSelect = FALSE;
+  if (N = get_argument (argc, argv, "-label")) {
+    remove_argument (N, &argc, argv);
+    base.Label = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+    base.LabelSelect = TRUE;
+  }
+
+  /* these options affect the output mode */
+  output.Close = FALSE;
+  if (N = get_argument (argc, argv, "-close")) {
+    if (!base.TimeSelect) {       
+      fprintf (stderr, "ERROR: syntax error in -close requires -time or -trange\n");
+      exit (1);
+    }
+    remove_argument (N, &argc, argv);
+    output.Close = TRUE;
+  }
+  output.TimeMode = START;
+  if (N = get_argument (argc, argv, "-tstop")) {
+    remove_argument (N, &argc, argv);
+    output.TimeMode = STOP;
+  }
+  if (N = get_argument (argc, argv, "-treg")) {
+    remove_argument (N, &argc, argv);
+    output.TimeMode = REG;
+  }
+  output.ElixirSmart = FALSE;
+  if (N = get_argument (argc, argv, "-ve")) {
+    remove_argument (N, &argc, argv);
+    output.ElixirSmart = TRUE;
+  }
+  output.verbose = TRUE;
+  if (N = get_argument (argc, argv, "-quiet")) {
+    remove_argument (N, &argc, argv);
+    output.verbose = FALSE;
+  }
+  output.table = (char *) NULL;
+  if (N = get_argument (argc, argv, "-fits")) {
+    remove_argument (N, &argc, argv);
+    output.table = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  output.bintable = (char *) NULL;
+  if (N = get_argument (argc, argv, "-binfits")) {
+    remove_argument (N, &argc, argv);
+    output.bintable = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  output.Criteria = FALSE;
+  if (N = get_argument (argc, argv, "-criteria")) {
+    output.Criteria = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  /* these options modify behavior */
+  output.Select = FALSE;
+  if (N = get_argument (argc, argv, "-select")) {
+    remove_argument (N, &argc, argv);
+    output.Select = TRUE;
+  }
+ 
+  /* these options modify behavior */
+  Recipe = FALSE;
+  if (N = get_argument (argc, argv, "-recipe")) {
+    remove_argument (N, &argc, argv);
+    Recipe = TRUE;
+    if (base.Type != T_NONE) {
+      fprintf (stderr, "-recipe and -type cannot be combined\n");
+      exit (1);
+    }
+  }
+ 
+  /* options which alter the database */
+  output.Delete = FALSE;
+  if (N = get_argument (argc, argv, "-del")) {
+    remove_argument (N, &argc, argv);
+    output.Delete = TRUE;
+  }
+  if (N = get_argument (argc, argv, "-delete")) {
+    remove_argument (N, &argc, argv);
+    output.Delete = TRUE;
+  }
+ 
+  output.Modify = FALSE;
+  if (N = get_argument (argc, argv, "-modify")) {
+    if (output.Delete) {
+      fprintf (stderr, "can't combine -delete and -modify flags\n");
+      exit (1);
+    }
+    remove_argument (N, &argc, argv);
+    output.Modify = TRUE;
+    output.ModifyEntry = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+    output.ModifyValue = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+    if (!strcasecmp (output.ModifyEntry, "label")) goto valid_entry;
+    if (!strcasecmp (output.ModifyEntry, "order")) goto valid_entry;
+    if (!strcasecmp (output.ModifyEntry, "tstop")) goto valid_entry;
+    if (!strcasecmp (output.ModifyEntry, "tstart")) goto valid_entry;
+    fprintf (stderr, "invalid entry for -modify %s\n", output.ModifyEntry);
+    exit (1);
+  valid_entry:
+    if (!strcasecmp (output.ModifyEntry, "tstart") || !strcasecmp (output.ModifyEntry, "tstop")) {
+      if (!str_to_time (output.ModifyValue, &output.TimeValue)) { 
+	fprintf (stderr, "ERROR: invalid time %s\n", output.ModifyValue);
+	exit (1);
+      }
+    }
+  }
+
+  /* consistency checks */
+  if ((base.Type == T_DARK) || (base.Type == T_BIAS) || (base.Type == T_MASK)) {
+    if (base.FilterSelect) {
+      fprintf (stderr, "ERROR: filter invalid with type %s\n", typename[base.Type]);
+      exit (1);
+    }
+  }
+  if ((base.Type != T_DARK) && base.ExptimeSelect) {
+    fprintf (stderr, "ERROR: exptime invalid with type %s\n", typename[base.Type]);
+    exit (1);
+  }
+  if (output.Select && !base.TimeSelect) {
+    fprintf (stderr, "ERROR: selection missing time\n");
+    exit (1);
+  }
+
+  /* arguments have all been read */
+  if (argc != 1) {
+    fprintf (stderr, "USAGE: detsearch [config ops] [-mosaic name] [-image name Nx Mode] [-time start] [-type type] [-ccd N] [-filter name]\n");
+    exit (1);
+  }
+
+  /* set up criteria based on image, mosaic, or base (all mutually exclusive) */
+  if (ImageSelect)  
+    crit = ImageCriteria (base, ImageFile, ImageExtend, ImageMode, &Ncrit);
+  if (MosaicSelect) 
+    crit = MosaicCriteria (base, ImageFile, &Ncrit);
+  if (!MosaicSelect && !ImageSelect)
+    crit = ExpandBase (base, &Ncrit, tstart, tstop, filt);
+
+  if (Recipe) {
+    crit = ExpandRecipe (crit, &Ncrit);
+  }
+
+  Ncriteria = Ncrit;
+  criteria = crit;
+
+  return (TRUE);
+}
+
+Criteria *ExpandBase (Criteria base, int *ncrit, unsigned long *tstart, unsigned long *tstop, int *filt) {
+
+  Criteria *crit;
+  int i, j, Nc, Ncrit, Ntimes, Nfilt; 
+
+  /* expand multiple -filter, -trange options */
+  Nfilt  = base.FilterSelect;
+  Ntimes = base.TimeSelect;
+  if (Ntimes == 0) Ntimes = 1;
+  if (Nfilt  == 0) Nfilt  = 1;
+
+  Ncrit = Nfilt*Ntimes;
+  ALLOCATE (crit, Criteria, Ncrit);
+
+  Nc = 0;
+  for (i = 0; i < Nfilt; i++) {
+    for (j = 0; j < Ntimes; j++) {
+      crit[Nc] = base;
+      if (tstart != (unsigned long *) NULL) {
+	crit[Nc].tstart       = tstart[j];
+	crit[Nc].tstop        = tstop[j];
+      } 
+      if (base.FilterSelect) {
+	crit[Nc].Filter       = filt[i];
+      } 
+      Nc ++;
+    }
+  }
+  *ncrit = Ncrit;
+  return (crit);
+}
Index: /trunk/Ohana/src/imregister/detrend/criteria.c
===================================================================
--- /trunk/Ohana/src/imregister/detrend/criteria.c	(revision 3)
+++ /trunk/Ohana/src/imregister/detrend/criteria.c	(revision 3)
@@ -0,0 +1,209 @@
+# include "imregister.h"
+# include "detrend.h"
+
+Match CheckCriteria (DetReg *image) {
+
+  Match match;
+  int i, close, crit;
+
+  match.state = MATCH_NONE;
+  match.crit  = 0;
+  match.image = -1;
+
+  close = FALSE;
+  for (i = 0; (i < Ncriteria) && (match.state == MATCH_NONE); i++) {
+
+    /***********  fix this *****/
+    if (criteria[i].CCDSelect    && (image[0].ccd             != criteria[i].CCD))    continue;
+    if (criteria[i].TypeSelect   && (image[0].type            != criteria[i].Type))   continue;
+    if (criteria[i].FilterSelect && (image[0].filter          != criteria[i].Filter)) continue;
+
+    if (criteria[i].EntrySelect  && (image[0].Nentry          != criteria[i].Entry))  continue;
+    if (criteria[i].LabelSelect  && (strcasecmp (image[0].label, criteria[i].Label))) continue;
+
+    if (criteria[i].TimeSelect   && (image[0].tstart           > criteria[i].tstop))   continue;
+    if (criteria[i].TimeSelect   && (image[0].tstop            < criteria[i].tstart)) {
+      close = TRUE;
+      crit  = i;
+      continue;
+    } 
+    match.crit  = i;
+    match.state = MATCH_PERFECT;
+  }
+
+  if ((match.state == MATCH_NONE) && close) {
+    match.crit  = crit;
+    match.state = MATCH_CLOSE;
+  }    
+  return (match);
+
+}
+
+/* 
+   the image only needs to match one criterion
+   close only counts for TimeSelect
+   multiple criteria can exist for Range, CCD, Filter
+*/
+
+Match *ExptimeCriteria (Match *match, int *nmatch) {
+
+  int i, j, Nimage, Nmatch, Nnew, NNEW, entry;
+  unsigned long dtime;
+  float Chi, ChiMin;
+  DetReg *image;
+  Match *new;
+
+  Nmatch = *nmatch;
+  image = get_images (&Nimage);
+
+  Nnew = 0;
+  NNEW = 100;
+  ALLOCATE (new, Match, NNEW);
+
+  for (i = 0; i < Ncriteria; i++) {
+
+    /* find min Chi value */
+    ChiMin = HUGE;
+    for (j = 0; j < Nmatch; j++) {
+      if (match[j].crit != i) continue;
+      if (!criteria[i].ExptimeSelect) {
+	new[Nnew] = match[j];
+	Nnew ++;
+	if (Nnew == NNEW) {
+	  NNEW += 100;
+	  REALLOCATE (new, Match, NNEW);
+	}
+	continue;
+      }
+
+      entry = match[j].image;
+
+      dtime = 0;
+      if (criteria[i].TimeSelect) {
+	if (criteria[i].tstart > image[entry].tstop) 
+	  dtime = criteria[i].tstart - image[entry].tstop;
+	if (criteria[i].tstop < image[entry].tstart) 
+	  dtime = image[entry].tstart - criteria[i].tstop;
+      }
+      Chi = dtime / 864.0 + abs (criteria[i].Exptime - image[entry].exptime);
+      ChiMin = MIN (Chi, ChiMin);
+    }
+
+    /* select entries with Chi <= ChiMin */
+    for (j = 0; j < Nmatch; j++) {
+      if (match[j].crit != i) continue;
+      if (!criteria[i].ExptimeSelect) continue;
+      entry = match[j].image;
+      
+      dtime = 0;
+      if (criteria[i].TimeSelect) {
+	if (criteria[i].tstart > image[entry].tstop) 
+	  dtime = criteria[i].tstart - image[entry].tstop;
+	if (criteria[i].tstop < image[entry].tstart) 
+	  dtime = image[entry].tstart - criteria[i].tstop;
+      }
+      Chi = dtime / 864.0 + abs (criteria[i].Exptime - image[entry].exptime);
+      if (Chi <= ChiMin) {
+	new[Nnew] = match[j];
+	Nnew ++;
+	if (Nnew == NNEW) {
+	  NNEW += 100;
+	  REALLOCATE (new, Match, NNEW);
+	}
+      }
+    }
+  }
+
+  free (match);
+  *nmatch = Nnew;
+  return (new);
+}
+
+Match *CloseCriteria (Match *match, int *nmatch) {
+
+  int i, j, Nimage, Nmatch, Nnew, NNEW, Ngood, entry;
+  unsigned long dmin, dtime;
+  Match *new;
+  DetReg *image;
+
+  image = get_images (&Nimage);
+
+  Nmatch = *nmatch;
+
+  Nnew = 0;
+  NNEW = 100;
+  ALLOCATE (new, Match, NNEW);
+
+  for (i = 0; i < Ncriteria; i++) {
+
+    Ngood = 0;
+
+    /* first include only perfect matches */
+    for (j = 0; j < Nmatch; j++) {
+      if (match[j].crit  != i) continue;
+      if (match[j].state != MATCH_PERFECT) continue;
+
+      Ngood ++;
+      new[Nnew] = match[j];
+      Nnew ++;
+      if (Nnew == NNEW) {
+	NNEW += 100;
+	REALLOCATE (new, Match, NNEW);
+      }	
+    } 
+
+    if (Ngood) continue;
+    if (!output.Close) continue;
+    if (!criteria[i].TimeSelect) continue;
+
+    /* find closest time */
+    dmin = 0xffffffff;
+    for (j = 0; j < Nmatch; j++) {
+      if (match[j].crit  != i) continue;
+      entry = match[j].image;
+      dmin = MIN (dmin, criteria[i].tstart - image[entry].tstop);
+    }
+
+    /* select images with dtime == dmin */
+    for (j = 0; j < Nmatch; j++) {
+      if (match[j].crit  != i) continue;
+      entry = match[j].image;
+      dtime = criteria[i].tstart - image[entry].tstop;
+      if (dtime <= dmin) {
+	new[Nnew] = match[j];
+	Nnew ++;
+	if (Nnew == NNEW) {
+	  NNEW += 100;
+	  REALLOCATE (new, Match, NNEW);
+	}	
+      }
+    }
+  }
+
+  free (match);
+  *nmatch = Nnew;
+  return (new);
+}
+
+
+
+
+
+/* CheckCriteria returns two pieces of information:
+   match state (MATCH_NONE, MATCH_CLOSE, MATCH_PERFECT)
+   match entry (i)
+*/
+   
+/* match[] contains all potentially valid matches.
+   if they are darks, there will be several with similar values for detdata[i].tstop
+   we want to minimize:
+   (tzero - tstop) and abs (ExpTime - detdata[i].exptime) 
+
+   Chi = (tzero - tstop) / 864 + abs (ExpTime - detdata[i].exptime)
+
+   if (tzero - tstop) = 2 days, this term contributes 200.  
+*/
+
+
+/* CloseCriteria returns all images which are either a perfect match
+   or which are close and have the same minimum time distance */
Index: /trunk/Ohana/src/imregister/detrend/db.c
===================================================================
--- /trunk/Ohana/src/imregister/detrend/db.c	(revision 3)
+++ /trunk/Ohana/src/imregister/detrend/db.c	(revision 3)
@@ -0,0 +1,218 @@
+# include "imregister.h"
+# include "detrend.h"
+
+/* variables which describe the db */
+char *dBPath;
+char *dBFile;
+char *dBTrash;
+FILE *f;
+Header header;
+Header theader;
+Matrix matrix;
+FTable table;
+DetReg *image;
+int Nimage;
+int lockstate, dbstate = LCK_UNLOCK;
+
+DetReg *get_images (int *N) {
+  *N = Nimage;
+  return (image);
+}
+
+int set_images (DetReg *new, int Nnew) {
+
+  int Nbytes;
+
+  free (image);
+
+  fits_modify (table.header, "NAXIS2", "%d", 1, Nnew);
+  table.header[0].Naxis[1] = Nnew;
+  Nbytes = fits_matrix_size (table.header);
+
+  Nimage = Nnew;
+  image = new;
+  REALLOCATE (image, DetReg, Nbytes);
+  table.buffer = (char *) image;
+  return (TRUE);
+}
+
+char *get_dBPath () {
+  return (dBPath);
+}
+
+int delete_image (DetReg *item) {
+  
+  int status;
+  char line[256];
+
+  if (output.verbose) fprintf (stderr, "deleting %s\n", item[0].filename);
+  sprintf (line, "mv -f %s/%s %s", dBPath, item[0].filename, dBTrash);
+  status = system (line);
+  if (status) fprintf (stderr, "trouble moving %s to trash (%s)\n", item[0].filename, dBTrash);
+
+  if (status) 
+    return (FALSE);
+  else 
+    return (TRUE);
+}
+
+int load_db () {
+
+  struct stat statbuf;
+  int status;
+  int Nx, Ny;
+
+  /* define dBFile based on config data */
+  dBPath = DetrendDB;
+  ALLOCATE (dBFile, char, strlen (dBPath) + 15);
+  sprintf (dBFile, "%s/detrend.db", DetrendDB);;
+  ALLOCATE (dBTrash, char, strlen (dBPath) + 15);
+  sprintf (dBTrash, "%s/trash", DetrendDB);
+
+  /* check on directories */
+  status = stat (dBPath, &statbuf);
+  if (output.Modify) {
+    if (status == -1) {
+      if (mkdirhier (dBPath) == -1) {
+	fprintf (stderr, "ERROR: can't find or create path %s\n", dBPath);
+	exit (1);
+      }
+    }
+  }
+  if (output.Delete) {
+    status = stat (dBTrash, &statbuf);
+    if (status == -1) {
+      if (mkdirhier (dBTrash) == -1) {
+	fprintf (stderr, "ERROR: detrend dB trash not found %s\n", dBTrash);
+	exit (1);
+      }
+    }
+  }
+  lockstate = (output.Modify || output.Delete) ? LCK_HARD : LCK_SOFT;
+
+  /* lock database (soft) */
+  f = fsetlockfile (dBFile, 300.0, lockstate, &dbstate);
+  if (dbstate == LCK_EMPTY) return (0);
+
+  if (f == (FILE *) NULL) {
+    fprintf (stderr, "ERROR: can't set lock on %s\n", dBFile);
+    exit (1);
+  }
+
+  /* load in table data */
+  table.header = &theader;
+  if (!fits_fread_header (f, &header))                     escape (UNLOCK, "ERROR: can't read primary header"); 
+  if (!fits_fread_matrix (f, &matrix, &header))            escape (UNLOCK, "ERROR: can't read primary header");
+  if (!fits_fread_ftable  (f, &table, "DETREND_DATABASE")) escape (UNLOCK, "ERROR: can't read primary header");
+
+  /* convert to internal format */
+  image = (DetReg *) table.buffer;
+  fits_scan (table.header, "NAXIS1", "%d", 1, &Nx);
+  fits_scan (table.header, "NAXIS2", "%d", 1, &Ny);
+  Nimage = Ny;
+
+  if (!ConvertStruct ((char *) image, sizeof (DetReg), Nimage, "detreg")) escape (UNLOCK, "ERROR: can't read primary header"); 
+  return (1);
+}
+
+
+/* save complete db file */
+int save_db () {
+
+  if (!ConvertStruct ((char *) image, sizeof (DetReg), Nimage, "detreg")) escape (UNLOCK, "ERROR: can't convert from native format");
+
+  /* write all images to file */
+  make_backup (dBFile);
+  Fseek (f, 0, SEEK_SET);
+  if (!fits_fwrite_header (f, &header))   escape (LOCK, "ERROR: can't update db");
+  if (!fits_fwrite_matrix (f, &matrix))   escape (LOCK, "ERROR: can't update db");
+  if (!fits_fwrite_Theader (f, &theader)) escape (LOCK, "ERROR: can't update db");
+  if (!fits_fwrite_table   (f, &table))   escape (LOCK, "ERROR: can't update db");
+  close_db ();
+  return (TRUE);
+}
+
+/* save subset in db file */
+int update_db (int *match, int Nmatch) {
+
+  int i, N, Nx, Ny;
+  VTable vtable;
+
+  fits_scan (table.header, "NAXIS1", "%d", 1, &Nx);
+  fits_scan (table.header, "NAXIS2", "%d", 1, &Ny);
+
+  /* make empty vtable from table */
+  vtable.header = table.header;
+  vtable.size = table.size;
+  vtable.Nrow = Ny;
+  vtable.pad = vtable.size - Nx*Ny;
+
+  /* insert selected rows in vtable */ 
+  ALLOCATE (vtable.row, int, Nmatch);
+  ALLOCATE (vtable.buffer, char *, Nmatch);
+  for (N = i = 0; i < Nmatch; i++) {
+    if (match[i] == -1) continue;
+    vtable.row[N] = match[i];
+    ALLOCATE (vtable.buffer[N], char, Nx);
+    memcpy (vtable.buffer[N], &image[match[i]], sizeof (DetReg));
+    ConvertStruct ((char *) vtable.buffer[N], sizeof (DetReg), 1, "detreg");
+    N++;
+  }
+  vtable.Nrow = N;
+
+  /* write subset to file */
+  make_backup (dBFile);
+  Fseek (f, 0, SEEK_SET);
+  if (!fits_fwrite_header (f, &header))   escape (LOCK, "ERROR: can't update db");
+  if (!fits_fwrite_matrix (f, &matrix))   escape (LOCK, "ERROR: can't update db");
+  if (!fits_fwrite_Theader (f, &theader)) escape (LOCK, "ERROR: can't update db");
+  if (!fits_fwrite_vtable   (f, &vtable)) escape (LOCK, "ERROR: can't update db");
+  close_db ();
+  return (TRUE);
+}
+
+int append_db (DetReg *new, int Nnew) {
+
+  VTable vtable;
+
+  fits_table_to_vtable (&table, &vtable);
+
+  ConvertStruct ((char *) new, sizeof (DetReg), Nnew, "detreg");
+  fits_vadd_rows (&vtable, new, Nnew, sizeof(DetReg));
+
+  /* write subset to file */
+  Fseek (f, 0, SEEK_SET);
+  if (!fits_fwrite_header (f, &header))   escape (LOCK, "ERROR: can't append to db");
+  if (!fits_fwrite_matrix (f, &matrix))   escape (LOCK, "ERROR: can't append to db");
+  if (!fits_fwrite_Theader (f, &theader)) escape (LOCK, "ERROR: can't append to db");
+  if (!fits_fwrite_vtable   (f, &vtable)) escape (LOCK, "ERROR: can't append to db");
+  close_db ();
+  return (TRUE);
+}
+
+int create_db () {
+
+  /* f & dBFile set by load_db */
+
+  /* define table layout */
+  define_table (&header, &matrix, &theader, &table);
+
+  /* convert to internal format */
+  image = (DetReg *) table.buffer;
+  Nimage = 0;
+
+  return (TRUE);
+}
+
+int close_db () {
+  if (dbstate == LCK_UNLOCK) return (TRUE);
+  fclearlockfile (dBFile, f, lockstate, &dbstate);
+  return (TRUE);
+}  
+
+int escape (int mode, char *message) {
+  
+  if (mode == UNLOCK) close_db ();
+  fprintf (stderr, "%s\n", message);
+  exit (1);
+}
Index: /trunk/Ohana/src/imregister/detrend/define.c
===================================================================
--- /trunk/Ohana/src/imregister/detrend/define.c	(revision 3)
+++ /trunk/Ohana/src/imregister/detrend/define.c	(revision 3)
@@ -0,0 +1,33 @@
+# include "imregister.h"
+# include "detrend.h"
+
+int define_table (Header *header, Matrix *matrix, Header *theader, FTable *table) {
+
+    /* create primary header */
+    fits_init_header (header);    
+    header[0].extend = TRUE;
+    fits_create_header (header);
+    fits_create_matrix (header, matrix);
+    fits_print (header, "NEXTEND", "%d", 1, 1);
+    
+    /* define bintable header & layout */
+    fits_create_table_header (theader, "BINTABLE", "DETREND_DATABASE");
+    
+    fits_define_bintable_column (theader, "J",    "START_TIME", "start time of measurement", "seconds since Jan 1, 1970 UT",  1.0, 0.0);
+    fits_define_bintable_column (theader, "J",    "STOP_TIME",  "stop time of measurement",  "seconds since Jan 1, 1970 UT",  1.0, 0.0);
+    fits_define_bintable_column (theader, "J",    "REG_TIME",   "time of registration",      "seconds since Jan 1, 1970 UT",  1.0, 0.0);
+    fits_define_bintable_column (theader, "E",    "EXPTIME",    "exposure time",             "seconds",                       1.0, 0.0); 
+    fits_define_bintable_column (theader, "J",    "IMAGETYP",   "detrend type number",       "",                              1.0, 0.0);
+    fits_define_bintable_column (theader, "J",    "FILTER",     "filter number",             "",                              1.0, 0.0);
+    fits_define_bintable_column (theader, "J",    "CCDNUM",     "ccd number",                "",                              1.0, 0.0);
+    fits_define_bintable_column (theader, "J",    "VERSION",    "image version number",      "",                              1.0, 0.0);
+    fits_define_bintable_column (theader, "J",    "ORDER",      "selection order",           "",                              1.0, 0.0);
+    fits_define_bintable_column (theader, "60A",  "RESERVED",   "space for additions",       "photcode",                      1.0, 0.0);
+    fits_define_bintable_column (theader, "64A",  "LABEL",      "data label",                "",                              1.0, 0.0);
+    fits_define_bintable_column (theader, "256A", "PATH",       "filename in db",            "",                              1.0, 0.0);
+
+    /* create table, add data values */
+    fits_create_table (theader, table);
+    
+    return (TRUE);
+}
Index: /trunk/Ohana/src/imregister/detrend/delete.c
===================================================================
--- /trunk/Ohana/src/imregister/detrend/delete.c	(revision 3)
+++ /trunk/Ohana/src/imregister/detrend/delete.c	(revision 3)
@@ -0,0 +1,48 @@
+# include "imregister.h"
+# include "detrend.h"
+
+int DeleteSubset (Match *match, int Nmatch) {
+
+  int i, j, status;
+  int *keep, Ndel, Nimage, Nsubset;
+  DetReg *image, *subset;
+
+  image = get_images (&Nimage);
+
+  ALLOCATE (keep, int, Nimage);
+  for (i = 0; i < Nimage; i++) keep[i] = TRUE;
+
+  Ndel = 0;
+  /* list matched images */
+  for (j = 0; j < Nmatch; j++) {
+    i = match[j].image;
+    if (i == -1) continue;
+    keep[i] = FALSE;
+
+    delete_image (&image[i]);
+    Ndel ++;
+  }
+  
+  if (Ndel == 0) { 
+    fprintf (stderr, "SUCCESS\n");
+    exit (0);
+  }
+
+  /* create new data list */
+  ALLOCATE (subset, DetReg, Nimage);
+  Nsubset = 0;
+  for (i = 0; i < Nimage; i++) {
+    if (keep[i]) {
+      subset[Nsubset] = image[i];
+      Nsubset ++;
+    }
+  }
+
+  set_images (subset, Nsubset);
+
+  save_db ();
+  close_db ();
+
+  fprintf (stderr, "SUCCESS\n");
+  exit (0);
+}
Index: /trunk/Ohana/src/imregister/detrend/entry.c
===================================================================
--- /trunk/Ohana/src/imregister/detrend/entry.c	(revision 3)
+++ /trunk/Ohana/src/imregister/detrend/entry.c	(revision 3)
@@ -0,0 +1,109 @@
+# include "imregister.h"
+# include "detrend.h"
+
+DetReg DefineEntry (Descriptor descriptor) {
+  
+  struct timeval now;
+  DetReg newdata;
+
+  gettimeofday (&now, (void *) NULL);
+  
+  /* now we have all of the data (except filename), set the new entry */
+  newdata.tstart    = descriptor.tstart;
+  newdata.tstop     = descriptor.tstop;
+  newdata.treg      = now.tv_sec;
+  newdata.type      = descriptor.type;
+  newdata.filter    = descriptor.filter;
+  newdata.ccd       = descriptor.CCD;
+  newdata.exptime   = descriptor.Exptime;
+  newdata.Norder    = descriptor.order;
+  bzero (newdata.dummy, 60);
+  snprintf (newdata.label, 64, "%s", descriptor.label);
+  
+  return (newdata);
+}
+
+/* we are generating a name based on type, etc.  determine valid path */
+int SaveEntry (char *input, DetReg *newdata, char *ID) {
+
+  int status;
+  int found, Ntry, fd, filestate;
+  char path[256], fullpath[256], filename[256], rootname[256], fullname[256], line[512];
+  char *dBPath;
+  char *filter_basename;
+  struct stat statbuf;
+
+
+  filter_basename = filterhash[newdata[0].filter];
+  dBPath = get_dBPath ();
+
+  if (newdata[0].type == T_FLAT) {
+    sprintf (path, "%s/%s", typename[newdata[0].type], filter_basename);
+  } else {
+    sprintf (path, "%s", typename[newdata[0].type]);
+  }    
+  sprintf (fullpath, "%s/%s", dBPath, path);
+
+  status = stat (fullpath, &statbuf);
+  if (status == -1) {
+    if (errno == ENOENT) {
+      if (mkdirhier (fullpath) == -1) {
+	fprintf (stderr, "ERROR: can't create path %s\n", fullpath);
+	exit (1);
+      }
+    } else {
+      fprintf (stderr, "ERROR: problem with path %s\n", fullpath);
+      exit (1);
+    }
+  }
+
+  /* base filename constructed from detrend type information */
+  switch (newdata[0].type) {
+  case T_DARK:
+  case T_BIAS:
+  case T_MASK:
+    sprintf (rootname, "%s.%s.%d.%02d", ID, typename[newdata[0].type], (int)newdata[0].exptime, newdata[0].ccd);
+    break;
+  default:
+    sprintf (rootname, "%s.%s.%s.%02d", ID, typename[newdata[0].type], filter_basename, newdata[0].ccd);
+  }
+
+  /* find & lock first file of the format name that does not exist */
+  found = FALSE;
+  for (Ntry = 0; !found && (Ntry < 100); Ntry++) {
+    sprintf (filename, "%s/%s.%02d.fits", path, rootname, Ntry);
+    sprintf (fullname, "%s/%s", dBPath, filename);
+    fd = setlockfile2 (fullname, 2.0, LCK_XCLD, &filestate);
+    if (filestate == LCK_EMPTY) {
+	found = TRUE;
+	newdata[0].Nentry = Ntry;
+    } 
+  }
+  if (!found) { 
+    fprintf (stderr, "ERROR: no available target files for %s/%s?\n", path, rootname);
+    exit (1);
+  }
+  strcpy (newdata[0].filename, filename);
+    
+  if (DEBUG) {
+    fprintf (stderr, "path: %s\n", path);
+    fprintf (stderr, "fullpath: %s\n", fullpath);
+    fprintf (stderr, "filename: %s\n", filename);
+    fprintf (stderr, "dBPath: %s\n", dBPath);
+    fprintf (stderr, "line: %s\n", line);
+  }
+
+  /* copy the file to the new name, add entry to database */
+  /* we need some error checking here - complain if filename > 255 */
+  /* the copy replaces the locked file, lock remains valid */
+
+  sprintf (line, "/bin/cp -f %s %s", input, fullname);
+  status = system (line);
+  if (status) {
+    fprintf (stderr, "ERROR: failure in image copy %s to %s\n", input, fullname);
+    exit (1);
+  }
+  clearlockfile2 (fullname, fd, LCK_XCLD, &filestate);
+
+  return (TRUE);
+}
Index: /trunk/Ohana/src/imregister/detrend/imdef.c
===================================================================
--- /trunk/Ohana/src/imregister/detrend/imdef.c	(revision 3)
+++ /trunk/Ohana/src/imregister/detrend/imdef.c	(revision 3)
@@ -0,0 +1,131 @@
+# include "imregister.h"
+# include "detrend.h"
+
+int DefineImage (char *filename, Descriptor *descriptor) {
+
+  int i, CCD;
+  char line[512];
+  Header header;
+
+  /* load remaining options from the image header */
+  if (!fits_read_header (filename, &header)) {
+    fprintf (stderr, "ERROR: trouble reading image header\n");
+    exit (1);
+  }
+
+  /* first decide on image TYPE */
+  if (descriptor[0].type == T_NONE) {
+    if (!fits_scan (&header, ImagetypeKeyword, "%s", 1, line)) {
+      fprintf (stderr, "ERROR: failure to read %s from header\n", ImagetypeKeyword);
+      exit (1);
+    }
+    for (i = 0; i < NTYPE; i++) {
+      if (!strncasecmp (line, typename[i], strlen(typename[i]))) {
+	descriptor[0].type = i;
+      }
+    }
+    if (descriptor[0].type == T_NONE) {
+      fprintf (stderr, "ERROR: invalid image type %s\n", line);
+      exit (1);
+    }
+  }    
+  /* conflicts */
+  if ((descriptor[0].type == T_DARK) && (descriptor[0].filter != FILTER_NONE)) {
+    fprintf (stderr, "ERROR: dark can't have a filter\n");
+    exit (1);
+  }
+  if ((descriptor[0].type == T_BIAS) && (descriptor[0].filter != FILTER_NONE)) {
+    fprintf (stderr, "ERROR: bias can't have a filter\n");
+    exit (1);
+  }
+  if ((descriptor[0].type == T_MASK) && (descriptor[0].filter != FILTER_NONE)) {
+    fprintf (stderr, "ERROR: mask can't have a filter\n");
+    exit (1);
+  }
+
+  /* now identify CCD number */
+  if (!descriptor[0].CCDSelect) {
+    if (descriptor[0].type != T_MODES) {
+      char ID[64];
+
+      descriptor[0].CCD = -1;
+      if (!fits_scan (&header, CCDnumKeyword, "%s", 1, ID)) {
+	fprintf (stderr, "ERROR: failure to read %s from header\n", CCDnumKeyword);
+	exit (1);
+      }
+      for (i = 0; (i < Nccd) && (CCD == -1); i++) {
+	if (strnumcmp (ID, ccds[i])) {
+	  descriptor[0].CCD = i;
+	}
+      }
+      if (descriptor[0].CCD == -1) {
+	fprintf (stderr, "warning: ccd id not found\n");
+	descriptor[0].CCD = 0;
+      }
+      descriptor[0].CCDSelect = TRUE;
+    } else {
+      descriptor[0].CCD = Nccd;
+    }
+  }
+
+  /* now get time range */
+  if (!descriptor[0].TimeSelect) {
+    if (!fits_scan (&header, "TVSTART",   "%s", 1, line)) {
+      fprintf (stderr, "ERROR: missing start time\n");
+      exit (1);
+    }
+    if (!str_to_time (line, &descriptor[0].tstart)) { 
+      fprintf (stderr, "ERROR: invalid time %s\n", line);
+      exit (1);
+    }
+    
+    if (!fits_scan (&header, "TVSTOP",   "%s", 1, line)) {
+      fprintf (stderr, "ERROR: missing stop time\n");
+      exit (1);
+    }
+    if (!str_to_time (line, &descriptor[0].tstop)) { 
+      fprintf (stderr, "ERROR: invalid time %s\n", line);
+      exit (1);
+    }
+  }
+
+  /* select the filter */
+  if (descriptor[0].type != T_DARK) goto skip_filter;
+  if (descriptor[0].type != T_BIAS) goto skip_filter;
+  if (descriptor[0].type != T_MASK) goto skip_filter;
+  if (descriptor[0].filter == FILTER_NONE) goto skip_filter;
+  if (!fits_scan (&header, FilterKeyword, "%s", 1, line)) {
+    fprintf (stderr, "ERROR: failure to read %s from header\n", FilterKeyword);
+    exit (1);
+  }
+  for (i = 0; (i < NFILTER) && (descriptor[0].filter == FILTER_NONE); i++) {
+    if (!strcasecmp (line, filtername[i])) {
+      descriptor[0].filter = filternum[i];
+    }
+  }      
+  if (descriptor[0].filter == FILTER_NONE) {
+    fprintf (stderr, "ERROR: invalid filter %s\n", line);
+    exit (1);
+  }
+skip_filter:
+
+  /* set the exposure time, if needed */
+  if (descriptor[0].ExptimeSelect && (descriptor[0].type != T_DARK)) {
+    fprintf (stderr, "exposure time is not allowed for type %s\n", typename[descriptor[0].type]);
+    exit (1);
+  }
+  if (!descriptor[0].ExptimeSelect && (descriptor[0].type == T_DARK)) {
+    if (!fits_scan (&header, ExptimeKeyword,  "%f", 1, &descriptor[0].Exptime)) {
+      fprintf (stderr, "ERROR: failure to read %s from header\n", ExptimeKeyword);
+      exit (1);
+    }
+  }
+
+  /* set the image ID (!!!!) -- this is not being done.. */
+  if (fits_scan (&header, "CRUNID",   "%s", 1, line)) {
+    descriptor[0].imageID = strcreate (line);
+  }
+  
+  return (TRUE);
+}
+
Index: /trunk/Ohana/src/imregister/detrend/match.c
===================================================================
--- /trunk/Ohana/src/imregister/detrend/match.c	(revision 3)
+++ /trunk/Ohana/src/imregister/detrend/match.c	(revision 3)
@@ -0,0 +1,35 @@
+# include "imregister.h"
+# include "detrend.h"
+
+Match *MatchCriteria (int *nmatch) {
+
+  int i;
+  int Nmatch, NMATCH, Nimage;
+  Match result, *match;
+  DetReg *image;
+
+  image = get_images (&Nimage);
+
+  /* find entries that matches criteria */
+  Nmatch = 0;
+  NMATCH = 100;
+  ALLOCATE (match, Match, NMATCH);
+
+  /* find set of images that matches criteria */
+  for (i = 0; i < Nimage; i++) {
+    result = CheckCriteria (&image[i]);
+    if (result.state == MATCH_NONE) continue;
+
+    result.image = i;
+    match[Nmatch] = result;
+    Nmatch ++;
+    if (Nmatch == NMATCH) {
+      NMATCH += 100;
+      REALLOCATE (match, Match, NMATCH);
+    }
+  }
+
+  *nmatch = Nmatch;
+  return (match);
+  
+}
Index: /trunk/Ohana/src/imregister/detrend/modify.c
===================================================================
--- /trunk/Ohana/src/imregister/detrend/modify.c	(revision 3)
+++ /trunk/Ohana/src/imregister/detrend/modify.c	(revision 3)
@@ -0,0 +1,38 @@
+# include "imregister.h"
+# include "detrend.h"
+
+int ModifySubset (Match *match, int Nmatch) {
+  
+  int i, j, Nimage;
+  int *list;
+  DetReg *image;
+  
+  image = get_images (&Nimage);
+  ALLOCATE (list, int, Nimage);
+
+  /* list matched images */
+  for (j = 0; j < Nmatch; j++) {
+    i = match[j].image;
+    list[j] = i;
+    
+    if (!strcasecmp (output.ModifyEntry, "label")) {
+      snprintf (image[i].label, 64, "%s", output.ModifyValue);
+    }
+    if (!strcasecmp (output.ModifyEntry, "order")) {
+      image[i].Norder = atoi (output.ModifyValue);
+    }
+    if (!strcasecmp (output.ModifyEntry, "tstart")) {
+      image[i].tstart = output.TimeValue;
+    }
+    if (!strcasecmp (output.ModifyEntry, "tstop")) {
+      image[i].tstop = output.TimeValue;
+    }
+  }
+
+  update_db (list, Nmatch);
+  close_db ();
+  fprintf (stderr, "SUCCESS\n");
+  exit (0);
+
+}
+
Index: /trunk/Ohana/src/imregister/detrend/mosaic.c
===================================================================
--- /trunk/Ohana/src/imregister/detrend/mosaic.c	(revision 3)
+++ /trunk/Ohana/src/imregister/detrend/mosaic.c	(revision 3)
@@ -0,0 +1,64 @@
+# include "imregister.h"
+# include "detrend.h"
+
+Criteria *MosaicCriteria (Criteria base, char *filename, int *ncrit) {
+
+  int i, Ncrit;
+  char line[80];
+  Header header;
+  Criteria *crit;
+
+  Ncrit = 1;
+  ALLOCATE (crit, Criteria, Ncrit);
+
+  /* load options from the image header */
+  if (!fits_read_header (filename, &header)) {
+    if (output.verbose) fprintf (stderr, "ERROR: trouble reading image header\n");
+    exit (1);
+  }
+
+  /* get Time from header */
+  base.tstop = base.tstart = parse_time (&header);
+  base.TimeSelect = TRUE;
+
+  /* get filter from header */
+  if (!fits_scan (&header, FilterKeyword, "%s", 1, line)) {
+    fprintf (stderr, "ERROR: trouble reading FILTER from header\n");
+    exit (1);
+  }
+  for (i = 0; i < strlen (line); i++) { if (isspace (line[i])) line[i] = '.'; }
+  for (i = 0; (i < NFILTER) && (base.Filter == FILTER_NONE); i++) {
+    if (!strcasecmp (line, filtername[i])) {
+      base.Filter = filternum[i];
+    }
+  }      
+  if (base.Filter == FILTER_NONE) {
+    fprintf (stderr, "ERROR: invalid filter %s\n", line);
+    exit (1);
+  }
+
+  /* get exptime from header */
+  if (!fits_scan (&header, ExptimeKeyword, "%f", 1, &base.Exptime)) {
+    fprintf (stderr, "ERROR: trouble reading EXPTIME from header\n");
+    exit (1);
+  }
+  
+  /* other settings implied by -mosaic */
+  base.CCDSelect = FALSE;
+  if ((base.Type != T_DARK) && (base.Type != T_BIAS) && (base.Type != T_MASK)) {
+    base.FilterSelect = TRUE;
+  } else {
+    base.FilterSelect = FALSE;
+  }      
+  if (base.Type == T_DARK) {
+    base.ExptimeSelect = TRUE;
+  } else {
+    base.ExptimeSelect = FALSE;
+  }      
+  output.Select = TRUE;
+
+  *ncrit = Ncrit;
+  crit[0] = base;
+  return (crit);
+}
+
Index: /trunk/Ohana/src/imregister/detrend/output.c
===================================================================
--- /trunk/Ohana/src/imregister/detrend/output.c	(revision 3)
+++ /trunk/Ohana/src/imregister/detrend/output.c	(revision 3)
@@ -0,0 +1,188 @@
+# include "imregister.h"
+# include "detrend.h"
+
+int OutputSubset (Match *match, int Nmatch) {
+
+  int Nimage;
+  DetReg *image;
+
+  image = get_images (&Nimage);
+
+  if (output.table != (char *) NULL) {
+    DumpFitsTable (output.table, image, match, Nmatch);
+  } 
+  if (output.bintable != (char *) NULL) {
+    DumpFitsBintable (output.bintable, image, match, Nmatch);
+  } 
+  PrintSubset (image, match, Nmatch);
+  if (output.verbose) fprintf (stderr, "SUCCESS\n");
+
+  exit (0);
+}
+
+/* write out complete binary FITS table in format of db */
+void DumpFitsBintable (char *filename, DetReg *image, Match *match, int Nmatch) {
+
+  int i, j, Nx;
+  Header header, theader;
+  Matrix matrix;
+  FTable table;
+  DetReg *subset;
+
+  /* define table layout */
+  define_table (&header, &matrix, &theader, &table);
+
+  ALLOCATE (subset, DetReg, MAX (1, Nmatch));
+  for (i = 0; i < Nmatch; i++){
+    j = match[i].image;
+    memcpy (&subset[i], &image[j], sizeof (DetReg));
+  }
+  ConvertStruct ((char *) subset, sizeof (DetReg), Nmatch, "detreg");
+  fits_add_rows (&table, subset, Nmatch, sizeof (DetReg));
+
+  fits_write_header  (filename, &header);
+  fits_write_matrix  (filename, &matrix);
+  fits_write_Theader (filename, &theader);
+  fits_write_table   (filename, &table);
+  exit (0);
+}
+
+int DumpFitsTable (char *filename, DetReg *detdata, Match *match, int Nmatch) {
+  
+  Header header, theader;
+  Matrix matrix;
+  FTable table;
+  DetReg *newdata;
+  FILE *f;
+  char *startstr, *stopstr, *regstr, line[421];
+  char *filtstr, *typestr, *ccdstr, *datestr;
+  int i;
+  unsigned long tsecond;
+
+  /* create primary header */
+  fits_init_header (&header);    
+  header.extend = TRUE;
+  fits_create_header (&header);
+  fits_create_matrix (&header, &matrix);
+  fits_print (&header, "NEXTEND", "%d", 1, 1);
+  
+  /* create table header */
+  fits_create_table_header (&theader, "TABLE", "MASTER_DETREND");
+      
+  /* add current date/time to header */
+  str_to_time ("now", &tsecond);
+  datestr = sec_to_date (tsecond);
+  fits_modify (&header,  "DATE", "%s", 1, datestr);
+  fits_modify (&theader, "DATE", "%s", 1, datestr);
+
+  /* define table layout */
+  fits_define_table_column (&theader, "A20",  "START_TIME", "start time of measurement", "yyyy/mm/dd,hh:mm:ss");
+  fits_define_table_column (&theader, "A20",  "STOP_TIME",  "stop time of measurement",  "yyyy/mm/dd,hh:mm:ss");
+  fits_define_table_column (&theader, "A20",  "REG_TIME",   "time of registration",      "yyyy/mm/dd,hh:mm:ss");
+  fits_define_table_column (&theader, "F7.1", "EXPTIME",    "exposure time",             "seconds"); 
+  fits_define_table_column (&theader, "A10",  "IMAGETYP",   "detrend type",              "");
+  fits_define_table_column (&theader, "A10",  "FILTER",     "filter name",               "");
+  fits_define_table_column (&theader, "A7",   "CCDID",      "ccd name",                  "");
+  fits_define_table_column (&theader, "I3",   "VERSION",    "image version number",      "");
+  fits_define_table_column (&theader, "I3",   "ORDER",      "selection order",           "");
+  fits_define_table_column (&theader, "A64",  "LABEL",      "data label",                "");
+  fits_define_table_column (&theader, "A256", "PATH",       "filename in db",            "");
+  
+  /* create table, add data values */
+  fits_create_table (&theader, &table);
+  
+  /* add data to table */
+  for (i = 0; i < Nmatch; i++) {
+    newdata = &detdata[match[i].image];
+    startstr = sec_to_date (newdata[0].tstart);
+    stopstr  = sec_to_date (newdata[0].tstop);
+    regstr   = sec_to_date (newdata[0].treg);
+    typestr  = typename[newdata[0].type];
+    filtstr  = filterhash[newdata[0].filter];
+    ccdstr   = ccds[newdata[0].ccd];
+    snprintf (line, 421, "%20s%20s%20s%7.1f%10s%10s%7s%3d%3d%64s%256s",
+	      startstr, stopstr, regstr, newdata[0].exptime,
+	      typestr, filtstr, ccdstr,
+	      newdata[0].Nentry, newdata[0].Norder, 
+	      newdata[0].label, newdata[0].filename);
+    fits_add_rows (&table, line, 1, strlen(line));
+    free (startstr);
+    free (stopstr);
+    free (regstr);
+  }
+
+  f = fopen (filename, "w");
+  if (f == (FILE *) NULL) {
+    fprintf (stderr, "Failure writing fits table\n");
+    return (FALSE);
+  }
+  fits_fwrite_header  (f, &header);
+  fits_fwrite_matrix  (f, &matrix);
+  fits_fwrite_Theader (f, &theader);
+  fits_fwrite_table   (f, &table);
+  fclose (f);
+  return (TRUE);
+}
+
+/* Select, TimeMode are global */
+int PrintSubset (DetReg *detdata, Match *match, int Nmatch) {
+  
+  char *dBPath, *typestr, *filtstr;
+  char *timestr;
+  int i, j;
+
+  dBPath = get_dBPath ();
+
+  /* list matched images */
+  for (j = 0; j < Nmatch; j++) {
+    i = match[j].image;
+    switch (output.TimeMode) {
+    case START:
+      timestr = sec_to_date (detdata[i].tstart);
+      break;
+    case STOP:
+      timestr = sec_to_date (detdata[i].tstop);
+      break;
+    case REG:
+      timestr = sec_to_date (detdata[i].treg);
+      break;
+    default:
+      if (output.verbose) fprintf (stderr, "ERROR: bad TimeMode\n");
+      exit (1);
+    }
+
+    typestr = typename[MIN (MAX (detdata[i].type, 0), NTYPE - 1)];
+    filtstr = filterhash[MIN (MAX (detdata[i].filter, 0), NFILTER - 1)];
+
+    /* output mode (Select vs List) */
+    if (output.Select) {
+      fprintf (stdout, "%s/%s\n", dBPath, detdata[i].filename);
+    } else {
+      fprintf (stdout, "%-40s = %19s %7s %6s %02d %2d %2d %6.1f  %20s\n", 
+	       detdata[i].filename, timestr, typestr, filtstr, detdata[i].ccd, 
+	       detdata[i].Nentry, detdata[i].Norder, detdata[i].exptime, detdata[i].label);
+    }
+    free (timestr);
+  }  
+  return (TRUE);
+}
+
+int PrintCriteria () {
+
+  int i;
+  char *start, *stop;
+
+  for (i = 0; i < Ncriteria; i++) {
+    start = sec_to_date (criteria[i].tstart);
+    stop  = sec_to_date (criteria[i].tstop);
+    
+    fprintf (stdout, "%19s %19s %7s %6s %s %6.1f\n", 
+	     start, stop, typename[criteria[i].Type], filterhash[criteria[i].Filter], 
+	     ccds[criteria[i].CCD], criteria[i].Exptime);
+
+    free (start);
+    free (stop);
+  }
+
+  exit (0);
+}
Index: /trunk/Ohana/src/imregister/detrend/recipe.c
===================================================================
--- /trunk/Ohana/src/imregister/detrend/recipe.c	(revision 3)
+++ /trunk/Ohana/src/imregister/detrend/recipe.c	(revision 3)
@@ -0,0 +1,115 @@
+# include "imregister.h"
+# include "detrend.h"
+
+Criteria *ExpandRecipe (Criteria *base, int *Ncrit) {
+
+  int i, j, N, Ns, NS;
+  Criteria *crit;
+  int Nbase;
+  
+  Nbase = *Ncrit;
+  Ns = 0;
+  ALLOCATE (crit, Criteria, 1);
+
+  for (N = 0; N < Nbase; N++) {
+
+    RecipeType = LoadRecipe (filterhash[base[N].Filter], &Nrecipe);
+
+    NS += Nrecipe;
+    REALLOCATE (crit, Criteria, NS);
+    
+    for (i = 0; i < Nrecipe; i++) {
+      crit[Ns] = base[N];
+      crit[Ns].TypeSelect = TRUE;
+      crit[Ns].Type = T_NONE;
+      
+      for (j = 0; j < NTYPE; j++) {
+	if (!strcasecmp (typename[j], RecipeType[i])) {
+	  crit[Ns].Type = j;
+	}
+      }
+      if (crit[Ns].Type == T_NONE) { 
+	fprintf (stderr, "ERROR: invalid image type %s\n", RecipeType[i]);
+	exit (1);
+      }
+      if (!strcasecmp (RecipeType[i], "bias") ||
+	  !strcasecmp (RecipeType[i], "dark") ||
+	  !strcasecmp (RecipeType[i], "mask")) {
+	crit[Ns].FilterSelect = FALSE;
+      }
+      if (!strcasecmp (RecipeType[i], "flat") ||
+	  !strcasecmp (RecipeType[i], "fringe") ||
+	  !strcasecmp (RecipeType[i], "modes")) {
+	crit[Ns].FilterSelect = TRUE;
+      }
+      if (!strcasecmp (RecipeType[i], "modes")) {
+	crit[Ns].CCDSelect = FALSE;
+      }
+      if (!strcasecmp (RecipeType[i], "dark")) {
+	crit[Ns].ExptimeSelect = TRUE;
+      }
+      Ns ++;
+    }
+  }
+
+  *Ncrit = Ns;
+  return (crit);
+}
+
+char **LoadRecipe (char *filter, int *nrecipe) {
+  
+  char **RecipeType;
+  int Nrecipe, NRECIPE;
+
+  int Nfield, found;
+  char *c, *p1, line[256], list[256], Filter[64];
+  FILE *f;
+  
+  /* open filter list file */
+  f = fopen (RecipeFile, "r");
+  if (f == (FILE *) NULL) {
+    fprintf (stderr, "error reading recipe %s\n", RecipeFile);
+    exit (1);
+  }
+
+  /* allocate dataspace needed */
+  NRECIPE = 10;
+  Nrecipe = 0;
+  ALLOCATE (RecipeType, char *, NRECIPE);
+
+  /* load data from file */
+  found = FALSE;
+  while (!found && (scan_line (f, line) != EOF)) {
+    for (c = line; isspace (*c); c++);
+    if (*c == '#') continue;
+    Nfield = sscanf (c, "%s %s", Filter, list);
+    if (Nfield != 2) { continue; }
+
+    if (!strcasecmp (filter, Filter)) found = TRUE;
+  }
+  fclose (f);  
+
+  if (!found) {
+    fprintf (stderr, "can't find filter %s\n", filter);
+    exit (1);
+  }
+
+  /* list contains word,word,word - parse these words to RecipeType */
+  p1 = list;
+  while ((c = strchr (p1, ',')) != (char *) NULL) {
+    *c = 0;
+    RecipeType[Nrecipe] = strcreate (p1);  
+    p1 = c + 1;
+    Nrecipe ++;
+    if (Nrecipe == NRECIPE) {
+      NRECIPE += 10;
+      REALLOCATE (RecipeType, char *, NRECIPE);
+    }
+  }
+  if (*p1) {
+    RecipeType[Nrecipe] = strcreate (p1);  
+    Nrecipe ++;
+  }    
+  *nrecipe = Nrecipe;
+  return (RecipeType);
+}
Index: /trunk/Ohana/src/imregister/detrend/select.c
===================================================================
--- /trunk/Ohana/src/imregister/detrend/select.c	(revision 3)
+++ /trunk/Ohana/src/imregister/detrend/select.c	(revision 3)
@@ -0,0 +1,93 @@
+# include "imregister.h"
+# include "detrend.h"
+
+Match SelectEntry (Match *list, int Nlist, Criteria *crit) {
+
+  /* force a single selection */
+
+  /* at this point, all external criteria for the given detrend images
+     are equivalently good (ie, date range, filters, type, etc).  the 
+     selection here is based on other options: 
+     1) Norder         - user assigned value to force selection
+     2) tstart         - start valid time
+     3) Nentry         - version number
+     4) MatchNumber    - method to force selection 
+  */
+
+  int i, j, entry, order, matchnum;
+  int nmatch, Nmatch, Nimage;
+  unsigned int tstart;
+  Match *match, *tmatch, answer;
+  DetReg *image;
+
+  image = get_images (&Nimage);
+
+  Nmatch = Nlist;
+  match = list;
+
+  /* select all images with the same, maximum Norder */
+  nmatch = 0;
+  ALLOCATE (tmatch, Match, Nmatch);
+  order = image[match[0].image].Norder;
+  for (j = 0; j < Nmatch; j++) {
+    i = match[j].image;
+    order = MAX (order, image[i].Norder);
+  }
+  for (j = 0; j < Nmatch; j++) {
+    i = match[j].image;
+    if (order <= image[i].Norder) {
+      tmatch[nmatch] = match[j];
+      nmatch ++;
+    }
+  }
+  match = tmatch;
+  Nmatch = nmatch;
+
+  /* select all images with the same, maximum tstart */
+  nmatch = 0;
+  ALLOCATE (tmatch, Match, Nmatch);
+  tstart = image[match[0].image].tstart;
+  for (j = 0; j < Nmatch; j++) {
+    i = match[j].image;
+    tstart = MAX (tstart, image[i].tstart);
+  }
+  for (j = 0; j < Nmatch; j++) {
+    i = match[j].image;
+    if (tstart <= image[i].tstart) {
+      tmatch[nmatch] = match[j];
+      nmatch ++;
+    }
+  }
+  free (match);
+  match = tmatch;
+  Nmatch = nmatch;
+
+  /* select all images with the same, maximum Nentry */
+  nmatch = 0;
+  ALLOCATE (tmatch, Match, Nmatch);
+  entry = image[match[0].image].Nentry;
+  for (j = 0; j < Nmatch; j++) {
+    i = match[j].image;
+    entry = MAX (entry, image[i].Nentry);
+  }
+  for (j = 0; j < Nmatch; j++) {
+    i = match[j].image;
+    if (entry <= image[i].Nentry) {
+      tmatch[nmatch] = match[j];
+      nmatch ++;
+    }
+  }
+  free (match);
+  match = tmatch;
+  Nmatch = nmatch;
+
+  /* if there are multiple matches, select MatchNumber entry 
+     0-Nmatch-1 , or -1 -> -Nmatch (saturate at ends) */
+  matchnum = crit[match[0].crit].MatchNumber;
+  if (matchnum < 0) matchnum += Nmatch;
+  matchnum = MAX (0, MIN (Nmatch - 1, matchnum));
+
+  answer = match[matchnum];
+  free (match);
+  return (answer);
+}
Index: /trunk/Ohana/src/imregister/detrend/unique.c
===================================================================
--- /trunk/Ohana/src/imregister/detrend/unique.c	(revision 3)
+++ /trunk/Ohana/src/imregister/detrend/unique.c	(revision 3)
@@ -0,0 +1,126 @@
+# include "imregister.h"
+# include "detrend.h"
+
+/* define a list of best images which have unique properties */ 
+Match *UniqueSubset (Match *match, int *nmatch) {
+
+  int Nsubset, Nunique, Ncrit, NCRIT;
+  int i, j, N, Nmatch, Nimage, found;
+  Criteria *crit;
+  Match *subset, *unique, *local;
+  DetReg *image;
+
+  Nmatch = *nmatch;
+  ALLOCATE (local, Match, Nmatch);
+
+  image = get_images (&Nimage);
+
+  /* create a set of complete criteria derived from the images */
+
+  Ncrit = 0;
+  NCRIT = 10;
+  ALLOCATE (crit, Criteria, NCRIT);
+  bzero (crit, (NCRIT - Ncrit)*sizeof(Criteria));
+
+  for (i = 0; i < Nmatch; i++) {
+    
+    local[i] = match[i];
+    N = match[i].image;
+    if (N == -1) continue;
+
+    found = FALSE;
+    for (j = 0; (j < Ncrit) && !found; j++) {
+      if (!cmp_crit (&crit[j], &image[N])) continue;
+      found = TRUE;
+      local[i].crit  = j;
+    }      
+    if (found) continue;
+    local[i].crit  = Ncrit;
+    set_crit (&crit[Ncrit], &image[N]);
+    Ncrit ++;
+    if (Ncrit == NCRIT) {
+      NCRIT += 10;
+      REALLOCATE (crit, Criteria, NCRIT);
+      bzero (&crit[Ncrit], (NCRIT - Ncrit)*sizeof(Criteria));
+    }
+  }
+      
+  /* we now have a set of criteria (crit, Ncrit) which describe the matched images
+     and a set of local matches (local) which link images to crit */
+
+  ALLOCATE (subset, Match, Nmatch);
+  ALLOCATE (unique, Match, Nmatch);
+
+  Nunique = 0;
+  for (i = 0; i < Ncrit; i++) {
+
+    /* extract the subset of local matches which are associated with crit[i] */
+    Nsubset= 0;
+    for (j = 0; j < Nmatch; j++) {
+      if (local[j].crit  != i) continue;
+      subset[Nsubset] = local[j];
+      Nsubset ++;
+    }
+
+    /* subset, Nsubset has a unique list of matched images */
+    unique[Nunique] = SelectEntry (subset, Nsubset, crit);
+    Nunique ++;
+  }
+  free (subset);
+  free (local);
+  free (match);
+
+  match = unique;
+  *nmatch = Nunique;
+
+  return (match);
+}
+
+
+/* 
+   return list of all images that have the same value of:
+   criteria = tstart, tstop, filter, ccd, type, exptime
+*/
+
+
+int cmp_crit (Criteria *crit, DetReg *image) {
+
+  /* image and criteria need to match on:
+     tstart, tstop, filter, ccd, type, exptime
+  */
+  
+  if (crit[0].Filter  != image[0].filter ) return (FALSE);
+  if (crit[0].CCD     != image[0].ccd    ) return (FALSE);
+  if (crit[0].Type    != image[0].type   ) return (FALSE);
+  if (crit[0].Exptime != image[0].exptime) return (FALSE);
+
+  if (crit[0].tstart  > image[0].tstop) return (FALSE);
+  if (crit[0].tstop   < image[0].tstop) return (FALSE);
+
+  /* we have overlapping time ranges.  set crit[0] to have the 
+     maximum of these time ranges */
+
+  crit[0].tstop  = MIN (crit[0].tstop,  image[0].tstop);
+  crit[0].tstart = MAX (crit[0].tstart, image[0].tstart);
+
+  return (TRUE);
+
+}
+
+int set_crit (Criteria *crit, DetReg *image) {
+
+  /* image and criteria need to match on:
+     tstart, tstop, filter, ccd, type, exptime
+  */
+
+  crit[0].tstart  = image[0].tstart;
+  crit[0].tstop   = image[0].tstop;  
+  crit[0].Filter  = image[0].filter; 
+  crit[0].CCD     = image[0].ccd;    
+  crit[0].Type    = image[0].type;   
+  crit[0].Exptime = image[0].exptime;
+
+  return (TRUE);
+
+}
+
Index: /trunk/Ohana/src/imregister/detrend/usage.c
===================================================================
--- /trunk/Ohana/src/imregister/detrend/usage.c	(revision 3)
+++ /trunk/Ohana/src/imregister/detrend/usage.c	(revision 3)
@@ -0,0 +1,30 @@
+# include "imregister.h"
+# include "detrend.h"
+
+int usage () {
+  
+  fprintf (stderr, "detsearch : select images from the detrend database\n");
+  fprintf (stderr, " USAGE: detsearch [-options...]\n");
+  fprintf (stderr, " -h : show this list\n");
+  fprintf (stderr, " --help : show this list\n");
+  fprintf (stderr, " -image filename (ccd) (mode) : find matching detrend data for this image \n");
+  fprintf (stderr, " -type (type) : limit selection by image type (bias, dark, flat, etc)\n");
+  fprintf (stderr, " -time yyyy/mm/dd,HH:MM:SS : specify time for selection\n");
+  fprintf (stderr, " -ccd (N) : limit selection to this ccd\n");
+  fprintf (stderr, " -filter (name) : limit selection to this filter\n");
+  fprintf (stderr, " -exptime (value) : limit selection to match this exposure time\n");
+  fprintf (stderr, " -tstop : display end of valid time range\n");
+  fprintf (stderr, " -treg  : display time of image registration\n");
+  fprintf (stderr, " -ve    : Elixir verbose (SUCCESS / ERROR) \n");
+  fprintf (stderr, " -quiet : Elixir quiet (no SUCCESS / ERROR) \n");
+  fprintf (stderr, " -close : select detrend data which is closest in time, overlap not forced\n");
+  fprintf (stderr, " -entry (value) : limit selection to match this entry\n");
+  fprintf (stderr, " -match (value) : only list the Nth matched entry\n");
+  fprintf (stderr, " -label (word)  : limit selection to match this label\n");
+  fprintf (stderr, " -select : force selection of the 'best' match\n");
+  fprintf (stderr, " -del    : delete the matched entries\n");
+  fprintf (stderr, " -delete : delete the matched entries\n");
+  fprintf (stderr, " -modify (entry) (value) : change entry in the selection to value\n");
+  fprintf (stderr, "   possible -modify entries: label, order, tstart, tstop\n");
+  exit (2);
+}
Index: /trunk/Ohana/src/imregister/imreg/args.imregister.c
===================================================================
--- /trunk/Ohana/src/imregister/imreg/args.imregister.c	(revision 3)
+++ /trunk/Ohana/src/imregister/imreg/args.imregister.c	(revision 3)
@@ -0,0 +1,57 @@
+# include "imregister.h"
+# include "imreg.h"
+
+/* args is now greatly simplified from the rsh-fork version */
+int args (int argc, char **argv) {
+
+  int N;
+
+  ConfigInit (&argc, argv); /* load elixir config data */
+  ConfigCamera ();          /* load camera information */
+  ConfigFilter ();          /* load filter information */
+
+  SingleIsSplit = FALSE;
+  if (N = get_argument (argc, argv, "-split")) {
+    remove_argument (N, &argc, argv);
+    SingleIsSplit = TRUE;
+  }
+
+  NoReg = FALSE;
+  if (N = get_argument (argc, argv, "-noreg")) {
+    remove_argument (N, &argc, argv);
+    NoReg = TRUE;
+  }
+
+  /* all imregister programs are implicitly modifying the db */
+  output.modify = TRUE;
+
+  if (strstr (argv[0], "imregister") != (char *) NULL) {
+    if (argc != 2) {
+      fprintf (stderr, "ERROR: Usage: imregister (filename) [-split] [-noreg]\n");
+      exit (1);
+    }
+    return (TRUE);
+  }
+  if (strstr (argv[0], "showiminfo") != (char *) NULL) {
+    if (argc != 2) {
+      fprintf (stderr, "ERROR: Usage: showiminfo (filename) [-split] [-noreg]\n");
+      exit (1);
+    }
+    return (TRUE);
+  }
+  if (strstr (argv[0], "imsort") != (char *) NULL) {
+    if (argc != 2) {
+      fprintf (stderr, "ERROR: Usage: imsort filename(s) [-split] [-noreg]\n");
+      exit (1);
+    }
+    return (TRUE);
+  }
+  if (strstr (argv[0], "imstatreg") != (char *) NULL) {
+    if (argc != 4) {
+      fprintf (stderr, "ERROR: Usage: imstatreg (fits) (stats) (sdat) [-split] [-noreg]\n");
+      exit (1);
+    }
+    return (TRUE);
+  }
+  return (FALSE);
+}
Index: /trunk/Ohana/src/imregister/imreg/args.imsearch.c
===================================================================
--- /trunk/Ohana/src/imregister/imreg/args.imsearch.c	(revision 3)
+++ /trunk/Ohana/src/imregister/imreg/args.imsearch.c	(revision 3)
@@ -0,0 +1,169 @@
+# include "imregister.h" 
+# include "imreg.h"
+
+/* criteria struct is global */
+int args (int argc, char **argv) {
+
+  int N, i;
+
+  ConfigInit (&argc, argv); /* load elixir config data */
+  ConfigCamera ();          /* load camera information */
+  ConfigFilter ();          /* load filter information */
+
+  /* define time range */
+  criteria.Ntimes = 0;
+  if (!get_trange_arguments (&argc, argv, &criteria.tstart, &criteria.tstop, &criteria.Ntimes)) {
+    fprintf (stderr, "ERROR: syntax error\n");
+    exit (1);
+  }
+
+  /* image type (dark, flat, bias, etc) */
+  criteria.TypeSelect = FALSE;
+  criteria.Type = T_NONE;
+  if (N = get_argument (argc, argv, "-type")) {
+    remove_argument (N, &argc, argv);
+    for (i = 0; (i < NTYPE) && (criteria.Type == T_NONE); i++) {
+      if (!strncasecmp (argv[N], typename[i], strlen(argv[N]))) criteria.Type = i;
+    }
+    if (criteria.Type == T_NONE) {
+      fprintf (stderr, "ERROR: invalid image type %s\n", argv[N]);
+      exit (1);
+    }
+    remove_argument (N, &argc, argv);
+    criteria.TypeSelect = TRUE;
+  }
+ 
+  /* exposure time */
+  criteria.ExptimeSelect = FALSE;
+  if (N = get_argument (argc, argv, "-etime")) {
+    remove_argument (N, &argc, argv);
+    criteria.Exptime = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+    criteria.ExptimeSelect = TRUE;
+  }
+ 
+  /* image mode (split, mef, single) */
+  criteria.ModeSelect = FALSE;
+  criteria.Mode = M_NONE;
+  if (N = get_argument (argc, argv, "-mode")) {
+    remove_argument (N, &argc, argv);
+    for (i = 0; (i < NMODE) && (criteria.Mode == M_NONE); i++) {
+      if (!strncasecmp (argv[N], modename[i], strlen(argv[N]))) criteria.Mode = i;
+    }
+    if (criteria.Mode == M_NONE) {
+      fprintf (stderr, "ERROR: invalid image mode %s\n", argv[N]);
+      exit (1);
+    }
+    remove_argument (N, &argc, argv);
+    criteria.ModeSelect = TRUE;
+  }
+
+  /* ccd number */
+  criteria.CCDSelect = FALSE;
+  if (N = get_argument (argc, argv, "-ccd")) {
+    remove_argument (N, &argc, argv);
+    criteria.CCD = -1;
+    for (i = 0; (i < Nccd) && (criteria.CCD == -1); i++) {
+      if (strnumcmp (ccds[i], argv[N])) {
+	criteria.CCD = i;
+      }
+    }
+    if (criteria.CCD == -1) {
+      fprintf (stderr, "ERROR: ccd %s choice out not found in camera config\n", argv[N]);
+      exit (1);
+    }
+
+    remove_argument (N, &argc, argv);
+    criteria.CCDSelect = TRUE;
+  }
+ 
+  /* filter name */
+  criteria.FilterSelect = FALSE;
+  if (N = get_argument (argc, argv, "-filter")) {
+    remove_argument (N, &argc, argv);
+    criteria.Filter = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+    criteria.FilterSelect = TRUE;
+    if (!strcasecmp (criteria.Filter, "X")) {
+      criteria.FilterSelect = FALSE;
+    }
+  }
+
+  /* string in image name */
+  criteria.NameSelect = FALSE;
+  if (N = get_argument (argc, argv, "-name")) {
+    remove_argument (N, &argc, argv);
+    criteria.Name = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+    criteria.NameSelect = TRUE;
+  }
+
+  /*** command-line options which modify the output list */
+  if (N = get_argument (argc, argv, "-treg")) {
+    remove_argument (N, &argc, argv);
+    SetOutputMode ("RegTimeMode");
+  }
+  if (N = get_argument (argc, argv, "-seq")) {
+    remove_argument (N, &argc, argv);
+    SetOutputMode ("CCDSeq");
+  }
+  if (N = get_argument (argc, argv, "-pt")) {
+    remove_argument (N, &argc, argv);
+    SetOutputMode ("PTstyle");
+  }
+  output.table = (char *) NULL;
+  if (N = get_argument (argc, argv, "-table")) {
+    remove_argument (N, &argc, argv);
+    output.table = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  output.bintable = (char *) NULL;
+  if (N = get_argument (argc, argv, "-bintable")) {
+    remove_argument (N, &argc, argv);
+    output.bintable = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  /*** command-line options which modify behavior (delete, modify, newpath, mef2split split2mef */
+  output.delete = output.modify = 0;
+  output.Newpath = output.mef2split = output.split2mef = FALSE;
+
+  if (N = get_argument (argc, argv, "-del")) {
+    remove_argument (N, &argc, argv);
+    output.delete ++;
+  }
+  if (N = get_argument (argc, argv, "-delete")) {
+    remove_argument (N, &argc, argv);
+    output.delete ++;
+  }
+  if (N = get_argument (argc, argv, "-newpath")) {
+    output.Newpath = TRUE;
+    remove_argument (N, &argc, argv);
+    output.oldpath = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+    output.newpath = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+    output.modify ++;
+  }
+  if (N = get_argument (argc, argv, "-mef2split")) {
+    remove_argument (N, &argc, argv);
+    output.mef2split = TRUE;
+    output.modify ++;
+  }
+  if (N = get_argument (argc, argv, "-split2mef")) {
+    remove_argument (N, &argc, argv);
+    output.split2mef = TRUE;
+    output.modify ++;
+  }
+  if (output.modify + output.delete > 1) {
+    fprintf (stderr, "can't specify more than one modifier at a time\n");
+    exit (1);
+  }
+
+  if (argc != 1) {
+    fprintf (stderr, "USAGE: imsearch [config ops] [-time start range] [-type type] [-mode mode] [-ccd N] [-filter name]\n");
+    exit (1);
+  }
+
+  return (TRUE);
+}
Index: /trunk/Ohana/src/imregister/imreg/db.c
===================================================================
--- /trunk/Ohana/src/imregister/imreg/db.c	(revision 3)
+++ /trunk/Ohana/src/imregister/imreg/db.c	(revision 3)
@@ -0,0 +1,161 @@
+# include "imregister.h"
+# include "imreg.h"
+
+/* variables which describe the db */
+char *dBFile;
+FILE *f;
+Header header;
+Header theader;
+Matrix matrix;
+FTable table;
+RegImage *image;
+int Nimage;
+int lockstate, dbstate;
+
+RegImage *get_images (int *N) {
+  *N = Nimage;
+  return (image);
+}
+
+int set_images (RegImage *new, int Nnew) {
+
+  int Nbytes;
+
+  free (image);
+
+  fits_modify (table.header, "NAXIS2", "%d", 1, Nnew);
+  table.header[0].Naxis[1] = Nnew;
+  Nbytes = fits_matrix_size (table.header);
+
+  Nimage = Nnew;
+  image = new;
+  REALLOCATE (image, RegImage, Nbytes);
+  table.buffer = (char *) image;
+  return (TRUE);
+}
+
+int load_db () {
+
+  int Nx, Ny;
+
+  lockstate = (output.modify || output.delete) ? LCK_HARD : LCK_SOFT;
+  dBFile = ImageDB; /* loaded in ConfigInit */ 
+
+  /* lock database (soft) */
+  f = fsetlockfile (dBFile, 300.0, lockstate, &dbstate);
+  if (dbstate == LCK_EMPTY) return (0);
+
+  if (f == (FILE *) NULL) {
+    fprintf (stderr, "ERROR: can't set lock on %s\n", dBFile);
+    exit (1);
+  }
+
+  /* load in table data */
+  table.header = &theader;
+  fits_fread_header (f, &header);
+  fits_fread_matrix (f, &matrix, &header);
+  fits_fread_ftable  (f, &table, "IMAGE_DATABASE");
+
+  /* convert to internal format */
+  image = (RegImage *) table.buffer;
+  fits_scan (table.header, "NAXIS1", "%d", 1, &Nx);
+  fits_scan (table.header, "NAXIS2", "%d", 1, &Ny);
+  Nimage = Ny;
+
+  ConvertStruct ((char *) image, sizeof (RegImage), Nimage, "regimage");
+  return (1);
+}
+
+/* save complete db file */
+int save_db () {
+
+  ConvertStruct ((char *) image, sizeof (RegImage), Nimage, "regimage");
+
+  /* write all images to file */
+  make_backup (dBFile);
+  Fseek (f, 0, SEEK_SET);
+  fits_fwrite_header (f, &header);
+  fits_fwrite_matrix (f, &matrix);
+  fits_fwrite_Theader (f, &theader);
+  fits_fwrite_table   (f, &table);
+  fclearlockfile (dBFile, f, lockstate, &dbstate);
+  return (TRUE);
+}
+
+/* save subset in db file */
+int update_db (int *match, int Nmatch) {
+
+  int i, N, Nx, Ny;
+  VTable vtable;
+
+  fits_scan (table.header, "NAXIS1", "%d", 1, &Nx);
+  fits_scan (table.header, "NAXIS2", "%d", 1, &Ny);
+
+  /* make empty vtable from table */
+  vtable.header = table.header;
+  vtable.size = table.size;
+  vtable.Nrow = Ny;
+  vtable.pad = vtable.size - Nx*Ny;
+
+  /* insert selected rows in vtable */ 
+  ALLOCATE (vtable.row, int, Nmatch);
+  ALLOCATE (vtable.buffer, char *, Nmatch);
+  for (N = i = 0; i < Nmatch; i++) {
+    if (match[i] == -1) continue;
+    vtable.row[N] = match[i];
+    ALLOCATE (vtable.buffer[N], char, Nx);
+    memcpy (vtable.buffer[N], &image[match[i]], sizeof (RegImage));
+    ConvertStruct ((char *) vtable.buffer[N], sizeof (RegImage), 1, "regimage");
+    N++;
+  }
+  vtable.Nrow = N;
+
+  /* write subset to file */
+  make_backup (dBFile);
+  Fseek (f, 0, SEEK_SET);
+  fits_fwrite_header (f, &header);
+  fits_fwrite_matrix (f, &matrix);
+  fits_fwrite_Theader (f, &theader);
+  fits_fwrite_vtable   (f, &vtable);
+  fclearlockfile (dBFile, f, lockstate, &dbstate);
+  return (TRUE);
+}
+
+int append_db (RegImage *new, int Nnew) {
+
+  VTable vtable;
+
+  fits_table_to_vtable (&table, &vtable);
+
+  ConvertStruct ((char *) new, sizeof (RegImage), Nnew, "regimage");
+  fits_vadd_rows (&vtable, new, Nnew, sizeof(RegImage));
+
+  /* write subset to file */
+  Fseek (f, 0, SEEK_SET);
+  fits_fwrite_header (f, &header);
+  fits_fwrite_matrix (f, &matrix);
+  fits_fwrite_Theader (f, &theader);
+  fits_fwrite_vtable   (f, &vtable);
+  fclearlockfile (dBFile, f, lockstate, &dbstate);
+  return (TRUE);
+}
+
+int create_db () {
+
+  /* f & dBFile set by load_db */
+
+  /* define table layout */
+  define_table (&header, &matrix, &theader, &table);
+
+  /* convert to internal format */
+  image = (RegImage *) table.buffer;
+  Nimage = 0;
+
+  return (TRUE);
+}
+
+int close_db () {
+  fclearlockfile (dBFile, f, LCK_HARD, &dbstate);
+  return (TRUE);
+}  
+
Index: /trunk/Ohana/src/imregister/imreg/define.c
===================================================================
--- /trunk/Ohana/src/imregister/imreg/define.c	(revision 3)
+++ /trunk/Ohana/src/imregister/imreg/define.c	(revision 3)
@@ -0,0 +1,48 @@
+# include "imregister.h"
+# include "imreg.h"
+
+int define_table (Header *header, Matrix *matrix, Header *theader, FTable *table) {
+
+  /* create primary header */
+  fits_init_header (header);    
+  header[0].extend = TRUE;
+  fits_create_header (header);
+  fits_create_matrix (header, matrix);
+  fits_print (header, "NEXTEND", "%d", 1, 1);
+    
+  /* define bintable header  layout */
+  fits_create_table_header (theader, "BINTABLE", "IMAGE_DATABASE");
+
+  fits_define_bintable_column (theader, "64A",  "FILE",       "filename in db",        "",                              1.0, 0.0);
+  fits_define_bintable_column (theader, "128A", "PATH",       "fullpath in db",        "",                              1.0, 0.0);
+  fits_define_bintable_column (theader, "32A",  "FILTER",     "filter name",           "",                              1.0, 0.0);
+  fits_define_bintable_column (theader, "32A",  "INSTRUMENT", "instrument",            "",                              1.0, 0.0);
+  fits_define_bintable_column (theader, "A",    "CCD",        "ccd identifier",        "",                              1.0, 0.0);
+  fits_define_bintable_column (theader, "A",    "MODE",       "mef/split/etc",         "",                              1.0, 0.0);
+  fits_define_bintable_column (theader, "A",    "TYPE",       "object/flat/bias/etc",  "",                              1.0, 0.0);
+  fits_define_bintable_column (theader, "25A",  "JUNK",       "space for expansion",   "",                              1.0, 0.0);
+  fits_define_bintable_column (theader, "E",    "EXPTIME",    "exposure time",        "seconds",                        1.0, 0.0); 
+  fits_define_bintable_column (theader, "E",    "AIRMASS",    "airmass",              "",                               1.0, 0.0); 
+  fits_define_bintable_column (theader, "E",    "SKY",        "background level",     "counts / pixel",                 1.0, 0.0); 
+  fits_define_bintable_column (theader, "E",    "BIAS",       "bias level",           "counts / pixel",                 1.0, 0.0); 
+  fits_define_bintable_column (theader, "E",    "FWHM",       "image quality",        "pixels",                         1.0, 0.0); 
+  fits_define_bintable_column (theader, "E",    "TELFOCUS",   "telescope focus",      "microns",                        1.0, 0.0); 
+  fits_define_bintable_column (theader, "E",    "XPROBE",     "bonnette probe x pos", "microns",                        1.0, 0.0); 
+  fits_define_bintable_column (theader, "E",    "YPROBE",     "bonnette probe y pos", "microns",                        1.0, 0.0); 
+  fits_define_bintable_column (theader, "E",    "ZPROBE",     "bonnette focus",       "microns",                        1.0, 0.0); 
+  fits_define_bintable_column (theader, "E",    "DETTEMP",    "detector temperature", "deg celcius",                    1.0, 0.0); 
+  fits_define_bintable_column (theader, "E",    "TELTEMP0",   "other temperature",    "deg celcius",                    1.0, 0.0); 
+  fits_define_bintable_column (theader, "E",    "TELTEMP1",   "other temperature",    "deg celcius",                    1.0, 0.0); 
+  fits_define_bintable_column (theader, "E",    "TELTEMP2",   "other temperature",    "deg celcius",                    1.0, 0.0); 
+  fits_define_bintable_column (theader, "E",    "TELTEMP3",   "other temperature",    "deg celcius",                    1.0, 0.0); 
+  fits_define_bintable_column (theader, "E",    "ROTANGLE",   "camera rotation angle", "degrees",                       1.0, 0.0); 
+  fits_define_bintable_column (theader, "E",    "RA",         "image ra",              "degrees",                       1.0, 0.0); 
+  fits_define_bintable_column (theader, "E",    "DEC",        "image dec",             "degrees",                       1.0, 0.0); 
+  fits_define_bintable_column (theader, "J",    "OBS_TIME",   "time of measurement",   "seconds since Jan 1, 1970 UT",  1.0, 0.0);
+  fits_define_bintable_column (theader, "J",    "REG_TIME",   "time of registration",  "seconds since Jan 1, 1970 UT",  1.0, 0.0);
+
+    /* create table, add data values */
+  fits_create_table (theader, table);
+
+  return (TRUE);
+}
Index: /trunk/Ohana/src/imregister/imreg/delete.c
===================================================================
--- /trunk/Ohana/src/imregister/imreg/delete.c	(revision 3)
+++ /trunk/Ohana/src/imregister/imreg/delete.c	(revision 3)
@@ -0,0 +1,39 @@
+# include "imregister.h"
+# include "imreg.h"
+
+void DeleteSubset (int *match, int Nmatch) {
+
+  int i, j;
+  int *keep, Nbad, Nimage, Nsubset;
+  RegImage *image, *subset;
+
+  image = get_images (&Nimage);
+
+  ALLOCATE (keep, int, Nimage);
+  for (i = 0; i < Nimage; i++) keep[i] = TRUE;
+
+  Nbad = 0;
+  for (i = 0; i < Nmatch; i++) {
+    j = match[i];
+    if (j == -1) continue;
+    keep[j] = FALSE;
+    Nbad ++;
+  }
+
+  Nsubset = Nimage - Nbad;
+  ALLOCATE (subset, RegImage, Nsubset);
+  for (j = i = 0; i < Nimage; i++) {
+    if (!keep[i]) continue;
+    subset[j] = image[i];
+    /* this or memcpy ? */
+    j++;
+  }
+
+  free (keep);
+  set_images (subset, Nsubset);
+
+  save_db ();
+  fprintf (stderr, "SUCCESS\n");
+  exit (0);
+
+}
Index: /trunk/Ohana/src/imregister/imreg/iminfo.c
===================================================================
--- /trunk/Ohana/src/imregister/imreg/iminfo.c	(revision 3)
+++ /trunk/Ohana/src/imregister/imreg/iminfo.c	(revision 3)
@@ -0,0 +1,166 @@
+# include "imregister.h"
+# include "imreg.h"
+
+char *getcwd_cfht ();
+
+RegImage *iminfo (char *filename) {
+
+  RegImage *image;
+  Header header;
+  int extend;
+  int Naxes, Nextend;
+  char Imagetype[80], line[80];
+  struct timeval now;
+  char *name, *cwd, *tempname;
+  double tmp;
+  float *dtime;
+
+  ALLOCATE (image, RegImage, 1);
+  bzero (image, sizeof (RegImage));
+
+  /* load in FITS header from image */
+  if (!fits_read_header (filename, &header)) {
+    fprintf (stderr, "ERROR: can't find image file %s\n", filename);
+    exit (1);
+  }
+
+  /* find the important header keyword values */
+  image[0].obstime = parse_time (&header);
+
+  gettimeofday (&now, (void *) NULL);
+  image[0].regtime = now.tv_sec;
+
+  image[0].sky = image[0].fwhm = image[0].bias = 0;
+  
+  /* default for a single CCD frame */
+  Naxes = 2; 
+  extend = FALSE;
+  image[0].mode = MODE_SINGLE;
+  image[0].ccd  = 0;
+
+  /* determine data layout (SINGLE, SPLIT, MEF, CUBE, SLICE) */
+  fits_scan (&header, "EXTEND",  "%t", 1, &extend);
+  fits_scan (&header, "NAXIS",  "%d", 1, &Naxes);
+  if (extend) { /* MEF file */
+    fits_scan (&header, "NEXTEND",  "%d", 1, &Nextend);
+    image[0].mode = MODE_MEF;
+    image[0].ccd  = Nextend;
+  } 
+  if (Naxes == 3) { /* data cube */
+    fits_scan (&header, "NAXIS3",  "%d", 1, &Nextend);
+    image[0].mode = MODE_CUBE;
+    image[0].ccd  = Nextend;
+    dtime = (float *)&image[0].junk[0];
+    fits_scan (&header, "SEQTIME", "%f", 1, dtime);
+  }
+  if (SingleIsSplit && (image[0].mode == MODE_SINGLE)) {
+    image[0].mode = MODE_SPLIT;
+    image[0].ccd  = MatchCCDName (&header);
+  }
+  /* is there a better way to id a 'split' image? */
+
+  /* extract other relevant data from header */
+  fits_scan (&header, ImagetypeKeyword,  "%s", 1, &Imagetype);
+
+  image[0].type = TYPE_NONE;
+  if (!strcasecmp (Imagetype, "OBJECT")) {
+    image[0].type = TYPE_OBJECT;
+  }
+  if (!strcasecmp (Imagetype, "DARK")) {
+    image[0].type = TYPE_DARK;
+  }
+  if (!strcasecmp (Imagetype, "BIAS")) {
+    image[0].type = TYPE_BIAS;
+  }
+  if (!strcasecmp (Imagetype, "FLAT")) {
+    image[0].type = TYPE_FLAT;
+  }
+  if (!strcasecmp (Imagetype, "SKYFLAT")) {
+    image[0].type = TYPE_FLAT;
+  }
+
+  /* grab interesting info from header */
+  fits_scan (&header, ExptimeKeyword,    "%f", 1, &image[0].exptime);
+  fits_scan (&header, AirmassKeyword,    "%f", 1, &image[0].airmass);
+  fits_scan (&header, FocusKeyword,      "%f", 1, &image[0].telfocus);
+  fits_scan (&header, Teldata1Keyword,   "%f", 1, &image[0].xprobe);
+  fits_scan (&header, Teldata2Keyword,   "%f", 1, &image[0].yprobe);
+  fits_scan (&header, Teldata3Keyword,   "%f", 1, &image[0].zprobe);
+  fits_scan (&header, DettempKeyword,    "%f", 1, &image[0].dettemp);
+  fits_scan (&header, RotationKeyword,   "%f", 1, &image[0].rotangle);
+
+  /* force strings to fit in available space (32 bytes) */
+  fits_scan (&header, CameraKeyword,     "%s", 1, line);
+  strncpy (image[0].instrument, line, 31);
+  image[0].instrument[31] = 0;
+
+  fits_scan (&header, FilterKeyword, "%s", 1, line);
+  MatchFilterList (line);
+  strncpy (image[0].filter, line, 31);
+  image[0].filter[31] = 0;
+
+  /* header has RA & DEC in decimal degrees */
+  if (RADecDegKeyword[0] & DECDecDegKeyword[0]) {
+    fits_scan (&header, RADecDegKeyword,  "%f", 1, &image[0].ra);
+    fits_scan (&header, DECDecDegKeyword, "%f", 1, &image[0].dec);
+  } else {
+    if (RASexigKeyword[0] & DECSexigKeyword[0]) {
+      fits_scan (&header, RASexigKeyword,  "%s", 1, line);
+      dms_to_ddd (&tmp, line);
+      image[0].ra = 15*tmp;
+      fits_scan (&header, DECSexigKeyword, "%s", 1, &line);
+      dms_to_ddd (&tmp, line);
+      image[0].dec = tmp;
+    }
+  }
+
+  /* this segment is strongly CFHT dependent.  also it is somewhat
+     poor: the file must have the probes in the right order.
+     load_probes checks the data validity, but has no gurantee that
+     the right range has been loaded */
+
+  /* to change the selected probes, change:
+     1) the probes[] entries below
+     2) the entries in the program 'gettemps' */
+
+  /* the probes have to agree with the entries in the program 'gettemps' */
+  {
+    int i;
+    double pvalues[4];
+    static int probes[] = {2, 36, 43, 45};
+    if (load_probes (TempLogFile, image[0].obstime, probes, pvalues, 4)) {
+      for (i = 0; i < 4; i++) {
+	image[0].teltemp[i] = pvalues[i];
+      }
+    } else {
+      fprintf (stderr, "failure to get probe data\n");
+      image[0].teltemp[0] = 200.0;
+      image[0].teltemp[1] = 200.0;
+      image[0].teltemp[2] = 200.0;
+      image[0].teltemp[3] = 200.0;
+    }
+  }
+  /* this should be a call to an external function... */
+  
+  /* extract the file name and the path */
+  name = filebasename (filename);
+  strcpy (image[0].filename, name);
+  name = pathname (filename);
+  if (name[0] != '/') {
+    cwd = getcwd_cfht (NULL, 1024);
+    ALLOCATE (tempname, char, strlen (cwd) + strlen (name) + 2);
+    if (!strcmp (name, ".")) {
+      sprintf (tempname, "%s", cwd);
+    } else {
+      sprintf (tempname, "%s/%s", cwd, name);
+    }      
+    free (name);
+    free (cwd);
+    name = tempname;
+  }    
+  strcpy (image[0].pathname, name);
+
+  return (image);
+
+}
+
Index: /trunk/Ohana/src/imregister/imreg/load_probes.c
===================================================================
--- /trunk/Ohana/src/imregister/imreg/load_probes.c	(revision 3)
+++ /trunk/Ohana/src/imregister/imreg/load_probes.c	(revision 3)
@@ -0,0 +1,108 @@
+# include "imregister.h"
+# define NBYTES 1024
+# define WINDOW 1800
+/* probes are updated every 600 seconds.  give us some leeway here */
+
+int load_probes (char *filename, unsigned long tzero, int *wantprobe, double *values, int Nprobe) {
+
+  FILE *f;
+  char line[256], closeline[256], *buffer, *c, *p;
+  int nprobe, probe[10];
+  int i, Nstart, Nread, Nbytes, Nshift, Nleft, done, close_enough;
+  double time, jdstart, tmp;
+  int Nsec, sec;
+
+  f = fopen (filename, "r");
+  if (f == (FILE *) NULL) {
+    fprintf (stderr, "can't open DataLogger file: %s\n", filename);
+    return (FALSE);
+  }
+
+  /* assume fixed format */
+  scan_line (f, line);
+  scan_line (f, line);
+  scan_line (f, line);
+  sscanf (line, "%*s %*s %*s %*s %lf", &jdstart);
+  Nsec = (jdstart - 2440587.5)*86400;
+  if (tzero < Nsec - WINDOW) {
+    fprintf (stderr, "missing time in DataLogger file\n");
+    return (FALSE);
+  }
+
+  scan_line (f, line);
+  scan_line (f, line);
+  scan_line (f, line);
+  sscanf (line, "%*s %*s %d", &nprobe);
+  for (i = 0; (i < nprobe) && (i < 10); i++) {
+    dparse (&tmp, i+4, line);
+    probe[i] = tmp;
+  }
+
+  /* check that probes match desired probes -- demand same order in file */
+  if (nprobe != Nprobe) {
+    fprintf (stderr, "wrong number of probes\n");
+    return (FALSE);
+  }
+  for (i = 0; (i < nprobe) && (i < 10); i++) {
+    if (probe[i] != wantprobe[i]) {
+      fprintf (stderr, "probe mismatch\n");
+      return (FALSE);
+    }
+  }
+  
+  ALLOCATE (buffer, char, NBYTES+1);
+    
+  Nstart = 0;
+  done = FALSE;
+  close_enough = FALSE;
+  while (!done && ((Nread = fread (&buffer[Nstart], 1, NBYTES - Nstart, f)) > 0)) {
+    Nbytes = Nread + Nstart;
+    buffer[Nbytes] = 0;
+    
+    /* we are using strchr lib functions - buffer can't have NULLs */
+    c = strrchr (buffer, '\n');
+    if (c == (char *) NULL) c = &buffer[Nbytes-1];
+    Nshift = c - buffer + 1;
+    
+    /* limit searches to the range buffer[0] - buffer[Nshift] */
+    p = &buffer[0];
+    while (1) {
+      c = strchr (p, '\n');
+      if (c == (char *) NULL) break;
+      if (c > &buffer[Nshift]) break;
+      *c = 0;
+      dparse (&time, 0, p);
+      sec = Nsec + time*86400;
+      if (sec + WINDOW > tzero) {
+	strcpy (closeline, p);
+	close_enough = TRUE;
+      }
+      if (sec > tzero) {
+	for (i = 0; i < Nprobe; i++) {
+	  dparse (&values[i], i+5, p);
+	}
+	free (buffer);
+	return (TRUE);
+      }
+      *c = '\n';
+      p = c + 1;
+    }
+    
+    Nleft  = Nbytes - Nshift;
+    if (Nleft > 0) memmove (buffer, &buffer[Nshift], Nleft);
+    
+    Nstart = Nleft;
+  }
+
+  if (close_enough) {
+    for (i = 0; i < Nprobe; i++) {
+      dparse (&values[i], i+5, closeline);
+    }
+    free (buffer);
+    return (TRUE);
+  }
+
+  fprintf (stderr, "time not in DataLogger file %ld\n", tzero);
+  free (buffer);
+  return (FALSE);
+}
Index: /trunk/Ohana/src/imregister/imreg/match.c
===================================================================
--- /trunk/Ohana/src/imregister/imreg/match.c	(revision 3)
+++ /trunk/Ohana/src/imregister/imreg/match.c	(revision 3)
@@ -0,0 +1,81 @@
+# include "imregister.h"
+# include "imreg.h"
+
+int *match_criteria (int *Nmatch) {
+
+  int i, j, Nname, Nimage;
+  int N, NMATCH;
+  int *match;
+  int reject;
+  RegImage *image;
+
+  /* create selection index */
+  N = 0;
+  NMATCH = 1000;
+  ALLOCATE (match, int, NMATCH);
+
+  if (criteria.NameSelect) Nname = strlen (criteria.Name);
+  
+  image = get_images (&Nimage);
+
+  /* find entries that matches criteria */
+  for (i = 0; i < Nimage; i++) {
+    for (j = 0, reject = TRUE; reject && (j < criteria.Ntimes); j++) {
+      reject = (image[i].obstime < criteria.tstart[j]) || (image[i].obstime > criteria.tstop[j]);
+    }
+    if (criteria.Ntimes && reject) continue;
+    if (criteria.FilterSelect  && (strcasecmp (image[i].filter, criteria.Filter))) continue;
+    if (criteria.ModeSelect    && (image[i].mode != criteria.Mode)) continue;
+    if (criteria.CCDSelect     && (image[i].ccd != criteria.CCD)) continue;
+    if (criteria.TypeSelect    && (image[i].type != criteria.Type)) continue;
+    if (criteria.ExptimeSelect && (fabs (image[i].exptime - criteria.Exptime) > 5.0)) continue;
+    if (criteria.NameSelect    && (strncasecmp (image[i].filename, criteria.Name, Nname))) continue;
+
+    match[N] = i;
+    N ++;
+    if (N == NMATCH) {
+      NMATCH += 1000;
+      REALLOCATE (match, int, NMATCH);
+    }
+  }
+  *Nmatch = N;
+  return (match);
+}
+
+int *match_images (RegImage *subset, int Nsubset, int *Nmatch) {
+  
+  int i, j, N, Nimage, Nfound;
+  int *match;
+  RegImage *image;
+
+  image = get_images (&Nimage);
+
+  /* find matching images - very inefficient : sort by obstime, find those first? */
+  ALLOCATE (match, int, Nsubset);
+  for (j = 0; j < Nsubset; j++) {
+    match[j] = -1;
+    for (i = 0; (match[j] == -1) && (i < Nimage); i++) {
+      if (image[i].obstime > subset[j].obstime + 1) continue;
+      if (image[i].obstime < subset[j].obstime - 1) continue;
+      if (image[i].ccd != subset[j].ccd) continue;
+      match[j] = i;
+    }
+  }
+  
+  Nfound = 0;
+  for (i = 0; i < Nsubset; i++) {
+    /* set the new values for this image */
+    N = match[i];
+    if (N == -1) continue;
+    image[N].fwhm = subset[i].fwhm; 
+    image[N].bias = subset[i].bias; 
+    image[N].sky  = subset[i].sky; 
+    image[N].ra   = subset[i].ra; 
+    image[N].dec  = subset[i].dec; 
+    /* if the image is MEF, these were not correctly assigned by imsort.
+       this step uses the values from the split ccd image */
+    Nfound ++;
+  }
+  *Nmatch = Nfound;
+  return (match);
+}
Index: /trunk/Ohana/src/imregister/imreg/modify.c
===================================================================
--- /trunk/Ohana/src/imregister/imreg/modify.c	(revision 3)
+++ /trunk/Ohana/src/imregister/imreg/modify.c	(revision 3)
@@ -0,0 +1,74 @@
+# include "imregister.h"
+# include "imreg.h"
+
+void ModifySubset (int *match, int Nmatch) {
+
+  int i, j, Nold;
+  char *tmppath;
+  char *ext, *root, *path;
+  int Nimage;
+  RegImage *image;
+
+  image = get_images (&Nimage);
+
+  /* create some necessary variables */
+  if (output.newpath) { 
+    Nold = strlen (output.oldpath);
+    ALLOCATE (tmppath, char, 128);
+  }
+
+  /* modify the selected entries */
+  for (j = 0; j < Nmatch; j++) {
+
+    i = match[j];
+
+    if (output.newpath) {
+      if (!strncmp (image[i].pathname, output.oldpath, Nold)) {
+	strcpy (tmppath, &image[i].pathname[Nold]);
+	snprintf (image[i].pathname, 128, "%s%s", output.newpath, tmppath);
+      }
+    }
+
+    if (output.mef2split) {
+      if (image[i].mode == MODE_MEF) {
+	root = filerootname (image[i].filename);
+	ext = fileextname (image[i].filename);
+	path = strcreate (image[i].pathname);
+
+	snprintf (image[i].pathname, 128, "%s/%s", path, root);
+	snprintf (image[i].filename, 64,  "%s%02d.%s", root, image[i].ccd, ext);
+	image[i].mode = MODE_SPLIT;
+	free (root);
+	free (ext);
+	free (path);
+      }
+    }
+
+    if (output.split2mef) {
+      if (image[i].mode == MODE_SPLIT) {
+	ext  = fileextname (image[i].filename);
+	root = filebasename (image[i].pathname);
+	path = pathname (image[i].pathname);
+
+	snprintf (image[i].pathname, 128, "%s", path);
+	snprintf (image[i].filename, 64,  "%s.%s", root, ext);
+	image[i].mode = MODE_MEF;
+	free (root);
+	free (ext);
+	free (path);
+      }
+    }
+  }
+
+  update_db (match, Nmatch);
+  fprintf (stderr, "SUCCESS\n");
+  exit (0);
+
+}
+
+
+/* 
+   MEF                      SPLIT
+   /path/filename.fits <--> /path/filename/filenameNN.fits
+*/
+
Index: /trunk/Ohana/src/imregister/imreg/output.c
===================================================================
--- /trunk/Ohana/src/imregister/imreg/output.c	(revision 3)
+++ /trunk/Ohana/src/imregister/imreg/output.c	(revision 3)
@@ -0,0 +1,235 @@
+# include "imregister.h"
+# include "imreg.h"
+
+static int RegTimeMode = FALSE;
+static int CCDSeq = FALSE;
+static int PTstyle = FALSE;
+
+void SetOutputMode (char *mode) {
+
+  if (!strcmp (mode, "RegTimeMode")) {
+    RegTimeMode = TRUE;
+    return;
+  }
+  if (!strcmp (mode, "CCDSeq")) {
+    CCDSeq = TRUE;
+    return;
+  }
+  if (!strcmp (mode, "PTstyle")) {
+    PTstyle = TRUE;
+    return;
+  }
+
+}
+
+/* given a subset list, write out the selected images, if desired */
+void OutputSubset (int *match, int Nmatch) {
+
+  int Nimage;
+  RegImage *image;
+
+  image = get_images (&Nimage);
+
+  if (output.table != (char *) NULL) {
+    DumpFitsTable (output.table, image, match, Nmatch);
+  } 
+
+  if (output.bintable != (char *) NULL) {
+    DumpFitsBintable (output.bintable, image, match, Nmatch);
+  } 
+
+  PrintSubset (image, match, Nmatch);
+  if (output.verbose) fprintf (stderr, "SUCCESS\n");
+
+  exit (0);
+}
+
+/* write out complete binary FITS table in format of db */
+void DumpFitsBintable (char *filename, RegImage *image, int *match, int Nmatch) {
+
+  int i, j, Nx;
+  Header header, theader;
+  Matrix matrix;
+  FTable table;
+  RegImage *subset;
+
+  /* define table layout */
+  define_table (&header, &matrix, &theader, &table);
+
+  ALLOCATE (subset, RegImage, MAX (1, Nmatch));
+  for (i = 0; i < Nmatch; i++){
+    j = match[i];
+    memcpy (&subset[i], &image[j], sizeof (RegImage));
+  }
+  ConvertStruct ((char *) subset, sizeof (RegImage), Nmatch, "regimage");
+  fits_add_rows (&table, subset, Nmatch, sizeof (RegImage));
+
+  fits_write_header  (filename, &header);
+  fits_write_matrix  (filename, &matrix);
+  fits_write_Theader (filename, &theader);
+  fits_write_table   (filename, &table);
+  exit (0);
+}
+
+void DumpFitsTable (char *filename, RegImage *image, int *match, int Nmatch) {
+  
+  int i;
+  char *obsstr, *regstr, *line, dummy[64];
+  char *modestr, *typestr, *ccdstr, *datestr;
+  unsigned long tsecond;
+  Header header, theader;
+  Matrix matrix;
+  FTable table;
+  RegImage *subset;
+
+  bzero (dummy, 64);
+  memset (dummy, ' ', 63);
+
+  /* create primary header */
+  fits_init_header (&header);    
+  header.extend = TRUE;
+  fits_create_header (&header);
+  fits_create_matrix (&header, &matrix);
+  fits_print (&header, "NEXTEND", "%d", 1, 1);
+  
+  /* create table header */
+  fits_create_table_header (&theader, "TABLE", "IMAGE_DATABASE");
+      
+  /* add current date/time to header */
+  str_to_time ("now", &tsecond);
+  datestr = sec_to_date (tsecond);
+  fits_modify (&header,  "DATE", "%s", 1, datestr);
+  fits_modify (&theader, "DATE", "%s", 1, datestr);
+
+  /* define table layout */
+  fits_define_table_column (&theader, "A64",   "FILE",       "filename in db",        "",                              1.0, 0.0);
+  fits_define_table_column (&theader, "A128",  "PATH",       "fullpath in db",        "",                              1.0, 0.0);
+  fits_define_table_column (&theader, "A32",   "FILTER",     "filter name",           "",                              1.0, 0.0);
+  fits_define_table_column (&theader, "A32",   "INSTRUMENT", "instrument",            "",                              1.0, 0.0);
+  fits_define_table_column (&theader, "A6",    "CCD",        "ccd identifier",        "",                              1.0, 0.0);
+  fits_define_table_column (&theader, "A6",    "MODE",       "mef/split/etc",         "",                              1.0, 0.0);
+  fits_define_table_column (&theader, "A8",    "TYPE",       "object/flat/bias/etc",  "",                              1.0, 0.0);
+  fits_define_table_column (&theader, "A25",   "JUNK",       "space for expansion",   "",                              1.0, 0.0); 
+  fits_define_table_column (&theader, "F6.1",  "EXPTIME",    "exposure time",        "seconds",                        1.0, 0.0); 
+  fits_define_table_column (&theader, "F5.3",  "AIRMASS",    "airmass",              "",                               1.0, 0.0);
+  fits_define_table_column (&theader, "F7.1",  "SKY",        "background level",     "counts / pixel",                 1.0, 0.0); 
+  fits_define_table_column (&theader, "F6.1",  "BIAS",       "bias level",           "counts / pixel",                 1.0, 0.0); 
+  fits_define_table_column (&theader, "F5.2",  "FWHM",       "image quality",        "pixels",                         1.0, 0.0); 
+  fits_define_table_column (&theader, "F5.1",  "TELFOCUS",   "telescope focus",      "microns",                        1.0, 0.0); 
+  fits_define_table_column (&theader, "F5.1",  "XPROBE",     "bonnette probe x pos", "microns",                        1.0, 0.0); 
+  fits_define_table_column (&theader, "F5.1",  "YPROBE",     "bonnette probe y pos", "microns",                        1.0, 0.0); 
+  fits_define_table_column (&theader, "F5.1",  "ZPROBE",     "bonnette focus",       "microns",                        1.0, 0.0); 
+  fits_define_table_column (&theader, "F5.1",  "DETTEMP",    "detector temperature", "deg celcius",                    1.0, 0.0); 
+  fits_define_table_column (&theader, "F5.1",  "TELTEMP0",   "other temperature",    "deg celcius",                    1.0, 0.0); 
+  fits_define_table_column (&theader, "F5.1",  "TELTEMP1",   "other temperature",    "deg celcius",                    1.0, 0.0); 
+  fits_define_table_column (&theader, "F5.1",  "TELTEMP2",   "other temperature",    "deg celcius",                    1.0, 0.0); 
+  fits_define_table_column (&theader, "F5.1",  "TELTEMP3",   "other temperature",    "deg celcius",                    1.0, 0.0); 
+  fits_define_table_column (&theader, "F5.1",  "ROTANGLE",   "camear rotation angle", "degrees",                       1.0, 0.0); 
+  fits_define_table_column (&theader, "F10.6", "RA",         "image ra",              "degrees",                       1.0, 0.0); 
+  fits_define_table_column (&theader, "F10.6", "DEC",        "image dec",             "degrees",                       1.0, 0.0); 
+  fits_define_table_column (&theader, "A20",   "OBS_TIME",   "time of measurement",   "seconds since Jan 1, 1970 UT",  1.0, 0.0);
+  fits_define_table_column (&theader, "A20",   "REG_TIME",   "time of registration",  "seconds since Jan 1, 1970 UT",  1.0, 0.0);
+
+  /* create table, add data values */
+  fits_create_table (&theader, &table);
+  
+  /* add data to table */
+  for (i = 0; i < Nmatch; i++) {
+    subset = &image[match[i]];
+    obsstr   = sec_to_date (subset[0].obstime);
+    regstr   = sec_to_date (subset[0].regtime);
+    typestr  = typename[(int)subset[0].type];
+    modestr  = modename[(int)subset[0].mode];
+    ccdstr   = ccds[(int)subset[0].ccd];
+
+    line = fits_table_print (&table, subset[0].pathname, subset[0].filename, 
+			     subset[0].filter, subset[0].instrument, ccdstr,
+			     modestr, typestr, dummy, 
+			     subset[0].exptime, subset[0].airmass, 
+			     subset[0].sky, subset[0].bias, subset[0].fwhm, 
+			     subset[0].telfocus, subset[0].xprobe, subset[0].yprobe, subset[0].zprobe, 
+			     subset[0].dettemp, 
+			     subset[0].teltemp[0], subset[0].teltemp[1], 
+			     subset[0].teltemp[2], subset[0].teltemp[3],
+			     subset[0].rotangle, 
+			     subset[0].ra, subset[0].dec, 
+			     obsstr, regstr);
+
+    fits_add_rows (&table, line, 1, strlen(line));
+    free (line);
+    free (obsstr);
+    free (regstr);
+  }
+
+  fits_write_header  (filename, &header);
+  fits_write_matrix  (filename, &matrix);
+  fits_write_Theader (filename, &theader);
+  fits_write_table   (filename, &table);
+  exit (0);
+}
+
+/* Select, TimeMode are global */
+int PrintSubset (RegImage *image, int *match, int Nmatch) {
+  
+  char ccdstr[64];  
+  int i, j;
+  char *pmode, *ptype, *timestr;
+
+  /* print the selected entries */
+  for (j = 0; j < Nmatch; j++) {
+    
+    i = match[j];
+
+    if ((image[i].mode < 0) || (image[i].mode >= NMODE)) 
+      pmode = modename[0];
+    else
+      pmode = modename[(int)image[i].mode];
+
+    if ((image[i].type < 0) || (image[i].type >= NTYPE)) 
+      ptype = typename[0];
+    else
+      ptype = typename[(int)image[i].type];
+
+    if (RegTimeMode) 
+      timestr = sec_to_date (image[i].regtime);
+    else
+      timestr = sec_to_date (image[i].obstime);
+
+    if (CCDSeq) {
+      sprintf (ccdstr, "%02d", image[i].ccd);
+    } else {
+      if ((image[i].ccd < 0) || (image[i].ccd >= Nccd)) {
+	sprintf (ccdstr, "%02d", image[i].ccd);
+      } else {
+      sprintf (ccdstr, "%s", ccds[(int)image[i].ccd]);
+      }
+    }      
+
+    if (PTstyle) {
+      /* this is somewhat poor: I have predefined a subset of value, and I can't guarantee that 'filter' has no spaces */
+      fprintf (stdout, "%s/%s %s %s %s\n", image[i].pathname, image[i].filename, image[i].filename, ccdstr, pmode);
+    } else {
+      /* this is somewhat poor: I have predefined a subset of value, and I can't guarantee that 'filter' has no spaces */
+      fprintf (stdout, "%5d %6s %6s %s  ", i, ptype, pmode, ccdstr);
+      fprintf (stdout, "%s %s  ", image[i].pathname, image[i].filename);
+      fprintf (stdout, "%s %f %s %f %f %f\n", image[i].filter, image[i].exptime, 
+	       timestr, image[i].fwhm, image[i].bias, image[i].sky);
+    }
+
+    free (timestr);
+  }
+  return (TRUE);
+}
+
+int dump_data (RegImage *image, int Nimage) {
+
+  int i;
+
+  for (i = 0; i < Nimage; i++) {
+    fprintf (stdout, "%s %f %f %f %s\n", image[i].filename, image[i].fwhm, image[i].sky, image[i].bias, image[i].filter);
+  }
+
+  fprintf (stdout, "SUCCESS\n");
+  exit (0);
+
+}
Index: /trunk/Ohana/src/imregister/imreg/submit.c
===================================================================
--- /trunk/Ohana/src/imregister/imreg/submit.c	(revision 3)
+++ /trunk/Ohana/src/imregister/imreg/submit.c	(revision 3)
@@ -0,0 +1,60 @@
+# include "imregister.h"
+# include "imreg.h"
+
+int SubmitImages (RegImage *image) {
+
+  int i;
+  char line[1024], *root, *path;
+
+  /* send these images to FIFOs for imstat and ptolemy */ 
+
+  /* image[0].ccd contains:
+     MEF    : Nccd
+     SPLIT  : ccd number
+     CUBE   : Nslice
+     SLICE  : slice number
+     SINGLE : 0
+  */
+
+  if (image[0].mode == MODE_MEF) {
+    for (i = 0; i < image[0].ccd; i++) {
+      root = filerootname (image[0].filename);
+      sprintf (line, "%s/%s %s/%s%s %s %s", image[0].pathname, image[0].filename, root, root, ccds[i], ccds[i], "MEF");
+      if (!WriteFIFO (ImstatFifo, line)) return (FALSE);
+      if (image[0].type == TYPE_OBJECT) {
+	if (!WriteFIFO (PtolemyFifo, line)) return (FALSE);
+      }
+    }
+  } 
+
+  if (image[0].mode == MODE_SINGLE) {
+    root = filerootname (image[0].filename);
+    sprintf (line, "%s/%s %s %02d %s", image[0].pathname, image[0].filename, root, 0, "SINGLE");
+    if (!WriteFIFO (ImstatFifo, line)) return (FALSE);
+    if (image[0].type == TYPE_OBJECT) {
+      if (!WriteFIFO (PtolemyFifo, line)) return (FALSE);
+    }
+  } 
+
+  if (image[0].mode == MODE_CUBE) {
+    root = filerootname (image[0].filename);
+    sprintf (line, "%s/%s %s %02d %s", image[0].pathname, image[0].filename, root, 0, "CUBE");
+    if (!WriteFIFO (ImstatFifo, line)) return (FALSE);
+    if (image[0].type == TYPE_OBJECT) {
+      if (!WriteFIFO (PtolemyFifo, line)) return (FALSE);
+    }
+  } 
+
+  if (image[0].mode == MODE_SPLIT) {
+    path = basename (image[0].pathname);
+    root = filerootname (image[0].filename);
+    sprintf (line, "%s/%s %s/%s %02d %s", image[0].pathname, image[0].filename, path, root, image[0].ccd, "SPLIT");
+    if (!WriteFIFO (ImstatFifo, line)) return (FALSE);
+    if (image[0].type == TYPE_OBJECT) {
+      if (!WriteFIFO (PtolemyFifo, line)) return (FALSE);
+    }
+  }    
+
+  return (TRUE);
+}
+  
Index: /trunk/Ohana/src/imregister/include/detrend.h
===================================================================
--- /trunk/Ohana/src/imregister/include/detrend.h	(revision 3)
+++ /trunk/Ohana/src/imregister/include/detrend.h	(revision 3)
@@ -0,0 +1,112 @@
+
+typedef struct {
+  int state; /* none, close, perfect */
+  int crit;  /* which criterion? */
+  int image; /* which detrend image? */
+} Match;
+
+typedef struct {
+  int TimeSelect;    unsigned long tstart, tstop;
+  char *label; 
+  char *imageID;
+  int order;
+  int type;
+  int CCDSelect;     int CCD;
+  int ExptimeSelect; float Exptime;
+  int filter;
+} Descriptor;
+
+/* MosaicSelect & ImageSelect define these values */
+typedef struct {
+  int TypeSelect;    int Type;
+  int CCDSelect;     int CCD;
+  int FilterSelect;  int Filter;
+  int EntrySelect;   int Entry;
+  int LabelSelect;   char *Label;
+  int ExptimeSelect; float Exptime;
+  int TimeSelect;    unsigned long tstart, tstop;
+  int MatchNumber;
+} Criteria;
+
+int Ncriteria;
+Criteria *criteria;
+
+struct {
+  int Select;
+  int Delete;
+  int Modify;
+  int ElixirSmart;
+  int TimeMode;
+  int Recipe;
+  int Close;
+  int Criteria;
+
+  char *ModifyEntry, *ModifyValue;
+  unsigned long TimeValue;
+  
+  int verbose;
+  char *table;
+  char *bintable;
+} output;
+
+enum {START, STOP, REG};
+enum {UNLOCK, LOCK, IGNORE};
+enum {MATCH_NONE, MATCH_CLOSE, MATCH_PERFECT};
+
+# define DEBUG 0
+
+# define NTYPE 10
+enum {T_NONE, T_OBJECT, T_DARK, T_BIAS, T_FLAT, T_MASK, T_FRINGE, T_SCATTER, T_MODES, T_ANY};
+static char typename[NTYPE][32] = {"none", "object", "dark", "bias", "flat", "mask", "fringe", "scatter", "modes", "any"};
+static char typecode[NTYPE] = {'x', 'o', 'd', 'b', 'f', 'm', 'r', 's'};
+
+# define NMODE 6
+enum {M_NONE, M_MEG, M_SPLIT, M_SINGLE, M_CUBE, M_SLICE};
+static char modename[6][32] = {"none", "MEF", "SPLIT", "SINGLE", "CUBE", "SLICE"};
+
+char **RecipeType;
+int Nrecipe;
+
+int SingleIsSplit;
+int NoReg;
+
+int regargs (int argc, char **argv, Descriptor *descriptor);
+int args (int argc, char **argv);
+int DefineImage (char *filename, Descriptor *descriptor);
+int define_table (Header *header, Matrix *matrix, Header *theader, FTable *table);
+char *get_dBPath ();
+DetReg DefineEntry (Descriptor descriptor);
+int SaveEntry (char *input, DetReg *newdata, char *ID);
+
+int load_db ();
+int save_db ();
+int update_db (int *match, int Nmatch);
+int append_db (DetReg *new, int Nnew);
+int create_db ();
+int close_db ();
+
+char **LoadRecipe (char *filter, int *nrecipe);
+
+Match *MatchCriteria (int *nmatch);
+Match *UniqueSubset (Match *match, int *nmatch);
+Match *CloseCriteria (Match *match, int *nmatch);
+Match *ExptimeCriteria (Match *match, int *nmatch);
+
+Match CheckCriteria (DetReg *image);
+DetReg *get_images (int *N);
+int set_images (DetReg *new, int Nnew);
+
+int delete_image (DetReg *image);
+int OutputSubset (Match *match, int Nmatch);
+int DumpFitsTable (char *filename, DetReg *detdata, Match *match, int Nmatch);
+int PrintSubset (DetReg *detdata, Match *match, int Nmatch);
+Match SelectEntry (Match *list, int Nlist, Criteria *crit);
+
+int ModifySubset (Match *match, int Nmatch);
+int DeleteSubset (Match *match, int Nmatch);
+int usage ();
+Criteria *MosaicCriteria (Criteria base, char *filename, int *ncrit);
+Criteria *ImageCriteria (Criteria base, char *filename, char *ImageExtend, char *ImageMode, int *ncrit);
+Criteria *ExpandBase (Criteria base, int *ncrit, unsigned long *tstart, unsigned long *tstop, int *filt);
+Criteria *ExpandRecipe (Criteria *base, int *Ncrit);
+
Index: /trunk/Ohana/src/imregister/include/imreg.h
===================================================================
--- /trunk/Ohana/src/imregister/include/imreg.h	(revision 3)
+++ /trunk/Ohana/src/imregister/include/imreg.h	(revision 3)
@@ -0,0 +1,61 @@
+struct {
+  int ModeSelect;    int Mode;
+  int TypeSelect;    int Type;
+  int CCDSelect;     int CCD;
+  int FilterSelect;  char *Filter;
+  int EntrySelect;   int Entry;
+  int LabelSelect;   char *Label;
+  int ExptimeSelect; float Exptime;
+  int TimeSelect;    unsigned long Time;
+  int NameSelect;    char *Name;
+  int Ntimes;        unsigned long *tstart, *tstop;
+  int MatchNumber;
+  int Close;
+} criteria;
+
+struct {
+  int delete;
+  int modify;
+
+  int Newpath, mef2split, split2mef;
+  char *oldpath, *newpath;
+
+  int verbose;
+  char *table;
+  char *bintable;
+} output;
+
+# define NTYPE 9
+enum {T_NONE, T_OBJECT, T_DARK, T_BIAS, T_FLAT, T_MASK, T_FRINGE, T_SCATTER, T_MODES};
+static char typename[NTYPE][32] = {"none", "object", "dark", "bias", "flat", "mask", "fringe", "scatter", "modes"};
+
+# define NMODE 6
+enum {M_NONE, M_MEG, M_SPLIT, M_SINGLE, M_CUBE, M_SLICE};
+static char modename[6][32] = {"none", "MEF", "SPLIT", "SINGLE", "CUBE", "SLICE"};
+
+int SingleIsSplit;
+int NoReg;
+
+int args (int argc, char **argv);
+RegImage *get_images (int *N);
+int set_images (RegImage *new, int Nnew);
+int load_db ();
+int save_db ();
+int update_db (int *match, int Nmatch);
+int append_db (RegImage *new, int Nnew);
+int create_db ();
+int close_db ();
+void DeleteSubset (int *match, int Nmatch);
+RegImage *iminfo (char *filename);
+int *match_criteria (int *Nmatch);
+int *match_images (RegImage *subset, int Nsubset, int *Nmatch);
+void ModifySubset (int *match, int Nmatch);
+void SetOutputMode (char *mode);
+void OutputSubset (int *match, int Nmatch);
+void DumpFitsBintable (char *filename, RegImage *image, int *match, int Nmatch);
+void DumpFitsTable (char *filename, RegImage *image, int *match, int Nmatch);
+int PrintSubset (RegImage *image, int *match, int Nmatch);
+int dump_data (RegImage *image, int Nimage);
+int SubmitImages (RegImage *image);
+int load_probes (char *filename, unsigned long tzero, int *wantprobe, double *values, int Nprobe);
+int define_table (Header *header, Matrix *matrix, Header *theader, FTable *table);
Index: /trunk/Ohana/src/imregister/include/imregister.h
===================================================================
--- /trunk/Ohana/src/imregister/include/imregister.h	(revision 3)
+++ /trunk/Ohana/src/imregister/include/imregister.h	(revision 3)
@@ -0,0 +1,90 @@
+# include <ohana.h>
+# include <loneos.h>
+# include <errno.h>
+# include <time.h>
+# include <ctype.h>
+
+/* config variables from very old versions - remove?
+char ImageTemplate[256];
+char DBServer[256];
+*/
+
+char ImstatFifo[256];
+char PtolemyFifo[256];
+
+char ImageDB[256];
+char DetrendDB[256];
+char PhotDB[256];
+char TransDB[256];
+char ImPhotDB[256];
+
+char PhotCodeFile[256];
+char TempLogFile[256];
+char FilterList[256];
+char CameraConfig[256];
+char RecipeFile[256];
+
+char DateKeyword[64];
+char DateMode[64];
+char UTKeyword[64];
+char MJDKeyword[64];
+char JDKeyword[64];
+char ExptimeKeyword[16];
+char ImagetypeKeyword[16];
+char CCDnumKeyword[16];
+char FilterKeyword[16];
+char AirmassKeyword[16];
+char FocusKeyword[16];
+char RotationKeyword[16];
+char DettempKeyword[16];
+char Teldata1Keyword[16];
+char Teldata2Keyword[16];
+char Teldata3Keyword[16];
+char RADecDegKeyword[16];
+char DECDecDegKeyword[16];
+char RASexigKeyword[16];
+char DECSexigKeyword[16];
+char CameraKeyword[16];
+
+/* global vars used by camera info */
+char **ccds;
+int  Nccd;
+
+/* global vars used by filter abstraction */
+# define FILTER_ANY  -1 
+# define FILTER_NONE 0
+int NFILTER;
+char **filtername;
+char **filterhash;
+int   *filternum;
+
+int dms_to_ddd (double *Value, char *string);
+int str_to_radec (double *ra, double *dec, char *str1, char *str2);
+int chk_time (char *line);
+double sec_to_jd (unsigned long second);
+unsigned long int jd_to_sec (double jd);
+char *sec_to_date (unsigned long second);
+unsigned long date_to_sec (char *date);
+int str_to_time (char *line, unsigned long *second);
+
+int Fseek (FILE *f, long offset, int whence);
+int get_trange_arguments (int *argc, char **argv, unsigned long **Tstart, unsigned long **Tstop, int *ntimes);
+int get_filter_arguments (int *argc, char **argv, int **Filt, int *Nfilt);
+
+void make_backup (char *filename);
+int parse_time (Header *header);
+void uppercase (char *string);
+void sort (float *value, int N);
+void dsort (double *value, int N);
+
+void ConfigCamera ();
+int MatchCCDName (Header *header);
+void ConfigFilter ();
+int MatchFilterList (char *line);
+void ConfigInit (int *argc, char **argv);
+void WarnConfig (char *config, char *key, char * mode, int N, char *var);
+int WriteFIFO (char *filename, char *line);
+double get_fwhm (char *filename);
+
+/* where is this defined ?? */
+char *basename (char *);
Index: /trunk/Ohana/src/imregister/src/convertimreg.c
===================================================================
--- /trunk/Ohana/src/imregister/src/convertimreg.c	(revision 3)
+++ /trunk/Ohana/src/imregister/src/convertimreg.c	(revision 3)
@@ -0,0 +1,56 @@
+# include "imregister.h"
+# include "imreg.h"
+static char *version = "convertimreg $Revision: 3.0 $";
+
+int main (int argc, char **argv) {
+ 
+  FILE *f;
+  Header header;
+  RegImage *pimage;
+  int i, Nimage, status, lockstate, dbstate;
+  int *match;
+  
+  get_version (argc, argv, version);
+  ConfigInit (&argc, argv);
+  ConfigCamera ();
+  ConfigFilter ();
+  
+  if (argc != 3) {
+    fprintf (stderr, "USAGE: convertregdb (input) (output)\n");
+    exit (1);
+  }
+  
+  /* load old-style pseudo-FITS table db */
+
+  /* lock database (soft) */
+  f = fsetlockfile (argv[1], 300.0, LCK_SOFT, &dbstate);
+  if (f == (FILE *) NULL) {
+    fprintf (stderr, "ERROR: can't open db\n");
+    exit (1);
+  }
+  Fseek (f, 0, SEEK_SET);
+
+  /* load in database header */
+  if (!fits_load_header (f, &header)) {
+    fprintf (stderr, "ERROR: trouble reading database header\n");
+    fclearlockfile (argv[1], f, lockstate, &dbstate);
+    exit (1);
+  }
+
+  /* load existing data from database */
+  fits_scan (&header, "NIMAGES", "%d", 1, &Nimage);
+  ALLOCATE (pimage, RegImage, Nimage);
+  status = Fread (pimage, sizeof(RegImage), Nimage, f, "regimage");
+  if (status != Nimage) {
+    fprintf (stderr, "ERROR: header and data in dB don't match (%d vs %d)\n", Nimage, status);
+    fclearlockfile (argv[1], f, lockstate, &dbstate);
+    exit (1);
+  }
+  fclearlockfile (argv[1], f, lockstate, &dbstate);
+
+  /* create complete subset */
+  ALLOCATE (match, int, Nimage);
+  for (i = 0; i < Nimage; i++) match[i] = i;
+
+  DumpFitsBintable (argv[2], pimage, match, Nimage);
+}
Index: /trunk/Ohana/src/imregister/src/detregister.c
===================================================================
--- /trunk/Ohana/src/imregister/src/detregister.c	(revision 3)
+++ /trunk/Ohana/src/imregister/src/detregister.c	(revision 3)
@@ -0,0 +1,72 @@
+# include "imregister.h"
+# include "detrend.h"
+static char *version = "detregister $Revision: 3.0 $";
+
+int main (int argc, char **argv) {
+ 
+  int status;
+  DetReg newdata;
+  Descriptor descriptor;
+  
+  get_version (argc, argv, version);
+  regargs (argc, argv, &descriptor);
+  DefineImage (argv[1], &descriptor);
+
+  newdata = DefineEntry (descriptor);
+  SaveEntry (argv[1], &newdata, descriptor.imageID);
+
+  status = load_db ();
+  if (!status) {
+    create_db ();
+  }
+  append_db (&newdata, 1);
+
+  fprintf (stderr, "SUCCESS\n");
+  exit (0);
+
+}
+
+/* detrend files created by mkdetrend have names of the following form:
+   
+   TYPE.CCD.FILTER.CRUN.NUMBER.fits 
+   
+   ie:
+   
+   bias.02.0.01Ak3.0.fits
+   
+   When they are registered, the NUMBER component needs to be
+   updated to match the next available number.
+   
+   This is a bit tricky.  We can easily identify 
+   TYPE, CCD, FILTER, and extrapolate to the NUMBER, but 
+   unambiguously identifying the CRUN is harder.  We could make it a 
+   required keyword on the command line, or insert it in the
+   image header and request it if it doesn't exist?
+
+    required fields:
+
+    tstart
+    tstop
+    type
+    ccd
+
+    filename (automatic)
+    treg (automatic)
+
+    case type 
+      flat:
+      ring:
+      scat:
+        filter is required
+      default:
+        filter is none
+
+    case type
+      dark:
+        exptime is required
+      bias:
+        exptime is 0.0
+      default:
+        exptime is NaN
+
+*/
Index: /trunk/Ohana/src/imregister/src/detsearch.c
===================================================================
--- /trunk/Ohana/src/imregister/src/detsearch.c	(revision 3)
+++ /trunk/Ohana/src/imregister/src/detsearch.c	(revision 3)
@@ -0,0 +1,75 @@
+# include "imregister.h"
+# include "detrend.h"
+static char *version = "detsearch $Revision: 3.0 $";
+
+int main (int argc, char **argv) {
+ 
+  int status;
+  Match *match;
+  int Nmatch;
+
+  /* args searches the argument list and generates an array of criteria */
+  get_version (argc, argv, version);
+  args (argc, argv);
+
+  status = load_db ();
+  if (!status) {
+    close_db ();
+    exit (0);
+  }
+  if (!output.Modify && !output.Delete) close_db ();
+  
+  match = MatchCriteria (&Nmatch);          /* match basic criteria */
+  match = ExptimeCriteria (match, &Nmatch); /* reduce matches based on Exptime */
+  match = CloseCriteria (match, &Nmatch);   /* reduce matches based on closeness */
+
+  if (output.Criteria) PrintCriteria ();
+	
+  if (output.Select) {
+    match = UniqueSubset (match, &Nmatch);
+    if (Nmatch == 0) {
+      if (output.verbose) fprintf (stderr, "ERROR: can't find any valid detrend files (%s %s %d)\n", typename[criteria[0].Type], filtername[criteria[0].Filter], criteria[0].CCD);
+      close_db ();
+      exit (1);
+    }
+  }
+
+  if (output.Modify) ModifySubset (match, Nmatch);
+  if (output.Delete) DeleteSubset (match, Nmatch);
+
+  OutputSubset (match, Nmatch);
+  exit (0);
+}
+
+/*
+
+selection options:
+
+CCDSelect
+TypeSelect
+TimeSelect
+FilterSelect
+ExptimeSelect
+EntrySelect
+LabelSelect
+
+
+ functional modes:
+
+   1) list - list all images that apply to a restrictive set of criteria
+   
+   2) select - choose the reference image(s)
+
+   3) delete - delete a set of images
+
+   4) modify - alter fields for a set of images
+
+   
+   methods to define criteria
+
+   - command line  [-time -type -ccd -filter -exptime]
+   - image  -> define time, filter, ccd
+   - mosaic -> define time, filter, exptime
+   - recipe -> defile type list based on filter
+
+*/
Index: /trunk/Ohana/src/imregister/src/imregister.c
===================================================================
--- /trunk/Ohana/src/imregister/src/imregister.c	(revision 3)
+++ /trunk/Ohana/src/imregister/src/imregister.c	(revision 3)
@@ -0,0 +1,55 @@
+# include "imregister.h"
+# include "imreg.h"
+static char *version = "imregister $Revision: 3.0 $";
+
+int main (int argc, char **argv) {
+ 
+  RegImage *image, *pimage;
+  int i, status, Nnew;
+  float *dtime;
+
+  get_version (argc, argv, version);
+  args (argc, argv);
+  image = iminfo (argv[1]);
+
+  /* define new entries (pimage, Nnew) */
+  switch (image[0].mode) {
+  case MODE_CUBE:
+    Nnew = image[0].ccd + 1;
+    ALLOCATE (pimage, RegImage, Nnew);
+    pimage[0] = image[0];
+    dtime = (float *)&image[0].junk[0];
+    for (i = 1; i < Nnew; i++) {
+      pimage[i] = image[0]; 
+      pimage[i].ccd = i - 1;
+      pimage[i].mode = MODE_SLICE;
+      pimage[i].obstime += *dtime*pimage[i].ccd;
+    }
+    break;
+  case MODE_MEF:
+    Nnew = image[0].ccd;
+    ALLOCATE (pimage, RegImage, Nnew);
+    for (i = 0; i < Nnew; i++) {
+      pimage[i] = image[0]; 
+      pimage[i].ccd = i;
+    }
+    break;
+  case MODE_SPLIT:
+  case MODE_SINGLE:
+    Nnew = 1;
+    pimage = &image[0];
+    break;
+  }
+
+  if (!NoReg) {
+    status = load_db ();
+    if (!status) {
+      create_db ();
+    }
+    append_db (pimage, Nnew);
+  }
+
+  fprintf (stderr, "SUCCESS: registered %s\n", argv[1]);
+  exit (0);
+}
+
Index: /trunk/Ohana/src/imregister/src/imregtable.c
===================================================================
--- /trunk/Ohana/src/imregister/src/imregtable.c	(revision 3)
+++ /trunk/Ohana/src/imregister/src/imregtable.c	(revision 3)
@@ -0,0 +1,48 @@
+# include "imregister.h"
+# include "imreg.h"
+static char *version = "imregtable $Revision: 3.0 $";
+
+int main (int argc, char **argv) {
+ 
+  int status, Nimage, Nx, Ny;
+  char *infile;
+  RegImage *image;
+  Header header, theader;
+  Matrix matrix;
+  FTable table;
+
+  get_version (argc, argv, version);
+  ConfigInit (&argc, argv);
+  ConfigCamera ();
+  ConfigFilter ();
+  
+  if (argc != 2) {
+    fprintf (stderr, "USAGE: imregtable (table)\n");
+    exit (1);
+  }
+  infile = argv[1];
+
+  /* load in table data */
+  table.header = &theader;
+  fits_read_header (infile, &header);
+  fits_read_matrix (infile, &matrix, &header);
+  fits_read_ftable  (infile, &table, "IMAGE_DATABASE");
+
+  /* convert to internal format */
+  image = (RegImage *) table.buffer;
+  fits_scan (table.header, "NAXIS1", "%d", 1, &Nx);
+  fits_scan (table.header, "NAXIS2", "%d", 1, &Ny);
+  Nimage = Ny;
+
+  ConvertStruct ((char *) image, sizeof (RegImage), Nimage, "regimage");
+
+  status = load_db ();
+  if (!status) {
+    create_db ();
+  }
+  append_db (image, Nimage);
+
+  fprintf (stderr, "SUCCESS: registered %s\n", argv[1]);
+  exit (0);
+}
+
Index: /trunk/Ohana/src/imregister/src/imsearch.c
===================================================================
--- /trunk/Ohana/src/imregister/src/imsearch.c	(revision 3)
+++ /trunk/Ohana/src/imregister/src/imsearch.c	(revision 3)
@@ -0,0 +1,60 @@
+# include "imregister.h"
+# include "imreg.h"
+static char *version = "imsearch $Revision: 3.0 $";
+
+int main (int argc, char **argv) {
+ 
+  int status, Nmatch;
+  int *match;
+
+  get_version (argc, argv, version);
+  args (argc, argv);
+
+  status = load_db ();
+  if (!status) {
+    close_db ();
+    exit (0);
+  }
+  if (!output.modify && !output.delete) close_db ();
+  
+  match = match_criteria (&Nmatch);
+
+  if (output.modify) ModifySubset (match, Nmatch);
+  if (output.delete) DeleteSubset (match, Nmatch);
+
+  OutputSubset (match, Nmatch);
+
+  exit (0);
+}
+
+/* 
+
+FITS table version:
+
+   load_db - open, read in database, store as RegImage structure
+   match   - return index 'match' to matched images
+   modify  - change value of selected images
+             write out subset of rows
+   delete  - remove selected images from image structure
+             write out entire table
+   output  - write out subset in various formats
+
+   get_images returns pointer to complete image structure
+
+
+SQL version:
+
+   load_db - set up connection
+   match   - convert criteria to SQL where clause and do:
+             'select from images [where clause]'
+             images structure is filled with result from query
+   modify  - change value of subset selection (identical)
+             update selected rows
+   delete  - user where clause and do 
+             'delete from images where clause'
+   output  - (identical)
+
+   get_images returns pointer to image subset from query
+   match[i] = i
+
+*/
Index: /trunk/Ohana/src/imregister/src/imsort.c
===================================================================
--- /trunk/Ohana/src/imregister/src/imsort.c	(revision 3)
+++ /trunk/Ohana/src/imregister/src/imsort.c	(revision 3)
@@ -0,0 +1,56 @@
+# include "imregister.h"
+# include "imreg.h"
+static char *version = "imsort $Revision: 3.0 $";
+
+int main (int argc, char **argv) {
+ 
+  RegImage *image, *pimage;
+  int i, status, Nnew;
+  float *dtime;
+
+  get_version (argc, argv, version);
+  args (argc, argv);
+  image = iminfo (argv[1]);
+  
+  /* define new entries (pimage, Nnew) */
+  switch (image[0].mode) {
+  case MODE_CUBE:
+    Nnew = image[0].ccd + 1;
+    ALLOCATE (pimage, RegImage, Nnew);
+    pimage[0] = image[0];
+    dtime = (float *)&image[0].junk[0];
+    for (i = 1; i < Nnew; i++) {
+      pimage[i] = image[0]; 
+      pimage[i].ccd = i - 1;
+      pimage[i].mode = MODE_SLICE;
+      pimage[i].obstime += *dtime*pimage[i].ccd;
+    }
+    break;
+  case MODE_MEF:
+    Nnew = image[0].ccd;
+    ALLOCATE (pimage, RegImage, Nnew);
+    for (i = 0; i < Nnew; i++) {
+      pimage[i] = image[0]; 
+      pimage[i].ccd = i;
+    }
+    break;
+  case MODE_SPLIT:
+  case MODE_SINGLE:
+    Nnew = 1;
+    pimage = &image[0];
+    break;
+  }
+  
+  if (!NoReg) {
+    status = load_db ();
+    if (!status) {
+      create_db ();
+    }
+    append_db (pimage, Nnew);
+  }
+
+  SubmitImages (image);
+  fprintf (stderr, "SUCCESS: registered %s\n", argv[1]);
+  exit (0);
+}
+
Index: /trunk/Ohana/src/imregister/src/imstatreg.c
===================================================================
--- /trunk/Ohana/src/imregister/src/imstatreg.c	(revision 3)
+++ /trunk/Ohana/src/imregister/src/imstatreg.c	(revision 3)
@@ -0,0 +1,83 @@
+# include "imregister.h"
+# include "imreg.h"
+static char *version = "imstatreg $Revision: 3.0 $";
+
+int main (int argc, char **argv) {
+ 
+  FILE *f;
+  RegImage *image;
+  float *dtime;
+  int i, Nentry, Nslice, *match, Nmatch, status;
+
+  get_version (argc, argv, version);
+  args (argc, argv);
+  image = iminfo (argv[1]);
+
+  /* if images is MEF or SPLIT/SINGLE, load stats file */
+  /* get stats file (has sky, bias, etc) */
+  switch (image[0].mode) {
+  case MODE_MEF:
+  case MODE_SPLIT:
+    f = fopen (argv[2], "r");
+    if (f == (FILE *) NULL) {
+      fprintf (stderr, "ERROR: can't open file.stats\n");
+      exit (1);
+    }
+    fscanf (f, "%f %f", &image[0].sky, &image[0].bias);
+    fclose (f);
+    image[0].fwhm = get_fwhm (argv[3]);
+    Nentry = 1;
+    break;
+  case MODE_SINGLE:
+    f = fopen (argv[2], "r");
+    if (f == (FILE *) NULL) {
+      fprintf (stderr, "ERROR: can't open file.stats\n");
+      exit (1);
+    }
+    status = fscanf (f, "%d %f %f", &image[0].ccd, &image[0].sky, &image[0].fwhm);
+    fclose (f);
+    Nentry = 1;
+    break;
+  case MODE_CUBE:
+    f = fopen (argv[2], "r");
+    if (f == (FILE *) NULL) {
+      fprintf (stderr, "ERROR: can't open file.stats\n");
+      exit (1);
+    }
+    status = 3;
+    Nslice = image[0].ccd;
+    Nentry = Nslice + 1;
+    REALLOCATE (image, RegImage, Nentry);
+    dtime = (float *)&image[0].junk[0];
+    for (i = 0; i < Nentry; i++) {
+      image[i] = image[0];
+      status = fscanf (f, "%d %f %f", &image[i].ccd, &image[i].sky, &image[i].fwhm);
+      if (image[i].ccd == Nslice) continue;
+      image[i].obstime += *dtime*image[i].ccd;
+    }
+    fclose (f);
+    Nentry = i;
+    break;
+  }
+  if (NoReg) dump_data (image, Nentry);
+
+  status = load_db ();
+  if (!status) {
+    fprintf (stderr, "ERROR: database does not yet exist\n");
+    close_db ();
+    exit (1);
+  }
+
+  match = match_images (image, Nentry, &Nmatch);
+  if (!Nmatch) {
+    fprintf (stderr, "ERROR: no matched images found\n");
+    close_db ();
+    exit (2);
+  }
+
+  update_db (match, Nmatch);
+
+  fprintf (stdout, "SUCCESS\n");
+  exit (0);
+}
+
Index: /trunk/Ohana/src/imregister/src/photcode.c
===================================================================
--- /trunk/Ohana/src/imregister/src/photcode.c	(revision 3)
+++ /trunk/Ohana/src/imregister/src/photcode.c	(revision 3)
@@ -0,0 +1,72 @@
+# include "imregister.h"
+static char *version = "photcode $Revision: 3.0 $";
+
+int main (int argc, char **argv) {
+
+  Header header;
+  char detector[80], filter[80], FilterList[256], *ID;
+  int i, ccd, VERBOSE, N, Nfilter;
+  char *photname;
+
+  get_version (argc, argv, version);
+  ConfigInit (&argc, argv);
+  ConfigCamera ();
+  ConfigFilter ();
+
+  VERBOSE = TRUE;
+  if (N = get_argument (argc, argv, "-quiet")) {
+    remove_argument (N, &argc, argv);
+    VERBOSE = FALSE;
+  }
+
+  if (argc != 4) { 
+    fprintf (stderr, "USAGE: photcode (file.fits) (ccd) (mode)\n");
+    exit (1);
+  }
+
+  /* read in image header */
+  if (!fits_read_header (argv[1], &header)) {
+    if (VERBOSE) fprintf (stderr, "ERROR: can't find image file %s (1)\n", argv[1]);
+    exit (1);
+  }
+
+  fits_scan (&header, CameraKeyword, "%s", 1, detector);
+  for (i = 0; i < strlen(detector); i++) { detector[i] = toupper (detector[i]); }
+  for (i = 0; i < strlen(detector); i++) { if (isspace (detector[i])) detector[i] = '.'; }
+
+  fits_scan (&header, FilterKeyword,   "%s", 1, filter);
+  for (i = 0; i < strlen (filter); i++) { if (isspace (filter[i])) filter[i] = '.'; }
+  Nfilter = FILTER_NONE;
+  for (i = 0; (i < NFILTER) && (Nfilter == FILTER_NONE); i++) {
+    if (!strcasecmp (filter, filtername[i])) {
+      Nfilter = filternum[i];
+    }
+  }      
+  if (Nfilter == FILTER_NONE) {
+    fprintf (stderr, "ERROR: invalid filter %s\n", filter);
+    exit (1);
+  }
+  strcpy (filter, filterhash[Nfilter]);
+
+  if (!strcasecmp (argv[3], "mef")) {
+    ID = strcreate (argv[2]);
+  } else {
+    ALLOCATE (ID, char, 80);
+    fits_scan (&header, CCDnumKeyword,  "%s", 1, ID);
+  }
+  ccd = -1;
+  for (i = 0; (i < Nccd) && (ccd == -1); i++) {
+    if (strnumcmp (ccds[i], ID)) {
+      ccd = i;
+    }
+  }
+  if (ccd == -1) {
+    fprintf (stderr, "warning: ccd %s not found in camera config file\n", ID);
+    ccd = 0;
+  }
+
+  fprintf (stdout, "%s.%s.%02d\n", detector, filter, ccd);
+
+  exit (0);
+
+}
Index: /trunk/Ohana/src/imregister/src/showiminfo.c
===================================================================
--- /trunk/Ohana/src/imregister/src/showiminfo.c	(revision 3)
+++ /trunk/Ohana/src/imregister/src/showiminfo.c	(revision 3)
@@ -0,0 +1,37 @@
+# include "imregister.h"
+# include "imreg.h"
+static char *version = "showiminfo $Revision: 3.0 $";
+
+int main (int argc, char **argv) {
+ 
+  char *obstime, *regtime;
+  RegImage *image, im;
+
+  get_version (argc, argv, version);
+  args (argc, argv);
+  image = iminfo (argv[1]);
+  im = image[0];
+  
+  fprintf (stderr, "\n");
+  fprintf (stderr, "filename: %s\n",   im.filename);
+  fprintf (stderr, "pathname: %s\n",   im.pathname);
+  fprintf (stderr, "filter: %s\n",     im.filter);
+  fprintf (stderr, "instrument: %s\n\n", im.instrument);
+
+  fprintf (stderr, "ccd: %d, mode: %d, type: %d\n\n", im.ccd, im.mode, im.type);
+
+  fprintf (stderr, "exptime: %f, airmass: %f, telfocus: %f\n", im.exptime, im.airmass, im.telfocus);
+  fprintf (stderr, "xprobe: %f, yprobe: %f, zprobe: %f\n", im.xprobe, im.yprobe, im.zprobe);
+  fprintf (stderr, "dettemp: %f, temp0: %f temp1: %f, temp2: %f, temp3: %f\n\n", 
+	   im.dettemp, im.teltemp[0], im.teltemp[1], im.teltemp[2], im.teltemp[3]);
+
+  fprintf (stderr, "ra: %f, dec: %f, rotangle: %f\n", im.ra, im.dec, im.rotangle);
+
+  obstime = sec_to_date (im.obstime);
+  regtime = sec_to_date (im.regtime);
+
+  fprintf (stderr, "obstime: %s\n", obstime);
+  fprintf (stderr, "regtime: %s\n", regtime);
+
+  exit (0);
+}
