Index: /trunk/psLib/src/dataIO/psFileUtilsErrors.dat
===================================================================
--- /trunk/psLib/src/dataIO/psFileUtilsErrors.dat	(revision 2805)
+++ /trunk/psLib/src/dataIO/psFileUtilsErrors.dat	(revision 2806)
@@ -25,14 +25,23 @@
 psFits_GETHDUTYPE_FAILED               Failed to determine an HDU type in file %s.\nCFITSIO Error: %s
 psFits_GETNUMKEYS_FAILED               Failed to determine the number of header keys in file %s.\nCFITSIO Error: %s
+psFits_GET_TABLE_SIZE_FAILED           Failed to determine the size of the current HDU table.\nCFITSIO Error: %s
 psFits_FILENAME_CREATE_FAILED          Could not create file,'%s'.\nCFITSIO Error: %s
 psFits_TYPE_UNSUPPORTED                Specified type, %s, is not supported.
 psFits_CREATE_HDU_FAILED               Could not create new image HDU in file,'%s'.\nCFITSIO Error: %s
-psFits_NOT_IMAGE_TYPE                  Current FITS HDU type must be an IMAGE.
+psFits_GET_HDU_TYPE_FAILED             Could not determine the HDU type.\nCFITSIO Error: %s
+psFits_NOT_IMAGE_TYPE                  Current FITS HDU type must be an image.
+psFits_NOT_TABLE_TYPE                  Current FITS HDU type must be a table.
 psFits_TABLE_FIRSTROW_NULL             Can't create a table without the first row, where table column information is derived.
 psFits_CFITSIO_ERROR                   CFITSIO error: %s
 psFits_METATYPE_INVALID                Specified FITS metadata type, %c, is not supported.
 psFits_METADATA_ADD_FAILED             Failed to add metadata item, %s.
-psFits_WRITE_FAILED                    Could not write psImage data to file,'%s'.\nCFITSIO Error: %s
+psFits_WRITE_FAILED                    Could not write data to file,'%s'.\nCFITSIO Error: %s
 psFits_IMAGE_NULL                      The input psImage was NULL.  Need a non-NULL psImage for operation to be performed.
 psFits_METADATA_NULL                   The input psMetadata was NULL.  Need a non-NULL psMetadata for operation to be performed.
+psFits_METADATA_PTYPE_UNSUPPORTED      A metadata item's primative type, %d, is not supported.
+psFits_ROW_INVALID                     Specified row, %d, is not valid for current table of %d rows.  
+psFits_GET_TABLE_ELEMENT               Failed to retrieve table element (%d,%d).\nCFITSIO Error: %s
+psFits_FIND_COLUMN                     Specified column, %s, was not found.\nCFITSIO Error: %s
+psFits_GET_COLTYPE                     Could not determine the datatype of the table column.\nCFITSIO Error: %s
+psFits_TABLE_READ_COL                  Failed to read table column.\nCFITSIO Error: %s
 #
Index: /trunk/psLib/src/dataIO/psFileUtilsErrors.h
===================================================================
--- /trunk/psLib/src/dataIO/psFileUtilsErrors.h	(revision 2805)
+++ /trunk/psLib/src/dataIO/psFileUtilsErrors.h	(revision 2806)
@@ -7,6 +7,6 @@
  *  @author Robert DeSonia, MHPCC
  *
- *  @version $Revision: 1.4 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2004-12-10 02:50:15 $
+ *  @version $Revision: 1.5 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2004-12-23 19:13:53 $
  *
  *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
@@ -47,15 +47,24 @@
 #define PS_ERRORTEXT_psFits_GETHDUTYPE_FAILED "Failed to determine an HDU type in file %s.\nCFITSIO Error: %s"
 #define PS_ERRORTEXT_psFits_GETNUMKEYS_FAILED "Failed to determine the number of header keys in file %s.\nCFITSIO Error: %s"
+#define PS_ERRORTEXT_psFits_GET_TABLE_SIZE_FAILED "Failed to determine the size of the current HDU table.\nCFITSIO Error: %s"
 #define PS_ERRORTEXT_psFits_FILENAME_CREATE_FAILED "Could not create file,'%s'.\nCFITSIO Error: %s"
 #define PS_ERRORTEXT_psFits_TYPE_UNSUPPORTED "Specified type, %s, is not supported."
 #define PS_ERRORTEXT_psFits_CREATE_HDU_FAILED "Could not create new image HDU in file,'%s'.\nCFITSIO Error: %s"
-#define PS_ERRORTEXT_psFits_NOT_IMAGE_TYPE "Current FITS HDU type must be an IMAGE."
+#define PS_ERRORTEXT_psFits_GET_HDU_TYPE_FAILED "Could not determine the HDU type.\nCFITSIO Error: %s"
+#define PS_ERRORTEXT_psFits_NOT_IMAGE_TYPE "Current FITS HDU type must be an image."
+#define PS_ERRORTEXT_psFits_NOT_TABLE_TYPE "Current FITS HDU type must be a table."
 #define PS_ERRORTEXT_psFits_TABLE_FIRSTROW_NULL "Can't create a table without the first row, where table column information is derived."
 #define PS_ERRORTEXT_psFits_CFITSIO_ERROR "CFITSIO error: %s"
 #define PS_ERRORTEXT_psFits_METATYPE_INVALID "Specified FITS metadata type, %c, is not supported."
 #define PS_ERRORTEXT_psFits_METADATA_ADD_FAILED "Failed to add metadata item, %s."
-#define PS_ERRORTEXT_psFits_WRITE_FAILED "Could not write psImage data to file,'%s'.\nCFITSIO Error: %s"
+#define PS_ERRORTEXT_psFits_WRITE_FAILED "Could not write data to file,'%s'.\nCFITSIO Error: %s"
 #define PS_ERRORTEXT_psFits_IMAGE_NULL "The input psImage was NULL.  Need a non-NULL psImage for operation to be performed."
 #define PS_ERRORTEXT_psFits_METADATA_NULL "The input psMetadata was NULL.  Need a non-NULL psMetadata for operation to be performed."
+#define PS_ERRORTEXT_psFits_METADATA_PTYPE_UNSUPPORTED "A metadata item's primative type, %d, is not supported."
+#define PS_ERRORTEXT_psFits_ROW_INVALID "Specified row, %d, is not valid for current table of %d rows.  "
+#define PS_ERRORTEXT_psFits_GET_TABLE_ELEMENT "Failed to retrieve table element (%d,%d).\nCFITSIO Error: %s"
+#define PS_ERRORTEXT_psFits_FIND_COLUMN "Specified column, %s, was not found.\nCFITSIO Error: %s"
+#define PS_ERRORTEXT_psFits_GET_COLTYPE "Could not determine the datatype of the table column.\nCFITSIO Error: %s"
+#define PS_ERRORTEXT_psFits_TABLE_READ_COL "Failed to read table column.\nCFITSIO Error: %s"
 //~End
 
Index: /trunk/psLib/src/dataIO/psFits.c
===================================================================
--- /trunk/psLib/src/dataIO/psFits.c	(revision 2805)
+++ /trunk/psLib/src/dataIO/psFits.c	(revision 2806)
@@ -7,6 +7,6 @@
  *  @author Robert DeSonia, MHPCC
  *
- *  @version $Revision: 1.2 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2004-12-10 02:50:15 $
+ *  @version $Revision: 1.3 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2004-12-23 19:13:53 $
  *
  *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
@@ -22,6 +22,48 @@
 #include "psString.h"
 #include "psLogMsg.h"
+#include "psTrace.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;
+    default:
+        return PS_TYPE_PTR;
+    }
+}
+
 
 static bool convertPsTypeToFits(psElemType type, int* bitPix, double* bZero, int* dataType)
@@ -103,17 +145,17 @@
 }
 
-static bool convertPsMetadataTypeToBinaryTForm(psMetadataType type, char** fitsType)
+static bool convertPsTypeToBinaryTForm(psElemType type, char** fitsType)
 {
     switch (type) {
-    case PS_META_BOOL:
+    case PS_TYPE_BOOL:
         *fitsType = "1L";
         break;
-    case PS_META_S32:
+    case PS_TYPE_S32:
         *fitsType = "1J";
         break;
-    case PS_META_F32:
+    case PS_TYPE_F32:
         *fitsType = "1E";
         break;
-    case PS_META_F64:
+    case PS_TYPE_F64:
         *fitsType = "1D";
         break;
@@ -380,5 +422,4 @@
     char keyValue[MAX_STRING_LENGTH];
     char keyComment[MAX_STRING_LENGTH];
-    psMetadataType metadataItemType;
     psBool tempBool;
     psBool success;
@@ -393,19 +434,39 @@
         switch (keyType) {
         case 'I':
-            metadataItemType = PS_META_S32;
-            success = psMetadataAdd(out, PS_LIST_TAIL, keyName, metadataItemType, keyComment, atoi(keyValue));
+            success = psMetadataAdd(out,
+                                    PS_LIST_TAIL,
+                                    keyName,
+                                    PS_TYPE_S32,
+                                    PS_META_PRIMITIVE,
+                                    keyComment,
+                                    atoi(keyValue));
             break;
         case 'F':
-            metadataItemType = PS_META_F64;
-            success = psMetadataAdd(out, PS_LIST_TAIL, keyName, metadataItemType, keyComment, atof(keyValue));
+            success = psMetadataAdd(out,
+                                    PS_LIST_TAIL,
+                                    keyName,
+                                    PS_TYPE_F64,
+                                    PS_META_PRIMITIVE,
+                                    keyComment,
+                                    atof(keyValue));
             break;
         case 'C':
-            metadataItemType = PS_META_STR;
-            success = psMetadataAdd(out, PS_LIST_TAIL, keyName, metadataItemType, keyComment, keyValue);
+            success = psMetadataAdd(out,
+                                    PS_LIST_TAIL,
+                                    keyName,
+                                    PS_TYPE_U8,
+                                    PS_META_STR,
+                                    keyComment,
+                                    keyValue);
             break;
         case 'L':
-            metadataItemType = PS_META_BOOL;
             tempBool = (keyValue[0] == 'T') ? 1 : 0;
-            success = psMetadataAdd(out, PS_LIST_TAIL, keyName, metadataItemType, keyComment, tempBool);
+            success = psMetadataAdd(out,
+                                    PS_LIST_TAIL,
+                                    keyName,
+                                    PS_TYPE_BOOL,
+                                    PS_META_PRIMITIVE,
+                                    keyComment,
+                                    tempBool);
             break;
         case 'U':
@@ -530,5 +591,5 @@
     // write the header, if any.
     if (header != NULL) {
-        psFitsWriteHeader(fits, header);
+        psFitsWriteHeader(header, fits);
     }
 
@@ -567,5 +628,5 @@
 }
 
-bool psFitsWriteHeader(psMetadata* header,
+bool psFitsWriteHeader(const psMetadata* header,
                        psFits* fits)
 {
@@ -583,4 +644,71 @@
     }
 
+    int status = 0;
+
+    //transverse the metadata list and add each key.
+
+    psListIterator* iter = psListIteratorAlloc(header->list,PS_LIST_HEAD);
+    psMetadataItem* item;
+    while ( (item=psListGetNext(iter)) != NULL ) {
+        if (item->type == PS_META_PRIMITIVE) { // we only write primitive data types.
+            switch (item->pType) {
+            case PS_TYPE_BOOL: {
+                    int value = item->data.B;
+                    fits_update_key(fits->p_fd,
+                                    TLOGICAL,
+                                    item->name,
+                                    &value,
+                                    item->comment,
+                                    &status);
+                    break;
+                }
+            case PS_TYPE_S32:
+                fits_update_key(fits->p_fd,
+                                TINT,
+                                item->name,
+                                &item->data.S32,
+                                item->comment,
+                                &status);
+                break;
+            case PS_TYPE_F32:
+                fits_update_key(fits->p_fd,
+                                TFLOAT,
+                                item->name,
+                                &item->data.F32,
+                                item->comment,
+                                &status);
+                break;
+            case PS_TYPE_F64:
+                fits_update_key(fits->p_fd,
+                                TDOUBLE,
+                                item->name,
+                                &item->data.F64,
+                                item->comment,
+                                &status);
+                break;
+            default:
+                psError(PS_ERR_BAD_PARAMETER_TYPE, true,
+                        PS_ERRORTEXT_psFits_METADATA_PTYPE_UNSUPPORTED,
+                        item->pType);
+                break;
+            }
+        } else if (item->type == PS_META_STR) {
+            fits_update_key(fits->p_fd,
+                            TSTRING,
+                            item->name,
+                            item->data.V,
+                            item->comment,
+                            &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;
@@ -589,19 +717,456 @@
 psMetadata* psFitsReadTableRow(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->p_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->p_fd, &numRows, &status);
+    fits_get_num_cols(fits->p_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;
+    }
+
+    // the row parameter in the proper range?
+    if (row < 1 || 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->p_fd, col, name,
+                               NULL, NULL, NULL, NULL, NULL, NULL, NULL, &status);
+        } else {
+            fits_get_acolparms(fits->p_fd, col, name,
+                               NULL, NULL, NULL, NULL, NULL, NULL, NULL, &status);
+        }
+
+        // get the column type
+        fits_get_coltype(fits->p_fd, col, &typecode, &repeat, &width, &status);
+
+        if (status == 0) {
+
+            #define READ_TABLE_ROW_CASE(FITSTYPE, TYPE) \
+        case FITSTYPE: { \
+                ps##TYPE value; \
+                int anynul = 0; \
+                fits_read_col(fits->p_fd, FITSTYPE, col,row+1, \
+                              1, 1, NULL, &value, &anynul, &status); \
+                if (anynul == 0) { \
+                    psMetadataAdd(data,PS_LIST_TAIL, name, \
+                                  PS_TYPE_S32, PS_META_PRIMITIVE, \
+                                  "", value); \
+                } \
+            } \
+            break;
+
+            switch (typecode) {
+            case TBYTE:
+            case TSHORT:
+                READ_TABLE_ROW_CASE(TLONG, S32)
+                READ_TABLE_ROW_CASE(TFLOAT, F32)
+                READ_TABLE_ROW_CASE(TDOUBLE, F64)
+            default:
+                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(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->p_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->p_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->p_fd, &numRows, &status);
+
+    psArray* result = psArrayAlloc(numRows);
+
+    fits_read_col_str(fits->p_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(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->p_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->p_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->p_fd, &numRows, &status);
+
+    // get the column datatype.
+    int typecode;
+    long repeat;
+    long width;
+    if ( fits_get_eqcoltype(fits->p_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->p_fd, typecode, colnum, 1 /* firstrow */,
+                  1 /* firstelem */, numRows, NULL, result->data.V,
+                  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->p_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;
+    int numCols = 0;
+    fits_get_num_rows(fits->p_fd, &numRows, &status);
+    fits_get_num_cols(fits->p_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;
+    }
+
+    psArray* table = psArrayAlloc(numCols);
+
+    for (int row = 0; row < numRows; row++) {
+        table->data[row] = psFitsReadTableRow(fits,row);
+    }
+
+    return table;
+}
 
 bool psFitsWriteTable(psFits* fits,
-                      psArray* table)
-{}
+                      psMetadata* header,
+                      psArray* table,
+                      char* extname)
+{
+    int status = 0;
+
+    if (fits == NULL) {
+        psError(PS_ERR_BAD_PARAMETER_NULL, true,
+                PS_ERRORTEXT_psFits_NULL);
+        return NULL;
+    }
+
+    if (table == NULL) {
+        psError(PS_ERR_BAD_PARAMETER_NULL, true,
+                PS_ERRORTEXT_psFits_IMAGE_NULL);
+        return false;
+    }
+
+    int rows = table->n;
+
+    // find all the columns needed
+    psArray* columns = psArrayAlloc(16);
+    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);
+            while ( (item=psListGetNext(iter)) != NULL) {
+                if (item->type == PS_META_PRIMITIVE) {
+                    bool found = false;
+                    for (int n=0; n < columns->n && ! found; n++) {
+                        if (strcmp(item->name,
+                                   ((psMetadataItem*)(columns->data[n]))->name) == 0) {
+                            found = true;
+                        }
+                    }
+                    if (! found) {
+                        psArrayAdd(columns, columns->nalloc, item);
+                    }
+                }
+            }
+            psFree(iter);
+        }
+    }
+
+    if (columns->n == 0) { // no table columns found
+        // XXX: Error?
+        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++) {
+        char* fitsType;
+        columnNames->data[n] = ((psMetadataItem*)columns->data[n])->name;
+        if ( ! convertPsTypeToBinaryTForm(((psMetadataItem*)columns->data[n])->pType,
+                                          &fitsType)) {
+            // XXX: error message
+            return false;
+        }
+        columnTypes->data[n] = fitsType;
+    }
+
+    fits_create_tbl(fits->p_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);
+
+    // fill in the table elements with data
+    for (int n = 0; n < columns->n; n++) {
+        int row;
+        item = columns->data[n];
+        psArray* columnItems = psArrayAlloc(table->n);
+        for (row = 0; row < table->n; row++) {
+            columnItems->data[row] = psMetadataLookup(table->data[row],item->name);
+        }
+
+        if (item->type == PS_META_PRIMITIVE) {
+            psVector* col = psVectorAlloc(table->n, item->pType);
+            switch (item->pType) {
+            case PS_TYPE_S32:
+                for (row = 0; row < table->n; row++) {
+                    col->data.S32[row] = item->data.S32;
+                }
+                fits_write_col_int(fits->p_fd,
+                                   n, // column number
+                                   1, // firstrow
+                                   1, // firstelem
+                                   table->n, // nelements
+                                   col->data.S32,
+                                   &status);
+                break;
+            case PS_TYPE_F32:
+                for (row = 0; row < table->n; row++) {
+                    col->data.F32[row] = item->data.F32;
+                }
+                fits_write_col_flt(fits->p_fd,
+                                   n, // column number
+                                   1, // firstrow
+                                   1, // firstelem
+                                   table->n, // nelements
+                                   col->data.F32,
+                                   &status);
+                break;
+            case PS_TYPE_S64:
+                for (row = 0; row < table->n; row++) {
+                    col->data.F64[row] = item->data.F64;
+                }
+                fits_write_col_dbl(fits->p_fd,
+                                   n, // column number
+                                   1, // firstrow
+                                   1, // firstelem
+                                   table->n, // nelements
+                                   col->data.F64,
+                                   &status);
+                break;
+            default:
+                // XXX: error message
+                psFree(col);
+                psFree(columnItems);
+                psFree(columnNames);
+                psFree(columnTypes);
+                psFree(columns);
+                return false;
+            }
+
+        } else if (item->type == PS_META_STR) {
+            psArray* col = psArrayAlloc(table->n);
+            for (row = 0; row < table->n; row++) {
+                col->data[row] = item->data.V;
+            }
+            fits_write_col_str(fits->p_fd,
+                               n, // column number
+                               1, // firstrow
+                               1, // firstelem
+                               table->n, // nelements
+                               (char**)col->data,
+                               &status);
+        }
+    }
+
+    return true;
+}
Index: /trunk/psLib/src/dataIO/psFits.h
===================================================================
--- /trunk/psLib/src/dataIO/psFits.h	(revision 2805)
+++ /trunk/psLib/src/dataIO/psFits.h	(revision 2806)
@@ -7,6 +7,6 @@
  *  @author Robert DeSonia, MHPCC
  *
- *  @version $Revision: 1.2 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2004-12-10 02:50:15 $
+ *  @version $Revision: 1.3 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2004-12-23 19:13:53 $
  *
  *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
@@ -143,5 +143,5 @@
  */
 bool psFitsWriteHeader(
-    psMetadata* header,                ///< the psMetadata data in which to write
+    const psMetadata* header,          ///< the psMetadata data in which to write
     psFits* fits                       ///< the psFits object
 );
@@ -162,9 +162,9 @@
  *  @return bool        TRUE is the write was successful, otherwise FALSE.
  */
-bool psFitsWriteImageSection(
-    psFits* fits,                      ///< the psFits object
+bool psFitsWriteImage(
+    psFits* fits,                      ///< the psFits object
+    const psMetadata* header,
     const psImage* input,              ///< the image to output
-    psRegion region,                   ///< the part of the FITS image to overwrite
-    int z                              ///< the z-plane of the FITS image data cube to use
+    int depth                          ///< the number of z-planes of the FITS image data cube
 );
 
@@ -223,6 +223,8 @@
 bool psFitsWriteTable(
     psFits* fits,                      ///< the psFits object
-    psArray* table
+    psMetadata* header,
+    psArray* table,
     ///< Array of psMetadata items, which contains the output data items of each row.
+    char* extname
 );
 
Index: /trunk/psLib/src/fileUtils/psFileUtilsErrors.dat
===================================================================
--- /trunk/psLib/src/fileUtils/psFileUtilsErrors.dat	(revision 2805)
+++ /trunk/psLib/src/fileUtils/psFileUtilsErrors.dat	(revision 2806)
@@ -25,14 +25,23 @@
 psFits_GETHDUTYPE_FAILED               Failed to determine an HDU type in file %s.\nCFITSIO Error: %s
 psFits_GETNUMKEYS_FAILED               Failed to determine the number of header keys in file %s.\nCFITSIO Error: %s
+psFits_GET_TABLE_SIZE_FAILED           Failed to determine the size of the current HDU table.\nCFITSIO Error: %s
 psFits_FILENAME_CREATE_FAILED          Could not create file,'%s'.\nCFITSIO Error: %s
 psFits_TYPE_UNSUPPORTED                Specified type, %s, is not supported.
 psFits_CREATE_HDU_FAILED               Could not create new image HDU in file,'%s'.\nCFITSIO Error: %s
-psFits_NOT_IMAGE_TYPE                  Current FITS HDU type must be an IMAGE.
+psFits_GET_HDU_TYPE_FAILED             Could not determine the HDU type.\nCFITSIO Error: %s
+psFits_NOT_IMAGE_TYPE                  Current FITS HDU type must be an image.
+psFits_NOT_TABLE_TYPE                  Current FITS HDU type must be a table.
 psFits_TABLE_FIRSTROW_NULL             Can't create a table without the first row, where table column information is derived.
 psFits_CFITSIO_ERROR                   CFITSIO error: %s
 psFits_METATYPE_INVALID                Specified FITS metadata type, %c, is not supported.
 psFits_METADATA_ADD_FAILED             Failed to add metadata item, %s.
-psFits_WRITE_FAILED                    Could not write psImage data to file,'%s'.\nCFITSIO Error: %s
+psFits_WRITE_FAILED                    Could not write data to file,'%s'.\nCFITSIO Error: %s
 psFits_IMAGE_NULL                      The input psImage was NULL.  Need a non-NULL psImage for operation to be performed.
 psFits_METADATA_NULL                   The input psMetadata was NULL.  Need a non-NULL psMetadata for operation to be performed.
+psFits_METADATA_PTYPE_UNSUPPORTED      A metadata item's primative type, %d, is not supported.
+psFits_ROW_INVALID                     Specified row, %d, is not valid for current table of %d rows.  
+psFits_GET_TABLE_ELEMENT               Failed to retrieve table element (%d,%d).\nCFITSIO Error: %s
+psFits_FIND_COLUMN                     Specified column, %s, was not found.\nCFITSIO Error: %s
+psFits_GET_COLTYPE                     Could not determine the datatype of the table column.\nCFITSIO Error: %s
+psFits_TABLE_READ_COL                  Failed to read table column.\nCFITSIO Error: %s
 #
Index: /trunk/psLib/src/fileUtils/psFileUtilsErrors.h
===================================================================
--- /trunk/psLib/src/fileUtils/psFileUtilsErrors.h	(revision 2805)
+++ /trunk/psLib/src/fileUtils/psFileUtilsErrors.h	(revision 2806)
@@ -7,6 +7,6 @@
  *  @author Robert DeSonia, MHPCC
  *
- *  @version $Revision: 1.4 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2004-12-10 02:50:15 $
+ *  @version $Revision: 1.5 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2004-12-23 19:13:53 $
  *
  *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
@@ -47,15 +47,24 @@
 #define PS_ERRORTEXT_psFits_GETHDUTYPE_FAILED "Failed to determine an HDU type in file %s.\nCFITSIO Error: %s"
 #define PS_ERRORTEXT_psFits_GETNUMKEYS_FAILED "Failed to determine the number of header keys in file %s.\nCFITSIO Error: %s"
+#define PS_ERRORTEXT_psFits_GET_TABLE_SIZE_FAILED "Failed to determine the size of the current HDU table.\nCFITSIO Error: %s"
 #define PS_ERRORTEXT_psFits_FILENAME_CREATE_FAILED "Could not create file,'%s'.\nCFITSIO Error: %s"
 #define PS_ERRORTEXT_psFits_TYPE_UNSUPPORTED "Specified type, %s, is not supported."
 #define PS_ERRORTEXT_psFits_CREATE_HDU_FAILED "Could not create new image HDU in file,'%s'.\nCFITSIO Error: %s"
-#define PS_ERRORTEXT_psFits_NOT_IMAGE_TYPE "Current FITS HDU type must be an IMAGE."
+#define PS_ERRORTEXT_psFits_GET_HDU_TYPE_FAILED "Could not determine the HDU type.\nCFITSIO Error: %s"
+#define PS_ERRORTEXT_psFits_NOT_IMAGE_TYPE "Current FITS HDU type must be an image."
+#define PS_ERRORTEXT_psFits_NOT_TABLE_TYPE "Current FITS HDU type must be a table."
 #define PS_ERRORTEXT_psFits_TABLE_FIRSTROW_NULL "Can't create a table without the first row, where table column information is derived."
 #define PS_ERRORTEXT_psFits_CFITSIO_ERROR "CFITSIO error: %s"
 #define PS_ERRORTEXT_psFits_METATYPE_INVALID "Specified FITS metadata type, %c, is not supported."
 #define PS_ERRORTEXT_psFits_METADATA_ADD_FAILED "Failed to add metadata item, %s."
-#define PS_ERRORTEXT_psFits_WRITE_FAILED "Could not write psImage data to file,'%s'.\nCFITSIO Error: %s"
+#define PS_ERRORTEXT_psFits_WRITE_FAILED "Could not write data to file,'%s'.\nCFITSIO Error: %s"
 #define PS_ERRORTEXT_psFits_IMAGE_NULL "The input psImage was NULL.  Need a non-NULL psImage for operation to be performed."
 #define PS_ERRORTEXT_psFits_METADATA_NULL "The input psMetadata was NULL.  Need a non-NULL psMetadata for operation to be performed."
+#define PS_ERRORTEXT_psFits_METADATA_PTYPE_UNSUPPORTED "A metadata item's primative type, %d, is not supported."
+#define PS_ERRORTEXT_psFits_ROW_INVALID "Specified row, %d, is not valid for current table of %d rows.  "
+#define PS_ERRORTEXT_psFits_GET_TABLE_ELEMENT "Failed to retrieve table element (%d,%d).\nCFITSIO Error: %s"
+#define PS_ERRORTEXT_psFits_FIND_COLUMN "Specified column, %s, was not found.\nCFITSIO Error: %s"
+#define PS_ERRORTEXT_psFits_GET_COLTYPE "Could not determine the datatype of the table column.\nCFITSIO Error: %s"
+#define PS_ERRORTEXT_psFits_TABLE_READ_COL "Failed to read table column.\nCFITSIO Error: %s"
 //~End
 
Index: /trunk/psLib/src/fileUtils/psFits.c
===================================================================
--- /trunk/psLib/src/fileUtils/psFits.c	(revision 2805)
+++ /trunk/psLib/src/fileUtils/psFits.c	(revision 2806)
@@ -7,6 +7,6 @@
  *  @author Robert DeSonia, MHPCC
  *
- *  @version $Revision: 1.2 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2004-12-10 02:50:15 $
+ *  @version $Revision: 1.3 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2004-12-23 19:13:53 $
  *
  *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
@@ -22,6 +22,48 @@
 #include "psString.h"
 #include "psLogMsg.h"
+#include "psTrace.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;
+    default:
+        return PS_TYPE_PTR;
+    }
+}
+
 
 static bool convertPsTypeToFits(psElemType type, int* bitPix, double* bZero, int* dataType)
@@ -103,17 +145,17 @@
 }
 
-static bool convertPsMetadataTypeToBinaryTForm(psMetadataType type, char** fitsType)
+static bool convertPsTypeToBinaryTForm(psElemType type, char** fitsType)
 {
     switch (type) {
-    case PS_META_BOOL:
+    case PS_TYPE_BOOL:
         *fitsType = "1L";
         break;
-    case PS_META_S32:
+    case PS_TYPE_S32:
         *fitsType = "1J";
         break;
-    case PS_META_F32:
+    case PS_TYPE_F32:
         *fitsType = "1E";
         break;
-    case PS_META_F64:
+    case PS_TYPE_F64:
         *fitsType = "1D";
         break;
@@ -380,5 +422,4 @@
     char keyValue[MAX_STRING_LENGTH];
     char keyComment[MAX_STRING_LENGTH];
-    psMetadataType metadataItemType;
     psBool tempBool;
     psBool success;
@@ -393,19 +434,39 @@
         switch (keyType) {
         case 'I':
-            metadataItemType = PS_META_S32;
-            success = psMetadataAdd(out, PS_LIST_TAIL, keyName, metadataItemType, keyComment, atoi(keyValue));
+            success = psMetadataAdd(out,
+                                    PS_LIST_TAIL,
+                                    keyName,
+                                    PS_TYPE_S32,
+                                    PS_META_PRIMITIVE,
+                                    keyComment,
+                                    atoi(keyValue));
             break;
         case 'F':
-            metadataItemType = PS_META_F64;
-            success = psMetadataAdd(out, PS_LIST_TAIL, keyName, metadataItemType, keyComment, atof(keyValue));
+            success = psMetadataAdd(out,
+                                    PS_LIST_TAIL,
+                                    keyName,
+                                    PS_TYPE_F64,
+                                    PS_META_PRIMITIVE,
+                                    keyComment,
+                                    atof(keyValue));
             break;
         case 'C':
-            metadataItemType = PS_META_STR;
-            success = psMetadataAdd(out, PS_LIST_TAIL, keyName, metadataItemType, keyComment, keyValue);
+            success = psMetadataAdd(out,
+                                    PS_LIST_TAIL,
+                                    keyName,
+                                    PS_TYPE_U8,
+                                    PS_META_STR,
+                                    keyComment,
+                                    keyValue);
             break;
         case 'L':
-            metadataItemType = PS_META_BOOL;
             tempBool = (keyValue[0] == 'T') ? 1 : 0;
-            success = psMetadataAdd(out, PS_LIST_TAIL, keyName, metadataItemType, keyComment, tempBool);
+            success = psMetadataAdd(out,
+                                    PS_LIST_TAIL,
+                                    keyName,
+                                    PS_TYPE_BOOL,
+                                    PS_META_PRIMITIVE,
+                                    keyComment,
+                                    tempBool);
             break;
         case 'U':
@@ -530,5 +591,5 @@
     // write the header, if any.
     if (header != NULL) {
-        psFitsWriteHeader(fits, header);
+        psFitsWriteHeader(header, fits);
     }
 
@@ -567,5 +628,5 @@
 }
 
-bool psFitsWriteHeader(psMetadata* header,
+bool psFitsWriteHeader(const psMetadata* header,
                        psFits* fits)
 {
@@ -583,4 +644,71 @@
     }
 
+    int status = 0;
+
+    //transverse the metadata list and add each key.
+
+    psListIterator* iter = psListIteratorAlloc(header->list,PS_LIST_HEAD);
+    psMetadataItem* item;
+    while ( (item=psListGetNext(iter)) != NULL ) {
+        if (item->type == PS_META_PRIMITIVE) { // we only write primitive data types.
+            switch (item->pType) {
+            case PS_TYPE_BOOL: {
+                    int value = item->data.B;
+                    fits_update_key(fits->p_fd,
+                                    TLOGICAL,
+                                    item->name,
+                                    &value,
+                                    item->comment,
+                                    &status);
+                    break;
+                }
+            case PS_TYPE_S32:
+                fits_update_key(fits->p_fd,
+                                TINT,
+                                item->name,
+                                &item->data.S32,
+                                item->comment,
+                                &status);
+                break;
+            case PS_TYPE_F32:
+                fits_update_key(fits->p_fd,
+                                TFLOAT,
+                                item->name,
+                                &item->data.F32,
+                                item->comment,
+                                &status);
+                break;
+            case PS_TYPE_F64:
+                fits_update_key(fits->p_fd,
+                                TDOUBLE,
+                                item->name,
+                                &item->data.F64,
+                                item->comment,
+                                &status);
+                break;
+            default:
+                psError(PS_ERR_BAD_PARAMETER_TYPE, true,
+                        PS_ERRORTEXT_psFits_METADATA_PTYPE_UNSUPPORTED,
+                        item->pType);
+                break;
+            }
+        } else if (item->type == PS_META_STR) {
+            fits_update_key(fits->p_fd,
+                            TSTRING,
+                            item->name,
+                            item->data.V,
+                            item->comment,
+                            &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;
@@ -589,19 +717,456 @@
 psMetadata* psFitsReadTableRow(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->p_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->p_fd, &numRows, &status);
+    fits_get_num_cols(fits->p_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;
+    }
+
+    // the row parameter in the proper range?
+    if (row < 1 || 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->p_fd, col, name,
+                               NULL, NULL, NULL, NULL, NULL, NULL, NULL, &status);
+        } else {
+            fits_get_acolparms(fits->p_fd, col, name,
+                               NULL, NULL, NULL, NULL, NULL, NULL, NULL, &status);
+        }
+
+        // get the column type
+        fits_get_coltype(fits->p_fd, col, &typecode, &repeat, &width, &status);
+
+        if (status == 0) {
+
+            #define READ_TABLE_ROW_CASE(FITSTYPE, TYPE) \
+        case FITSTYPE: { \
+                ps##TYPE value; \
+                int anynul = 0; \
+                fits_read_col(fits->p_fd, FITSTYPE, col,row+1, \
+                              1, 1, NULL, &value, &anynul, &status); \
+                if (anynul == 0) { \
+                    psMetadataAdd(data,PS_LIST_TAIL, name, \
+                                  PS_TYPE_S32, PS_META_PRIMITIVE, \
+                                  "", value); \
+                } \
+            } \
+            break;
+
+            switch (typecode) {
+            case TBYTE:
+            case TSHORT:
+                READ_TABLE_ROW_CASE(TLONG, S32)
+                READ_TABLE_ROW_CASE(TFLOAT, F32)
+                READ_TABLE_ROW_CASE(TDOUBLE, F64)
+            default:
+                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(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->p_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->p_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->p_fd, &numRows, &status);
+
+    psArray* result = psArrayAlloc(numRows);
+
+    fits_read_col_str(fits->p_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(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->p_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->p_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->p_fd, &numRows, &status);
+
+    // get the column datatype.
+    int typecode;
+    long repeat;
+    long width;
+    if ( fits_get_eqcoltype(fits->p_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->p_fd, typecode, colnum, 1 /* firstrow */,
+                  1 /* firstelem */, numRows, NULL, result->data.V,
+                  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->p_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;
+    int numCols = 0;
+    fits_get_num_rows(fits->p_fd, &numRows, &status);
+    fits_get_num_cols(fits->p_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;
+    }
+
+    psArray* table = psArrayAlloc(numCols);
+
+    for (int row = 0; row < numRows; row++) {
+        table->data[row] = psFitsReadTableRow(fits,row);
+    }
+
+    return table;
+}
 
 bool psFitsWriteTable(psFits* fits,
-                      psArray* table)
-{}
+                      psMetadata* header,
+                      psArray* table,
+                      char* extname)
+{
+    int status = 0;
+
+    if (fits == NULL) {
+        psError(PS_ERR_BAD_PARAMETER_NULL, true,
+                PS_ERRORTEXT_psFits_NULL);
+        return NULL;
+    }
+
+    if (table == NULL) {
+        psError(PS_ERR_BAD_PARAMETER_NULL, true,
+                PS_ERRORTEXT_psFits_IMAGE_NULL);
+        return false;
+    }
+
+    int rows = table->n;
+
+    // find all the columns needed
+    psArray* columns = psArrayAlloc(16);
+    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);
+            while ( (item=psListGetNext(iter)) != NULL) {
+                if (item->type == PS_META_PRIMITIVE) {
+                    bool found = false;
+                    for (int n=0; n < columns->n && ! found; n++) {
+                        if (strcmp(item->name,
+                                   ((psMetadataItem*)(columns->data[n]))->name) == 0) {
+                            found = true;
+                        }
+                    }
+                    if (! found) {
+                        psArrayAdd(columns, columns->nalloc, item);
+                    }
+                }
+            }
+            psFree(iter);
+        }
+    }
+
+    if (columns->n == 0) { // no table columns found
+        // XXX: Error?
+        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++) {
+        char* fitsType;
+        columnNames->data[n] = ((psMetadataItem*)columns->data[n])->name;
+        if ( ! convertPsTypeToBinaryTForm(((psMetadataItem*)columns->data[n])->pType,
+                                          &fitsType)) {
+            // XXX: error message
+            return false;
+        }
+        columnTypes->data[n] = fitsType;
+    }
+
+    fits_create_tbl(fits->p_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);
+
+    // fill in the table elements with data
+    for (int n = 0; n < columns->n; n++) {
+        int row;
+        item = columns->data[n];
+        psArray* columnItems = psArrayAlloc(table->n);
+        for (row = 0; row < table->n; row++) {
+            columnItems->data[row] = psMetadataLookup(table->data[row],item->name);
+        }
+
+        if (item->type == PS_META_PRIMITIVE) {
+            psVector* col = psVectorAlloc(table->n, item->pType);
+            switch (item->pType) {
+            case PS_TYPE_S32:
+                for (row = 0; row < table->n; row++) {
+                    col->data.S32[row] = item->data.S32;
+                }
+                fits_write_col_int(fits->p_fd,
+                                   n, // column number
+                                   1, // firstrow
+                                   1, // firstelem
+                                   table->n, // nelements
+                                   col->data.S32,
+                                   &status);
+                break;
+            case PS_TYPE_F32:
+                for (row = 0; row < table->n; row++) {
+                    col->data.F32[row] = item->data.F32;
+                }
+                fits_write_col_flt(fits->p_fd,
+                                   n, // column number
+                                   1, // firstrow
+                                   1, // firstelem
+                                   table->n, // nelements
+                                   col->data.F32,
+                                   &status);
+                break;
+            case PS_TYPE_S64:
+                for (row = 0; row < table->n; row++) {
+                    col->data.F64[row] = item->data.F64;
+                }
+                fits_write_col_dbl(fits->p_fd,
+                                   n, // column number
+                                   1, // firstrow
+                                   1, // firstelem
+                                   table->n, // nelements
+                                   col->data.F64,
+                                   &status);
+                break;
+            default:
+                // XXX: error message
+                psFree(col);
+                psFree(columnItems);
+                psFree(columnNames);
+                psFree(columnTypes);
+                psFree(columns);
+                return false;
+            }
+
+        } else if (item->type == PS_META_STR) {
+            psArray* col = psArrayAlloc(table->n);
+            for (row = 0; row < table->n; row++) {
+                col->data[row] = item->data.V;
+            }
+            fits_write_col_str(fits->p_fd,
+                               n, // column number
+                               1, // firstrow
+                               1, // firstelem
+                               table->n, // nelements
+                               (char**)col->data,
+                               &status);
+        }
+    }
+
+    return true;
+}
Index: /trunk/psLib/src/fileUtils/psFits.h
===================================================================
--- /trunk/psLib/src/fileUtils/psFits.h	(revision 2805)
+++ /trunk/psLib/src/fileUtils/psFits.h	(revision 2806)
@@ -7,6 +7,6 @@
  *  @author Robert DeSonia, MHPCC
  *
- *  @version $Revision: 1.2 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2004-12-10 02:50:15 $
+ *  @version $Revision: 1.3 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2004-12-23 19:13:53 $
  *
  *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
@@ -143,5 +143,5 @@
  */
 bool psFitsWriteHeader(
-    psMetadata* header,                ///< the psMetadata data in which to write
+    const psMetadata* header,          ///< the psMetadata data in which to write
     psFits* fits                       ///< the psFits object
 );
@@ -162,9 +162,9 @@
  *  @return bool        TRUE is the write was successful, otherwise FALSE.
  */
-bool psFitsWriteImageSection(
-    psFits* fits,                      ///< the psFits object
+bool psFitsWriteImage(
+    psFits* fits,                      ///< the psFits object
+    const psMetadata* header,
     const psImage* input,              ///< the image to output
-    psRegion region,                   ///< the part of the FITS image to overwrite
-    int z                              ///< the z-plane of the FITS image data cube to use
+    int depth                          ///< the number of z-planes of the FITS image data cube
 );
 
@@ -223,6 +223,8 @@
 bool psFitsWriteTable(
     psFits* fits,                      ///< the psFits object
-    psArray* table
+    psMetadata* header,
+    psArray* table,
     ///< Array of psMetadata items, which contains the output data items of each row.
+    char* extname
 );
 
Index: /trunk/psLib/src/fits/psFits.c
===================================================================
--- /trunk/psLib/src/fits/psFits.c	(revision 2805)
+++ /trunk/psLib/src/fits/psFits.c	(revision 2806)
@@ -7,6 +7,6 @@
  *  @author Robert DeSonia, MHPCC
  *
- *  @version $Revision: 1.2 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2004-12-10 02:50:15 $
+ *  @version $Revision: 1.3 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2004-12-23 19:13:53 $
  *
  *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
@@ -22,6 +22,48 @@
 #include "psString.h"
 #include "psLogMsg.h"
+#include "psTrace.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;
+    default:
+        return PS_TYPE_PTR;
+    }
+}
+
 
 static bool convertPsTypeToFits(psElemType type, int* bitPix, double* bZero, int* dataType)
@@ -103,17 +145,17 @@
 }
 
-static bool convertPsMetadataTypeToBinaryTForm(psMetadataType type, char** fitsType)
+static bool convertPsTypeToBinaryTForm(psElemType type, char** fitsType)
 {
     switch (type) {
-    case PS_META_BOOL:
+    case PS_TYPE_BOOL:
         *fitsType = "1L";
         break;
-    case PS_META_S32:
+    case PS_TYPE_S32:
         *fitsType = "1J";
         break;
-    case PS_META_F32:
+    case PS_TYPE_F32:
         *fitsType = "1E";
         break;
-    case PS_META_F64:
+    case PS_TYPE_F64:
         *fitsType = "1D";
         break;
@@ -380,5 +422,4 @@
     char keyValue[MAX_STRING_LENGTH];
     char keyComment[MAX_STRING_LENGTH];
-    psMetadataType metadataItemType;
     psBool tempBool;
     psBool success;
@@ -393,19 +434,39 @@
         switch (keyType) {
         case 'I':
-            metadataItemType = PS_META_S32;
-            success = psMetadataAdd(out, PS_LIST_TAIL, keyName, metadataItemType, keyComment, atoi(keyValue));
+            success = psMetadataAdd(out,
+                                    PS_LIST_TAIL,
+                                    keyName,
+                                    PS_TYPE_S32,
+                                    PS_META_PRIMITIVE,
+                                    keyComment,
+                                    atoi(keyValue));
             break;
         case 'F':
-            metadataItemType = PS_META_F64;
-            success = psMetadataAdd(out, PS_LIST_TAIL, keyName, metadataItemType, keyComment, atof(keyValue));
+            success = psMetadataAdd(out,
+                                    PS_LIST_TAIL,
+                                    keyName,
+                                    PS_TYPE_F64,
+                                    PS_META_PRIMITIVE,
+                                    keyComment,
+                                    atof(keyValue));
             break;
         case 'C':
-            metadataItemType = PS_META_STR;
-            success = psMetadataAdd(out, PS_LIST_TAIL, keyName, metadataItemType, keyComment, keyValue);
+            success = psMetadataAdd(out,
+                                    PS_LIST_TAIL,
+                                    keyName,
+                                    PS_TYPE_U8,
+                                    PS_META_STR,
+                                    keyComment,
+                                    keyValue);
             break;
         case 'L':
-            metadataItemType = PS_META_BOOL;
             tempBool = (keyValue[0] == 'T') ? 1 : 0;
-            success = psMetadataAdd(out, PS_LIST_TAIL, keyName, metadataItemType, keyComment, tempBool);
+            success = psMetadataAdd(out,
+                                    PS_LIST_TAIL,
+                                    keyName,
+                                    PS_TYPE_BOOL,
+                                    PS_META_PRIMITIVE,
+                                    keyComment,
+                                    tempBool);
             break;
         case 'U':
@@ -530,5 +591,5 @@
     // write the header, if any.
     if (header != NULL) {
-        psFitsWriteHeader(fits, header);
+        psFitsWriteHeader(header, fits);
     }
 
@@ -567,5 +628,5 @@
 }
 
-bool psFitsWriteHeader(psMetadata* header,
+bool psFitsWriteHeader(const psMetadata* header,
                        psFits* fits)
 {
@@ -583,4 +644,71 @@
     }
 
+    int status = 0;
+
+    //transverse the metadata list and add each key.
+
+    psListIterator* iter = psListIteratorAlloc(header->list,PS_LIST_HEAD);
+    psMetadataItem* item;
+    while ( (item=psListGetNext(iter)) != NULL ) {
+        if (item->type == PS_META_PRIMITIVE) { // we only write primitive data types.
+            switch (item->pType) {
+            case PS_TYPE_BOOL: {
+                    int value = item->data.B;
+                    fits_update_key(fits->p_fd,
+                                    TLOGICAL,
+                                    item->name,
+                                    &value,
+                                    item->comment,
+                                    &status);
+                    break;
+                }
+            case PS_TYPE_S32:
+                fits_update_key(fits->p_fd,
+                                TINT,
+                                item->name,
+                                &item->data.S32,
+                                item->comment,
+                                &status);
+                break;
+            case PS_TYPE_F32:
+                fits_update_key(fits->p_fd,
+                                TFLOAT,
+                                item->name,
+                                &item->data.F32,
+                                item->comment,
+                                &status);
+                break;
+            case PS_TYPE_F64:
+                fits_update_key(fits->p_fd,
+                                TDOUBLE,
+                                item->name,
+                                &item->data.F64,
+                                item->comment,
+                                &status);
+                break;
+            default:
+                psError(PS_ERR_BAD_PARAMETER_TYPE, true,
+                        PS_ERRORTEXT_psFits_METADATA_PTYPE_UNSUPPORTED,
+                        item->pType);
+                break;
+            }
+        } else if (item->type == PS_META_STR) {
+            fits_update_key(fits->p_fd,
+                            TSTRING,
+                            item->name,
+                            item->data.V,
+                            item->comment,
+                            &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;
@@ -589,19 +717,456 @@
 psMetadata* psFitsReadTableRow(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->p_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->p_fd, &numRows, &status);
+    fits_get_num_cols(fits->p_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;
+    }
+
+    // the row parameter in the proper range?
+    if (row < 1 || 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->p_fd, col, name,
+                               NULL, NULL, NULL, NULL, NULL, NULL, NULL, &status);
+        } else {
+            fits_get_acolparms(fits->p_fd, col, name,
+                               NULL, NULL, NULL, NULL, NULL, NULL, NULL, &status);
+        }
+
+        // get the column type
+        fits_get_coltype(fits->p_fd, col, &typecode, &repeat, &width, &status);
+
+        if (status == 0) {
+
+            #define READ_TABLE_ROW_CASE(FITSTYPE, TYPE) \
+        case FITSTYPE: { \
+                ps##TYPE value; \
+                int anynul = 0; \
+                fits_read_col(fits->p_fd, FITSTYPE, col,row+1, \
+                              1, 1, NULL, &value, &anynul, &status); \
+                if (anynul == 0) { \
+                    psMetadataAdd(data,PS_LIST_TAIL, name, \
+                                  PS_TYPE_S32, PS_META_PRIMITIVE, \
+                                  "", value); \
+                } \
+            } \
+            break;
+
+            switch (typecode) {
+            case TBYTE:
+            case TSHORT:
+                READ_TABLE_ROW_CASE(TLONG, S32)
+                READ_TABLE_ROW_CASE(TFLOAT, F32)
+                READ_TABLE_ROW_CASE(TDOUBLE, F64)
+            default:
+                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(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->p_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->p_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->p_fd, &numRows, &status);
+
+    psArray* result = psArrayAlloc(numRows);
+
+    fits_read_col_str(fits->p_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(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->p_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->p_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->p_fd, &numRows, &status);
+
+    // get the column datatype.
+    int typecode;
+    long repeat;
+    long width;
+    if ( fits_get_eqcoltype(fits->p_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->p_fd, typecode, colnum, 1 /* firstrow */,
+                  1 /* firstelem */, numRows, NULL, result->data.V,
+                  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->p_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;
+    int numCols = 0;
+    fits_get_num_rows(fits->p_fd, &numRows, &status);
+    fits_get_num_cols(fits->p_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;
+    }
+
+    psArray* table = psArrayAlloc(numCols);
+
+    for (int row = 0; row < numRows; row++) {
+        table->data[row] = psFitsReadTableRow(fits,row);
+    }
+
+    return table;
+}
 
 bool psFitsWriteTable(psFits* fits,
-                      psArray* table)
-{}
+                      psMetadata* header,
+                      psArray* table,
+                      char* extname)
+{
+    int status = 0;
+
+    if (fits == NULL) {
+        psError(PS_ERR_BAD_PARAMETER_NULL, true,
+                PS_ERRORTEXT_psFits_NULL);
+        return NULL;
+    }
+
+    if (table == NULL) {
+        psError(PS_ERR_BAD_PARAMETER_NULL, true,
+                PS_ERRORTEXT_psFits_IMAGE_NULL);
+        return false;
+    }
+
+    int rows = table->n;
+
+    // find all the columns needed
+    psArray* columns = psArrayAlloc(16);
+    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);
+            while ( (item=psListGetNext(iter)) != NULL) {
+                if (item->type == PS_META_PRIMITIVE) {
+                    bool found = false;
+                    for (int n=0; n < columns->n && ! found; n++) {
+                        if (strcmp(item->name,
+                                   ((psMetadataItem*)(columns->data[n]))->name) == 0) {
+                            found = true;
+                        }
+                    }
+                    if (! found) {
+                        psArrayAdd(columns, columns->nalloc, item);
+                    }
+                }
+            }
+            psFree(iter);
+        }
+    }
+
+    if (columns->n == 0) { // no table columns found
+        // XXX: Error?
+        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++) {
+        char* fitsType;
+        columnNames->data[n] = ((psMetadataItem*)columns->data[n])->name;
+        if ( ! convertPsTypeToBinaryTForm(((psMetadataItem*)columns->data[n])->pType,
+                                          &fitsType)) {
+            // XXX: error message
+            return false;
+        }
+        columnTypes->data[n] = fitsType;
+    }
+
+    fits_create_tbl(fits->p_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);
+
+    // fill in the table elements with data
+    for (int n = 0; n < columns->n; n++) {
+        int row;
+        item = columns->data[n];
+        psArray* columnItems = psArrayAlloc(table->n);
+        for (row = 0; row < table->n; row++) {
+            columnItems->data[row] = psMetadataLookup(table->data[row],item->name);
+        }
+
+        if (item->type == PS_META_PRIMITIVE) {
+            psVector* col = psVectorAlloc(table->n, item->pType);
+            switch (item->pType) {
+            case PS_TYPE_S32:
+                for (row = 0; row < table->n; row++) {
+                    col->data.S32[row] = item->data.S32;
+                }
+                fits_write_col_int(fits->p_fd,
+                                   n, // column number
+                                   1, // firstrow
+                                   1, // firstelem
+                                   table->n, // nelements
+                                   col->data.S32,
+                                   &status);
+                break;
+            case PS_TYPE_F32:
+                for (row = 0; row < table->n; row++) {
+                    col->data.F32[row] = item->data.F32;
+                }
+                fits_write_col_flt(fits->p_fd,
+                                   n, // column number
+                                   1, // firstrow
+                                   1, // firstelem
+                                   table->n, // nelements
+                                   col->data.F32,
+                                   &status);
+                break;
+            case PS_TYPE_S64:
+                for (row = 0; row < table->n; row++) {
+                    col->data.F64[row] = item->data.F64;
+                }
+                fits_write_col_dbl(fits->p_fd,
+                                   n, // column number
+                                   1, // firstrow
+                                   1, // firstelem
+                                   table->n, // nelements
+                                   col->data.F64,
+                                   &status);
+                break;
+            default:
+                // XXX: error message
+                psFree(col);
+                psFree(columnItems);
+                psFree(columnNames);
+                psFree(columnTypes);
+                psFree(columns);
+                return false;
+            }
+
+        } else if (item->type == PS_META_STR) {
+            psArray* col = psArrayAlloc(table->n);
+            for (row = 0; row < table->n; row++) {
+                col->data[row] = item->data.V;
+            }
+            fits_write_col_str(fits->p_fd,
+                               n, // column number
+                               1, // firstrow
+                               1, // firstelem
+                               table->n, // nelements
+                               (char**)col->data,
+                               &status);
+        }
+    }
+
+    return true;
+}
Index: /trunk/psLib/src/fits/psFits.h
===================================================================
--- /trunk/psLib/src/fits/psFits.h	(revision 2805)
+++ /trunk/psLib/src/fits/psFits.h	(revision 2806)
@@ -7,6 +7,6 @@
  *  @author Robert DeSonia, MHPCC
  *
- *  @version $Revision: 1.2 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2004-12-10 02:50:15 $
+ *  @version $Revision: 1.3 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2004-12-23 19:13:53 $
  *
  *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
@@ -143,5 +143,5 @@
  */
 bool psFitsWriteHeader(
-    psMetadata* header,                ///< the psMetadata data in which to write
+    const psMetadata* header,          ///< the psMetadata data in which to write
     psFits* fits                       ///< the psFits object
 );
@@ -162,9 +162,9 @@
  *  @return bool        TRUE is the write was successful, otherwise FALSE.
  */
-bool psFitsWriteImageSection(
-    psFits* fits,                      ///< the psFits object
+bool psFitsWriteImage(
+    psFits* fits,                      ///< the psFits object
+    const psMetadata* header,
     const psImage* input,              ///< the image to output
-    psRegion region,                   ///< the part of the FITS image to overwrite
-    int z                              ///< the z-plane of the FITS image data cube to use
+    int depth                          ///< the number of z-planes of the FITS image data cube
 );
 
@@ -223,6 +223,8 @@
 bool psFitsWriteTable(
     psFits* fits,                      ///< the psFits object
-    psArray* table
+    psMetadata* header,
+    psArray* table,
     ///< Array of psMetadata items, which contains the output data items of each row.
+    char* extname
 );
 
