Index: trunk/Ohana/src/libfits/header/F_scan.c
===================================================================
--- trunk/Ohana/src/libfits/header/F_scan.c	(revision 39323)
+++ trunk/Ohana/src/libfits/header/F_scan.c	(revision 39324)
@@ -44,12 +44,18 @@
   if (p[8] != '=') return (FALSE);
 
+  s = gfits_keyword_start (p); /* points at first char (not ') */
+  q = gfits_keyword_end (p); /* points at following space or ' */
+
+  // these are invalid conditions:
+  if (s - p > 80) return FALSE;
+  if (q - p > 80) return FALSE;
+
   /* extract data into char array (exclude containing ' chars) */
+  Nchar = MIN (80, MAX (0, (q - s)));
+  bzero (tmp, 81);
+  memcpy (tmp, s, Nchar);
+
+  // for string types, copy the data to the target pointer
   if (!strcmp (mode, "%s")) {
-    s = gfits_keyword_start (p); /* points at first char (not ') */
-    q = gfits_keyword_end (p); /* points at following space or ' */
-
-    Nchar = MAX (0, (q - s));
-    bzero (tmp, 81);
-    memcpy (tmp, s, Nchar);
     stripwhite (tmp);
     strcpy (va_arg (argp, char *), tmp);
@@ -59,11 +65,8 @@
   /* remaining options are numerical data */
   /* need to interpret 1.0d5 as 1.0e5 */
-  s = gfits_keyword_start (p); /* points at first char (not ') */
-  q = gfits_keyword_end (p); /* points at following space or ' */
 
   if (!strcmp (mode, "%f") || !strcmp (mode, "%lf")) {
-    fvalue = strtod (s, &q);
-    if ((*q == 'd') || (*q == 'D')) 
-      fvalue *= pow (10.0, atof (q + 1));
+    fvalue = strtod (tmp, &q);
+    if ((*q == 'd') || (*q == 'D')) fvalue *= pow (10.0, atof (q + 1));
 
     if (!strcmp (mode, "%f"))   { *va_arg (argp, float *)  = fvalue; return (TRUE); }
@@ -71,5 +74,5 @@
   }
 
-  value = strtoll (s, &q, 0);
+  value = strtoll (tmp, &q, 0);
   if ((*q == 'd') || (*q == 'D')) value *= pow (10.0, atof (q + 1));
 
@@ -96,5 +99,5 @@
 int gfits_vscan_alt (Header *header, char *field, char *mode, int N, va_list argp) {
 
-  char *p, *q, *s, tmp[81];
+  char *p, *q, *s, tmp[128];
   int Nchar, status;
 
@@ -117,8 +120,10 @@
   /* comment from data line */
   if (!strcmp (mode, "%C")) {
-    q = gfits_keyword_end (p) + 3;
+    q = gfits_keyword_end (p);
+    if (!q) return (FALSE);
+    q += 3;
     q = MIN (p + 80, q);
     bzero (tmp, 81);
-    Nchar = MIN (80, p + 80 - q);
+    Nchar = MAX (0, MIN (80, p + 80 - q));
     memcpy (tmp, q, Nchar);
     stripwhite (tmp);
@@ -147,5 +152,5 @@
 int gfits_vscan_hierarch (Header *header, char *field, char *mode, int N, va_list argp) {
 
-  char *p, *q, *s, tmp[81];
+  char *p, *q, *s, tmp[128];
   int Nchar, Nfield;
   long long value;
@@ -172,5 +177,5 @@
     q = MIN (p + HIERARCH_LENGTH, q);
     bzero (tmp, 81);
-    Nchar = MIN (HIERARCH_LENGTH, p + HIERARCH_LENGTH - q);
+    Nchar = MAX (0, MIN (HIERARCH_LENGTH, p + HIERARCH_LENGTH - q));
     memcpy (tmp, q, Nchar);
     stripwhite (tmp);
@@ -179,20 +184,13 @@
   }
 
-  /* extract data into char array (exclude containing ' chars) */
-  if (!strcmp (mode, "%s")) {
-    s = gfits_hierarch_keyword_start (p, field); /* points at first char (not ') */
-    q = gfits_hierarch_keyword_end (p, field); /* points at following space or ' */
-
-    Nchar = MIN (HIERARCH_LENGTH, MAX (0, (q - s)));
-    bzero (tmp, 81);
-    memcpy (tmp, s, Nchar);
-    stripwhite (tmp);
-    strcpy (va_arg (argp, char *), tmp);
-    return (TRUE);
-  }
-  
+  s = gfits_hierarch_keyword_start (p, field); /* points at first char (not ') */
+  q = gfits_hierarch_keyword_end (p, field); /* points at following space or ' */
+
+  // these are invalid conditions:
+  if (s - p > 80) return FALSE;
+  if (q - p > 80) return FALSE;
+
   /* boolean data, requires int target */
   if (!strcmp (mode, "%t")) {
-    s = gfits_hierarch_keyword_start (p, field);
     if (*s == 'T') {
       *va_arg (argp, int *) = TRUE;
@@ -205,13 +203,22 @@
   }
 
+  /* extract data into char array (exclude containing ' chars) */
+  Nchar = MIN (HIERARCH_LENGTH, MAX (0, (q - s)));
+  bzero (tmp, 81);
+  memcpy (tmp, s, Nchar);
+
+  // for string types, copy the data to the target pointer
+  if (!strcmp (mode, "%s")) {
+    stripwhite (tmp);
+    strcpy (va_arg (argp, char *), tmp);
+    return (TRUE);
+  }
+  
   /* remaining options are numerical data */
   /* need to interpret 1.0d5 as 1.0e5 */
-  s = gfits_hierarch_keyword_start (p, field); /* points at first char (not ') */
-  q = gfits_hierarch_keyword_end (p, field); /* points at following space or ' */
 
   if (!strcmp (mode, "%f") || !strcmp (mode, "%lf")) {
-    fvalue = strtod (s, &q);
-    if ((*q == 'd') || (*q == 'D')) 
-      fvalue *= pow (10.0, atof (q + 1));
+    fvalue = strtod (tmp, &q);
+    if ((*q == 'd') || (*q == 'D')) fvalue *= pow (10.0, atof (q + 1));
 
     if (!strcmp (mode, "%f"))   { *va_arg (argp, float *)  = fvalue; return (TRUE); }
@@ -219,5 +226,5 @@
   }
 
-  value = strtoll (s, &q, 0);
+  value = strtoll (tmp, &q, 0);
   if ((*q == 'd') || (*q == 'D')) value *= pow (10.0, atof (q + 1));
 
Index: trunk/Ohana/src/libfits/table/F_set_column.c
===================================================================
--- trunk/Ohana/src/libfits/table/F_set_column.c	(revision 39323)
+++ trunk/Ohana/src/libfits/table/F_set_column.c	(revision 39324)
@@ -1,4 +1,5 @@
 # include <ohana.h>
 # include <gfitsio.h>
+# define OHANA_MEMCHECK 0
 
 # define SWAP_NONE 
@@ -34,4 +35,14 @@
   double Bscale, Bzero;
 
+# if (OHANA_MEMCHECK)
+  memset (tlabel,  0x7f, 256);
+  memset (field,   0x7f, 256);
+  memset (format,  0x7f, 256);
+  memset (type,    0x7f, 64);
+  memset (tmpline, 0x7f, 64);
+
+  ohana_memcheck_block (data);
+# endif
+
   if (label == (char *) NULL) return (FALSE);
   if (label[0] == 0) return (FALSE);
@@ -42,5 +53,5 @@
   for (i = 1; strcasecmp (label, tlabel) && (i < Nfields + 1); i++) {
     snprintf (field, 256, "TTYPE%d", i);
-    gfits_scan (header, field, "%s", 1, tlabel);
+    if (!gfits_scan (header, field, "%s", 1, tlabel)) return FALSE;
   }
   if (strcasecmp (label, tlabel)) return (FALSE);
@@ -57,5 +68,5 @@
   }
   snprintf (field, 256, "TFORM%d", N);
-  gfits_scan (header, field, "%s", 1, format);
+  if (!gfits_scan (header, field, "%s", 1, format)) return FALSE;
 
   if (!gfits_bintable_format (format, type, &Nval, &Nbytes)) return (FALSE);
@@ -72,9 +83,12 @@
   if (Ny != Nrow) return (FALSE);
 
+  // if we call this function with a null pointer, we are only validating the header and allocating the data array
+  if (!data) return TRUE;
+
   /* scan columns to find insert point */
   Nstart = 0;
   for (i = 1; i < N; i++) {
     snprintf (field, 256, "TFORM%d", i);
-    gfits_scan (header, field, "%s", 1, format);
+    if (!gfits_scan (header, field, "%s", 1, format)) return FALSE;
     gfits_bintable_format (format, tmpline, &Nv, &Nb);
     Nstart += Nv*Nb;
@@ -86,4 +100,5 @@
   Pin = data;
   Pout = array;
+
   // does it makes sense to scale 'char' data?
   if (!strcmp (type, "char")) {
@@ -92,4 +107,5 @@
     }
   }
+
   if (!strcmp (type, "byte")) {
     for (i = 0; i < Nval*Nrow; i++, Pin+=Nbytes, Pout+=Nbytes) {
@@ -97,4 +113,5 @@
     }
   }
+
   if (!strcmp (type, "short")) {
     for (i = 0; i < Nval*Nrow; i++, Pin+=Nbytes, Pout+=Nbytes) {
@@ -105,4 +122,5 @@
     }  
   }
+  
   if (!strcmp (type, "int")) {
     for (i = 0; i < Nval*Nrow; i++, Pin+=Nbytes, Pout+=Nbytes) {
@@ -113,4 +131,5 @@
     }
   }
+
   if (!strcmp (type, "int64_t")) {
     // XXX 64 bit int operations with Bzero & Bscale are inaccurate even with doubles
@@ -131,4 +150,5 @@
     }
   }
+
   if (!strcmp (type, "float")) {
     for (i = 0; i < Nval*Nrow; i++, Pin+=Nbytes, Pout+=Nbytes) {
@@ -139,4 +159,5 @@
     }
   }
+
   if (!strcmp (type, "double")) {
     for (i = 0; i < Nval*Nrow; i++, Pin+=Nbytes, Pout+=Nbytes) {
@@ -179,5 +200,16 @@
   }
 
+# if (OHANA_MEMCHECK)
+  myAssert ( tlabel[255] == 0x7f, "oops");
+  myAssert (  field[255] == 0x7f, "oops");
+  myAssert ( format[255] == 0x7f, "oops");
+  myAssert (   type[63]  == 0x7f, "oops");
+  myAssert (tmpline[63]  == 0x7f, "oops");
+
+ ohana_memcheck (TRUE);
+# endif
+
   free (array);
+
   return (TRUE);
 }
Index: trunk/Ohana/src/libfits/table/F_uncompress_T.c
===================================================================
--- trunk/Ohana/src/libfits/table/F_uncompress_T.c	(revision 39323)
+++ trunk/Ohana/src/libfits/table/F_uncompress_T.c	(revision 39324)
@@ -8,4 +8,5 @@
 int gfits_distribute_table_gzp2 (FTable *table, TableField *field, char *raw, int row_start, int Nrows);
 
+# define OHANA_MEMCHECK 0
 # define VERBOSE_DUMP 0
 
@@ -164,12 +165,15 @@
   gettimeofday (&startTimer, (void *) NULL);
 
-  // this allocates the pointer data array for the full set of tiles (NOT the heap)
-  char *tmpbuffer = NULL;
-  ALLOCATE_ZERO (tmpbuffer, char, max_width*Ny);
+  if (OHANA_MEMCHECK) ohana_memcheck (TRUE);
+
+  // this allocates the pointer data array for the full set of tiles (NOT the heap) by
+  // calling with an empty data array, data values are not actually copied (this is done
+  // below after decompression)
   for (i = 0; i < Nfields; i++) {
-    if (!gfits_set_bintable_column (tgtheader, tgttable, fields[i].ttype, tmpbuffer, Ny)) ESCAPE;
-  }
-  free (tmpbuffer);
+    if (!gfits_set_bintable_column (tgtheader, tgttable, fields[i].ttype, NULL, Ny)) ESCAPE;
+  }
     
+  if (OHANA_MEMCHECK) ohana_memcheck (TRUE);
+
   int Ntile = srcheader->Naxis[1];
   int ztilelast;
Index: trunk/Ohana/src/libohana/Makefile
===================================================================
--- trunk/Ohana/src/libohana/Makefile	(revision 39323)
+++ trunk/Ohana/src/libohana/Makefile	(revision 39324)
@@ -66,6 +66,6 @@
 $(DESTLIB)/libohana.$(DLLTYPE): $(LIB)/libohana.$(ARCH).$(DLLTYPE)
 
-TESTPROG = sprintf_floats
-# TESTPROG = memtest typetest string 
+# TESTPROG = sprintf_floats
+TESTPROG = memtest typetest string 
 
 $(TESTPROG) : % : $(TESTBIN)/% $(OBJS)
Index: trunk/Ohana/src/libohana/include/ohana_allocate.h
===================================================================
--- trunk/Ohana/src/libohana/include/ohana_allocate.h	(revision 39323)
+++ trunk/Ohana/src/libohana/include/ohana_allocate.h	(revision 39324)
@@ -41,8 +41,10 @@
 void  ohana_free (const char *file, int line, const char *func, void *in);
 void  ohana_memdump_func (int mode);
-int   ohana_memcheck_func (int mode);
+int   ohana_memcheck_func (const char *myFile, int myLine, const char *myFunc, int mode);
+void ohana_memcheck_block_func (const char *myFile, int myLine, const char *myFunc, void *in);
 void  real_free (void *in);
 
-# define ohana_memcheck(X) ohana_memcheck_func (X)
+# define ohana_memcheck(X) ohana_memcheck_func (__FILE__, __LINE__, __func__, X)
+# define ohana_memcheck_block(X) ohana_memcheck_block_func (__FILE__, __LINE__, __func__, X)
 # define ohana_memdump(X) ohana_memdump_func (X);
 
@@ -77,4 +79,5 @@
 
 # define ohana_memcheck(X) ohana_memcheck_noop (X)
+# define ohana_memcheck_block(X) ohana_memcheck_noop (X)
 # define ohana_memdump(X) /* NOP */
 void  real_free (void *in);
Index: trunk/Ohana/src/libohana/src/ohana_allocate.c
===================================================================
--- trunk/Ohana/src/libohana/src/ohana_allocate.c	(revision 39323)
+++ trunk/Ohana/src/libohana/src/ohana_allocate.c	(revision 39324)
@@ -18,4 +18,5 @@
 
 static OhanaMemblock *lastBlock = NULL;
+static int Nblock = 0;
 
 # if (TEST_SAVE_FREE_BLOCKS) 
@@ -95,4 +96,5 @@
   lastBlock = new;
 
+  Nblock ++;
   pthread_mutex_unlock(&memBlockListMutex);
 
@@ -212,4 +214,6 @@
   if (!in) return;
 
+  if (!lastBlock) ohana_memabort ("no memory allocated yet (%s@%d : %s)\n", file, line, func);
+
   // fprintf (stderr, "free %zx\n", (size_t) in);
 
@@ -221,4 +225,6 @@
   // fprintf (stderr, "  file: %s, line: %d, func: %s, size: %zd, addr: %zx\n", 
   // ref->file, ref->line, ref->func, ref->size, (size_t) ref);
+
+  if (!lastBlock) ohana_memabort ("corruption? (%s@%d : %s)\n", file, line, func);
 
   pthread_mutex_lock(&memBlockListMutex);
@@ -227,4 +233,6 @@
   OhanaMemblock *prevBlock = ref->prevBlock;
 
+  if (!nextBlock && !prevBlock && (Nblock > 1)) ohana_memabort ("orphan block?? (%s@%d : %s)\n", file, line, func);
+
   // remove this memBlock from the list
   if (nextBlock) {
@@ -238,4 +246,6 @@
   }
   
+  if (!lastBlock && (Nblock > 1)) ohana_memabort ("corruption? (%s@%d : %s)\n", file, line, func);
+
   // XXX FOR TESTING, save the freed blocks
 # if (TEST_SAVE_FREE_BLOCKS)
@@ -252,4 +262,7 @@
   memset (ptr, 0x77, ref->size);
 
+  Nblock --;
+  if (Nblock < 0) ohana_memabort ("excess frees? (%s@%d : %s)\n", file, line, func);
+
   pthread_mutex_unlock(&memBlockListMutex);
   
@@ -265,5 +278,5 @@
 }
 
-int ohana_memcheck_func (int VERBOSE) {
+int ohana_memcheck_func (const char *myFile, int myLine, const char *myFunc, int VERBOSE) {
 
   if (!lastBlock) {
@@ -310,5 +323,6 @@
 
   if (Ntotal || VERBOSE) {
-    fprintf (stderr, "%zd memory blocks allocated (%zd bytes total), %zd good, %zd bad\n", Ntotal, Nbytes, Ngood, Nbad);
+    fprintf (stderr, "%zd memory blocks allocated (%zd bytes total), %zd good, %zd bad ", Ntotal, Nbytes, Ngood, Nbad);
+    fprintf (stderr, "@ %s:%d (%s)\n", myFile, myLine, myFunc);
   }
 
@@ -415,5 +429,6 @@
 
   if (Ntotal_drop || VERBOSE) {
-    fprintf (stderr, "%zd memory blocks dropped   (%zd bytes total), %zd good, %zd bad\n", Ntotal_drop, Nbytes_drop, Ngood_drop, Nbad_drop);
+    fprintf (stderr, "%zd memory blocks dropped   (%zd bytes total), %zd good, %zd bad", Ntotal_drop, Nbytes_drop, Ngood_drop, Nbad_drop);
+    fprintf (stderr, "@ %s:%d (%d)\n", myFile, myLine, myFunc);
   }
 
@@ -422,4 +437,22 @@
  
   return status;
+}
+
+void ohana_memcheck_block_func (const char *myFile, int myLine, const char *myFunc, void *in) {
+
+  OhanaMemblock *ref;
+
+  if (!in) return;
+
+  if (!lastBlock) ohana_memabort ("no memory allocated yet (%s@%d : %s)\n", myFile, myLine, myFunc);
+
+  ref = (OhanaMemblock *) in - 1;
+
+  if (ref->freed) ohana_memabort ("memory already freed (%s, %d, %s [%d bytes])\n", ref->file, ref->line, ref->func, ref->size);
+
+  OhanaMemblock *nextBlock = ref->nextBlock;
+  OhanaMemblock *prevBlock = ref->prevBlock;
+
+  if (!nextBlock && !prevBlock) ohana_memabort ("orphan block?? (%s@%d : %s)\n", myFile, myLine, myFunc);
 }
 
