Index: trunk/psLib/src/fits/Makefile.am
===================================================================
--- trunk/psLib/src/fits/Makefile.am	(revision 5217)
+++ trunk/psLib/src/fits/Makefile.am	(revision 5511)
@@ -3,7 +3,10 @@
 noinst_LTLIBRARIES = libpslibfits.la
 
-libpslibfits_la_CPPFLAGS = $(SRCINC) $(CFITSIO_CFLAGS) 
+libpslibfits_la_CFLAGS = $(SRCINC) $(CFITSIO_CFLAGS) $(AM_CFLAGS)
 libpslibfits_la_SOURCES = \
-	psFits.c
+	psFits.c \
+	psFitsHeader.c \
+	psFitsImage.c \
+	psFitsTable.c
 
 EXTRA_DIST = fits.i
@@ -11,3 +14,6 @@
 pslibincludedir = $(includedir)
 pslibinclude_HEADERS = \
-	psFits.h
+	psFits.h \
+	psFitsHeader.h \
+	psFitsImage.h \
+	psFitsTable.h
Index: trunk/psLib/src/fits/fits.i
===================================================================
--- trunk/psLib/src/fits/fits.i	(revision 5217)
+++ trunk/psLib/src/fits/fits.i	(revision 5511)
@@ -1,2 +1,5 @@
 /* fits headers */
 %include "psFits.h"
+%include "psFitsHeader.h"
+%include "psFitsImage.h"
+%include "psFitsTable.h"
Index: trunk/psLib/src/fits/psFits.c
===================================================================
--- trunk/psLib/src/fits/psFits.c	(revision 5217)
+++ trunk/psLib/src/fits/psFits.c	(revision 5511)
@@ -7,6 +7,6 @@
  *  @author Robert DeSonia, MHPCC
  *
- *  @version $Revision: 1.50 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2005-09-28 20:02:46 $
+ *  @version $Revision: 1.51 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2005-11-14 22:18:30 $
  *
  *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
@@ -28,222 +28,4 @@
 #define MAX_STRING_LENGTH 256  // maximum length string for FITS routines
 
-// list of FITS header keys to ignore.
-static char* standardFitsKeys[] = {
-                                      NULL
-                                  };
-
-static psElemType convertFitsToPsType(int datatype)
-{
-    switch (datatype) {
-    case TBYTE:
-        return PS_TYPE_U8;
-    case TSBYTE:
-        return PS_TYPE_S8;
-    case TSHORT:
-        return PS_TYPE_S16;
-    case TUSHORT:
-        return PS_TYPE_U16;
-    case TLONG:
-        if (sizeof(long) == 8) {
-            return PS_TYPE_S64;
-        }
-        // no break
-    case TINT:
-        return PS_TYPE_S32;
-    case TULONG:
-        if (sizeof(unsigned long) == 8) {
-            return PS_TYPE_U64;
-        }
-        // no break
-    case TUINT:
-        return PS_TYPE_U32;
-    case TLONGLONG:
-        return PS_TYPE_S64;
-    case TFLOAT:
-        return PS_TYPE_F32;
-    case TDOUBLE:
-        return PS_TYPE_F64;
-    case TCOMPLEX:
-        return PS_TYPE_C32;
-    case TDBLCOMPLEX:
-        return PS_TYPE_C64;
-    case TLOGICAL:
-        return PS_TYPE_BOOL;
-    default:
-        psError(PS_ERR_IO, true,
-                "Unknown FITS datatype, %d.",
-                datatype);
-        return 0;
-    }
-}
-
-static bool convertPsTypeToFits(int type, int* bitPix, double* bZero, int* dataType)
-{
-
-    int bitpix;
-    int datatype;
-    double bzero = 0.0;
-
-    switch (type) {
-
-    case PS_TYPE_U8:
-        bitpix = BYTE_IMG;
-        datatype = TBYTE;
-        break;
-
-    case PS_TYPE_S8:
-        bitpix = BYTE_IMG;
-        bzero = INT8_MIN;
-        datatype = TSBYTE;
-        break;
-
-    case PS_TYPE_U16:
-        bitpix = SHORT_IMG;
-        bzero = -1.0 * INT16_MIN;
-        datatype = TUSHORT;
-        break;
-
-    case PS_TYPE_S16:
-        bitpix = SHORT_IMG;
-        datatype = TSHORT;
-        break;
-
-    case PS_TYPE_U32:
-        bitpix = LONG_IMG;
-        bzero = -1.0 * INT32_MIN;
-        datatype = TUINT;
-        break;
-
-    case PS_TYPE_S32:
-        bitpix = LONG_IMG;
-        datatype = TINT;
-        break;
-
-    case PS_TYPE_F32:
-        bitpix = FLOAT_IMG;
-        datatype = TFLOAT;
-        break;
-
-    case PS_TYPE_F64:
-        bitpix = DOUBLE_IMG;
-        datatype = TDOUBLE;
-        break;
-
-    case PS_DATA_STRING:
-        bitpix = BYTE_IMG;
-        datatype = TSTRING;
-        break;
-
-    case PS_DATA_BOOL:
-        bitpix = BYTE_IMG;
-        datatype = TLOGICAL;
-        break;
-
-    default: {
-            char* typeStr;
-            PS_TYPE_NAME(typeStr,type);
-            psError(PS_ERR_BAD_PARAMETER_TYPE, true,
-                    PS_ERRORTEXT_psFits_TYPE_UNSUPPORTED,
-                    typeStr);
-            return false;
-        }
-    }
-
-    // pass the requested parameters  (NULL parameters are not set, of course).
-    if (bitPix != NULL) {
-        *bitPix = bitpix;
-    }
-
-    if (dataType != NULL) {
-        *dataType = datatype;
-    }
-
-    if (bZero != NULL) {
-        *bZero = bzero;
-    }
-
-    return true;
-}
-
-static char getTForm(int 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_C32:
-        return 'C';
-    case PS_TYPE_C64:
-        return 'M';
-    case PS_TYPE_BOOL:
-        return 'L';
-    case PS_DATA_STRING:
-        return 'A';
-    default:
-        return '?';
-    }
-}
-
-
-static bool getMetadataTForm(psMetadataItem* item, char** fitsType, int repeat)
-{
-    if (item == NULL) {
-        return false;
-    }
-
-    *fitsType = NULL;
-    char tform = getTForm(item->type);
-
-    switch (item->type) {
-    case PS_TYPE_U8:
-    case PS_TYPE_S8:
-    case PS_TYPE_S16:
-    case PS_TYPE_S32:
-    case PS_TYPE_U64:
-    case PS_TYPE_S64:
-    case PS_TYPE_U16:
-    case PS_TYPE_U32:
-    case PS_TYPE_F32:
-    case PS_TYPE_F64:
-    case PS_TYPE_C32:
-    case PS_TYPE_C64:
-    case PS_TYPE_BOOL:
-        psStringAppend(fitsType, "%d%c",repeat,tform);
-        break;
-
-    case PS_DATA_STRING:
-        psStringAppend(fitsType,"%dA",
-                       strlen(item->data.V)*repeat);
-        break;
-
-    case PS_DATA_VECTOR: {
-            psVector* vec = item->data.V;
-            tform = getTForm(vec->type.type);
-            psStringAppend(fitsType,"%d%c",repeat*vec->n,tform);
-        }
-        break;
-
-    default:
-        return false;
-    }
-
-    return true;
-}
-
 static bool isHDUEmpty(const psFits* fits)
 {
@@ -264,101 +46,28 @@
 }
 
+static bool fitsClose(psFits* fits)
+{
+    int status = 0;
+
+    if (fits != NULL) {
+        if (fits_close_file(fits->fd, &status)) {
+            char fitsErr[MAX_STRING_LENGTH];
+            fits_get_errstatus(status, fitsErr);
+            psError(PS_ERR_IO, true,
+                    "Error while closing psFits object. CFITSIO error: %s",
+                    fitsErr);
+            return false;
+        }
+    }
+
+    return true;
+}
+
 static void fitsFree(psFits* fits)
 {
-    int status = 0;
-
-    if (fits != NULL) {
-        (void)fits_close_file(fits->fd, &status);
-        psFree(fits->filename);
-    }
+    (void)fitsClose(fits);
 }
 
-psFits* psFitsAlloc(const char* name)
-{
-    int status = 0;
-    fitsfile *fptr = NULL;      /* Pointer to the FITS file */
-
-    if (name == NULL) {
-        psError(PS_ERR_BAD_PARAMETER_NULL, true,
-                PS_ERRORTEXT_psFits_FILENAME_NULL);
-        return NULL;
-    }
-
-    /* Open/Create the FITS file */
-    if (access(name, F_OK) == 0) {     // file exists
-        (void)fits_open_file(&fptr, name, READWRITE, &status);
-        if (fptr == NULL) { // if failed, try openning as just read-only
-            status = 0;
-            (void)fits_open_file(&fptr, name, READONLY, &status);
-        }
-        if (fptr == NULL || status != 0) {
-            char fitsErr[MAX_STRING_LENGTH];
-            fits_get_errstatus(status, fitsErr);
-            psError(PS_ERR_BAD_PARAMETER_VALUE, true,
-                    PS_ERRORTEXT_psFits_FILENAME_INVALID,
-                    name, fitsErr);
-            return NULL;
-        }
-    } else {  // file does not exist, so create.
-        (void)fits_create_file(&fptr, name, &status);
-        if (fptr == NULL || status != 0) {
-            char fitsErr[MAX_STRING_LENGTH];
-            fits_get_errstatus(status, fitsErr);
-            psError(PS_ERR_IO, true,
-                    PS_ERRORTEXT_psFits_FILENAME_CREATE_FAILED,
-                    name, fitsErr);
-            return NULL;
-        }
-    }
-
-    psFits* fits = psAlloc(sizeof(psFits));
-    fits->filename = psAlloc(strlen(name)+1);
-    fits->fd = fptr;
-    strcpy((char*)fits->filename,name);
-    psMemSetDeallocator(fits,(psFreeFunc)fitsFree);
-
-    return fits;
-}
-
-
-bool psMemCheckFits(psPtr ptr)
-{
-    return ( psMemGetDeallocator(ptr) == (psFreeFunc)fitsFree );
-}
-
-
-bool psFitsMoveExtName(const psFits* fits,
-                       const char* extname)
-{
-    int status = 0;
-
-    if (fits == NULL) {
-        psError(PS_ERR_BAD_PARAMETER_NULL, true,
-                PS_ERRORTEXT_psFits_NULL);
-        return false;
-    }
-
-    if (extname == NULL) {
-        psError(PS_ERR_BAD_PARAMETER_NULL, true,
-                PS_ERRORTEXT_psFits_EXTNAME_NULL);
-        return false;
-    }
-
-
-    if (fits_movnam_hdu(fits->fd, ANY_HDU, (char*)extname, 0, &status) != 0) {
-        char fitsErr[MAX_STRING_LENGTH];
-        fits_get_errstatus(status, fitsErr);
-        psError(PS_ERR_LOCATION_INVALID, true,
-                PS_ERRORTEXT_psFits_EXTNAME_INVALID,
-                extname, fits->filename, fitsErr);
-        return false;
-    }
-
-    return true;
-}
-
-bool psFitsMoveExtNum(const psFits* fits,
-                      int extnum,
-                      bool relative)
+bool psFitsClose(psFits* fits)
 {
     if (fits == NULL) {
@@ -368,1443 +77,388 @@
     }
 
+    bool status = fitsClose(fits);
+    psMemSetDeallocator(fits,NULL);
+    psFree(fits);
+
+    return status;
+}
+
+psFits* psFitsOpen(const char* name, const char* mode)
+{
     int status = 0;
-    int hdutype = 0;
-
-    if (relative) {
-        fits_movrel_hdu(fits->fd, extnum, &hdutype, &status);
-        if (status != 0) {
+    fitsfile *fptr = NULL;      /* Pointer to the FITS file */
+
+    if (name == NULL) {
+        psError(PS_ERR_BAD_PARAMETER_NULL, true,
+                PS_ERRORTEXT_psFits_FILENAME_NULL);
+        return NULL;
+    }
+
+    /* check the mode to determine how to open/create file */
+    int iomode;
+    bool newFile;
+    if (strcmp(mode,"r") == 0) {
+        iomode = READONLY;
+        newFile = false;
+    } else if (strcmp(mode,"rw") == 0 || strcmp(mode,"r+") == 0) {
+        iomode = READWRITE;
+        newFile = false;
+    } else if (strcmp(mode,"w") == 0 || strcmp(mode,"w+") == 0) {
+        iomode = READWRITE;
+        newFile = true;
+    } else if (strcmp(mode,"a") == 0|| strcmp(mode,"a+") == 0) {
+        iomode = READWRITE;
+        newFile = (access(name, F_OK) != 0);
+    } else {
+        // mode is not valid
+        psError(PS_ERR_BAD_PARAMETER_VALUE, true,
+                "Specified mode, '%s', is invalid.  Supported modes are r, r+, rw, w, w+, a, or a+.",
+                mode);
+        return NULL;
+    }
+
+    if (newFile) {
+        /* Check if an existing file is in the way before creating file*/
+        if (access(name, F_OK) == 0) {
+            // file exists, delete old one first
+            remove
+                (name);
+        }
+
+        #if ( CFITSIO_DISKFILE == 1 )
+        (void)fits_create_diskfile(
+            #else
+            (void)fits_create_file(
+                #endif
+                &fptr,
+                name,
+                &status);
+            if (fptr == NULL || status != 0) {
+            char fitsErr[MAX_STRING_LENGTH]
+                ;
+                fits_get_errstatus(status, fitsErr);
+                psError(PS_ERR_IO, true,
+                        PS_ERRORTEXT_psFits_FILENAME_CREATE_FAILED,
+                        name, fitsErr);
+                return NULL;
+            }
+        } else {
+            #if ( CFITSIO_DISKFILE == 1 )
+            (void)fits_open_diskfile(
+                #else
+                (void)fits_open_file(
+                    #endif
+                    &fptr,
+                    name,
+                    iomode,
+                    &status);
+                if (fptr == NULL || status != 0) {
+                char fitsErr[MAX_STRING_LENGTH]
+                    ;
+                    fits_get_errstatus(status, fitsErr);
+                    psError(PS_ERR_BAD_PARAMETER_VALUE, true,
+                            PS_ERRORTEXT_psFits_FILENAME_INVALID,
+                            name, fitsErr);
+                    return NULL;
+                }
+            }
+
+            psFits* fits = psAlloc(sizeof(psFits));
+        fits->fd = fptr;
+        psMemSetDeallocator(fits,(psFreeFunc)fitsFree);
+
+        return fits;
+    }
+
+    bool psMemCheckFits(psPtr ptr)
+    {
+        return ( psMemGetDeallocator(ptr) == (psFreeFunc)fitsFree );
+    }
+
+
+    bool psFitsMoveExtName(const psFits* fits,
+                           const char* extname)
+    {
+        int status = 0;
+
+        if (fits == NULL) {
+            psError(PS_ERR_BAD_PARAMETER_NULL, true,
+                    PS_ERRORTEXT_psFits_NULL);
+            return false;
+        }
+
+        if (extname == NULL) {
+            psError(PS_ERR_BAD_PARAMETER_NULL, true,
+                    PS_ERRORTEXT_psFits_EXTNAME_NULL);
+            return false;
+        }
+
+
+        if (fits_movnam_hdu(fits->fd, ANY_HDU, (char*)extname, 0, &status) != 0) {
             char fitsErr[MAX_STRING_LENGTH];
             fits_get_errstatus(status, fitsErr);
             psError(PS_ERR_LOCATION_INVALID, true,
-                    PS_ERRORTEXT_psFits_EXTNUM_REL_MOVE_FAILED,
-                    extnum, fits->filename, fitsErr);
-            return false;
-        }
-    } else {
-        fits_movabs_hdu(fits->fd, extnum+1, &hdutype, &status);
-        if (status != 0) {
-            char fitsErr[MAX_STRING_LENGTH];
-            fits_get_errstatus(status, fitsErr);
-            psError(PS_ERR_LOCATION_INVALID, true,
-                    PS_ERRORTEXT_psFits_EXTNUM_ABS_MOVE_FAILED,
-                    extnum, fits->filename, fitsErr);
-            return false;
-        }
-    }
-
-    return true;
-}
-
-int psFitsGetExtNum(const psFits* fits)
-{
-    int hdunum;
-
-    if (fits == NULL) {
-        psError(PS_ERR_BAD_PARAMETER_NULL, true,
-                PS_ERRORTEXT_psFits_NULL);
-        return PS_FITS_TYPE_NONE;
-    }
-
-
-    return fits_get_hdu_num(fits->fd,&hdunum) - 1;
-}
-
-psString psFitsGetExtName(const psFits* fits)
-{
-    if (fits == NULL) {
-        psError(PS_ERR_BAD_PARAMETER_NULL, true,
-                PS_ERRORTEXT_psFits_NULL);
-        return NULL;
-    }
-
-    int status = 0;
-    char name[MAX_STRING_LENGTH];
-
-    if (fits_read_key_str(fits->fd, "EXTNAME", name, NULL, &status) != 0) {
-        status = 0;
-        if (fits_read_key_str(fits->fd, "HDUNAME", name, NULL, &status) != 0) {
-            int num = psFitsGetExtNum(fits);
-            snprintf(name, MAX_STRING_LENGTH, "EXT-%3d",num);
-        }
-    }
-    return psStringCopy(name);
-}
-
-bool psFitsSetExtName(psFits* fits, const char* name)
-{
-    if (fits == NULL) {
-        psError(PS_ERR_BAD_PARAMETER_NULL, true,
-                PS_ERRORTEXT_psFits_NULL);
-        return false;
-    }
-
-    if (name == NULL) {
-        psError(PS_ERR_BAD_PARAMETER_NULL, true,
-                PS_ERRORTEXT_psFits_EXTNAME_NULL);
-        return false;
-    }
-
-    int status = 0;
-
-    if (fits_update_key_str(fits->fd, "EXTNAME", (char*)name, NULL, &status) != 0) {
-        char fitsErr[MAX_STRING_LENGTH];
-        (void)fits_get_errstatus(status, fitsErr);
-        psError(PS_ERR_IO, true,
-                PS_ERRORTEXT_psFits_WRITE_FAILED,
-                fits->filename, fitsErr);
-        return false;
-    }
-
-    return true;
-}
-
-int psFitsGetSize(const psFits* fits)
-{
-    if (fits == NULL) {
-        psError(PS_ERR_BAD_PARAMETER_NULL, true,
-                PS_ERRORTEXT_psFits_NULL);
-        return 0;
-    }
-
-    int num = 0;
-    int status = 0;
-
-    if (fits_get_num_hdus(fits->fd, &num, &status) != 0) {
-        char fitsErr[MAX_STRING_LENGTH];
-        fits_get_errstatus(status, fitsErr);
-        psError(PS_ERR_LOCATION_INVALID, true,
-                PS_ERRORTEXT_psFits_GETNUMHDUS_FAILED,
-                fits->filename, fitsErr);
-        return 0;
-    }
-
-    return num;
-}
-
-psFitsType psFitsGetExtType(const psFits* fits)
-{
-    if (fits == NULL) {
-        psError(PS_ERR_BAD_PARAMETER_NULL, true,
-                PS_ERRORTEXT_psFits_NULL);
-        return PS_FITS_TYPE_NONE;
-    }
-
-    int status = 0;
-    int hdutype = PS_FITS_TYPE_NONE;
-
-    if (fits_get_hdu_type(fits->fd, &hdutype, &status) != 0) {
-        char fitsErr[MAX_STRING_LENGTH];
-        fits_get_errstatus(status, fitsErr);
-        psError(PS_ERR_LOCATION_INVALID, true,
-                PS_ERRORTEXT_psFits_GETHDUTYPE_FAILED,
-                fits->filename, fitsErr);
-        return PS_FITS_TYPE_NONE;
-    }
-
-    if (hdutype == PS_FITS_TYPE_IMAGE &&
-            psFitsGetExtNum(fits) > 0 &&
-            isHDUEmpty(fits)) {
-        return PS_FITS_TYPE_ANY;
-    }
-
-    return hdutype;
-}
-
-psMetadata* psFitsReadHeader(psMetadata* out,
-                             const psFits* fits)
-{
-    if (fits == NULL) {
-        psError(PS_ERR_BAD_PARAMETER_NULL, true,
-                PS_ERRORTEXT_psFits_NULL);
-        return NULL;
-    }
-
-    if (out == NULL) {
-        out = psMetadataAlloc();
-        if (out == NULL) {
-            psError(PS_ERR_UNKNOWN, false,
-                    "Failed to allocate a new psMetadata container.");
+                    PS_ERRORTEXT_psFits_EXTNAME_INVALID,
+                    extname, fitsErr);
+            return false;
+        }
+
+        return true;
+    }
+
+    bool psFitsMoveExtNum(const psFits* fits,
+                          int extnum,
+                          bool relative)
+    {
+        if (fits == NULL) {
+            psError(PS_ERR_BAD_PARAMETER_NULL, true,
+                    PS_ERRORTEXT_psFits_NULL);
+            return false;
+        }
+
+        int status = 0;
+        int hdutype = 0;
+
+        if (relative) {
+            fits_movrel_hdu(fits->fd, extnum, &hdutype, &status);
+            if (status != 0) {
+                char fitsErr[MAX_STRING_LENGTH];
+                fits_get_errstatus(status, fitsErr);
+                psError(PS_ERR_LOCATION_INVALID, true,
+                        PS_ERRORTEXT_psFits_EXTNUM_REL_MOVE_FAILED,
+                        extnum, fitsErr);
+                return false;
+            }
+        } else {
+            fits_movabs_hdu(fits->fd, extnum+1, &hdutype, &status);
+            if (status != 0) {
+                char fitsErr[MAX_STRING_LENGTH];
+                fits_get_errstatus(status, fitsErr);
+                psError(PS_ERR_LOCATION_INVALID, true,
+                        PS_ERRORTEXT_psFits_EXTNUM_ABS_MOVE_FAILED,
+                        extnum, fitsErr);
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    bool psFitsMoveLast(const psFits* fits)
+    {
+        if (fits == NULL) {
+            psError(PS_ERR_BAD_PARAMETER_NULL, true,
+                    PS_ERRORTEXT_psFits_NULL);
+            return false;
+        }
+
+        return psFitsMoveExtNum(fits,psFitsGetSize(fits),false);
+    }
+
+    int psFitsGetExtNum(const psFits* fits)
+    {
+        int hdunum;
+
+        if (fits == NULL) {
+            psError(PS_ERR_BAD_PARAMETER_NULL, true,
+                    PS_ERRORTEXT_psFits_NULL);
+            return PS_FITS_TYPE_NONE;
+        }
+
+
+        return fits_get_hdu_num(fits->fd,&hdunum) - 1;
+    }
+
+    psString psFitsGetExtName(const psFits* fits)
+    {
+        if (fits == NULL) {
+            psError(PS_ERR_BAD_PARAMETER_NULL, true,
+                    PS_ERRORTEXT_psFits_NULL);
             return NULL;
         }
-    }
-
-    // Get number of key names
-    int numKeys = 0;
-    int keyNum = 0;
-    int status = 0;
-    fits_get_hdrpos(fits->fd, &numKeys, &keyNum, &status);
-
-    // Get each key name. Keywords start at one.
-    char keyType;
-    char keyName[MAX_STRING_LENGTH];
-    char keyValue[MAX_STRING_LENGTH];
-    char keyComment[MAX_STRING_LENGTH];
-    psBool tempBool;
-    psBool success;
-    psBool stdKey;
-    for (int i = 1; i <= numKeys; i++) {
-
-        fits_read_keyn(fits->fd, i, keyName, keyValue, keyComment, &status);
-
-        stdKey = false;
-
-        int stdKeyIdx = 0;
-        while (standardFitsKeys[stdKeyIdx] != NULL && ! stdKey) {
-            if (strcmp(keyName,standardFitsKeys[stdKeyIdx++]) == 0) {
-                stdKey = true;
-            }
-        }
-
-        if (keyValue[0] != 0) { // blank values are not handled by fits_get_keytype
-            fits_get_keytype(keyValue, &keyType, &status);
-        } else {
-            keyType = 'C';
-        }
-        if (status != 0) {
-            break;
-        }
-
-        if (! stdKey) {
-            switch (keyType) {
-            case 'X': // bit
-            case 'I': // short int.
-            case 'J': // int.
-            case 'B': // byte
-                success = psMetadataAdd(out,
-                                        PS_LIST_TAIL,
-                                        keyName,
-                                        PS_DATA_S32 | PS_META_DUPLICATE_OK,
-                                        keyComment,
-                                        atoi(keyValue));
-                break;
-            case 'U': // unsigned int. may not fit in a psS32
-            case 'K': // long int. can't all fit in a psS32
-            case 'F':
-                success = psMetadataAdd(out,
-                                        PS_LIST_TAIL,
-                                        keyName,
-                                        PS_DATA_F64 | PS_META_DUPLICATE_OK,
-                                        keyComment,
-                                        atof(keyValue));
-                break;
-            case 'C':
-                // remove the single-quotes at front/end
-                if (keyValue[0] == '\'' && keyValue[strlen(keyValue)-1] == '\'') {
-                    keyValue[strlen(keyValue)-1] = '\0';
-                    success = psMetadataAdd(out,
-                                            PS_LIST_TAIL,
-                                            keyName,
-                                            PS_DATA_STRING | PS_META_DUPLICATE_OK,
-                                            keyComment,
-                                            keyValue+1);
-                } else {
-                    success = psMetadataAdd(out,
-                                            PS_LIST_TAIL,
-                                            keyName,
-                                            PS_DATA_STRING | PS_META_DUPLICATE_OK,
-                                            keyComment,
-                                            keyValue);
-                }
-                break;
-            case 'L':
-                tempBool = (keyValue[0] == 'T') ? 1 : 0;
-                success = psMetadataAdd(out,
-                                        PS_LIST_TAIL,
-                                        keyName,
-                                        PS_DATA_BOOL | PS_META_DUPLICATE_OK,
-                                        keyComment,
-                                        tempBool);
-                break;
-            default:
-                psError(PS_ERR_IO, true,
-                        PS_ERRORTEXT_psFits_METATYPE_INVALID,
-                        keyType);
-                return out;
-            }
-
-            if (!success) {
-                psError(PS_ERR_UNKNOWN, false,
-                        PS_ERRORTEXT_psFits_METADATA_ADD_FAILED,
-                        keyName);
-                return out;
-            }
-        }
-
-    }
-
-    if ( status != 0) {
-        char fitsErr[MAX_STRING_LENGTH];
-        (void)fits_get_errstatus(status, fitsErr);
-        psError(PS_ERR_IO, true,
-                PS_ERRORTEXT_psFits_METADATA_ADD_FAILED,
-                fitsErr);
-        return false;
-    }
-
-    return out;
-}
-
-psMetadata* psFitsReadHeaderSet(psMetadata* out,
-                                const psFits* fits)
-{
-    if (fits == NULL) {
-        psError(PS_ERR_BAD_PARAMETER_NULL, true,
-                PS_ERRORTEXT_psFits_NULL);
-        psFree(out);
-        return NULL;
-    }
-
-    if (out == NULL) {
-        out = psMetadataAlloc();
-        if (out == NULL) {
-            psError(PS_ERR_UNKNOWN, false,
-                    "Failed to allocate a new psMetadata container.");
-            return NULL;
-        }
-    }
-
-    int size = psFitsGetSize(fits);
-
-    int origPosition = psFitsGetExtNum(fits);
-
-    for (int lcv=0; lcv < size; lcv++) {
-        psFitsMoveExtNum(fits, lcv, false);
-
-        char* name = NULL;
-        if (lcv == 0) {
-            name = psStringCopy("PHU");
-        } else {
-            name = psFitsGetExtName(fits);
-        }
-
-        psMetadata* header = psFitsReadHeader(NULL, fits);
-        if (name != NULL && header != NULL) {
-            psMetadataAddMetadata(out, PS_LIST_HEAD, name, 0, "FITS Header",
-                                  header);
-        } else {
-            psWarning("Failed to read HDU#%d header data.",
-                      lcv);
-        }
-
-        psFree(name);
-        psFree(header);
-    }
-
-    // reposition to the original position
-    psFitsMoveExtNum(fits, origPosition, false);
-
-    return out;
-}
-
-psImage* psFitsReadImage(psImage* output, // a psImage to recycle.
-                         const psFits* fits,    // the psFits object
-                         psRegion region, // the region in the FITS image to read
-                         int z)           // the z-plane in the FITS image cube to read
-{
-    psS32 status = 0;           /* CFITSIO file vars */
-    psS32 nAxis = 0;
-    psS32 anynull = 0;
-    psS32 bitPix = 0;           /* Pixel type */
-    long nAxes[3];
-    long firstPixel[3];         /* lower-left corner of image subset */
-    long lastPixel[3];          /* upper-right corner of image subset */
-    long increment[3];          /* increment for image subset */
-    char fitsErr[80] = "";      /* CFITSIO error message string */
-    psS32 fitsDatatype = 0;
-    psS32 datatype = 0;
-
-    if (fits == NULL) {
-        psError(PS_ERR_BAD_PARAMETER_NULL, true,
-                PS_ERRORTEXT_psFits_NULL);
-        psFree(output);
-        return NULL;
-    }
-
-    // check to see if we even are positioned on an image HDU
-    int hdutype;
-    if ( fits_get_hdu_type(fits->fd,&hdutype, &status) != 0) {
-        char fitsErr[MAX_STRING_LENGTH];
-        (void)fits_get_errstatus(status, fitsErr);
-        psError(PS_ERR_IO, true,
-                PS_ERRORTEXT_psFits_GET_HDU_TYPE_FAILED,
-                fitsErr);
-        return NULL;
-    }
-    if (hdutype != IMAGE_HDU) {
-        psError(PS_ERR_IO, true,
-                PS_ERRORTEXT_psFits_NOT_IMAGE_TYPE);
-        return NULL;
-    }
-
-    /* Get the data type 'bitPix' from the FITS image */
-    if (fits_get_img_equivtype(fits->fd, &bitPix, &status) != 0) {
-        fits_get_errstatus(status, fitsErr);
-        psError(PS_ERR_IO, true,
-                PS_ERRORTEXT_psFits_DATATYPE_UNKNOWN,
-                fitsErr);
-        psFree(output);
-        return NULL;
-    }
-
-    /* Get the dimensions 'nAxis' from the FITS image */
-    if (fits_get_img_dim(fits->fd, &nAxis, &status) != 0) {
-        (void)fits_get_errstatus(status, fitsErr);
-        psError(PS_ERR_IO, true,
-                PS_ERRORTEXT_psFits_IMAGE_DIM_UNKNOWN,
-                fitsErr);
-        psFree(output);
-        return NULL;
-    }
-
-    /* Validate the number of axis */
-    if ((nAxis < 2) || (nAxis > 3)) {
-        psError(PS_ERR_IO, true,
-                PS_ERRORTEXT_psFits_IMAGE_DIMENSION_UNSUPPORTED,
-                nAxis);
-        psFree(output);
-        return NULL;
-    }
-
-    /* Get the Image size from the FITS file */
-    if (fits_get_img_size(fits->fd, nAxis, nAxes, &status) != 0) {
-        (void)fits_get_errstatus(status, fitsErr);
-        psError(PS_ERR_IO, true,
-                PS_ERRORTEXT_psFits_IMAGE_SIZE_UNKNOWN,
-                fitsErr);
-        psFree(output);
-        return NULL;
-    }
-
-    firstPixel[0] = region.x0 + 1;
-    firstPixel[1] = region.y0 + 1;
-    firstPixel[2] = z + 1;
-
-    if (region.x1 > 0) {
-        lastPixel[0] = region.x1;
-    } else {
-        lastPixel[0] = nAxes[0] + region.x1; // n.b., region.x1 < 0
-    }
-    if (region.y1 > 0) {
-        lastPixel[1] = region.y1;
-    } else {
-        lastPixel[1] = nAxes[1] + region.y1; // n.b., region.y1 < 0
-    }
-    lastPixel[2] = z + 1;
-
-    increment[0] = 1;
-    increment[1] = 1;
-    increment[2] = 1;
-
-    switch (bitPix) {
-    case BYTE_IMG:
-        datatype = PS_TYPE_U8;
-        fitsDatatype = TBYTE;
-        break;
-    case SBYTE_IMG:
-        datatype = PS_TYPE_S8;
-        fitsDatatype = TSBYTE;
-        break;
-    case USHORT_IMG:
-        datatype = PS_TYPE_U16;
-        fitsDatatype = TUSHORT;
-        break;
-    case SHORT_IMG:
-        datatype = PS_TYPE_S16;
-        fitsDatatype = TSHORT;
-        break;
-    case ULONG_IMG:
-        datatype = PS_TYPE_U32;
-        fitsDatatype = TUINT;
-        break;
-    case LONG_IMG:
-        datatype = PS_TYPE_S32;
-        fitsDatatype = TINT;
-        break;
-    case LONGLONG_IMG:
-        datatype = PS_TYPE_S64;
-        fitsDatatype = TLONGLONG;
-        break;
-    case FLOAT_IMG:
-        datatype = PS_TYPE_F32;
-        fitsDatatype = TFLOAT;
-        break;
-    case DOUBLE_IMG:
-        datatype = PS_TYPE_F64;
-        fitsDatatype = TDOUBLE;
-        break;
-    default:
-        psError(PS_ERR_IO, true,
-                PS_ERRORTEXT_psFits_FITS_TYPE_UNSUPPORTED,
-                bitPix);
-        psFree(output);
-        return NULL;
-    }
-
-    output = psImageRecycle(output,
-                            lastPixel[0]-firstPixel[0]+1,
-                            lastPixel[1]-firstPixel[1]+1,
-                            datatype);
-
-    if (output == NULL) {
-        psError(PS_ERR_UNKNOWN, false,
-                "Failed to allocate a properly sized image.");
-        return false;
-    }
-
-    // n.b., this assumes contiguous image buffer
-    if (fits_read_subset(fits->fd, fitsDatatype, firstPixel, lastPixel, increment,
-                         NULL, output->data.V[0], &anynull, &status) != 0) {
-        psFree(output);
-        (void)fits_get_errstatus(status, fitsErr);
-        psError(PS_ERR_IO, true,
-                PS_ERRORTEXT_psFits_READ_FAILED,
-                fitsErr);
-        return NULL;
-    }
-
-    return output;
-
-}
-
-bool psFitsWriteImage(psFits* fits,
-                      psMetadata* header,
-                      const psImage* input,
-                      int numZPlanes)
-{
-
-    if (fits == NULL) {
-        psError(PS_ERR_BAD_PARAMETER_NULL, true,
-                PS_ERRORTEXT_psFits_NULL);
-        return false;
-    }
-
-    if (input == NULL) {
-        psError(PS_ERR_BAD_PARAMETER_NULL, true,
-                PS_ERRORTEXT_psFits_IMAGE_NULL);
-        return false;
-    }
-    int numCols = input->numCols;
-    int numRows = input->numRows;
-
-    int status = 0;
-
-    // determine the FITS-equivalent parameters
-    int bitPix;
-    double bZero;
-    int dataType;
-    if (! convertPsTypeToFits(input->type.type, &bitPix, &bZero, &dataType) ) {
-        return false;
-    }
-
-    int naxis = 3;
-    long naxes[3];
-
-    naxes[0] = numCols;
-    naxes[1] = numRows;
-    naxes[2] = numZPlanes;
-
-    if (numZPlanes < 2) {
-        naxis = 2;
-    }
-
-    fits_create_img(fits->fd, bitPix, naxis, naxes, &status);
-
-    if (bZero != 0) {        // set the bscale/bzero
-        fits_write_key_dbl(fits->fd, "BZERO", bZero, 12, "Pixel Value Offset", &status);
-        fits_write_key_dbl(fits->fd, "BSCALE", 1.0, 12, "Pixel Value Scale", &status);
-        fits_set_bscale(fits->fd, 1.0, bZero, &status);
-    }
-
-    // write the header, if any.
-    if (header != NULL) {
-        psFitsWriteHeader(header, (psPtr)fits);
-    }
-
-    if (input->parent == NULL) { // if no parent, assume that the image data is contiguous
-        fits_write_img(fits->fd,
-                       dataType,              // datatype
-                       1,                     // writing to the first z-plane
-                       numCols*numRows,       // number of elements to write, i.e., the whole image
-                       input->data.V[0],      // the data
-                       &status);
-    } else { // image data may not be contiguous; write one row at a time
-        int firstPixel = 1;
-        for (int row = 0; row < numRows; row++) {
-            fits_write_img(fits->fd,
-                           dataType,          // datatype
-                           firstPixel,
-                           numCols,           // number of elements to write, i.e., one row's worth
-                           input->data.V[row],// the raw row data
-                           &status);
-            firstPixel += numCols;  // move to next row
-        }
-    }
-
-    if ( status != 0) {
-        char fitsErr[MAX_STRING_LENGTH];
-        (void)fits_get_errstatus(status, fitsErr);
-        psError(PS_ERR_IO, true,
-                PS_ERRORTEXT_psFits_WRITE_FAILED,
-                fits->filename, fitsErr);
-        return false;
-    }
-
-    return true;
-
-}
-
-bool psFitsUpdateImage(psFits* fits,
-                       const psImage* input,
-                       psRegion region,
-                       int z)
-{
-    int status = 0;
-
-    if (fits == NULL) {
-        psError(PS_ERR_BAD_PARAMETER_NULL, true,
-                PS_ERRORTEXT_psFits_NULL);
-        return false;
-    }
-
-    if (input == NULL) {
-        psError(PS_ERR_BAD_PARAMETER_NULL, true,
-                PS_ERRORTEXT_psFits_IMAGE_NULL);
-        return false;
-    }
-
-    // check to see if we are positioned on an image HDU
-    int hdutype;
-    if ( fits_get_hdu_type(fits->fd,&hdutype, &status) != 0) {
-        char fitsErr[MAX_STRING_LENGTH];
-        (void)fits_get_errstatus(status, fitsErr);
-        psError(PS_ERR_IO, true,
-                PS_ERRORTEXT_psFits_GET_HDU_TYPE_FAILED,
-                fitsErr);
-        return NULL;
-    }
-    if (hdutype != IMAGE_HDU) {
-        psError(PS_ERR_IO, true,
-                PS_ERRORTEXT_psFits_NOT_IMAGE_TYPE);
-        return NULL;
-    }
-
-    int numCols = input->numCols;
-    int numRows = input->numRows;
-
-    // determine the FITS-equivalent parameters
-    int bitPix;
-    double bZero;
-    int dataType;
-    if (! convertPsTypeToFits(input->type.type, &bitPix, &bZero, &dataType) ) {
-        return false;
-    }
-
-    //check to see if the HDU has the same datatype
-    int fileBitpix;
-    int naxis;
-    long nAxes[3];
-    nAxes[2] = 1;
-    fits_get_img_param(fits->fd, 3, &fileBitpix, &naxis, nAxes, &status);
-
-    //check to see if the HDU has the same datatype
-    if (bitPix != fileBitpix) {
-        char* fitsTypeStr;
-        char* imageTypeStr;
-        PS_TYPE_NAME(fitsTypeStr,fileBitpix);
-        PS_TYPE_NAME(imageTypeStr,input->type.type);
-        psError(PS_ERR_IO, true,
-                PS_ERRORTEXT_psFits_IMAGE_UPDATE_TYPE_MISMATCH,
-                fitsTypeStr, imageTypeStr);
-        return false;
-    }
-
-    //check if the HDU has the z-plane requested
-    if (z >= nAxes[2]) {
-        psError(PS_ERR_BAD_PARAMETER_SIZE, true,
-                PS_ERRORTEXT_psFits_FITS_Z_SMALL,
-                nAxes[2],z);
-        return false;
-    }
-
-    // determine the region in the FITS file domain
-    long firstPixel[3];
-    long lastPixel[3];
-
-    firstPixel[0] = region.x0 + 1;
-    firstPixel[1] = region.y0 + 1;
-    firstPixel[2] = z + 1;
-
-    if (region.x1 > 0) {
-        lastPixel[0] = region.x1;
-    } else {
-        lastPixel[0] = nAxes[0] + region.x1; // n.b., region.x1 < 0
-    }
-    if (region.y1 > 0) {
-        lastPixel[1] = region.y1;
-    } else {
-        lastPixel[1] = nAxes[1] + region.y1; // n.b., region.y1 < 0
-    }
-    lastPixel[2] = z + 1;
-
-    if (firstPixel[0] < 1 || firstPixel[0] > nAxes[0] ||
-            firstPixel[1] < 1 || firstPixel[1] > nAxes[1] ||
-            lastPixel[0] < 1 || lastPixel[0] > nAxes[0] ||
-            lastPixel[1] < 1 || lastPixel[1] > nAxes[1]) {
-        psError(PS_ERR_BAD_PARAMETER_VALUE, true,
-                "Specified region [%d:%d,%d:%d], is not valid given the %dx%d FITS image.",
-                region.y0,region.y1-1,region.x0,region.x1-1);
-        return false;
-
-    }
-
-    int dx = lastPixel[0] - firstPixel[0];
-    int dy = lastPixel[1] - firstPixel[1];
-    if (dx > numCols ||
-            dy > numRows) {
-        psError(PS_ERR_BAD_PARAMETER_VALUE, true,
-                "The region [%d:%d,%d:%d], is not valid given the input %dx%d image.",
-                firstPixel[1]-1,lastPixel[1]-1,
-                firstPixel[0]-1,lastPixel[0]-1,
-                numCols, numRows);
-        return false;
-    }
-
-    psImage* subset;
-    if (dx != numCols || dy != numRows) {
-        // the input image needs to be subsetted
-        subset = psImageSubset((psImage*)input, psRegionSet(0,dx+1,0,dy+1));
-    } else {
-        subset = psMemIncrRefCounter((psImage*)input);
-    }
-
-    fits_write_subset(fits->fd, dataType, firstPixel, lastPixel, subset->data.V[0], &status);
-
-    if ( status != 0) {
-        char fitsErr[MAX_STRING_LENGTH];
-        (void)fits_get_errstatus(status, fitsErr);
-        psError(PS_ERR_IO, true,
-                PS_ERRORTEXT_psFits_WRITE_FAILED,
-                fits->filename, fitsErr);
-        return false;
-    }
-
-    return true;
-}
-
-bool psFitsWriteHeader(const psMetadata* output,
-                       psFits* fits)
-{
-
-    if (fits == NULL) {
-        psError(PS_ERR_BAD_PARAMETER_NULL, true,
-                PS_ERRORTEXT_psFits_NULL);
-        return false;
-    }
-
-    if (output == NULL) {
-        psError(PS_ERR_BAD_PARAMETER_NULL, true,
-                PS_ERRORTEXT_psFits_METADATA_NULL);
-        return false;
-    }
-
-    int status = 0;
-
-    //transverse the metadata list and add each key.
-
-    psListIterator* iter = psListIteratorAlloc(output->list,PS_LIST_HEAD,true);
-    psMetadataItem* item;
-    while ( (item=psListGetAndIncrement(iter)) != NULL ) {
-        switch (item->type) {
-        case PS_DATA_BOOL: {
-                int value = item->data.B;
-                fits_update_key(fits->fd,
-                                TLOGICAL,
-                                item->name,
-                                &value,
-                                item->comment,
-                                &status);
-                break;
-            }
-        case PS_DATA_S32:
-            fits_update_key(fits->fd,
-                            TINT,
-                            item->name,
-                            &item->data.S32,
-                            item->comment,
-                            &status);
-            break;
-        case PS_DATA_F32:
-            fits_update_key(fits->fd,
-                            TFLOAT,
-                            item->name,
-                            &item->data.F32,
-                            item->comment,
-                            &status);
-            break;
-        case PS_DATA_F64:
-            fits_update_key(fits->fd,
-                            TDOUBLE,
-                            item->name,
-                            &item->data.F64,
-                            item->comment,
-                            &status);
-            break;
-        case PS_DATA_STRING:
-            fits_update_key(fits->fd,
-                            TSTRING,
-                            item->name,
-                            item->data.V,
-                            item->comment,
-                            &status);
-            break;
-        default:  // all other META types are ignored
-            break;
-        }
-
-        if ( status != 0) {
+
+        int status = 0;
+        char name[MAX_STRING_LENGTH];
+
+        if (fits_read_key_str(fits->fd, "EXTNAME", name, NULL, &status) != 0) {
+            status = 0;
+            if (fits_read_key_str(fits->fd, "HDUNAME", name, NULL, &status) != 0) {
+                int num = psFitsGetExtNum(fits);
+                snprintf(name, MAX_STRING_LENGTH, "EXT-%3d",num);
+            }
+        }
+        return psStringCopy(name);
+    }
+
+    bool psFitsSetExtName(psFits* fits, const char* name)
+    {
+        if (fits == NULL) {
+            psError(PS_ERR_BAD_PARAMETER_NULL, true,
+                    PS_ERRORTEXT_psFits_NULL);
+            return false;
+        }
+
+        if (name == NULL) {
+            psError(PS_ERR_BAD_PARAMETER_NULL, true,
+                    PS_ERRORTEXT_psFits_EXTNAME_NULL);
+            return false;
+        }
+
+        int status = 0;
+
+        if (fits_update_key_str(fits->fd, "EXTNAME", (char*)name, NULL, &status) != 0) {
             char fitsErr[MAX_STRING_LENGTH];
             (void)fits_get_errstatus(status, fitsErr);
             psError(PS_ERR_IO, true,
                     PS_ERRORTEXT_psFits_WRITE_FAILED,
-                    fits->filename, fitsErr);
-            return false;
-        }
-    }
-
-    return true;
-}
-
-psMetadata* psFitsReadTableRow(const psFits* fits,
-                               int row)
-{
-    long numRows;
-    int numCols;
-    int status = 0;
-
-    if (fits == NULL) {
-        psError(PS_ERR_BAD_PARAMETER_NULL, true,
-                PS_ERRORTEXT_psFits_NULL);
-        return NULL;
-    }
-
-    // check to see if we even are positioned on a table HDU
-    int hdutype;
-    fits_get_hdu_type(fits->fd,&hdutype, &status);
-    if ( status != 0) {
-        char fitsErr[MAX_STRING_LENGTH];
-        (void)fits_get_errstatus(status, fitsErr);
-        psError(PS_ERR_IO, true,
-                PS_ERRORTEXT_psFits_GET_HDU_TYPE_FAILED,
-                fitsErr);
-        return NULL;
-    }
-    if (hdutype != ASCII_TBL && hdutype != BINARY_TBL) {
-        psError(PS_ERR_IO, true,
-                PS_ERRORTEXT_psFits_NOT_TABLE_TYPE);
-        return NULL;
-    }
-
-    // get the size of the FITS table
-    fits_get_num_rows(fits->fd, &numRows, &status);
-    fits_get_num_cols(fits->fd, &numCols, &status);
-    if ( status != 0) {
-        char fitsErr[MAX_STRING_LENGTH];
-        (void)fits_get_errstatus(status, fitsErr);
-        psError(PS_ERR_IO, true,
-                PS_ERRORTEXT_psFits_GET_TABLE_SIZE_FAILED,
-                fitsErr);
-        return NULL;
-    }
-
-    psTrace(".psFits.psFitsReadTableRow",5,"Table size is %ix%i\n",numCols, numRows);
-    // the row parameter in the proper range?
-    if (row < 0 || row >= numRows) {
-        psError(PS_ERR_BAD_PARAMETER_VALUE, true,
-                PS_ERRORTEXT_psFits_ROW_INVALID,
-                row,numRows);
-        return NULL;
-    }
-
-    psMetadata* data = psMetadataAlloc();
-
-    int typecode;
-    long repeat;
-    long width;
-    char name[60];
-    for (int col = 1; col <= numCols; col++) {
-        // get the column name
-        if (hdutype == BINARY_TBL) {
-            fits_get_bcolparms(fits->fd, col, name,
-                               NULL, NULL, NULL, NULL, NULL, 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 (status == 0) {
-
-            #define READ_TABLE_ROW_CASE(FITSTYPE, NATIVETYPE, TYPE) \
-        case FITSTYPE: { \
-                if (repeat == 1) { \
-                    NATIVETYPE value; \
-                    int anynul = 0; \
-                    fits_read_col(fits->fd, FITSTYPE, col,row+1, \
-                                  1, 1, NULL, &value, &anynul, &status); \
-                    psTrace(".psFits.psFitsReadTableRow",5,"Column #%i, '%s', is type %i, repeat %i, Value = %g\n", \
-                            col, name, typecode, repeat, (double)value); \
-                    psMetadataAdd(data,PS_LIST_TAIL, name, \
-                                  PS_DATA_##TYPE, \
-                                  "", (ps##TYPE)value); \
-                } else { \
-                    psVector* value = psVectorAlloc(repeat,PS_DATA_##TYPE); \
-                    int anynul = 0; \
-                    fits_read_col(fits->fd, FITSTYPE, col,row+1, \
-                                  1, repeat, NULL, value->data.U8, &anynul, &status); \
-                    psMetadataAdd(data,PS_LIST_TAIL, name, \
-                                  PS_DATA_VECTOR, \
-                                  "", value); \
-                    psFree(value); \
-                } \
-                break; \
-            }
-
-            switch (typecode) {
-            case TBYTE:
-            case TSHORT:
-            case TLONGLONG:
-                READ_TABLE_ROW_CASE(TLONG, long, S32)
-                READ_TABLE_ROW_CASE(TFLOAT, float, F32)
-                READ_TABLE_ROW_CASE(TDOUBLE, double, F64)
-                READ_TABLE_ROW_CASE(TLOGICAL, bool, BOOL);
-            case TSTRING: {
-                    char* value = psAlloc(repeat+1);
-                    int anynul = 0;
-                    fits_read_col(fits->fd, TSTRING, col,row+1,
-                                  1, 1, NULL, &value, &anynul, &status);
-                    psTrace(".psFits.psFitsReadTableRow",5,"Column #%i, '%s', is type %i, repeat %i, value = %s\n",
-                            col, name, typecode, repeat, value);
-                    if (anynul == 0) {
-                        psMetadataAdd(data,PS_LIST_TAIL, name,
-                                      PS_DATA_STRING,
-                                      "", value);
-                    }
-                    psFree(value);
-                    break;
-                }
-            default:
-                psWarning("Data type (%d) not supportted for column %d",
-                          typecode, col);
-
-                psTrace("psFits.psFitsReadTableRow", 2,
-                        "Column %d or row %d was of a non primitive type, %d",
-                        col, row, typecode);
-            }
-        }
-
-        if ( status != 0) {
-            char fitsErr[MAX_STRING_LENGTH];
-            (void)fits_get_errstatus(status, fitsErr);
-            psError(PS_ERR_IO, true,
-                    PS_ERRORTEXT_psFits_GET_TABLE_ELEMENT,
-                    col,row,fitsErr);
-            psFree(data);
-            return NULL;
-        }
-
-    }
-
-    return data;
-}
-
-psArray* psFitsReadTableColumn(const psFits* fits,
-                               const char* colname)
-{
-    int colnum = 0;
-    int status = 0;
-
-    if (fits == NULL) {
-        psError(PS_ERR_BAD_PARAMETER_NULL, true,
-                PS_ERRORTEXT_psFits_NULL);
-        return NULL;
-    }
-
-    // check to see if we even are positioned on a table HDU
-    int hdutype;
-    if ( fits_get_hdu_type(fits->fd,&hdutype, &status) != 0) {
-        char fitsErr[MAX_STRING_LENGTH];
-        (void)fits_get_errstatus(status, fitsErr);
-        psError(PS_ERR_IO, true,
-                PS_ERRORTEXT_psFits_GET_HDU_TYPE_FAILED,
-                fitsErr);
-        return NULL;
-    }
-    if (hdutype != ASCII_TBL && hdutype != BINARY_TBL) {
-        psError(PS_ERR_IO, true,
-                PS_ERRORTEXT_psFits_NOT_TABLE_TYPE);
-        return NULL;
-    }
-
-    // find the column by name
-    if ( fits_get_colnum(fits->fd, CASESEN, (char*)colname, &colnum, &status) != 0) {
-        char fitsErr[MAX_STRING_LENGTH];
-        (void)fits_get_errstatus(status, fitsErr);
-        psError(PS_ERR_IO, true,
-                PS_ERRORTEXT_psFits_FIND_COLUMN,
-                colname, fitsErr);
-        return NULL;
-    }
-
-    // get the number of rows
-    long numRows = 0;
-    fits_get_num_rows(fits->fd, &numRows, &status);
-
-    // get the column length.
-    int width;
-    if ( fits_get_col_display_width(fits->fd, colnum, &width, &status) != 0) {
-        char fitsErr[MAX_STRING_LENGTH];
-        (void)fits_get_errstatus(status, fitsErr);
-        psError(PS_ERR_IO, true,
-                PS_ERRORTEXT_psFits_GET_COLTYPE,
-                fitsErr);
-        return NULL;
-    }
-
-    // allocate the buffers
-    psArray* result = psArrayAlloc(numRows);
-    for (int row = 0; row < numRows; row++) {
-        result->data[row] = psAlloc((width+1)*sizeof(char));
-    }
-    result->n = numRows;
-
-    fits_read_col_str(fits->fd,
-                      colnum,
-                      1, // firstrow
-                      1, // firestelem
-                      numRows,
-                      "", // nulstr
-                      (char**)result->data,
-                      NULL,
-                      &status);
-
-    if ( status != 0) {
-        char fitsErr[MAX_STRING_LENGTH];
-        (void)fits_get_errstatus(status, fitsErr);
-        psError(PS_ERR_IO, true,
-                PS_ERRORTEXT_psFits_TABLE_READ_COL,
-                fitsErr);
-        return NULL;
-    }
-
-    return result;
-}
-
-psVector* psFitsReadTableColumnNum(const psFits* fits,
-                                   const char* colname)
-{
-    int status = 0;
-    int colnum = 0;
-
-    if (fits == NULL) {
-        psError(PS_ERR_BAD_PARAMETER_NULL, true,
-                PS_ERRORTEXT_psFits_NULL);
-        return NULL;
-    }
-
-    // check to see if we even are positioned on a table HDU
-    int hdutype;
-    if ( fits_get_hdu_type(fits->fd,&hdutype, &status) != 0) {
-        char fitsErr[MAX_STRING_LENGTH];
-        (void)fits_get_errstatus(status, fitsErr);
-        psError(PS_ERR_IO, true,
-                PS_ERRORTEXT_psFits_GET_HDU_TYPE_FAILED,
-                fitsErr);
-        return NULL;
-    }
-    if (hdutype != ASCII_TBL && hdutype != BINARY_TBL) {
-        psError(PS_ERR_IO, true,
-                PS_ERRORTEXT_psFits_NOT_TABLE_TYPE);
-        return NULL;
-    }
-
-    // find the column by name
-    if ( fits_get_colnum(fits->fd, CASESEN, (char*)colname, &colnum, &status) != 0) {
-        char fitsErr[MAX_STRING_LENGTH];
-        (void)fits_get_errstatus(status, fitsErr);
-        psError(PS_ERR_IO, true,
-                PS_ERRORTEXT_psFits_FIND_COLUMN,
-                colname, fitsErr);
-        return NULL;
-    }
-
-    // get the number of rows
-    long numRows = 0;
-    fits_get_num_rows(fits->fd,
-                      &numRows,
-                      &status);
-
-    // get the column datatype.
-    int typecode;
-    long repeat;
-    long width;
-    if ( fits_get_eqcoltype(fits->fd, colnum, &typecode, &repeat, &width, &status) != 0) {
-        char fitsErr[MAX_STRING_LENGTH];
-        (void)fits_get_errstatus(status, fitsErr);
-        psError(PS_ERR_IO, true,
-                PS_ERRORTEXT_psFits_GET_COLTYPE,
-                fitsErr);
-        return NULL;
-    }
-
-    psVector* result = psVectorAlloc(numRows, convertFitsToPsType(typecode));
-
-    fits_read_col(fits->fd,
-                  typecode,
-                  colnum,
-                  1 /* firstrow */,
-                  1 /* firstelem */,
-                  numRows,
-                  NULL,
-                  (psPtr)(result->data.U8),
-                  NULL,
-                  &status);
-
-    if ( status != 0) {
-        char fitsErr[MAX_STRING_LENGTH];
-        (void)fits_get_errstatus(status, fitsErr);
-        psError(PS_ERR_IO, true,
-                PS_ERRORTEXT_psFits_TABLE_READ_COL,
-                fitsErr);
-        return NULL;
-    }
-
-    return result;
-}
-
-
-psArray* psFitsReadTable(psFits* fits)
-{
-    int status = 0;
-
-    if (fits == NULL) {
-        psError(PS_ERR_BAD_PARAMETER_NULL, true,
-                PS_ERRORTEXT_psFits_NULL);
-        return NULL;
-    }
-
-    // check to see if we even are positioned on a table HDU
-    int hdutype;
-    if ( fits_get_hdu_type(fits->fd,&hdutype, &status) != 0) {
-        char fitsErr[MAX_STRING_LENGTH];
-        (void)fits_get_errstatus(status, fitsErr);
-        psError(PS_ERR_IO, true,
-                PS_ERRORTEXT_psFits_GET_HDU_TYPE_FAILED,
-                fitsErr);
-        return NULL;
-    }
-    if (hdutype != ASCII_TBL && hdutype != BINARY_TBL) {
-        psError(PS_ERR_IO, true,
-                PS_ERRORTEXT_psFits_NOT_TABLE_TYPE);
-        return NULL;
-    }
-
-    // get the size of the FITS table
-    long numRows = 0;
-    fits_get_num_rows(fits->fd, &numRows, &status);
-    if ( status != 0) {
-        char fitsErr[MAX_STRING_LENGTH];
-        (void)fits_get_errstatus(status, fitsErr);
-        psError(PS_ERR_IO, true,
-                PS_ERRORTEXT_psFits_GET_TABLE_SIZE_FAILED,
-                fitsErr);
-        return NULL;
-    }
-
-
-    psArray* table = psArrayAlloc(numRows);
-
-    for (int row = 0; row < numRows; row++) {
-        psTrace(".psFits.psFitsReadTable",5,"Reading row %i of %i\n",row, numRows);
-        table->data[row] = psFitsReadTableRow(fits,row);
-    }
-
-    return table;
-}
-
-bool psFitsWriteTable(psFits* fits,
-                      const psMetadata* header,
-                      const psArray* table)
-{
-    int status = 0;
-
-    if (fits == NULL) {
-        psError(PS_ERR_BAD_PARAMETER_NULL, true,
-                PS_ERRORTEXT_psFits_NULL);
-        return false;
-    }
-
-    if (table == NULL) {
-        psError(PS_ERR_BAD_PARAMETER_NULL, true,
-                PS_ERRORTEXT_psFits_IMAGE_NULL);
-        return false;
-    }
-
-    int rows = table->n;
-    if (rows < 1) {
-        // no table data, what can I do?
-        psError(PS_ERR_BAD_PARAMETER_SIZE, true,
-                PS_ERRORTEXT_psFits_TABLE_EMPTY);
-        return false;
-    }
-
-    // find all the columns needed
-    psArray* columns = psArrayAlloc(((psMetadata*)table->data[0])->list->n);
-    columns->n=0;
-
-    // find the unique items in the array of metadata 'rows'
-    psMetadataItem* item;
-    for (int row=0; row < rows; row++) {
-        psMetadata* rowMeta = table->data[row];
-        if (rowMeta != NULL) {
-            psListIterator* iter = psListIteratorAlloc(rowMeta->list,
-                                   PS_LIST_HEAD,true);
-            while ( (item=psListGetAndIncrement(iter)) != NULL) {
-                if (PS_DATA_IS_PRIMITIVE(item->type) ||
-                        item->type == PS_DATA_STRING ||
-                        item->type == PS_DATA_VECTOR) {
-                    bool found = false;
-                    psMetadataItem* fItem = NULL;
-                    int n;
-                    for (n=0; n < columns->n && ! found; n++) {
-                        fItem = (psMetadataItem*)(columns->data[n]);
-                        if (strcmp(item->name, fItem->name) == 0) {
-                            found = true;
-                            break;
-                        }
-                    }
-                    if (! found) {
-                        psArrayAdd(columns, columns->nalloc, item);
-                    } else if (item->type == PS_DATA_STRING &&
-                               strlen(fItem->data.V) < strlen(item->data.V)) {
-                        // got to keep the longest string value as to know what size to create the table column
-                        psMemDecrRefCounter(fItem);
-                        columns->data[n] = psMemIncrRefCounter(item);
-
-                    } else if (item->type == PS_DATA_VECTOR &&
-                               ((psVector*)(fItem->data.V))->n < ((psVector*)(item->data.V))->n) {
-                        psMemDecrRefCounter(fItem);
-                        columns->data[n] = psMemIncrRefCounter(item);
-                    }
-                } else {
-                    // unsupported type -- treating as an error
-                    psError(PS_ERR_BAD_PARAMETER_TYPE, true,
-                            "Unsupported data type (%d) for Metadata Item '%s' in row %d.",
-                            item->type, item->name, row);
-                    psFree(iter);
-                    psFree(columns);
-                    return false;
-                }
-            }
-            psFree(iter);
-        }
-    }
-
-    if (columns->n == 0) { // no table columns found
-        psError(PS_ERR_BAD_PARAMETER_SIZE, true,
-                "Did not find any column data to write to a table.");
-        psFree(columns);
-        return false;
-    }
-
-    //create list of column names and types.
-    psArray* columnNames = psArrayAlloc(columns->n);
-    psArray* columnTypes = psArrayAlloc(columns->n);
-    for (int n=0; n < columns->n; n++) {
-        columnNames->data[n] = psMemIncrRefCounter(((psMetadataItem*)columns->data[n])->name);
-        if ( ! getMetadataTForm((psMetadataItem*)columns->data[n],
-                                (char**)&(columnTypes->data[n]),1) ) {
-            psError(PS_ERR_UNKNOWN, true,
-                    "Failed to determine the FITS data type of '%s' (type=%d).",
-                    columnNames->data[n],
-                    ((psMetadataItem*)columns->data[n])->type);
-            psFree(columns);
-            psFree(columnNames);
-            psFree(columnTypes);
-            return false;
-        }
-    }
-
-    char* extname = NULL;
-    if (header != NULL) {
-        extname = psMetadataLookupPtr(NULL, header, "EXTNAME");
-        if ( extname == NULL) {
-            extname = psMetadataLookupPtr(NULL, header, "HDUNAME");
-        }
-    }
-
-    fits_create_tbl(fits->fd,
-                    BINARY_TBL,
-                    table->n, // number of rows in table
-                    columns->n, // number of columns in table
-                    (char**)columnNames->data, // names of the columns
-                    (char**)columnTypes->data, // format of the columns
-                    NULL, // physical unit of columns
-                    extname, // extension name
-                    &status);
-
-    psFree(columnNames);
-    psFree(columnTypes);
-
-    // fill in the table elements with data
-    for (int n = 0; n < columns->n; n++) {
-        int row;
-        item = columns->data[n];
-        if (PS_DATA_IS_PRIMITIVE(item->type) ) {
-            psVector* col = psVectorAlloc(table->n, item->type);
-            int dataSize = PSELEMTYPE_SIZEOF(item->type);
-            int dataType;
-            convertPsTypeToFits(item->type, NULL,NULL,&dataType);
-            for (row = 0; row < table->n; row++) {
-                psMetadataItem* dataItem = psMetadataLookup(
-                                               table->data[row],
-                                               item->name);
-                memcpy(&col->data.U8[row*dataSize],&dataItem->data,dataSize);
-            }
-            fits_write_col(fits->fd,
-                           dataType,
-                           n+1, // column number
-                           1, // firstrow
-                           1, // firstelem
-                           table->n, // nelements
-                           col->data.U8,
-                           &status);
-            psFree(col);
-        } else if (item->type == PS_DATA_STRING) {
-            psArray* colArray = psArrayAlloc(table->n);
-            for (row = 0; row < table->n; row++) {
-                colArray->data[row] = psMemIncrRefCounter(
-                                          psMetadataLookupStr(NULL,
-                                                              table->data[row],
-                                                              item->name));
-            }
-            fits_write_col_str(fits->fd,
-                               n+1,
-                               1,
-                               1,
-                               table->n,
-                               (char**)colArray->data,
-                               &status);
-            psFree(colArray);
-        } else if (item->type == PS_DATA_VECTOR) {
-            psVector* vec = (psVector*)(item->data.V);
-            psVector* col = psVectorAlloc(table->n*vec->n, vec->type.type);
-            int dataSize = PSELEMTYPE_SIZEOF(vec->type.type)*vec->n;
-            int dataType;
-            convertPsTypeToFits(vec->type.type, NULL,NULL,&dataType);
-            for (row = 0; row < table->n; row++) {
-                psMetadataItem* dataItem = psMetadataLookup(
-                                               table->data[row],
-                                               item->name);
-                memcpy(&col->data.U8[row*dataSize],
-                       ((psVector*)(dataItem->data.V))->data.U8,
-                       dataSize);
-            }
-            fits_write_col(fits->fd,
-                           dataType,
-                           n+1, // column number
-                           1, // firstrow
-                           1, // firstelem
-                           table->n*vec->n, // nelements
-                           col->data.U8,
-                           &status);
-            psFree(col);
-        }
-        if (status != 0) {
+                    fitsErr);
+            return false;
+        }
+
+        return true;
+    }
+
+    bool psFitsDeleteExtNum(psFits* fits,
+                            int extnum,
+                            bool relative)
+    {
+        if (fits == NULL) {
+            psError(PS_ERR_BAD_PARAMETER_NULL, true,
+                    PS_ERRORTEXT_psFits_NULL);
+            return false;
+        }
+
+        // move to the specified HDU
+        if (! psFitsMoveExtNum(fits,extnum,relative) ) {
+            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
+                    "Failed to delete HDU #%d",
+                    extnum);
+            return false;
+        }
+
+        int status = 0;
+
+        // OK, now let's delete the HDU
+        if (fits_delete_hdu(fits->fd, NULL, &status) != 0) {
             char fitsErr[MAX_STRING_LENGTH];
             (void)fits_get_errstatus(status, fitsErr);
             psError(PS_ERR_IO, true,
                     PS_ERRORTEXT_psFits_WRITE_FAILED,
-                    fits->filename, fitsErr);
-            psFree(columns);
-            return false;
-        }
-
-    }
-
-    psFree(columns);
-
-    return true;
-}
-
-bool psFitsUpdateTable(psFits* fits,
-                       const psMetadata* data,
-                       int row)
-{
-    int status = 0;
-
-    if (fits == NULL) {
-        psError(PS_ERR_BAD_PARAMETER_NULL, true,
-                PS_ERRORTEXT_psFits_NULL);
-        return false;
-    }
-
-    if (data == NULL) {
-        psError(PS_ERR_BAD_PARAMETER_NULL, true,
-                PS_ERRORTEXT_psFits_IMAGE_NULL);
-        return false;
-    }
-
-    // check to see if we even are positioned on a table HDU
-    int hdutype;
-    if ( fits_get_hdu_type(fits->fd,&hdutype, &status) != 0) {
-        char fitsErr[MAX_STRING_LENGTH];
-        (void)fits_get_errstatus(status, fitsErr);
-        psError(PS_ERR_IO, true,
-                PS_ERRORTEXT_psFits_GET_HDU_TYPE_FAILED,
-                fitsErr);
-        return false;
-    }
-    if (hdutype != ASCII_TBL && hdutype != BINARY_TBL) {
-        psError(PS_ERR_IO, true,
-                PS_ERRORTEXT_psFits_NOT_TABLE_TYPE);
-        return false;
-    }
-
-    psMetadataIterator* iter = psMetadataIteratorAlloc((psPtr)data,PS_LIST_HEAD,NULL);
-
-    psMetadataItem* item;
-
-    while ( (item=psMetadataGetAndIncrement(iter)) != NULL) {
-        if (PS_DATA_IS_PRIMITIVE(item->type) ||
-                item->type == PS_DATA_BOOL ||
-                item->type == PS_DATA_STRING) {
-            // operating on primitive data type or string, i.e., not a complex object
-            int colnum = 0;
-
-            if ( fits_get_colnum(fits->fd, CASESEN, item->name, &colnum, &status) == 0) {
-                // cooresponding column found in table
-                int dataType;
-                convertPsTypeToFits(item->type, NULL, NULL, &dataType);
-
-                if (fits_write_col(fits->fd, dataType, colnum, row+1, 1, 1, &item->data,&status) != 0) {
-                    char fitsErr[MAX_STRING_LENGTH];
-                    (void)fits_get_errstatus(status, fitsErr);
-                    psError(PS_ERR_IO, true,
-                            PS_ERRORTEXT_psFits_WRITE_FAILED,
-                            fits->filename, fitsErr);
-                    psFree(iter);
-                    return false;
-                }
-            } else {
-                // the column was not found.
-                psWarning("No column with the name '%s' exists in the table.",
-                          item->name);
-            }
-        }
-    }
-
-    psFree(iter);
-
-    return true;
-}
+                    fitsErr);
+            return false;
+        }
+
+        return true;
+    }
+
+    bool psFitsDeleteExtName(psFits* fits,
+                             const char* extname)
+    {
+        if (fits == NULL) {
+            psError(PS_ERR_BAD_PARAMETER_NULL, true,
+                    PS_ERRORTEXT_psFits_NULL);
+            return false;
+        }
+
+        // move to the specified HDU
+        if (! psFitsMoveExtName(fits,extname) ) {
+            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
+                    "Failed to delete HDU with the name '%s'",
+                    extname);
+            return false;
+        }
+
+
+        int status = 0;
+
+        // OK, now let's delete the HDU
+        if (fits_delete_hdu(fits->fd, NULL, &status) != 0) {
+            char fitsErr[MAX_STRING_LENGTH];
+            (void)fits_get_errstatus(status, fitsErr);
+            psError(PS_ERR_IO, true,
+                    PS_ERRORTEXT_psFits_WRITE_FAILED,
+                    fitsErr);
+            return false;
+        }
+
+        return true;
+    }
+
+    int psFitsGetSize(const psFits* fits)
+    {
+        if (fits == NULL) {
+            psError(PS_ERR_BAD_PARAMETER_NULL, true,
+                    PS_ERRORTEXT_psFits_NULL);
+            return 0;
+        }
+
+        int num = 0;
+        int status = 0;
+
+        if (fits_get_num_hdus(fits->fd, &num, &status) != 0) {
+            char fitsErr[MAX_STRING_LENGTH];
+            fits_get_errstatus(status, fitsErr);
+            psError(PS_ERR_LOCATION_INVALID, true,
+                    PS_ERRORTEXT_psFits_GETNUMHDUS_FAILED,
+                    fitsErr);
+            return 0;
+        }
+
+        return num;
+    }
+
+    psFitsType psFitsGetExtType(const psFits* fits)
+    {
+        if (fits == NULL) {
+            psError(PS_ERR_BAD_PARAMETER_NULL, true,
+                    PS_ERRORTEXT_psFits_NULL);
+            return PS_FITS_TYPE_NONE;
+        }
+
+        int status = 0;
+        int hdutype = PS_FITS_TYPE_NONE;
+
+        if (fits_get_hdu_type(fits->fd, &hdutype, &status) != 0) {
+            char fitsErr[MAX_STRING_LENGTH];
+            fits_get_errstatus(status, fitsErr);
+            psError(PS_ERR_LOCATION_INVALID, true,
+                    PS_ERRORTEXT_psFits_GETHDUTYPE_FAILED,
+                    fitsErr);
+            return PS_FITS_TYPE_NONE;
+        }
+
+        if (hdutype == PS_FITS_TYPE_IMAGE &&
+                psFitsGetExtNum(fits) > 0 &&
+                isHDUEmpty(fits)) {
+            return PS_FITS_TYPE_ANY;
+        }
+
+        return hdutype;
+    }
+
+    bool psFitsTruncate(psFits* fits)
+    {
+        if (fits == NULL) {
+            psError(PS_ERR_BAD_PARAMETER_NULL, true,
+                    PS_ERRORTEXT_psFits_NULL);
+            return PS_FITS_TYPE_NONE;
+        }
+
+        int newEnd = psFitsGetExtNum(fits);
+
+        psFitsMoveLast(fits);
+        int end = psFitsGetExtNum(fits);
+
+        // delete HDUs from end to beginning position + 1;
+        for (int lcv=end;lcv > newEnd; lcv--) {
+            if (! psFitsDeleteExtNum(fits,lcv,false)) {
+                // failed to delete an HDU!?
+                psError(PS_ERR_UNKNOWN, false,
+                        "Failed to truncate file.  HDU #%d out of %d could not be deleted.",
+                        lcv,end);
+                return false;
+            }
+        }
+
+        return true;
+    }
Index: trunk/psLib/src/fits/psFits.h
===================================================================
--- trunk/psLib/src/fits/psFits.h	(revision 5217)
+++ trunk/psLib/src/fits/psFits.h	(revision 5511)
@@ -7,6 +7,6 @@
  *  @author Robert DeSonia, MHPCC
  *
- *  @version $Revision: 1.21 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2005-09-15 21:22:21 $
+ *  @version $Revision: 1.22 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2005-11-14 22:18:30 $
  *
  *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
@@ -16,5 +16,5 @@
 #define PS_FITS_H
 
-#include<fitsio.h>
+#include <fitsio.h>
 
 #include "psType.h"
@@ -49,6 +49,4 @@
 {
     fitsfile* fd;                      ///< the CFITSIO fits files handle.
-    const char* filename;              ///< the filename of the fits file
-    bool writable;                     ///< Is the file writable?
 }
 psFits;
@@ -59,13 +57,30 @@
  *                     NULL if the open of the FITS file failed
  */
-psFits* psFitsAlloc(
-    const char* name                   ///< the FITS file name
+psFits* psFitsOpen(
+    const char* filename,              ///< the FITS file name
+    const char* mode
+    /**< File open mode. Could be one of the following:
+     *       'r' (read only),
+     *       'r+' (read & write),
+     *       'rw' (same as 'r+'), or
+     *       'w' (create new file for writing)
+     */
+);
+
+/** Closes a FITS file.
+ *
+ *  @return bool      TRUE if FITS file was successfully closed, otherwise FALSE
+ */
+bool psFitsClose(
+    psFits* fits                       ///< psFits object to close
 );
 
 /** Checks the type of a particular pointer.
  *
- *  Uses the appropriate deallocation function in psMemBlock to check the ptr datatype.
+ *  Uses the appropriate deallocation function in psMemBlock to check the ptr
+ *  datatype.
  *
- *  @return bool:       True if the pointer matches a psFits structure, false otherwise.
+ *  @return bool:       True if the pointer matches a psFits structure, false
+ *                      otherwise.
  */
 bool psMemCheckFits(
@@ -76,5 +91,6 @@
 /** Moves the FITS HDU to the specified extension name.
  *
- *  @return psFitsType    The HDU type, or PS_FITS_TYPE_NONE if move failed.
+ *  @return bool        TRUE if the extension name was found and move was
+ *                      successful, otherwise FALSE
  */
 bool psFitsMoveExtName(
@@ -85,5 +101,6 @@
 /** Moves the FITS HDU to the specified extension number
  *
- *  @return psFitsType    The HDU type, or PS_FITS_TYPE_NONE if move failed.
+ *  @return bool        TRUE if the extension number was found and move was
+ *                      successful, otherwise FALSE
  */
 bool psFitsMoveExtNum(
@@ -91,4 +108,12 @@
     int extnum,                        ///< the extension number to move to (zero is primary HDU)
     bool relative                      ///< if true, extnum is a relative number to the current position
+);
+
+/** Moves the FITS HDU to the end of the file
+ *
+ *  @return bool        TRUE if the move was successful, otherwise FALSE
+*/
+bool psFitsMoveLast(
+    const psFits* fits                 ///< the psFits object to move
 );
 
@@ -129,4 +154,23 @@
 );
 
+/** Remove the an HDU as specified by number
+ *
+ *  @return bool        TRUE if the specified HDU was removed, otherwise FALSE
+ */
+bool psFitsDeleteExtNum(
+    psFits* fits,                      ///< the psFits object
+    int extnum,                        ///< the extension number to delete (zero is primary HDU)
+    bool relative                      ///< if true, extnum is a relative number to the current position
+);
+
+/** Remove the an HDU as specified by extension name
+ *
+ *  @return bool        TRUE if the specified HDU was removed, otherwise FALSE
+ */
+bool psFitsDeleteExtName(
+    psFits* fits,                      ///< the psFits object
+    const char* extname                ///< the extension name to delete
+);
+
 /** Get the extension type of the current HDU.
  *
@@ -138,141 +182,10 @@
 );
 
-/** Reads the header of the current HDU.
+/** Delete all extensions after the current position
  *
- *  @return psMetadata*   the header data
+ *  @return bool        TRUE if the operation was successful, otherwise FALSE
  */
-psMetadata* psFitsReadHeader(
-    psMetadata* out,
-    ///< The psMetadata to add the header data.  If null, a new psMetadata is created.
-
-    const psFits* fits                 ///< the psFits object
-);
-
-/** Reads the header of all HDUs.  The current HDU is not changed.
- *
- *  @return psMetadata*      the header data set as a number of metadata entries
- */
-psMetadata* psFitsReadHeaderSet(
-    psMetadata* out,
-    ///< The psMetadata to add the header data via psMetadata items.  If null, a
-    ///< new psMetadata is created.  The keys of the psMetadata are the extension names
-    ///< of the cooresponding HDUs.
-
-    const psFits* fits                       ///< the psFits object
-);
-
-/** Writes the values of the metadata to the current HDU header.
- *
- *  @return bool        if TRUE, the write was successful, otherwise FALSE.
- */
-bool psFitsWriteHeader(
-    const psMetadata* output,          ///< the psMetadata data in which to write
+bool psFitsTruncate(
     psFits* fits                       ///< the psFits object
-);
-
-/** Reads an image, given the desired region and z-plane.
- *
- *  @return psImage*     the read image or NULL if there was an error.
- */
-psImage* psFitsReadImage(
-    psImage* out,                      ///< a psImage to recycle.
-    const psFits* fits,                ///< the psFits object
-    psRegion region,                   ///< the region in the FITS image to read
-    int z                              ///< the z-plane in the FITS image cube to read
-);
-
-/** Writes an image, given the desired region and z-plane.
- *
- *  @return bool        TRUE is the write was successful, otherwise FALSE.
- */
-bool psFitsWriteImage(
-    psFits* fits,                      ///< the psFits object
-    psMetadata* header,                ///< header items for the new HDU.  Can be NULL.
-    const psImage* input,              ///< the image to output
-    int depth                          ///< the number of z-planes of the FITS image data cube
-);
-
-/** Updates the FITS file image, given the desired region and z-plane.
- *
- *  @return bool        TRUE is the write was successful, otherwise FALSE.
- */
-bool psFitsUpdateImage(
-    psFits* fits,                      ///< the psFits object
-    const psImage* input,              ///< the image to output
-    psRegion region,                   ///< the region in the FITS image to write
-    int z                              ///< the z-planes of the FITS image data cube to write
-);
-
-/** Reads a table row.  The current HDU type must be either
- *  PS_FITS_TYPE_BINARY_TABLE or PS_FITS_TYPE_ASCII_TABLE.
- *
- *  @return psMetadata*    The table row's data.  The keys are the column names.
- */
-psMetadata* psFitsReadTableRow(
-    const psFits* fits,                ///< the psFits object
-    int row                            ///< row number to read
-);
-
-/** Reads a table column.  The current HDU type must be either
- *  PS_FITS_TYPE_BINARY_TABLE or PS_FITS_TYPE_ASCII_TABLE.
- *
- *  @return psArray*    Array of data items for the specified column or NULL
- *                      if an error occurred.
- */
-psArray* psFitsReadTableColumn(
-    const psFits* fits,                ///< the psFits object
-    const char* colname                ///< the column name
-);
-
-/** Reads a table column of numbers.  The current HDU type must be either
- *  PS_FITS_TYPE_BINARY_TABLE or PS_FITS_TYPE_ASCII_TABLE.
- *
- *  @return psVector*    Vector of data for the specified column or NULL
- *                       if an error occurred.
- */
-psVector* psFitsReadTableColumnNum(
-    const psFits* fits,                ///< the psFits object
-    const char* colname                ///< the column name
-);
-
-
-/** Reads a whole FITS table.  The current HDU type must be either
- *  PS_FITS_TYPE_BINARY_TABLE or PS_FITS_TYPE_ASCII_TABLE.
- *
- *  @return psArray*     Array of psMetadata items, which contains the output
- *                       data items of each row.
- *
- *  @see psFitsReadTableRow
- */
-psArray* psFitsReadTable(
-    psFits* fits                       ///< the psFits object
-);
-
-/** Writes a whole FITS table.  The current HDU type must be either
- *  PS_FITS_TYPE_BINARY_TABLE or PS_FITS_TYPE_ASCII_TABLE.
- *
- *  @return bool        TRUE if the write was successful, otherwise FALSE
- *
- *  @see psFitsReadTableRow
- */
-bool psFitsWriteTable(
-    psFits* fits,                      ///< the psFits object
-    const psMetadata* header,          ///< header items for the new HDU.  Can be NULL.
-    const psArray* table
-    ///< Array of psMetadata items, which contains the output data items of each row.
-);
-
-/** Updates a FITS table.  The current HDU type must be either
- *  PS_FITS_TYPE_BINARY_TABLE or PS_FITS_TYPE_ASCII_TABLE.
- *
- *  @return bool        TRUE if the write was successful, otherwise FALSE
- *
- *  @see psFitsWriteTable
- */
-bool psFitsUpdateTable(
-    psFits* fits,                ///< the psFits object
-    const psMetadata* data,
-    ///< Array of psMetadata items, which contains the output data items of each row.
-    int row                            ///< the row number to update.
 );
 
Index: trunk/psLib/src/fits/psFitsHeader.c
===================================================================
--- trunk/psLib/src/fits/psFitsHeader.c	(revision 5511)
+++ trunk/psLib/src/fits/psFitsHeader.c	(revision 5511)
@@ -0,0 +1,303 @@
+/** @file  psFitsHeader.c
+ *
+ *  @brief Contains Fits header I/O routines
+ *
+ *  @ingroup FileIO
+ *
+ *  @author Robert DeSonia, MHPCC
+ *
+ *  @version $Revision: 1.1 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2005-11-14 22:18:30 $
+ *
+ *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
+ */
+
+#include <unistd.h>
+
+#include "psFits.h"
+#include "string.h"
+#include "psError.h"
+#include "psErrorText.h"
+#include "psImageStructManip.h"
+#include "psMemory.h"
+#include "psString.h"
+#include "psLogMsg.h"
+#include "psTrace.h"
+#include "psVector.h"
+
+#define MAX_STRING_LENGTH 256  // maximum length string for FITS routines
+
+// list of FITS header keys to ignore.
+static char* standardFitsKeys[] = {
+                                      NULL
+                                  };
+
+psMetadata* psFitsReadHeader(psMetadata* out,
+                             const psFits* fits)
+{
+    if (fits == NULL) {
+        psError(PS_ERR_BAD_PARAMETER_NULL, true,
+                PS_ERRORTEXT_psFits_NULL);
+        return NULL;
+    }
+
+    if (out == NULL) {
+        out = psMetadataAlloc();
+        if (out == NULL) {
+            psError(PS_ERR_UNKNOWN, false,
+                    "Failed to allocate a new psMetadata container.");
+            return NULL;
+        }
+    }
+
+    // Get number of key names
+    int numKeys = 0;
+    int keyNum = 0;
+    int status = 0;
+    fits_get_hdrpos(fits->fd, &numKeys, &keyNum, &status);
+
+    // Get each key name. Keywords start at one.
+    char keyType;
+    char keyName[MAX_STRING_LENGTH];
+    char keyValue[MAX_STRING_LENGTH];
+    char keyComment[MAX_STRING_LENGTH];
+    psBool tempBool;
+    psBool success;
+    psBool stdKey;
+    for (int i = 1; i <= numKeys; i++) {
+
+        fits_read_keyn(fits->fd, i, keyName, keyValue, keyComment, &status);
+
+        stdKey = false;
+
+        int stdKeyIdx = 0;
+        while (standardFitsKeys[stdKeyIdx] != NULL && ! stdKey) {
+            if (strcmp(keyName,standardFitsKeys[stdKeyIdx++]) == 0) {
+                stdKey = true;
+            }
+        }
+
+        if (keyValue[0] != 0) { // blank values are not handled by fits_get_keytype
+            fits_get_keytype(keyValue, &keyType, &status);
+        } else {
+            keyType = 'C';
+        }
+        if (status != 0) {
+            break;
+        }
+
+        if (! stdKey) {
+            switch (keyType) {
+            case 'X': // bit
+            case 'I': // short int.
+            case 'J': // int.
+            case 'B': // byte
+                success = psMetadataAdd(out,
+                                        PS_LIST_TAIL,
+                                        keyName,
+                                        PS_DATA_S32 | PS_META_DUPLICATE_OK,
+                                        keyComment,
+                                        atoi(keyValue));
+                break;
+            case 'U': // unsigned int. may not fit in a psS32
+            case 'K': // long int. can't all fit in a psS32
+            case 'F':
+                success = psMetadataAdd(out,
+                                        PS_LIST_TAIL,
+                                        keyName,
+                                        PS_DATA_F64 | PS_META_DUPLICATE_OK,
+                                        keyComment,
+                                        atof(keyValue));
+                break;
+            case 'C':
+                // remove the single-quotes at front/end
+                if (keyValue[0] == '\'' && keyValue[strlen(keyValue)-1] == '\'') {
+                    keyValue[strlen(keyValue)-1] = '\0';
+                    success = psMetadataAdd(out,
+                                            PS_LIST_TAIL,
+                                            keyName,
+                                            PS_DATA_STRING | PS_META_DUPLICATE_OK,
+                                            keyComment,
+                                            keyValue+1);
+                } else {
+                    success = psMetadataAdd(out,
+                                            PS_LIST_TAIL,
+                                            keyName,
+                                            PS_DATA_STRING | PS_META_DUPLICATE_OK,
+                                            keyComment,
+                                            keyValue);
+                }
+                break;
+            case 'L':
+                tempBool = (keyValue[0] == 'T') ? 1 : 0;
+                success = psMetadataAdd(out,
+                                        PS_LIST_TAIL,
+                                        keyName,
+                                        PS_DATA_BOOL | PS_META_DUPLICATE_OK,
+                                        keyComment,
+                                        tempBool);
+                break;
+            default:
+                psError(PS_ERR_IO, true,
+                        PS_ERRORTEXT_psFits_METATYPE_INVALID,
+                        keyType);
+                return out;
+            }
+
+            if (!success) {
+                psError(PS_ERR_UNKNOWN, false,
+                        PS_ERRORTEXT_psFits_METADATA_ADD_FAILED,
+                        keyName);
+                return out;
+            }
+        }
+
+    }
+
+    if ( status != 0) {
+        char fitsErr[MAX_STRING_LENGTH];
+        (void)fits_get_errstatus(status, fitsErr);
+        psError(PS_ERR_IO, true,
+                PS_ERRORTEXT_psFits_METADATA_ADD_FAILED,
+                fitsErr);
+        return false;
+    }
+
+    return out;
+}
+
+psMetadata* psFitsReadHeaderSet(psMetadata* out,
+                                const psFits* fits)
+{
+    if (fits == NULL) {
+        psError(PS_ERR_BAD_PARAMETER_NULL, true,
+                PS_ERRORTEXT_psFits_NULL);
+        psFree(out);
+        return NULL;
+    }
+
+    if (out == NULL) {
+        out = psMetadataAlloc();
+        if (out == NULL) {
+            psError(PS_ERR_UNKNOWN, false,
+                    "Failed to allocate a new psMetadata container.");
+            return NULL;
+        }
+    }
+
+    int size = psFitsGetSize(fits);
+
+    int origPosition = psFitsGetExtNum(fits);
+
+    for (int lcv=0; lcv < size; lcv++) {
+        psFitsMoveExtNum(fits, lcv, false);
+
+        char* name = NULL;
+        if (lcv == 0) {
+            name = psStringCopy("PHU");
+        } else {
+            name = psFitsGetExtName(fits);
+        }
+
+        psMetadata* header = psFitsReadHeader(NULL, fits);
+        if (name != NULL && header != NULL) {
+            psMetadataAddMetadata(out, PS_LIST_HEAD, name, 0, "FITS Header",
+                                  header);
+        } else {
+            psWarning("Failed to read HDU#%d header data.",
+                      lcv);
+        }
+
+        psFree(name);
+        psFree(header);
+    }
+
+    // reposition to the original position
+    psFitsMoveExtNum(fits, origPosition, false);
+
+    return out;
+}
+
+bool psFitsWriteHeader(const psMetadata* output,
+                       psFits* fits)
+{
+
+    if (fits == NULL) {
+        psError(PS_ERR_BAD_PARAMETER_NULL, true,
+                PS_ERRORTEXT_psFits_NULL);
+        return false;
+    }
+
+    if (output == NULL) {
+        psError(PS_ERR_BAD_PARAMETER_NULL, true,
+                PS_ERRORTEXT_psFits_METADATA_NULL);
+        return false;
+    }
+
+    int status = 0;
+
+    //transverse the metadata list and add each key.
+
+    psListIterator* iter = psListIteratorAlloc(output->list,PS_LIST_HEAD,true);
+    psMetadataItem* item;
+    while ( (item=psListGetAndIncrement(iter)) != NULL ) {
+        switch (item->type) {
+        case PS_DATA_BOOL: {
+                int value = item->data.B;
+                fits_update_key(fits->fd,
+                                TLOGICAL,
+                                item->name,
+                                &value,
+                                item->comment,
+                                &status);
+                break;
+            }
+        case PS_DATA_S32:
+            fits_update_key(fits->fd,
+                            TINT,
+                            item->name,
+                            &item->data.S32,
+                            item->comment,
+                            &status);
+            break;
+        case PS_DATA_F32:
+            fits_update_key(fits->fd,
+                            TFLOAT,
+                            item->name,
+                            &item->data.F32,
+                            item->comment,
+                            &status);
+            break;
+        case PS_DATA_F64:
+            fits_update_key(fits->fd,
+                            TDOUBLE,
+                            item->name,
+                            &item->data.F64,
+                            item->comment,
+                            &status);
+            break;
+        case PS_DATA_STRING:
+            fits_update_key(fits->fd,
+                            TSTRING,
+                            item->name,
+                            item->data.V,
+                            item->comment,
+                            &status);
+            break;
+        default:  // all other META types are ignored
+            break;
+        }
+
+        if ( status != 0) {
+            char fitsErr[MAX_STRING_LENGTH];
+            (void)fits_get_errstatus(status, fitsErr);
+            psError(PS_ERR_IO, true,
+                    PS_ERRORTEXT_psFits_WRITE_FAILED,
+                    fitsErr);
+            return false;
+        }
+    }
+
+    return true;
+}
+
Index: trunk/psLib/src/fits/psFitsHeader.h
===================================================================
--- trunk/psLib/src/fits/psFitsHeader.h	(revision 5511)
+++ trunk/psLib/src/fits/psFitsHeader.h	(revision 5511)
@@ -0,0 +1,79 @@
+/** @file  psFitsHeader.h
+ *
+ *  @brief Contains Fits header I/O routines
+ *
+ *  @ingroup FileIO
+ *
+ *  @author Robert DeSonia, MHPCC
+ *
+ *  @version $Revision: 1.1 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2005-11-14 22:18:30 $
+ *
+ *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
+ */
+
+#ifndef PS_FITSHEADER_H
+#define PS_FITSHEADER_H
+
+#include "psFits.h"
+#include "psMetadata.h"
+
+/// @addtogroup FileIO
+/// @{
+
+/** Reads the header of the current HDU.
+ *
+ *  @return psMetadata*   the header data
+ */
+psMetadata* psFitsReadHeader(
+    psMetadata* out,
+    ///< The psMetadata to add the header data.  If null, a new psMetadata is created.
+    const psFits* fits                 ///< the psFits object
+);
+
+/** Reads the header of all HDUs.  The current HDU is not changed.
+ *
+ *  @return psMetadata*      the header data set as a number of metadata entries
+ */
+psMetadata* psFitsReadHeaderSet(
+    psMetadata* out,
+    ///< The psMetadata to add the header data via psMetadata items.  If null, a
+    ///< new psMetadata is created.  The keys of the psMetadata are the extension names
+    ///< of the cooresponding HDUs.
+
+    const psFits* fits                       ///< the psFits object
+);
+
+/** Writes the values of the metadata to the current HDU header.
+ *
+ *  @return bool        if TRUE, the write was successful, otherwise FALSE.
+ */
+bool psFitsWriteHeader(
+    const psMetadata* output,          ///< the psMetadata data in which to write
+    psFits* fits                       ///< the psFits object
+);
+
+/** Updates the given header to be compatible with the supplied image, updating
+ *  BITPIX, NAXIS1, and NAXIS2.  The extension name is (re)set to the given
+ *  extname.
+ *
+ *  @return psMetadata*     updated header.
+ */
+psMetadata* psFitsHeaderFromImage(
+    psMetadata* header,                ///< the header to update
+    psImage* image,                    ///< the image to use to determine update values
+    const char* extname                ///< the extension name
+);
+
+/** Updates the given header to be compatible with the given table, i.e. psArray
+ *  of psMetadata. The extension name is (re)set to the given extname.
+ */
+psMetadata* psFitsHeaderFromTable(
+    psMetadata* header,                ///< the header to update
+    psArray* table,                    ///< the table to use to update header
+    const char* extname                ///< the extension name
+);
+
+/// @}
+
+#endif // #ifndef PS_FITS_H
Index: trunk/psLib/src/fits/psFitsImage.c
===================================================================
--- trunk/psLib/src/fits/psFitsImage.c	(revision 5511)
+++ trunk/psLib/src/fits/psFitsImage.c	(revision 5511)
@@ -0,0 +1,515 @@
+/** @file  psFitsImage.c
+ *
+ *  @brief Contains Fits I/O routines
+ *
+ *  @ingroup FileIO
+ *
+ *  @author Robert DeSonia, MHPCC
+ *
+ *  @version $Revision: 1.1 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2005-11-14 22:18:30 $
+ *
+ *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
+ */
+
+#include <unistd.h>
+
+#include "psFits.h"
+#include "string.h"
+#include "psError.h"
+#include "psErrorText.h"
+#include "psImageStructManip.h"
+#include "psMemory.h"
+#include "psString.h"
+#include "psLogMsg.h"
+#include "psTrace.h"
+#include "psVector.h"
+
+#include "psFitsHeader.h"
+
+#define MAX_STRING_LENGTH 256  // maximum length string for FITS routines
+
+
+static bool convertPsTypeToFits(int type, int* bitPix, double* bZero, int* dataType)
+{
+
+    int bitpix;
+    int datatype;
+    double bzero = 0.0;
+
+    switch (type) {
+
+    case PS_TYPE_U8:
+        bitpix = BYTE_IMG;
+        datatype = TBYTE;
+        break;
+
+    case PS_TYPE_S8:
+        bitpix = BYTE_IMG;
+        bzero = INT8_MIN;
+        datatype = TSBYTE;
+        break;
+
+    case PS_TYPE_U16:
+        bitpix = SHORT_IMG;
+        bzero = -1.0 * INT16_MIN;
+        datatype = TUSHORT;
+        break;
+
+    case PS_TYPE_S16:
+        bitpix = SHORT_IMG;
+        datatype = TSHORT;
+        break;
+
+    case PS_TYPE_U32:
+        bitpix = LONG_IMG;
+        bzero = -1.0 * INT32_MIN;
+        datatype = TUINT;
+        break;
+
+    case PS_TYPE_S32:
+        bitpix = LONG_IMG;
+        datatype = TINT;
+        break;
+
+    case PS_TYPE_F32:
+        bitpix = FLOAT_IMG;
+        datatype = TFLOAT;
+        break;
+
+    case PS_TYPE_F64:
+        bitpix = DOUBLE_IMG;
+        datatype = TDOUBLE;
+        break;
+
+    case PS_DATA_STRING:
+        bitpix = BYTE_IMG;
+        datatype = TSTRING;
+        break;
+
+    case PS_DATA_BOOL:
+        bitpix = BYTE_IMG;
+        datatype = TLOGICAL;
+        break;
+
+    default: {
+            char* typeStr;
+            PS_TYPE_NAME(typeStr,type);
+            psError(PS_ERR_BAD_PARAMETER_TYPE, true,
+                    PS_ERRORTEXT_psFits_TYPE_UNSUPPORTED,
+                    typeStr);
+            return false;
+        }
+    }
+
+    // pass the requested parameters  (NULL parameters are not set, of course).
+    if (bitPix != NULL) {
+        *bitPix = bitpix;
+    }
+
+    if (dataType != NULL) {
+        *dataType = datatype;
+    }
+
+    if (bZero != NULL) {
+        *bZero = bzero;
+    }
+
+    return true;
+}
+
+psImage* psFitsReadImage(psImage* output, // a psImage to recycle.
+                         const psFits* fits,    // the psFits object
+                         psRegion region, // the region in the FITS image to read
+                         int z)           // the z-plane in the FITS image cube to read
+{
+    psS32 status = 0;           /* CFITSIO file vars */
+    psS32 nAxis = 0;
+    psS32 anynull = 0;
+    psS32 bitPix = 0;           /* Pixel type */
+    long nAxes[3];
+    long firstPixel[3];         /* lower-left corner of image subset */
+    long lastPixel[3];          /* upper-right corner of image subset */
+    long increment[3];          /* increment for image subset */
+    char fitsErr[80] = "";      /* CFITSIO error message string */
+    psS32 fitsDatatype = 0;
+    psS32 datatype = 0;
+
+    if (fits == NULL) {
+        psError(PS_ERR_BAD_PARAMETER_NULL, true,
+                PS_ERRORTEXT_psFits_NULL);
+        psFree(output);
+        return NULL;
+    }
+
+    // check to see if we even are positioned on an image HDU
+    int hdutype;
+    if ( fits_get_hdu_type(fits->fd,&hdutype, &status) != 0) {
+        char fitsErr[MAX_STRING_LENGTH];
+        (void)fits_get_errstatus(status, fitsErr);
+        psError(PS_ERR_IO, true,
+                PS_ERRORTEXT_psFits_GET_HDU_TYPE_FAILED,
+                fitsErr);
+        return NULL;
+    }
+    if (hdutype != IMAGE_HDU) {
+        psError(PS_ERR_IO, true,
+                PS_ERRORTEXT_psFits_NOT_IMAGE_TYPE);
+        return NULL;
+    }
+
+    /* Get the data type 'bitPix' from the FITS image */
+    if (fits_get_img_equivtype(fits->fd, &bitPix, &status) != 0) {
+        fits_get_errstatus(status, fitsErr);
+        psError(PS_ERR_IO, true,
+                PS_ERRORTEXT_psFits_DATATYPE_UNKNOWN,
+                fitsErr);
+        psFree(output);
+        return NULL;
+    }
+
+    /* Get the dimensions 'nAxis' from the FITS image */
+    if (fits_get_img_dim(fits->fd, &nAxis, &status) != 0) {
+        (void)fits_get_errstatus(status, fitsErr);
+        psError(PS_ERR_IO, true,
+                PS_ERRORTEXT_psFits_IMAGE_DIM_UNKNOWN,
+                fitsErr);
+        psFree(output);
+        return NULL;
+    }
+
+    /* Validate the number of axis */
+    if ((nAxis < 2) || (nAxis > 3)) {
+        psError(PS_ERR_IO, true,
+                PS_ERRORTEXT_psFits_IMAGE_DIMENSION_UNSUPPORTED,
+                nAxis);
+        psFree(output);
+        return NULL;
+    }
+
+    /* Get the Image size from the FITS file */
+    if (fits_get_img_size(fits->fd, nAxis, nAxes, &status) != 0) {
+        (void)fits_get_errstatus(status, fitsErr);
+        psError(PS_ERR_IO, true,
+                PS_ERRORTEXT_psFits_IMAGE_SIZE_UNKNOWN,
+                fitsErr);
+        psFree(output);
+        return NULL;
+    }
+
+    firstPixel[0] = region.x0 + 1;
+    firstPixel[1] = region.y0 + 1;
+    firstPixel[2] = z + 1;
+
+    if (region.x1 > 0) {
+        lastPixel[0] = region.x1;
+    } else {
+        lastPixel[0] = nAxes[0] + region.x1; // n.b., region.x1 < 0
+    }
+    if (region.y1 > 0) {
+        lastPixel[1] = region.y1;
+    } else {
+        lastPixel[1] = nAxes[1] + region.y1; // n.b., region.y1 < 0
+    }
+    lastPixel[2] = z + 1;
+
+    increment[0] = 1;
+    increment[1] = 1;
+    increment[2] = 1;
+
+    switch (bitPix) {
+    case BYTE_IMG:
+        datatype = PS_TYPE_U8;
+        fitsDatatype = TBYTE;
+        break;
+    case SBYTE_IMG:
+        datatype = PS_TYPE_S8;
+        fitsDatatype = TSBYTE;
+        break;
+    case USHORT_IMG:
+        datatype = PS_TYPE_U16;
+        fitsDatatype = TUSHORT;
+        break;
+    case SHORT_IMG:
+        datatype = PS_TYPE_S16;
+        fitsDatatype = TSHORT;
+        break;
+    case ULONG_IMG:
+        datatype = PS_TYPE_U32;
+        fitsDatatype = TUINT;
+        break;
+    case LONG_IMG:
+        datatype = PS_TYPE_S32;
+        fitsDatatype = TINT;
+        break;
+    case LONGLONG_IMG:
+        datatype = PS_TYPE_S64;
+        fitsDatatype = TLONGLONG;
+        break;
+    case FLOAT_IMG:
+        datatype = PS_TYPE_F32;
+        fitsDatatype = TFLOAT;
+        break;
+    case DOUBLE_IMG:
+        datatype = PS_TYPE_F64;
+        fitsDatatype = TDOUBLE;
+        break;
+    default:
+        psError(PS_ERR_IO, true,
+                PS_ERRORTEXT_psFits_FITS_TYPE_UNSUPPORTED,
+                bitPix);
+        psFree(output);
+        return NULL;
+    }
+
+    output = psImageRecycle(output,
+                            lastPixel[0]-firstPixel[0]+1,
+                            lastPixel[1]-firstPixel[1]+1,
+                            datatype);
+
+    if (output == NULL) {
+        psError(PS_ERR_UNKNOWN, false,
+                "Failed to allocate a properly sized image.");
+        return false;
+    }
+
+    // n.b., this assumes contiguous image buffer
+    if (fits_read_subset(fits->fd, fitsDatatype, firstPixel, lastPixel, increment,
+                         NULL, output->data.V[0], &anynull, &status) != 0) {
+        psFree(output);
+        (void)fits_get_errstatus(status, fitsErr);
+        psError(PS_ERR_IO, true,
+                PS_ERRORTEXT_psFits_READ_FAILED,
+                fitsErr);
+        return NULL;
+    }
+
+    return output;
+
+}
+
+bool psFitsWriteImage(psFits* fits,
+                      psMetadata* header,
+                      const psImage* input,
+                      int numZPlanes)
+{
+
+    if (fits == NULL) {
+        psError(PS_ERR_BAD_PARAMETER_NULL, true,
+                PS_ERRORTEXT_psFits_NULL);
+        return false;
+    }
+
+    if (input == NULL) {
+        psError(PS_ERR_BAD_PARAMETER_NULL, true,
+                PS_ERRORTEXT_psFits_IMAGE_NULL);
+        return false;
+    }
+    int numCols = input->numCols;
+    int numRows = input->numRows;
+
+    int status = 0;
+
+    // determine the FITS-equivalent parameters
+    int bitPix;
+    double bZero;
+    int dataType;
+    if (! convertPsTypeToFits(input->type.type, &bitPix, &bZero, &dataType) ) {
+        return false;
+    }
+
+    int naxis = 3;
+    long naxes[3];
+
+    naxes[0] = numCols;
+    naxes[1] = numRows;
+    naxes[2] = numZPlanes;
+
+    if (numZPlanes < 2) {
+        naxis = 2;
+    }
+
+    fits_create_img(fits->fd, bitPix, naxis, naxes, &status);
+
+    if (bZero != 0) {        // set the bscale/bzero
+        fits_write_key_dbl(fits->fd, "BZERO", bZero, 12, "Pixel Value Offset", &status);
+        fits_write_key_dbl(fits->fd, "BSCALE", 1.0, 12, "Pixel Value Scale", &status);
+        fits_set_bscale(fits->fd, 1.0, bZero, &status);
+    }
+
+    // write the header, if any.
+    if (header != NULL) {
+        psFitsWriteHeader(header, (psPtr)fits);
+    }
+
+    if (input->parent == NULL) { // if no parent, assume that the image data is contiguous
+        fits_write_img(fits->fd,
+                       dataType,              // datatype
+                       1,                     // writing to the first z-plane
+                       numCols*numRows,       // number of elements to write, i.e., the whole image
+                       input->data.V[0],      // the data
+                       &status);
+    } else { // image data may not be contiguous; write one row at a time
+        int firstPixel = 1;
+        for (int row = 0; row < numRows; row++) {
+            fits_write_img(fits->fd,
+                           dataType,          // datatype
+                           firstPixel,
+                           numCols,           // number of elements to write, i.e., one row's worth
+                           input->data.V[row],// the raw row data
+                           &status);
+            firstPixel += numCols;  // move to next row
+        }
+    }
+
+    if ( status != 0) {
+        char fitsErr[MAX_STRING_LENGTH];
+        (void)fits_get_errstatus(status, fitsErr);
+        psError(PS_ERR_IO, true,
+                PS_ERRORTEXT_psFits_WRITE_FAILED,
+                fitsErr);
+        return false;
+    }
+
+    return true;
+
+}
+
+bool psFitsUpdateImage(psFits* fits,
+                       const psImage* input,
+                       psRegion region,
+                       int z)
+{
+    int status = 0;
+
+    if (fits == NULL) {
+        psError(PS_ERR_BAD_PARAMETER_NULL, true,
+                PS_ERRORTEXT_psFits_NULL);
+        return false;
+    }
+
+    if (input == NULL) {
+        psError(PS_ERR_BAD_PARAMETER_NULL, true,
+                PS_ERRORTEXT_psFits_IMAGE_NULL);
+        return false;
+    }
+
+    // check to see if we are positioned on an image HDU
+    int hdutype;
+    if ( fits_get_hdu_type(fits->fd,&hdutype, &status) != 0) {
+        char fitsErr[MAX_STRING_LENGTH];
+        (void)fits_get_errstatus(status, fitsErr);
+        psError(PS_ERR_IO, true,
+                PS_ERRORTEXT_psFits_GET_HDU_TYPE_FAILED,
+                fitsErr);
+        return NULL;
+    }
+    if (hdutype != IMAGE_HDU) {
+        psError(PS_ERR_IO, true,
+                PS_ERRORTEXT_psFits_NOT_IMAGE_TYPE);
+        return NULL;
+    }
+
+    int numCols = input->numCols;
+    int numRows = input->numRows;
+
+    // determine the FITS-equivalent parameters
+    int bitPix;
+    double bZero;
+    int dataType;
+    if (! convertPsTypeToFits(input->type.type, &bitPix, &bZero, &dataType) ) {
+        return false;
+    }
+
+    //check to see if the HDU has the same datatype
+    int fileBitpix;
+    int naxis;
+    long nAxes[3];
+    nAxes[2] = 1;
+    fits_get_img_param(fits->fd, 3, &fileBitpix, &naxis, nAxes, &status);
+
+    //check to see if the HDU has the same datatype
+    if (bitPix != fileBitpix) {
+        char* fitsTypeStr;
+        char* imageTypeStr;
+        PS_TYPE_NAME(fitsTypeStr,fileBitpix);
+        PS_TYPE_NAME(imageTypeStr,input->type.type);
+        psError(PS_ERR_IO, true,
+                PS_ERRORTEXT_psFits_IMAGE_UPDATE_TYPE_MISMATCH,
+                fitsTypeStr, imageTypeStr);
+        return false;
+    }
+
+    //check if the HDU has the z-plane requested
+    if (z >= nAxes[2]) {
+        psError(PS_ERR_BAD_PARAMETER_SIZE, true,
+                PS_ERRORTEXT_psFits_FITS_Z_SMALL,
+                nAxes[2],z);
+        return false;
+    }
+
+    // determine the region in the FITS file domain
+    long firstPixel[3];
+    long lastPixel[3];
+
+    firstPixel[0] = region.x0 + 1;
+    firstPixel[1] = region.y0 + 1;
+    firstPixel[2] = z + 1;
+
+    if (region.x1 > 0) {
+        lastPixel[0] = region.x1;
+    } else {
+        lastPixel[0] = nAxes[0] + region.x1; // n.b., region.x1 < 0
+    }
+    if (region.y1 > 0) {
+        lastPixel[1] = region.y1;
+    } else {
+        lastPixel[1] = nAxes[1] + region.y1; // n.b., region.y1 < 0
+    }
+    lastPixel[2] = z + 1;
+
+    if (firstPixel[0] < 1 || firstPixel[0] > nAxes[0] ||
+            firstPixel[1] < 1 || firstPixel[1] > nAxes[1] ||
+            lastPixel[0] < 1 || lastPixel[0] > nAxes[0] ||
+            lastPixel[1] < 1 || lastPixel[1] > nAxes[1]) {
+        psError(PS_ERR_BAD_PARAMETER_VALUE, true,
+                "Specified region [%d:%d,%d:%d], is not valid given the %dx%d FITS image.",
+                region.y0,region.y1-1,region.x0,region.x1-1);
+        return false;
+
+    }
+
+    int dx = lastPixel[0] - firstPixel[0];
+    int dy = lastPixel[1] - firstPixel[1];
+    if (dx > numCols ||
+            dy > numRows) {
+        psError(PS_ERR_BAD_PARAMETER_VALUE, true,
+                "The region [%d:%d,%d:%d], is not valid given the input %dx%d image.",
+                firstPixel[1]-1,lastPixel[1]-1,
+                firstPixel[0]-1,lastPixel[0]-1,
+                numCols, numRows);
+        return false;
+    }
+
+    psImage* subset;
+    if (dx != numCols || dy != numRows) {
+        // the input image needs to be subsetted
+        subset = psImageSubset((psImage*)input, psRegionSet(0,dx+1,0,dy+1));
+    } else {
+        subset = psMemIncrRefCounter((psImage*)input);
+    }
+
+    fits_write_subset(fits->fd, dataType, firstPixel, lastPixel, subset->data.V[0], &status);
+
+    if ( status != 0) {
+        char fitsErr[MAX_STRING_LENGTH];
+        (void)fits_get_errstatus(status, fitsErr);
+        psError(PS_ERR_IO, true,
+                PS_ERRORTEXT_psFits_WRITE_FAILED,
+                fitsErr);
+        return false;
+    }
+
+    return true;
+}
+
Index: trunk/psLib/src/fits/psFitsImage.h
===================================================================
--- trunk/psLib/src/fits/psFitsImage.h	(revision 5511)
+++ trunk/psLib/src/fits/psFitsImage.h	(revision 5511)
@@ -0,0 +1,64 @@
+/** @file  psFitsImage.h
+ *
+ *  @brief Contains Fits I/O routines
+ *
+ *  @ingroup FileIO
+ *
+ *  @author Robert DeSonia, MHPCC
+ *
+ *  @version $Revision: 1.1 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2005-11-14 22:18:30 $
+ *
+ *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
+ */
+
+#ifndef PS_FITSIMAGE_H
+#define PS_FITSIMAGE_H
+
+#include "psFits.h"
+
+#include "psType.h"
+#include "psArray.h"
+#include "psVector.h"
+#include "psMetadata.h"
+#include "psImage.h"
+
+/// @addtogroup FileIO
+/// @{
+
+/** Reads an image, given the desired region and z-plane.
+ *
+ *  @return psImage*     the read image or NULL if there was an error.
+ */
+psImage* psFitsReadImage(
+    psImage* out,                      ///< a psImage to recycle.
+    const psFits* fits,                ///< the psFits object
+    psRegion region,                   ///< the region in the FITS image to read
+    int z                              ///< the z-plane in the FITS image cube to read
+);
+
+/** Writes an image, given the desired region and z-plane.
+ *
+ *  @return bool        TRUE is the write was successful, otherwise FALSE.
+ */
+bool psFitsWriteImage(
+    psFits* fits,                      ///< the psFits object
+    psMetadata* header,                ///< header items for the new HDU.  Can be NULL.
+    const psImage* input,              ///< the image to output
+    int depth                          ///< the number of z-planes of the FITS image data cube
+);
+
+/** Updates the FITS file image, given the desired region and z-plane.
+ *
+ *  @return bool        TRUE is the write was successful, otherwise FALSE.
+ */
+bool psFitsUpdateImage(
+    psFits* fits,                      ///< the psFits object
+    const psImage* input,              ///< the image to output
+    psRegion region,                   ///< the region in the FITS image to write
+    int z                              ///< the z-planes of the FITS image data cube to write
+);
+
+/// @}
+
+#endif // #ifndef PS_FITS_H
Index: trunk/psLib/src/fits/psFitsTable.c
===================================================================
--- trunk/psLib/src/fits/psFitsTable.c	(revision 5511)
+++ trunk/psLib/src/fits/psFitsTable.c	(revision 5511)
@@ -0,0 +1,873 @@
+/** @file  psFitsTable.c
+ *
+ *  @brief Contains Fits I/O routines
+ *
+ *  @ingroup FileIO
+ *
+ *  @author Robert DeSonia, MHPCC
+ *
+ *  @version $Revision: 1.1 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2005-11-14 22:18:30 $
+ *
+ *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
+ */
+
+#include "psFits.h"
+#include "string.h"
+#include "psError.h"
+#include "psErrorText.h"
+#include "psImageStructManip.h"
+#include "psMemory.h"
+#include "psString.h"
+#include "psLogMsg.h"
+#include "psTrace.h"
+#include "psVector.h"
+
+#define MAX_STRING_LENGTH 256  // maximum length string for FITS routines
+
+static psElemType convertFitsToPsType(int datatype)
+{
+    switch (datatype) {
+    case TBYTE:
+        return PS_TYPE_U8;
+    case TSBYTE:
+        return PS_TYPE_S8;
+    case TSHORT:
+        return PS_TYPE_S16;
+    case TUSHORT:
+        return PS_TYPE_U16;
+    case TLONG:
+        if (sizeof(long) == 8) {
+            return PS_TYPE_S64;
+        }
+        // no break
+    case TINT:
+        return PS_TYPE_S32;
+    case TULONG:
+        if (sizeof(unsigned long) == 8) {
+            return PS_TYPE_U64;
+        }
+        // no break
+    case TUINT:
+        return PS_TYPE_U32;
+    case TLONGLONG:
+        return PS_TYPE_S64;
+    case TFLOAT:
+        return PS_TYPE_F32;
+    case TDOUBLE:
+        return PS_TYPE_F64;
+    case TCOMPLEX:
+        return PS_TYPE_C32;
+    case TDBLCOMPLEX:
+        return PS_TYPE_C64;
+    case TLOGICAL:
+        return PS_TYPE_BOOL;
+    default:
+        psError(PS_ERR_IO, true,
+                "Unknown FITS datatype, %d.",
+                datatype);
+        return 0;
+    }
+}
+
+static bool convertPsTypeToFits(int type, int* bitPix, double* bZero, int* dataType)
+{
+
+    int bitpix;
+    int datatype;
+    double bzero = 0.0;
+
+    switch (type) {
+
+    case PS_TYPE_U8:
+        bitpix = BYTE_IMG;
+        datatype = TBYTE;
+        break;
+
+    case PS_TYPE_S8:
+        bitpix = BYTE_IMG;
+        bzero = INT8_MIN;
+        datatype = TSBYTE;
+        break;
+
+    case PS_TYPE_U16:
+        bitpix = SHORT_IMG;
+        bzero = -1.0 * INT16_MIN;
+        datatype = TUSHORT;
+        break;
+
+    case PS_TYPE_S16:
+        bitpix = SHORT_IMG;
+        datatype = TSHORT;
+        break;
+
+    case PS_TYPE_U32:
+        bitpix = LONG_IMG;
+        bzero = -1.0 * INT32_MIN;
+        datatype = TUINT;
+        break;
+
+    case PS_TYPE_S32:
+        bitpix = LONG_IMG;
+        datatype = TINT;
+        break;
+
+    case PS_TYPE_F32:
+        bitpix = FLOAT_IMG;
+        datatype = TFLOAT;
+        break;
+
+    case PS_TYPE_F64:
+        bitpix = DOUBLE_IMG;
+        datatype = TDOUBLE;
+        break;
+
+    case PS_DATA_STRING:
+        bitpix = BYTE_IMG;
+        datatype = TSTRING;
+        break;
+
+    case PS_DATA_BOOL:
+        bitpix = BYTE_IMG;
+        datatype = TLOGICAL;
+        break;
+
+    default: {
+            char* typeStr;
+            PS_TYPE_NAME(typeStr,type);
+            psError(PS_ERR_BAD_PARAMETER_TYPE, true,
+                    PS_ERRORTEXT_psFits_TYPE_UNSUPPORTED,
+                    typeStr);
+            return false;
+        }
+    }
+
+    // pass the requested parameters  (NULL parameters are not set, of course).
+    if (bitPix != NULL) {
+        *bitPix = bitpix;
+    }
+
+    if (dataType != NULL) {
+        *dataType = datatype;
+    }
+
+    if (bZero != NULL) {
+        *bZero = bzero;
+    }
+
+    return true;
+}
+
+static char getTForm(int 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_C32:
+        return 'C';
+    case PS_TYPE_C64:
+        return 'M';
+    case PS_TYPE_BOOL:
+        return 'L';
+    case PS_DATA_STRING:
+        return 'A';
+    default:
+        return '?';
+    }
+}
+
+static bool getMetadataTForm(psMetadataItem* item, char** fitsType, int repeat)
+{
+    if (item == NULL) {
+        return false;
+    }
+
+    *fitsType = NULL;
+    char tform = getTForm(item->type);
+
+    switch (item->type) {
+    case PS_TYPE_U8:
+    case PS_TYPE_S8:
+    case PS_TYPE_S16:
+    case PS_TYPE_S32:
+    case PS_TYPE_U64:
+    case PS_TYPE_S64:
+    case PS_TYPE_U16:
+    case PS_TYPE_U32:
+    case PS_TYPE_F32:
+    case PS_TYPE_F64:
+    case PS_TYPE_C32:
+    case PS_TYPE_C64:
+    case PS_TYPE_BOOL:
+        psStringAppend(fitsType, "%d%c",repeat,tform);
+        break;
+
+    case PS_DATA_STRING:
+        psStringAppend(fitsType,"%dA",
+                       strlen(item->data.V)*repeat);
+        break;
+
+    case PS_DATA_VECTOR: {
+            psVector* vec = item->data.V;
+            tform = getTForm(vec->type.type);
+            psStringAppend(fitsType,"%d%c",repeat*vec->n,tform);
+        }
+        break;
+
+    default:
+        return false;
+    }
+
+    return true;
+}
+
+psMetadata* psFitsReadTableRow(const psFits* fits,
+                               int row)
+{
+    long numRows;
+    int numCols;
+    int status = 0;
+
+    if (fits == NULL) {
+        psError(PS_ERR_BAD_PARAMETER_NULL, true,
+                PS_ERRORTEXT_psFits_NULL);
+        return NULL;
+    }
+
+    // check to see if we even are positioned on a table HDU
+    int hdutype;
+    fits_get_hdu_type(fits->fd,&hdutype, &status);
+    if ( status != 0) {
+        char fitsErr[MAX_STRING_LENGTH];
+        (void)fits_get_errstatus(status, fitsErr);
+        psError(PS_ERR_IO, true,
+                PS_ERRORTEXT_psFits_GET_HDU_TYPE_FAILED,
+                fitsErr);
+        return NULL;
+    }
+    if (hdutype != ASCII_TBL && hdutype != BINARY_TBL) {
+        psError(PS_ERR_IO, true,
+                PS_ERRORTEXT_psFits_NOT_TABLE_TYPE);
+        return NULL;
+    }
+
+    // get the size of the FITS table
+    fits_get_num_rows(fits->fd, &numRows, &status);
+    fits_get_num_cols(fits->fd, &numCols, &status);
+    if ( status != 0) {
+        char fitsErr[MAX_STRING_LENGTH];
+        (void)fits_get_errstatus(status, fitsErr);
+        psError(PS_ERR_IO, true,
+                PS_ERRORTEXT_psFits_GET_TABLE_SIZE_FAILED,
+                fitsErr);
+        return NULL;
+    }
+
+    psTrace(".psFits.psFitsReadTableRow",5,"Table size is %ix%i\n",numCols, numRows);
+    // the row parameter in the proper range?
+    if (row < 0 || row >= numRows) {
+        psError(PS_ERR_BAD_PARAMETER_VALUE, true,
+                PS_ERRORTEXT_psFits_ROW_INVALID,
+                row,numRows);
+        return NULL;
+    }
+
+    psMetadata* data = psMetadataAlloc();
+
+    int typecode;
+    long repeat;
+    long width;
+    char name[60];
+    for (int col = 1; col <= numCols; col++) {
+        // get the column name
+        if (hdutype == BINARY_TBL) {
+            fits_get_bcolparms(fits->fd, col, name,
+                               NULL, NULL, NULL, NULL, NULL, 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 (status == 0) {
+
+            #define READ_TABLE_ROW_CASE(FITSTYPE, NATIVETYPE, TYPE) \
+        case FITSTYPE: { \
+                if (repeat == 1) { \
+                    NATIVETYPE value; \
+                    int anynul = 0; \
+                    fits_read_col(fits->fd, FITSTYPE, col,row+1, \
+                                  1, 1, NULL, &value, &anynul, &status); \
+                    psTrace(".psFits.psFitsReadTableRow",5,"Column #%i, '%s', is type %i, repeat %i, Value = %g\n", \
+                            col, name, typecode, repeat, (double)value); \
+                    psMetadataAdd(data,PS_LIST_TAIL, name, \
+                                  PS_DATA_##TYPE, \
+                                  "", (ps##TYPE)value); \
+                } else { \
+                    psVector* value = psVectorAlloc(repeat,PS_DATA_##TYPE); \
+                    int anynul = 0; \
+                    fits_read_col(fits->fd, FITSTYPE, col,row+1, \
+                                  1, repeat, NULL, value->data.U8, &anynul, &status); \
+                    psMetadataAdd(data,PS_LIST_TAIL, name, \
+                                  PS_DATA_VECTOR, \
+                                  "", value); \
+                    psFree(value); \
+                } \
+                break; \
+            }
+
+            switch (typecode) {
+            case TBYTE:
+            case TSHORT:
+            case TLONGLONG:
+                READ_TABLE_ROW_CASE(TLONG, long, S32)
+                READ_TABLE_ROW_CASE(TFLOAT, float, F32)
+                READ_TABLE_ROW_CASE(TDOUBLE, double, F64)
+                READ_TABLE_ROW_CASE(TLOGICAL, bool, BOOL);
+            case TSTRING: {
+                    char* value = psAlloc(repeat+1);
+                    int anynul = 0;
+                    fits_read_col(fits->fd, TSTRING, col,row+1,
+                                  1, 1, NULL, &value, &anynul, &status);
+                    psTrace(".psFits.psFitsReadTableRow",5,"Column #%i, '%s', is type %i, repeat %i, value = %s\n",
+                            col, name, typecode, repeat, value);
+                    if (anynul == 0) {
+                        psMetadataAdd(data,PS_LIST_TAIL, name,
+                                      PS_DATA_STRING,
+                                      "", value);
+                    }
+                    psFree(value);
+                    break;
+                }
+            default:
+                psWarning("Data type (%d) not supportted for column %d",
+                          typecode, col);
+
+                psTrace("psFits.psFitsReadTableRow", 2,
+                        "Column %d or row %d was of a non primitive type, %d",
+                        col, row, typecode);
+            }
+        }
+
+        if ( status != 0) {
+            char fitsErr[MAX_STRING_LENGTH];
+            (void)fits_get_errstatus(status, fitsErr);
+            psError(PS_ERR_IO, true,
+                    PS_ERRORTEXT_psFits_GET_TABLE_ELEMENT,
+                    col,row,fitsErr);
+            psFree(data);
+            return NULL;
+        }
+
+    }
+
+    return data;
+}
+
+psArray* psFitsReadTableColumn(const psFits* fits,
+                               const char* colname)
+{
+    int colnum = 0;
+    int status = 0;
+
+    if (fits == NULL) {
+        psError(PS_ERR_BAD_PARAMETER_NULL, true,
+                PS_ERRORTEXT_psFits_NULL);
+        return NULL;
+    }
+
+    // check to see if we even are positioned on a table HDU
+    int hdutype;
+    if ( fits_get_hdu_type(fits->fd,&hdutype, &status) != 0) {
+        char fitsErr[MAX_STRING_LENGTH];
+        (void)fits_get_errstatus(status, fitsErr);
+        psError(PS_ERR_IO, true,
+                PS_ERRORTEXT_psFits_GET_HDU_TYPE_FAILED,
+                fitsErr);
+        return NULL;
+    }
+    if (hdutype != ASCII_TBL && hdutype != BINARY_TBL) {
+        psError(PS_ERR_IO, true,
+                PS_ERRORTEXT_psFits_NOT_TABLE_TYPE);
+        return NULL;
+    }
+
+    // find the column by name
+    if ( fits_get_colnum(fits->fd, CASESEN, (char*)colname, &colnum, &status) != 0) {
+        char fitsErr[MAX_STRING_LENGTH];
+        (void)fits_get_errstatus(status, fitsErr);
+        psError(PS_ERR_IO, true,
+                PS_ERRORTEXT_psFits_FIND_COLUMN,
+                colname, fitsErr);
+        return NULL;
+    }
+
+    // get the number of rows
+    long numRows = 0;
+    fits_get_num_rows(fits->fd, &numRows, &status);
+
+    // get the column length.
+    int width;
+    if ( fits_get_col_display_width(fits->fd, colnum, &width, &status) != 0) {
+        char fitsErr[MAX_STRING_LENGTH];
+        (void)fits_get_errstatus(status, fitsErr);
+        psError(PS_ERR_IO, true,
+                PS_ERRORTEXT_psFits_GET_COLTYPE,
+                fitsErr);
+        return NULL;
+    }
+
+    // allocate the buffers
+    psArray* result = psArrayAlloc(numRows);
+    for (int row = 0; row < numRows; row++) {
+        result->data[row] = psAlloc((width+1)*sizeof(char));
+    }
+    result->n = numRows;
+
+    fits_read_col_str(fits->fd,
+                      colnum,
+                      1, // firstrow
+                      1, // firestelem
+                      numRows,
+                      "", // nulstr
+                      (char**)result->data,
+                      NULL,
+                      &status);
+
+    if ( status != 0) {
+        char fitsErr[MAX_STRING_LENGTH];
+        (void)fits_get_errstatus(status, fitsErr);
+        psError(PS_ERR_IO, true,
+                PS_ERRORTEXT_psFits_TABLE_READ_COL,
+                fitsErr);
+        return NULL;
+    }
+
+    return result;
+}
+
+psVector* psFitsReadTableColumnNum(const psFits* fits,
+                                   const char* colname)
+{
+    int status = 0;
+    int colnum = 0;
+
+    if (fits == NULL) {
+        psError(PS_ERR_BAD_PARAMETER_NULL, true,
+                PS_ERRORTEXT_psFits_NULL);
+        return NULL;
+    }
+
+    // check to see if we even are positioned on a table HDU
+    int hdutype;
+    if ( fits_get_hdu_type(fits->fd,&hdutype, &status) != 0) {
+        char fitsErr[MAX_STRING_LENGTH];
+        (void)fits_get_errstatus(status, fitsErr);
+        psError(PS_ERR_IO, true,
+                PS_ERRORTEXT_psFits_GET_HDU_TYPE_FAILED,
+                fitsErr);
+        return NULL;
+    }
+    if (hdutype != ASCII_TBL && hdutype != BINARY_TBL) {
+        psError(PS_ERR_IO, true,
+                PS_ERRORTEXT_psFits_NOT_TABLE_TYPE);
+        return NULL;
+    }
+
+    // find the column by name
+    if ( fits_get_colnum(fits->fd, CASESEN, (char*)colname, &colnum, &status) != 0) {
+        char fitsErr[MAX_STRING_LENGTH];
+        (void)fits_get_errstatus(status, fitsErr);
+        psError(PS_ERR_IO, true,
+                PS_ERRORTEXT_psFits_FIND_COLUMN,
+                colname, fitsErr);
+        return NULL;
+    }
+
+    // get the number of rows
+    long numRows = 0;
+    fits_get_num_rows(fits->fd,
+                      &numRows,
+                      &status);
+
+    // get the column datatype.
+    int typecode;
+    long repeat;
+    long width;
+    if ( fits_get_eqcoltype(fits->fd, colnum, &typecode, &repeat, &width, &status) != 0) {
+        char fitsErr[MAX_STRING_LENGTH];
+        (void)fits_get_errstatus(status, fitsErr);
+        psError(PS_ERR_IO, true,
+                PS_ERRORTEXT_psFits_GET_COLTYPE,
+                fitsErr);
+        return NULL;
+    }
+
+    psVector* result = psVectorAlloc(numRows, convertFitsToPsType(typecode));
+
+    fits_read_col(fits->fd,
+                  typecode,
+                  colnum,
+                  1 /* firstrow */,
+                  1 /* firstelem */,
+                  numRows,
+                  NULL,
+                  (psPtr)(result->data.U8),
+                  NULL,
+                  &status);
+
+    if ( status != 0) {
+        char fitsErr[MAX_STRING_LENGTH];
+        (void)fits_get_errstatus(status, fitsErr);
+        psError(PS_ERR_IO, true,
+                PS_ERRORTEXT_psFits_TABLE_READ_COL,
+                fitsErr);
+        return NULL;
+    }
+
+    return result;
+}
+
+
+psArray* psFitsReadTable(psFits* fits)
+{
+    int status = 0;
+
+    if (fits == NULL) {
+        psError(PS_ERR_BAD_PARAMETER_NULL, true,
+                PS_ERRORTEXT_psFits_NULL);
+        return NULL;
+    }
+
+    // check to see if we even are positioned on a table HDU
+    int hdutype;
+    if ( fits_get_hdu_type(fits->fd,&hdutype, &status) != 0) {
+        char fitsErr[MAX_STRING_LENGTH];
+        (void)fits_get_errstatus(status, fitsErr);
+        psError(PS_ERR_IO, true,
+                PS_ERRORTEXT_psFits_GET_HDU_TYPE_FAILED,
+                fitsErr);
+        return NULL;
+    }
+    if (hdutype != ASCII_TBL && hdutype != BINARY_TBL) {
+        psError(PS_ERR_IO, true,
+                PS_ERRORTEXT_psFits_NOT_TABLE_TYPE);
+        return NULL;
+    }
+
+    // get the size of the FITS table
+    long numRows = 0;
+    fits_get_num_rows(fits->fd, &numRows, &status);
+    if ( status != 0) {
+        char fitsErr[MAX_STRING_LENGTH];
+        (void)fits_get_errstatus(status, fitsErr);
+        psError(PS_ERR_IO, true,
+                PS_ERRORTEXT_psFits_GET_TABLE_SIZE_FAILED,
+                fitsErr);
+        return NULL;
+    }
+
+
+    psArray* table = psArrayAlloc(numRows);
+
+    for (int row = 0; row < numRows; row++) {
+        psTrace(".psFits.psFitsReadTable",5,"Reading row %i of %i\n",row, numRows);
+        table->data[row] = psFitsReadTableRow(fits,row);
+    }
+
+    return table;
+}
+
+bool psFitsWriteTable(psFits* fits,
+                      const psMetadata* header,
+                      const psArray* table)
+{
+    int status = 0;
+
+    if (fits == NULL) {
+        psError(PS_ERR_BAD_PARAMETER_NULL, true,
+                PS_ERRORTEXT_psFits_NULL);
+        return false;
+    }
+
+    if (table == NULL) {
+        psError(PS_ERR_BAD_PARAMETER_NULL, true,
+                PS_ERRORTEXT_psFits_IMAGE_NULL);
+        return false;
+    }
+
+    int rows = table->n;
+    if (rows < 1) {
+        // no table data, what can I do?
+        psError(PS_ERR_BAD_PARAMETER_SIZE, true,
+                PS_ERRORTEXT_psFits_TABLE_EMPTY);
+        return false;
+    }
+
+    // find all the columns needed
+    psArray* columns = psArrayAlloc(((psMetadata*)table->data[0])->list->n);
+    columns->n=0;
+
+    // find the unique items in the array of metadata 'rows'
+    psMetadataItem* item;
+    for (int row=0; row < rows; row++) {
+        psMetadata* rowMeta = table->data[row];
+        if (rowMeta != NULL) {
+            psListIterator* iter = psListIteratorAlloc(rowMeta->list,
+                                   PS_LIST_HEAD,true);
+            while ( (item=psListGetAndIncrement(iter)) != NULL) {
+                if (PS_DATA_IS_PRIMITIVE(item->type) ||
+                        item->type == PS_DATA_STRING ||
+                        item->type == PS_DATA_VECTOR) {
+                    bool found = false;
+                    psMetadataItem* fItem = NULL;
+                    int n;
+                    for (n=0; n < columns->n && ! found; n++) {
+                        fItem = (psMetadataItem*)(columns->data[n]);
+                        if (strcmp(item->name, fItem->name) == 0) {
+                            found = true;
+                            break;
+                        }
+                    }
+                    if (! found) {
+                        psArrayAdd(columns, columns->nalloc, item);
+                    } else if (item->type == PS_DATA_STRING &&
+                               strlen(fItem->data.V) < strlen(item->data.V)) {
+                        // got to keep the longest string value as to know what size to create the table column
+                        psMemDecrRefCounter(fItem);
+                        columns->data[n] = psMemIncrRefCounter(item);
+
+                    } else if (item->type == PS_DATA_VECTOR &&
+                               ((psVector*)(fItem->data.V))->n < ((psVector*)(item->data.V))->n) {
+                        psMemDecrRefCounter(fItem);
+                        columns->data[n] = psMemIncrRefCounter(item);
+                    }
+                } else {
+                    // unsupported type -- treating as an error
+                    psError(PS_ERR_BAD_PARAMETER_TYPE, true,
+                            "Unsupported data type (%d) for Metadata Item '%s' in row %d.",
+                            item->type, item->name, row);
+                    psFree(iter);
+                    psFree(columns);
+                    return false;
+                }
+            }
+            psFree(iter);
+        }
+    }
+
+    if (columns->n == 0) { // no table columns found
+        psError(PS_ERR_BAD_PARAMETER_SIZE, true,
+                "Did not find any column data to write to a table.");
+        psFree(columns);
+        return false;
+    }
+
+    //create list of column names and types.
+    psArray* columnNames = psArrayAlloc(columns->n);
+    psArray* columnTypes = psArrayAlloc(columns->n);
+    for (int n=0; n < columns->n; n++) {
+        columnNames->data[n] = psMemIncrRefCounter(((psMetadataItem*)columns->data[n])->name);
+        if ( ! getMetadataTForm((psMetadataItem*)columns->data[n],
+                                (char**)&(columnTypes->data[n]),1) ) {
+            psError(PS_ERR_UNKNOWN, true,
+                    "Failed to determine the FITS data type of '%s' (type=%d).",
+                    columnNames->data[n],
+                    ((psMetadataItem*)columns->data[n])->type);
+            psFree(columns);
+            psFree(columnNames);
+            psFree(columnTypes);
+            return false;
+        }
+    }
+
+    char* extname = NULL;
+    if (header != NULL) {
+        extname = psMetadataLookupPtr(NULL, header, "EXTNAME");
+        if ( extname == NULL) {
+            extname = psMetadataLookupPtr(NULL, header, "HDUNAME");
+        }
+    }
+
+    fits_create_tbl(fits->fd,
+                    BINARY_TBL,
+                    table->n, // number of rows in table
+                    columns->n, // number of columns in table
+                    (char**)columnNames->data, // names of the columns
+                    (char**)columnTypes->data, // format of the columns
+                    NULL, // physical unit of columns
+                    extname, // extension name
+                    &status);
+
+    psFree(columnNames);
+    psFree(columnTypes);
+
+    // fill in the table elements with data
+    for (int n = 0; n < columns->n; n++) {
+        int row;
+        item = columns->data[n];
+        if (PS_DATA_IS_PRIMITIVE(item->type) ) {
+            psVector* col = psVectorAlloc(table->n, item->type);
+            int dataSize = PSELEMTYPE_SIZEOF(item->type);
+            int dataType;
+            convertPsTypeToFits(item->type, NULL,NULL,&dataType);
+            for (row = 0; row < table->n; row++) {
+                psMetadataItem* dataItem = psMetadataLookup(
+                                               table->data[row],
+                                               item->name);
+                memcpy(&col->data.U8[row*dataSize],&dataItem->data,dataSize);
+            }
+            fits_write_col(fits->fd,
+                           dataType,
+                           n+1, // column number
+                           1, // firstrow
+                           1, // firstelem
+                           table->n, // nelements
+                           col->data.U8,
+                           &status);
+            psFree(col);
+        } else if (item->type == PS_DATA_STRING) {
+            psArray* colArray = psArrayAlloc(table->n);
+            for (row = 0; row < table->n; row++) {
+                colArray->data[row] = psMemIncrRefCounter(
+                                          psMetadataLookupStr(NULL,
+                                                              table->data[row],
+                                                              item->name));
+            }
+            fits_write_col_str(fits->fd,
+                               n+1,
+                               1,
+                               1,
+                               table->n,
+                               (char**)colArray->data,
+                               &status);
+            psFree(colArray);
+        } else if (item->type == PS_DATA_VECTOR) {
+            psVector* vec = (psVector*)(item->data.V);
+            psVector* col = psVectorAlloc(table->n*vec->n, vec->type.type);
+            int dataSize = PSELEMTYPE_SIZEOF(vec->type.type)*vec->n;
+            int dataType;
+            convertPsTypeToFits(vec->type.type, NULL,NULL,&dataType);
+            for (row = 0; row < table->n; row++) {
+                psMetadataItem* dataItem = psMetadataLookup(
+                                               table->data[row],
+                                               item->name);
+                memcpy(&col->data.U8[row*dataSize],
+                       ((psVector*)(dataItem->data.V))->data.U8,
+                       dataSize);
+            }
+            fits_write_col(fits->fd,
+                           dataType,
+                           n+1, // column number
+                           1, // firstrow
+                           1, // firstelem
+                           table->n*vec->n, // nelements
+                           col->data.U8,
+                           &status);
+            psFree(col);
+        }
+        if (status != 0) {
+            char fitsErr[MAX_STRING_LENGTH];
+            (void)fits_get_errstatus(status, fitsErr);
+            psError(PS_ERR_IO, true,
+                    PS_ERRORTEXT_psFits_WRITE_FAILED,
+                    fitsErr);
+            psFree(columns);
+            return false;
+        }
+
+    }
+
+    psFree(columns);
+
+    return true;
+}
+
+bool psFitsUpdateTable(psFits* fits,
+                       const psMetadata* data,
+                       int row)
+{
+    int status = 0;
+
+    if (fits == NULL) {
+        psError(PS_ERR_BAD_PARAMETER_NULL, true,
+                PS_ERRORTEXT_psFits_NULL);
+        return false;
+    }
+
+    if (data == NULL) {
+        psError(PS_ERR_BAD_PARAMETER_NULL, true,
+                PS_ERRORTEXT_psFits_IMAGE_NULL);
+        return false;
+    }
+
+    // check to see if we even are positioned on a table HDU
+    int hdutype;
+    if ( fits_get_hdu_type(fits->fd,&hdutype, &status) != 0) {
+        char fitsErr[MAX_STRING_LENGTH];
+        (void)fits_get_errstatus(status, fitsErr);
+        psError(PS_ERR_IO, true,
+                PS_ERRORTEXT_psFits_GET_HDU_TYPE_FAILED,
+                fitsErr);
+        return false;
+    }
+    if (hdutype != ASCII_TBL && hdutype != BINARY_TBL) {
+        psError(PS_ERR_IO, true,
+                PS_ERRORTEXT_psFits_NOT_TABLE_TYPE);
+        return false;
+    }
+
+    psMetadataIterator* iter = psMetadataIteratorAlloc((psPtr)data,PS_LIST_HEAD,NULL);
+
+    psMetadataItem* item;
+
+    while ( (item=psMetadataGetAndIncrement(iter)) != NULL) {
+        if (PS_DATA_IS_PRIMITIVE(item->type) ||
+                item->type == PS_DATA_BOOL ||
+                item->type == PS_DATA_STRING) {
+            // operating on primitive data type or string, i.e., not a complex object
+            int colnum = 0;
+
+            if ( fits_get_colnum(fits->fd, CASESEN, item->name, &colnum, &status) == 0) {
+                // cooresponding column found in table
+                int dataType;
+                convertPsTypeToFits(item->type, NULL, NULL, &dataType);
+
+                if (fits_write_col(fits->fd, dataType, colnum, row+1, 1, 1, &item->data,&status) != 0) {
+                    char fitsErr[MAX_STRING_LENGTH];
+                    (void)fits_get_errstatus(status, fitsErr);
+                    psError(PS_ERR_IO, true,
+                            PS_ERRORTEXT_psFits_WRITE_FAILED,
+                            fitsErr);
+                    psFree(iter);
+                    return false;
+                }
+            } else {
+                // the column was not found.
+                psWarning("No column with the name '%s' exists in the table.",
+                          item->name);
+            }
+        }
+    }
+
+    psFree(iter);
+
+    return true;
+}
Index: trunk/psLib/src/fits/psFitsTable.h
===================================================================
--- trunk/psLib/src/fits/psFitsTable.h	(revision 5511)
+++ trunk/psLib/src/fits/psFitsTable.h	(revision 5511)
@@ -0,0 +1,104 @@
+/** @file  psFitsTable.h
+ *
+ *  @brief Contains Fits I/O routines
+ *
+ *  @ingroup FileIO
+ *
+ *  @author Robert DeSonia, MHPCC
+ *
+ *  @version $Revision: 1.1 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2005-11-14 22:18:30 $
+ *
+ *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
+ */
+
+#ifndef PS_FITSTABLE_H
+#define PS_FITSTABLE_H
+
+#include "psFits.h"
+
+#include "psType.h"
+#include "psArray.h"
+#include "psVector.h"
+#include "psMetadata.h"
+#include "psImage.h"
+
+/// @addtogroup FileIO
+/// @{
+
+/** Reads a table row.  The current HDU type must be either
+ *  PS_FITS_TYPE_BINARY_TABLE or PS_FITS_TYPE_ASCII_TABLE.
+ *
+ *  @return psMetadata*    The table row's data.  The keys are the column names.
+ */
+psMetadata* psFitsReadTableRow(
+    const psFits* fits,                ///< the psFits object
+    int row                            ///< row number to read
+);
+
+/** Reads a table column.  The current HDU type must be either
+ *  PS_FITS_TYPE_BINARY_TABLE or PS_FITS_TYPE_ASCII_TABLE.
+ *
+ *  @return psArray*    Array of data items for the specified column or NULL
+ *                      if an error occurred.
+ */
+psArray* psFitsReadTableColumn(
+    const psFits* fits,                ///< the psFits object
+    const char* colname                ///< the column name
+);
+
+/** Reads a table column of numbers.  The current HDU type must be either
+ *  PS_FITS_TYPE_BINARY_TABLE or PS_FITS_TYPE_ASCII_TABLE.
+ *
+ *  @return psVector*    Vector of data for the specified column or NULL
+ *                       if an error occurred.
+ */
+psVector* psFitsReadTableColumnNum(
+    const psFits* fits,                ///< the psFits object
+    const char* colname                ///< the column name
+);
+
+
+/** Reads a whole FITS table.  The current HDU type must be either
+ *  PS_FITS_TYPE_BINARY_TABLE or PS_FITS_TYPE_ASCII_TABLE.
+ *
+ *  @return psArray*     Array of psMetadata items, which contains the output
+ *                       data items of each row.
+ *
+ *  @see psFitsReadTableRow
+ */
+psArray* psFitsReadTable(
+    psFits* fits                       ///< the psFits object
+);
+
+/** Writes a whole FITS table.  The current HDU type must be either
+ *  PS_FITS_TYPE_BINARY_TABLE or PS_FITS_TYPE_ASCII_TABLE.
+ *
+ *  @return bool        TRUE if the write was successful, otherwise FALSE
+ *
+ *  @see psFitsReadTableRow
+ */
+bool psFitsWriteTable(
+    psFits* fits,                      ///< the psFits object
+    const psMetadata* header,          ///< header items for the new HDU.  Can be NULL.
+    const psArray* table
+    ///< Array of psMetadata items, which contains the output data items of each row.
+);
+
+/** Updates a FITS table.  The current HDU type must be either
+ *  PS_FITS_TYPE_BINARY_TABLE or PS_FITS_TYPE_ASCII_TABLE.
+ *
+ *  @return bool        TRUE if the write was successful, otherwise FALSE
+ *
+ *  @see psFitsWriteTable
+ */
+bool psFitsUpdateTable(
+    psFits* fits,                ///< the psFits object
+    const psMetadata* data,
+    ///< Array of psMetadata items, which contains the output data items of each row.
+    int row                            ///< the row number to update.
+);
+
+/// @}
+
+#endif // #ifndef PS_FITS_H
