Index: /branches/eam_branches/ipp-20110710/psLib/src/fits/Makefile.am
===================================================================
--- /branches/eam_branches/ipp-20110710/psLib/src/fits/Makefile.am	(revision 32338)
+++ /branches/eam_branches/ipp-20110710/psLib/src/fits/Makefile.am	(revision 32339)
@@ -9,4 +9,5 @@
 	psFitsImage.c \
 	psFitsTable.c \
+	psFitsTableNew.c \
 	psFitsFloat.c \
 	psFitsFloatFile.c \
@@ -20,4 +21,5 @@
 	psFitsImage.h \
 	psFitsTable.h \
+	psFitsTableNew.h \
 	psFitsFloat.h \
 	psFitsFloatFile.h \
Index: /branches/eam_branches/ipp-20110710/psLib/src/fits/psFitsTableNew.c
===================================================================
--- /branches/eam_branches/ipp-20110710/psLib/src/fits/psFitsTableNew.c	(revision 32339)
+++ /branches/eam_branches/ipp-20110710/psLib/src/fits/psFitsTableNew.c	(revision 32339)
@@ -0,0 +1,673 @@
+/** @file  psFitsTableNew.c
+ *
+ *  @brief Contains Memory efficient functions for accessing  Fits tables
+ *
+ *  @ingroup FileIO
+ *
+ *  @author Bill Sweeney IfA
+ *
+ *
+ *  Copyright 2011 Institute for Astronomy, University of Hawaii
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "psFits.h"
+#include "string.h"
+#include "psError.h"
+
+#include "psImageStructManip.h"
+#include "psMemory.h"
+#include "psString.h"
+#include "psLogMsg.h"
+#include "psTrace.h"
+#include "psVector.h"
+#include "psFitsTable.h"
+#include "psFitsTableNew.h"
+#include "psFitsHeader.h"
+#include "psAbort.h"
+#include "psAssert.h"
+
+// #define MAX_STRING_LENGTH 256  // maximum length string for FITS routines
+
+
+// Check if the FITS file is an empty table
+static bool emptyTableCheck(const psFits *fits // FITS file
+                            )
+{
+    PS_ASSERT_FITS_NON_NULL(fits, false);
+
+    if (psFitsGetExtNum(fits) == 0 && !psFitsMoveExtNum(fits, 1, false)) {
+        psError(PS_ERR_IO, false, "Unable to move to first extension to read table.");
+        return false;
+    }
+
+    int status = 0;                     // CFITSIO status
+    int hdutype;                        // Type of HDU
+    fits_get_hdu_type(fits->fd, &hdutype, &status);
+    if (status) {
+        psFitsError(status, true, "Could not determine the HDU type.");
+        return false;
+    }
+    if (hdutype == IMAGE_HDU) {
+        // It could be an empty table
+        int naxis = 0;                  // Dimensions of image
+        if (fits_get_img_dim(fits->fd, &naxis, &status) != 0) {
+            psFitsError(status, true, "Unable to determine dimension for table.");
+            return false;
+        }
+        if (naxis != 0) {
+            psFitsError(PS_ERR_BAD_FITS, true, "Current FITS HDU is not a table.");
+            return false;
+        }
+        return true;
+    }
+
+    return false;
+}
+
+// Check the FITS file in preparation for reading a table
+static bool readTableCheck(const psFits *fits // FITS file
+                           )
+{
+    PS_ASSERT_FITS_NON_NULL(fits, false);
+
+    if (psFitsGetExtNum(fits) == 0 && !psFitsMoveExtNum(fits, 1, false)) {
+        psError(PS_ERR_IO, false, "Unable to move to first extension to read table.");
+        return false;
+    }
+
+    // check that we are positioned on a table HDU
+    int status = 0;                     // CFITSIO status
+    int hdutype;                        // Type of HDU
+    fits_get_hdu_type(fits->fd, &hdutype, &status);
+    if (status) {
+        psFitsError(status, true, "Could not determine the HDU type.");
+        return false;
+    }
+    if (hdutype != ASCII_TBL && hdutype != BINARY_TBL) {
+        return false;
+    }
+    return true;
+}
+
+void
+freeTable(psFitsTable *table)
+{
+    for (int col = 0; col < table->numCols; col++) {
+        psFitsTableColumn *column = &table->columns[col];
+        psFree(column->name);
+        if (column->type == PS_DATA_STRING) {
+            for (int row; row < table->numRows; row++) {
+                psFree(column->data.str);
+            }
+        } else if (column->type == PS_DATA_VECTOR) {
+            for (int row; row < table->numRows; row++) {
+                psFree(column->data.vec);
+            }
+        }
+        // all of the members in the data union are pointers so just pick S32
+        psFree(column->data.S32);
+    }
+    psFree(table->columns);
+    psFree(table->index);
+}
+
+psFitsTable* psFitsTableAlloc(int numCols, int numRows) {
+    if (numCols <= 0) {
+        psError(PS_ERR_BAD_PARAMETER_VALUE, true,
+                "Can't allocate a psFitsTable with %d columns.", numCols);
+        return NULL;
+    }
+
+    psFitsTable *table = psAlloc(sizeof(psFitsTable));
+    table->index = psMetadataAlloc();
+    table->numRows = numRows;
+    table->numCols = numCols;
+    table->columns = psAlloc(sizeof(psFitsTableColumn) * numCols);
+    memset(table->columns, sizeof(psFitsTableColumn) * numCols, 0);
+    psMemSetDeallocator(table, (psFreeFunc) freeTable);
+
+    return table;
+}
+
+psFitsTable* psFitsReadTableNew(const psFits* fits)
+{
+    PS_ASSERT_FITS_NON_NULL(fits, NULL);
+    // PS_ASSERT_INT_NONNEGATIVE(row, NULL);
+
+    if (!readTableCheck(fits)) {
+        if (emptyTableCheck(fits)) {
+            return NULL;
+        }
+        psError(PS_ERR_BAD_FITS, true, "Extension is not a table");
+        return NULL;
+    }
+
+    // get the size of the FITS table
+    long numRows;
+    int numCols;
+    int status = 0;
+    fits_get_num_rows(fits->fd, &numRows, &status);
+    fits_get_num_cols(fits->fd, &numCols, &status);
+    if (status) {
+        psFitsError(status, true, "Failed to determine the size of the current HDU table.");
+        return NULL;
+    }
+
+    psTrace("psLib.fits",5,"Table size is %ix%li\n",numCols, numRows);
+
+    psFitsTable *table = psFitsTableAlloc(numCols, numRows);
+
+    int hdutype;                        // Type of HDU: need to distinguish ASCII and binary tables
+    fits_get_hdu_type(fits->fd, &hdutype, &status);
+    if (psFitsError(status, true, "Could not determine the HDU type.")) {
+        return false;
+    }
+
+    int typecode;
+    long repeat;
+    long width;
+    char name[60];
+    for (int col = 1; col <= numCols; col++) {
+        // get the column name
+        double tscal;
+        double tzero;
+        if (hdutype == BINARY_TBL) {
+            fits_get_bcolparms(fits->fd, col, name,
+                               NULL, NULL, NULL, &tscal, &tzero, NULL, NULL, &status);
+        } else {
+            fits_get_acolparms(fits->fd, col, name,
+                               NULL, NULL, NULL, NULL, NULL, NULL, NULL, &status);
+        }
+        // get the column type
+        fits_get_coltype(fits->fd, col, &typecode, &repeat, &width, &status);
+        if (psFitsError(status, true, "Unable to get column type for column %d", col)) {
+            psFree(table);
+            return NULL;
+        }
+
+#define READ_TABLE_ROW_CASE(FITSTYPE, NATIVETYPE, TYPE, VECTYPE) \
+        case FITSTYPE: { \
+                column->type = PS_DATA_##TYPE; \
+                column->data.TYPE = psAlloc(sizeof(ps##TYPE)*table->numRows); \
+                if (repeat == 1) { \
+                    column->elementSize = 1; \
+                    NATIVETYPE *values = (NATIVETYPE *) psAlloc(sizeof(NATIVETYPE) * table->numRows); \
+                    int anynul = 0; \
+                    fits_read_col(fits->fd, FITSTYPE, col, 1, \
+                                  1, numRows, NULL, values, &anynul, &status); \
+                    for (int lcv = 0; lcv < table->numRows; lcv++) { \
+                        column->data.TYPE[lcv] = values[lcv]; \
+                    } \
+                    psTrace("psLib.fits",5,"Column #%i, '%s', is type %i, repeat %li\n", \
+                            col, name, typecode, repeat); \
+                    psFree(values); \
+                } else { \
+                    column->elementSize = repeat; \
+                    column->type = PS_DATA_VECTOR; \
+                    column->vectorType = PS_DATA_##TYPE; \
+                    column->data.vec = psAlloc(sizeof(psVector*) * table->numRows); \
+                    for (int row = 0; row < table->numRows; row++) { \
+                        NATIVETYPE* values = psAlloc(sizeof(NATIVETYPE)*repeat); \
+                        psVector* vec = psVectorAlloc(repeat, PS_TYPE_##VECTYPE); \
+                        int anynul = 0; \
+                        fits_read_col(fits->fd, FITSTYPE, col,row+1, \
+                                  1, repeat, NULL, values, &anynul, &status); \
+                        for (int lcv = 0; lcv < repeat; lcv++) { \
+                            vec->data.VECTYPE[lcv] = values[lcv]; \
+                        } \
+                        column->data.vec[row] = vec; \
+                        psFree(values); \
+                    } \
+                    \
+                } \
+                break; \
+            }
+
+        // Handle cases where the data is "really" unsigned
+        if (typecode == TLONG && tzero == 2147483648) {
+            typecode = TULONG;
+        } else if (typecode == TSHORT && tzero == 32768) {
+            typecode = TUSHORT;
+        }
+
+        // Save the column number for this column in the index metadata
+        psMetadataAddS32(table->index, PS_LIST_TAIL, name, 0, NULL, col-1);
+
+        psFitsTableColumn *column = &table->columns[col-1];
+        // This second copy of the name makes it easily available when writing the table
+        column->name = psStringCopy(name);
+        switch (typecode) {
+            READ_TABLE_ROW_CASE(TBYTE, long, S32, S32);
+            READ_TABLE_ROW_CASE(TSHORT, short, S16, S16);
+            READ_TABLE_ROW_CASE(TUSHORT, unsigned short, U16, U16);
+            READ_TABLE_ROW_CASE(TULONG, unsigned long, U32, U32);
+            READ_TABLE_ROW_CASE(TLONG, long, S32, S32);
+            READ_TABLE_ROW_CASE(TLONGLONG, psS64, S64, S64);
+            READ_TABLE_ROW_CASE(TFLOAT, float, F32, F32);
+            READ_TABLE_ROW_CASE(TDOUBLE, double, F64, F64);
+            READ_TABLE_ROW_CASE(TLOGICAL, bool, BOOL, S8);
+          case TSTRING: {
+              column->data.str = psAlloc(sizeof(psString) * table->numRows);
+              column->type = PS_DATA_STRING;
+              column->elementSize = 0;
+              for (int row = 0; row < table->numRows; row++) {
+                  psString value = psStringAlloc(repeat);
+                  int anynul = 0;
+                  fits_read_col(fits->fd, TSTRING, col,row+1, 1, 1, NULL, &value, &anynul, &status);
+                  psTrace("psLib.fits", 5, "Column #%i, '%s', is type %i, repeat %li, value = %s\n",
+                          col, name, typecode, repeat, value);
+                  if (anynul) {
+                      psFree(value);
+                      value = NULL;
+                  }
+                  column->data.str[row] = value;
+                  int len = strlen(value);
+                  if (len > column->elementSize) {
+                    column->elementSize = len;
+                  }
+              }
+              break;
+          }
+          default:
+            psWarning("Data type (%d) not supportted for column %d", typecode, col);
+            psTrace("psLib.fits", 2, "Column %d was of a non primitive type, %d",
+                    col, typecode);
+        }
+
+        if (psFitsError(status, true, "Failed to retrieve table column %d", col)) {
+            psFree(table);
+            return NULL;
+        }
+    }
+
+    return table;
+}
+
+// return the column number with a given name
+int psFitsTableGetColumnNumber(psFitsTable *table, const char *name)
+{
+    bool mdok;
+    int col = psMetadataLookupS32(&mdok, table->index, name);
+
+    if (!mdok) {
+        psFitsError(mdok, true, "Failed to lookup column index for %s", name);
+        return -1;
+    }
+
+    return col;
+}
+
+#define psFitsTableGetNumTYPE(TYPE, NAME) \
+ps##TYPE psFitsTableGet##NAME(bool *status, psFitsTable *table, int row, const char *name) \
+{ \
+    ps##TYPE value = 0; \
+    if (status) { \
+        *status = true; \
+    } \
+    \
+    if (row >= table->numRows || row < 0) { \
+        if (status) { \
+            *status = false; \
+        } \
+        return 0; \
+    } \
+    bool mdok; \
+    int col = psMetadataLookupS32(&mdok, table->index, name); \
+    if (!mdok) { \
+        if (status) { \
+            *status = false; \
+        } \
+        return 0; \
+    } \
+    if (col < 0) { \
+        if (status) { \
+            *status = false; \
+        } \
+        return 0; \
+    } \
+    psFitsTableColumn *column = &table->columns[col]; \
+    switch (column->type) { \
+        case PS_DATA_S8: \
+        value = (ps##TYPE)column->data.S8[row]; \
+        break; \
+    case PS_DATA_S16: \
+        value = (ps##TYPE)column->data.S16[row]; \
+        break; \
+    case PS_DATA_S32: \
+        value = (ps##TYPE)column->data.S32[row]; \
+        break; \
+    case PS_DATA_S64: \
+        value = (ps##TYPE)column->data.S64[row]; \
+        break; \
+    case PS_DATA_U8: \
+        value = (ps##TYPE)column->data.U8[row]; \
+        break; \
+    case PS_DATA_U16: \
+        value = (ps##TYPE)column->data.U16[row]; \
+        break; \
+    case PS_DATA_U32: \
+        value = (ps##TYPE)column->data.U32[row]; \
+        break; \
+    case PS_DATA_U64: \
+        value = (ps##TYPE)column->data.U64[row]; \
+        break; \
+    case PS_DATA_F32: \
+        value = (ps##TYPE)column->data.F32[row]; \
+        break; \
+    case PS_DATA_F64: \
+        value = (ps##TYPE)column->data.F64[row]; \
+        break; \
+    case PS_DATA_BOOL: \
+        if (column->data.BOOL[row]) { \
+            value = 1; \
+        } \
+        break; \
+    default: \
+        /* if you get to this point, the value is not a number. */ \
+        if (status) {  \
+            *status = false; \
+        }  \
+        break; \
+    } \
+    return value; \
+}
+
+// #define psFitsTableGetNumTYPE(TYPE, NAME)
+
+psFitsTableGetNumTYPE(S8, S8);
+psFitsTableGetNumTYPE(U8, U8);
+psFitsTableGetNumTYPE(S16, S16);
+psFitsTableGetNumTYPE(U16, U16);
+psFitsTableGetNumTYPE(S32, S32);
+psFitsTableGetNumTYPE(U32, U32);
+psFitsTableGetNumTYPE(S64, S64);
+psFitsTableGetNumTYPE(U64, U64);
+psFitsTableGetNumTYPE(F32, F32);
+psFitsTableGetNumTYPE(F64, F64);
+psFitsTableGetNumTYPE(Bool, BOOL);
+
+// remove rows from table that are marked in the mask array as censored.
+bool psFitsTableCensor(psFitsTable *table, bool *censorMask)
+{
+    int newRow = 0;
+    for (int row = 0; row < table->numRows; row++) {
+        if (censorMask[row]) {
+            for (int col = 0; col < table->numCols; col++) {
+                psFitsTableColumn *column = &table->columns[col];
+                if (column->type == PS_DATA_VECTOR) {
+                    psFree(column->data.vec[row]);
+                    column->data.vec[row] = NULL;
+                } else if (column->type == PS_DATA_STRING) {
+                    psFree(column->data.str[row]);
+                    column->data.str[row] = NULL;
+                }
+            }
+        } else {
+            if (newRow < row) {
+                // slide data for this row into new destination
+                for (int col = 0; col < table->numCols; col++) {
+                    psFitsTableColumn *column = &table->columns[col];
+                    switch (column->type) {
+                    case PS_DATA_S16:    
+                        column->data.S16[newRow] = column->data.S16[row];
+                        break;
+                    case PS_DATA_U16:    
+                        column->data.U16[newRow] = column->data.U16[row];
+                        break;
+                    case PS_DATA_S32:    
+                        column->data.S32[newRow] = column->data.S32[row];
+                        break;
+                    case PS_DATA_U32:    
+                        column->data.U32[newRow] = column->data.U32[row];
+                        break;
+                    case PS_DATA_S64:    
+                        column->data.S64[newRow] = column->data.S64[row];
+                        break;
+                    case PS_DATA_F32:    
+                        column->data.F32[newRow] = column->data.F32[row];
+                        break;
+                    case PS_DATA_F64:    
+                        column->data.F64[newRow] = column->data.F64[row];
+                        break;
+                    case PS_DATA_BOOL:
+                        column->data.S8[newRow] = column->data.S8[row];
+                        break;
+                    case    PS_DATA_STRING:
+                        // dest pointer has been freed above or moved
+                        column->data.str[newRow] = column->data.str[row];
+                        // zero source to avoid double free
+                        column->data.str[row] = NULL;
+                        break;
+                    case    PS_DATA_VECTOR:
+                        // dest pointer was freed above or zeroed.
+                        column->data.vec[newRow] = column->data.vec[row];
+                        // zero source to avoid double free
+                        column->data.vec[row] = NULL;
+                        break;
+                    default:
+                        psError(PS_ERR_PROGRAMMING, true, "unexpected column type: %d found", column->type);
+                        return false;
+                    }
+                }
+            }
+            newRow++;
+        }
+    }
+
+    // set the new number of rows
+    table->numRows = newRow;
+
+    return true;
+}
+
+// Get the TFORM character, given a PS type
+static inline char getTForm(psDataType type)
+{
+    switch (type) {
+    case PS_TYPE_U8:
+    case PS_TYPE_S8:
+        return 'B';
+    case PS_TYPE_S16:
+        return 'I';
+    case PS_TYPE_S32:
+        return 'J';
+    case PS_TYPE_U64:
+    case PS_TYPE_S64:
+        return 'K';
+    case PS_TYPE_U16:
+        return 'U';
+    case PS_TYPE_U32:
+        return 'V';
+    case PS_TYPE_F32:
+        return 'E';
+    case PS_TYPE_F64:
+        return 'D';
+    case PS_TYPE_BOOL:
+        return 'L';
+    case PS_DATA_STRING:
+        return 'A';
+    default:
+        psError(PS_ERR_UNKNOWN, true, "Unknown type: %x\n", type);
+        return '?';
+    }
+}
+
+static bool fitsInsertTableNew(psFits* fits,          // FITS file
+                            const psMetadata* header, // FITS header to write
+                            psFitsTable *table,       // internal representation of the table
+                            const char *extname,      // Extension name to give table
+                            bool after,               // Write table after current extension?
+                            bool writeData            // Write data?
+                            )
+{
+    PS_ASSERT_FITS_NON_NULL(fits, false);
+    PS_ASSERT_FITS_WRITABLE(fits, false);
+    PS_ASSERT_PTR_NON_NULL(table, false);
+
+    int status = 0;
+
+    long numRows = table->numRows;
+    if (writeData && numRows < 1) {
+        // no table data, what can I do?
+        psError(PS_ERR_BAD_PARAMETER_SIZE, true,
+                _("Can't create a table without any rows."));
+        return false;
+    }
+
+    // Create array of column names and types.
+    psArray *columnNames = psArrayAlloc(table->numCols); // Array of column names, for cfitsio
+    psArray *columnTypes = psArrayAlloc(table->numCols); // Array of column types, for cfitsio
+    for (long i = 0; i < table->numCols; i++) {
+        psFitsTableColumn *column = &table->columns[i];
+        columnNames->data[i] = psMemIncrRefCounter(column->name);
+        psString colType = NULL;        // The FITS column type
+        size_t size = column->elementSize;
+        if (column->type == PS_DATA_VECTOR) {
+            psStringAppend(&colType, "%zd%c", size, getTForm(column->vectorType));
+        } else {
+            psStringAppend(&colType, "%zd%c", size, getTForm(column->type));
+        }
+        columnTypes->data[i] = colType;
+    }
+
+    // Create the table HDU
+    int numHDUs = psFitsGetSize(fits);  // Number of HDUs in file
+    if (numHDUs == 0) {
+        // We're creating the first extension
+        fits_create_tbl(fits->fd,
+                        BINARY_TBL,
+                        writeData ? numRows : 0, // number of rows in table
+                        table->numCols, // number of columns in table
+                        (char**)columnNames->data, // names of the columns
+                        (char**)columnTypes->data, // format of the columns
+                        NULL, // physical unit of columns
+                        NULL, // skip extension name: we set the by hand below
+                        &status);
+    } else {
+        if (!after) {
+            if (psFitsGetExtNum(fits) == 0) {
+                // We're creating a replacement primary HDU.
+                // Set status to signal fits_insert_img to insert a new primary HDU
+                status = PREPEND_PRIMARY;
+            } else {
+                // Move back one to perform an insert after the previous HDU
+                psFitsMoveExtNum(fits, -1, true);
+            }
+        }
+        // Insert the table
+        fits_insert_btbl(fits->fd,
+                         writeData ? numRows : 0, // number of rows in table
+                         table->numCols, // number of columns in table
+                         (char**)columnNames->data, // names of the columns
+                         (char**)columnTypes->data, // format of the columns
+                         NULL, // physical unit of columns
+                         NULL, // skip extension name: we set this by hand below
+                         0, &status);
+    }
+    psFree(columnNames);
+    psFree(columnTypes);
+
+    if (status != 0) {
+        psFitsError(status, true, "Unable to create FITS table with %d columns and %d rows",
+                    table->numCols, table->numRows);
+        return false;
+    }
+
+    // Write header
+    if (header && !psFitsWriteHeader(fits, header)) {
+        psError(PS_ERR_IO, false, "Unable to write FITS header.\n");
+        return false;
+    }
+
+    // write the header, if any.
+    if (extname && strlen(extname) > 0) {
+        if (!psFitsSetExtName(fits, extname)) {
+            psError(PS_ERR_IO, false, "Unable to write FITS header extension name.\n");
+            return false;
+        }
+    }
+
+    if (writeData) {
+        // psMetadataIteratorSet(colSpecsIter, PS_LIST_HEAD);
+        for (long colNum = 1; colNum <= table->numCols; colNum++) {
+            // Note: colNum is unit-indexed, because it's for cfitsio
+            psFitsTableColumn *column = &table->columns[colNum - 1];
+            // colSpec *spec = colSpecItem->data.V; // The specification
+            if (PS_DATA_IS_PRIMITIVE(column->type)) {
+                int fitsDataType;           // Data type for cfitsio
+                p_psFitsTypeToCfitsio(column->type, NULL, NULL, &fitsDataType);
+                fits_write_col(fits->fd,
+                               fitsDataType,
+                               colNum, // column number
+                               1, // first row
+                               1, // first element
+                               table->numRows, // number of rows
+                               column->data.U8, // the data
+                               &status);
+                // psFree(columnData);
+            } else {
+                switch (column->type) {
+                  case PS_DATA_STRING: {
+                      fits_write_col_str(fits->fd, colNum, 1, 1, table->numRows, (char**)column->data.str, &status);
+                      // psFree(strings);
+                      break;
+                  }
+                  case PS_DATA_VECTOR: {
+                      size_t dataSize = PSELEMTYPE_SIZEOF(column->vectorType); // Size of data, in bytes
+                      psVector *columnData = psVectorAlloc(column->elementSize * table->numRows * dataSize, PS_TYPE_U8);
+                      psVectorInit(columnData, 0);
+                      for (long i = 0; i < table->numRows; i++) {
+                          psVector *vector = column->data.vec[i];
+                          memcpy(&columnData->data.U8[i * dataSize * column->elementSize], vector->data.U8,
+                                 vector->n * dataSize);
+                      }
+
+                      int fitsDataType;           // Data type for cfitsio
+                      p_psFitsTypeToCfitsio(column->vectorType, NULL, NULL, &fitsDataType);
+                      fits_write_col(fits->fd, fitsDataType, colNum, 1, 1, table->numRows * column->elementSize,
+                                     columnData->data.U8, &status);
+                      psFree(columnData);
+                      break;
+                  }
+                  default:
+                    psAbort("Should never get here.\n");
+                }
+            }
+
+            // Check error status from writing column
+            if (status != 0) {
+                psFitsError(status, true, "Unable to write column %ld of FITS table", colNum);
+                return false;
+            }
+        }
+    }
+
+    // This forces a re-scan of the header to ensure everything's kosher.  We found this occassionally
+    // necessary for compressed images, which are tables, so perhaps it helps here too.  I guess it can't
+    // hurt.
+    ffrdef(fits->fd, &status);
+    if (psFitsError(status, true, "Could not re-scan HDU.")) {
+        return false;
+    }
+
+    return true;
+}
+
+bool psFitsWriteTableNew(psFits* fits,
+                      const psMetadata* header,
+                      psFitsTable* table,
+                      const char *extname)
+{
+    PS_ASSERT_FITS_NON_NULL(fits, false);
+    PS_ASSERT_FITS_WRITABLE(fits, false);
+    if (!psFitsMoveLast(fits)) {
+        psError(PS_ERR_UNKNOWN, false, "Unable to move to last extension to write table");
+        return false;
+    }
+    bool writeData = table->numRows > 0;
+    return fitsInsertTableNew(fits, header, table, extname, true, writeData);
+}
Index: /branches/eam_branches/ipp-20110710/psLib/src/fits/psFitsTableNew.h
===================================================================
--- /branches/eam_branches/ipp-20110710/psLib/src/fits/psFitsTableNew.h	(revision 32339)
+++ /branches/eam_branches/ipp-20110710/psLib/src/fits/psFitsTableNew.h	(revision 32339)
@@ -0,0 +1,69 @@
+/* @file  psFitsTableNew.h
+ * @brief Contains Fits I/O routines
+ *
+ * @author EAM, PAP, JH
+ * @author Robert DeSonia, MHPCC
+ *
+ * @version $Revision: 1.7 $ $Name: not supported by cvs2svn $
+ * @date $Date: 2007-10-09 02:56:23 $
+ * Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
+ */
+
+#ifndef PS_FITSTABLENEW_H
+#define PS_FITSTABLENEW_H
+
+typedef struct {
+    psString    name;
+    psDataType  type;
+    psDataType  vectorType;             // type inside if Vector
+    int         elementSize;            // 1 for primitives, strlen for strings
+                                        // vector length for vectors
+    // only types supported by fits tables will be implemented
+    union {
+        bool *BOOL;                     ///< boolean data
+        psS8 *S8;                       ///< Signed 8-bit integer data.
+        psS16 *S16;                     ///< Signed 16-bit integer data.
+        psS32 *S32;                     ///< Signed 32-bit integer data.
+        psS64 *S64;                     ///< Signed 64-bit integer data.
+        psU8 *U8;                       ///< Unsigned 8-bit integer data.
+        psU16 *U16;                     ///< Unsigned 16-bit integer data.
+        psU32 *U32;                     ///< Unsigned 32-bit integer data.
+        psU64 *U64;                     ///< Unsigned 64-bit integer data.
+        psF32 *F32;                     ///< Single-precision float data.
+        psF64 *F64;                     ///< Double-precision float data.
+        psString *str;                  ///< string data
+        psVector **vec;                 ///< vector
+    } data;                             ///< Union for data types.
+} psFitsTableColumn;
+
+typedef struct {
+    int numRows;
+    int numCols;
+    psMetadata  *index;
+    psFitsTableColumn *columns;
+} psFitsTable;
+
+// return column number of column with name (-1 if not found)
+int psFitsTableGetColumnNumber(psFitsTable *table, const char *name);
+
+psFitsTable *psFitsReadTableNew(const psFits *fits);
+bool psFitsWriteTableNew(psFits *fits, const psMetadata *header, psFitsTable *table, const char *extname);
+
+// remove rows from table whose entry in the supplied array are true
+bool psFitsTableCensor(psFitsTable *table, bool *rowMask);
+
+// Get value for given row and column name
+psBool psFitsTableGetBool(bool *status, psFitsTable *table, int row, const char* name);
+psS8 psFitsTableGetS8(bool *status, psFitsTable *table, int row, const char* name);
+psU8 psFitsTableGetU8(bool *status, psFitsTable *table, int row, const char* name);
+psS16 psFitsTableGetS16(bool *status, psFitsTable *table, int row, const char* name);
+psU16 psFitsTableGetU16(bool *status, psFitsTable *table, int row, const char* name);
+psS32 psFitsTableGetS32(bool *status, psFitsTable *table, int row, const char* name);
+psU32 psFitsTableGetU32(bool *status, psFitsTable *table, int row, const char* name);
+psS64 psFitsTableGetS64(bool *status, psFitsTable *table, int row, const char* name);
+psU64 psFitsTableGetU64(bool *status, psFitsTable *table, int row, const char* name);
+
+psF32 psFitsTableGetF32(bool *status, psFitsTable *table, int row, const char* name);
+psF64 psFitsTableGetF64(bool *status, psFitsTable *table, int row, const char* name);
+
+#endif
Index: /branches/eam_branches/ipp-20110710/psLib/src/pslib_strict.h
===================================================================
--- /branches/eam_branches/ipp-20110710/psLib/src/pslib_strict.h	(revision 32338)
+++ /branches/eam_branches/ipp-20110710/psLib/src/pslib_strict.h	(revision 32339)
@@ -41,4 +41,5 @@
 #include "psFitsImage.h"
 #include "psFitsTable.h"
+#include "psFitsTableNew.h"
 #include "psFitsFloat.h"
 #include "psFitsFloatFile.h"
Index: /branches/eam_branches/ipp-20110710/psLib/src/sys/psMemory.c
===================================================================
--- /branches/eam_branches/ipp-20110710/psLib/src/sys/psMemory.c	(revision 32338)
+++ /branches/eam_branches/ipp-20110710/psLib/src/sys/psMemory.c	(revision 32339)
@@ -515,18 +515,32 @@
 	    continue;
 	}
-	if (memBlock->nextBlock && memBlock->nextBlock->inFlight) {
-	    // nope, we need to try again
-	    MUTEX_UNLOCK(&memBlockListMutex);
-	    usleep (BLOCK_SLEEP);
-	    retryLock ++;
-	    continue;
-	}
-	if (memBlock->previousBlock && memBlock->previousBlock->inFlight) {
-	    // nope, we need to try again
-	    MUTEX_UNLOCK(&memBlockListMutex);
-	    usleep (BLOCK_SLEEP);
-	    retryLock ++;
-	    continue;
-	}
+        if (memBlock->nextBlock && memBlock->nextBlock->inFlight) {
+            // we reply on the value of 'inFlight'.  we should crash if this block is corrupted
+            if (memBlock->nextBlock->startblock != P_PS_MEMMAGIC) {
+                PS_MEM_ABORT(__func__, "Unsafe to Continue\n");
+            }
+            if (memBlock->nextBlock->endblock != P_PS_MEMMAGIC) {
+                PS_MEM_ABORT(__func__, "Unsafe to Continue\n");
+            }
+            // nope, we need to try again
+            MUTEX_UNLOCK(&memBlockListMutex);
+            usleep (BLOCK_SLEEP);
+            retryLock ++;
+            continue;
+        }
+        if (memBlock->previousBlock && memBlock->previousBlock->inFlight) {
+            // we reply on the value of 'inFlight'.  we should crash if this block is corrupted
+            if (memBlock->previousBlock->startblock != P_PS_MEMMAGIC) {
+                PS_MEM_ABORT(__func__, "Unsafe to Continue\n");
+            }
+            if (memBlock->previousBlock->endblock != P_PS_MEMMAGIC) {
+                PS_MEM_ABORT(__func__, "Unsafe to Continue\n");
+            }
+            // nope, we need to try again
+            MUTEX_UNLOCK(&memBlockListMutex);
+            usleep (BLOCK_SLEEP);
+            retryLock ++;
+            continue;
+        }
 
 	// the markers are ours!
@@ -889,5 +903,7 @@
                       psMemBlock ***array,
                       FILE * fd,
-                      bool persistence)
+                      bool persistence,
+		      int maxDisplayedLeaksCount          ///< List at most maxDisplayedLeaksCount (-1 for all)
+		  )
 {
     psS32 nleak = 0;
@@ -896,5 +912,7 @@
 
     // XXX move this elsewhere?
-    fprintf (stderr, "set %d locks, cleared %d locks, retry on %d locks (memID %ld)\n", setLock, clearLock, retryLock, memid);
+    if (fd != NULL) {
+      fprintf (fd, "set %d locks, cleared %d locks, retry on %d locks (memID %ld)\n", setLock, clearLock, retryLock, memid);
+    }
 
     // make sure that the memblock list is free of corruption before we crawl
@@ -915,4 +933,22 @@
     for (memBlock = topBlock; memBlock->nextBlock != NULL; memBlock = memBlock->nextBlock) { }
 
+    int maxToDisplay = maxDisplayedLeaksCount;
+    psMemBlock *memBlockBackup = memBlock;
+    if (maxToDisplay == -1 ) {
+      for (; memBlock != NULL; memBlock = memBlock->previousBlock) {
+	if ( (memBlock->refCounter > 0) &&
+	     ( (persistence) || (!persistence && !memBlock->persistent) ) &&
+	     (memBlock->id >= id0)) {
+	  nleak++;
+	}
+      }
+      maxToDisplay=nleak;
+    }
+    if (fd != NULL) {
+      fprintf(fd, "Number of leaks to display: %d\n", maxToDisplay);
+    }
+    memBlock = memBlockBackup;
+
+    nleak=0;
     // iterate through the block list starting with the oldest block
     for (; memBlock != NULL; memBlock = memBlock->previousBlock) {
@@ -924,5 +960,5 @@
 
 	    // only print a max of 500 leaks (make this an argument)
-            if ((nleak < 500) && (fd != NULL)) {
+            if ( (nleak <= maxToDisplay) && (fd != NULL) ) {
                 if (nleak == 1) {
                     fprintf(fd, "# func at (file:line)  ID: X  Ref: X\n");
Index: /branches/eam_branches/ipp-20110710/psLib/src/sys/psMemory.h
===================================================================
--- /branches/eam_branches/ipp-20110710/psLib/src/sys/psMemory.h	(revision 32338)
+++ /branches/eam_branches/ipp-20110710/psLib/src/sys/psMemory.h	(revision 32339)
@@ -367,4 +367,11 @@
     bool persistence                   ///< make check across all object even persistent ones
 );
+int psMemCheckLeaks2(
+    psMemId id0,                       ///< don't list blocks with id < id0
+    psMemBlock ***array,               ///< pointer to array of pointers to leaked blocks, or NULL
+    FILE * fd,                         ///< print list of leaks to fd (or NULL)
+    bool persistence,                  ///< make check across all object even persistent ones
+    int maxDisplayedLeaksCount         ///< List at most maxDisplayedLeaksCount (-1 for all)
+);
 #else // ifdef DOXYGEN
 int p_psMemCheckLeaks(
@@ -375,9 +382,12 @@
     psMemBlock ***array,                ///< pointer to array of pointers to leaked blocks, or NULL
     FILE * fd,                          ///< print list of leaks to fd (or NULL)
-    bool persistence                    ///< make check across all object even persistent ones
-);
-#ifndef SWIG
+    bool persistence,                   ///< make check across all object even persistent ones
+    int maxDisplayedLeaksCount          ///< List at most maxDisplayedLeaksCount (-1 for all)
+);
+#ifndef SWIG
+#define psMemCheckLeaks2(id0, array, fd, persistence, maxDisplayedLeaksCount) \
+      p_psMemCheckLeaks(__FILE__, __LINE__, __func__, id0, array, fd, persistence, maxDisplayedLeaksCount)
 #define psMemCheckLeaks(id0, array, fd, persistence) \
-      p_psMemCheckLeaks(__FILE__, __LINE__, __func__, id0, array, fd, persistence)
+      p_psMemCheckLeaks(__FILE__, __LINE__, __func__, id0, array, fd, persistence, 500)
 #endif // ifndef SWIG
 #endif // ifdef DOXYGEN
Index: /branches/eam_branches/ipp-20110710/psLib/src/types/psMetadataConfig.c
===================================================================
--- /branches/eam_branches/ipp-20110710/psLib/src/types/psMetadataConfig.c	(revision 32338)
+++ /branches/eam_branches/ipp-20110710/psLib/src/types/psMetadataConfig.c	(revision 32339)
@@ -72,5 +72,4 @@
 static bool parseMetadataItem(char *keyName, psArray *levelArray,
                               char *linePtr, psMetadataFlags flags);
-static psString formatMetadataItem(psMetadataItem *item);
 static psArray *p_psMetadataKeyArray(psMetadata *md);
 static bool parseGeneric(char *keyName,
@@ -1337,5 +1336,5 @@
             return NULL;
         }
-        psString str = formatMetadataItem(item);
+        psString str = psMetadataItemFormat(item);
         if (!str) {
             psError(PS_ERR_UNKNOWN, false, "failed to format psMetadataItem");
@@ -1355,6 +1354,6 @@
 }
 
-
-static psString formatMetadataItem(psMetadataItem *item)
+// format a single metadata item for output (consistent with config dump I/O, includes return char)
+psString psMetadataItemFormat(psMetadataItem *item)
 {
     PS_ASSERT_METADATA_ITEM_NON_NULL(item, NULL);
@@ -1380,5 +1379,5 @@
             psMetadataItem *multiItem = NULL;
             while ((multiItem = psListGetAndIncrement(iter))) {
-                psString str = formatMetadataItem(multiItem);
+                psString str = psMetadataItemFormat(multiItem);
                 psStringAppend(&content, "%s", str);
                 psFree(str);
@@ -1597,5 +1596,4 @@
 }
 
-
 static psArray *p_psMetadataKeyArray(psMetadata *md)
 {
Index: /branches/eam_branches/ipp-20110710/psLib/src/types/psMetadataConfig.h
===================================================================
--- /branches/eam_branches/ipp-20110710/psLib/src/types/psMetadataConfig.h	(revision 32338)
+++ /branches/eam_branches/ipp-20110710/psLib/src/types/psMetadataConfig.h	(revision 32339)
@@ -79,4 +79,12 @@
 );
 
+/** format metadata item.
+ *
+ *  Metadata Item is formatted to a string consistent with the MDC file formats
+ *
+ *  @return char:           allocated formatted string
+*/
+psString psMetadataItemFormat(psMetadataItem *item);
+
 /** Converts a psMetadata structure (including any nested psMetadata) into a
  *  configuration file formatted string that is written out to filename.
