Index: /trunk/ippToPsps/src/Batch.c
===================================================================
--- /trunk/ippToPsps/src/Batch.c	(revision 31024)
+++ /trunk/ippToPsps/src/Batch.c	(revision 31025)
@@ -88,5 +88,5 @@
 
     // destroy objects
-    this->config->destroy(this->config);
+    this->fitsGenerator->destroy(this->fitsGenerator);
     this->initData->destroy(this->initData);
 
@@ -228,12 +228,7 @@
     }
 
-    // create a Config object
+    // create a FitsGenerator object
     strcat(configsBaseDir, configsDir);
-    this->config = new_Config(configsBaseDir);
-    if (this->config == NULL) {
-
-        this->exitCode = PS_EXIT_CONFIG_ERROR;
-        return false;
-    }
+    this->fitsGenerator = new_FitsGenerator(configsBaseDir);
 
     // create full FITS out path
@@ -318,5 +313,5 @@
     this->inputFiles = NULL;
     this->fitsOut = NULL;
-    this->config = NULL;
+    this->fitsGenerator = NULL;
     this->pmconfig = NULL;
     this->exitCode = PS_EXIT_SUCCESS;
Index: /trunk/ippToPsps/src/Batch.h
===================================================================
--- /trunk/ippToPsps/src/Batch.h	(revision 31024)
+++ /trunk/ippToPsps/src/Batch.h	(revision 31025)
@@ -18,5 +18,5 @@
 #include <dvo_util.h>
 
-#include "Config.h"
+#include "FitsGenerator.h"
 #include "Fits.h"
 #include "InitData.h"
@@ -34,19 +34,19 @@
 
     // fields
-    char surveyType[10];        // the survey type, eg 3PI, MD01, STS, SSS
-    int8_t surveyID;            // survey ID
-    char fitsInPath[1000];      // path to FITS input
-    char resultsPath[1000];     // path to results file
-    xmlDocPtr resultsXmlDoc;    // pointer to XML document for results
-    uint16_t numOfInputFiles;   // number of input files
-    char** inputFiles;          // array of input file names
-    Fits *fitsOut;              // output FITS file
-    pmConfig* pmconfig;         // pmConfig
-    dvoConfig* dvoConfig;       // dvo database
-    Config* config;             // Config object
-    InitData* initData;         // InitData object
-    char todaysDate[20];        // today's date
-    int exitCode;               // ps exit code
-    bool testMode;              // test mode boolean
+    char surveyType[10];           // the survey type, eg 3PI, MD01, STS, SSS
+    int8_t surveyID;               // survey ID
+    char fitsInPath[1000];         // path to FITS input
+    char resultsPath[1000];        // path to results file
+    xmlDocPtr resultsXmlDoc;       // pointer to XML document for results
+    uint16_t numOfInputFiles;      // number of input files
+    char** inputFiles;             // array of input file names
+    Fits *fitsOut;                 // output FITS file
+    pmConfig* pmconfig;            // pmConfig
+    dvoConfig* dvoConfig;          // dvo database
+    FitsGenerator* fitsGenerator;  // FitsGenerator object
+    InitData* initData;            // InitData object
+    char todaysDate[20];           // today's date
+    int exitCode;                  // ps exit code
+    bool testMode;                 // test mode boolean
 
     // methods
Index: unk/ippToPsps/src/Config.c
===================================================================
--- /trunk/ippToPsps/src/Config.c	(revision 31024)
+++ 	(revision )
@@ -1,756 +1,0 @@
-/** @file Config.c
- *
- *  @ingroup ippToPsps
- *
- *  @author IfA
- *  Copyright 2011 Institute for Astronomy, University of Hawaii
- */
-
-#include "Config.h"
-#include <ctype.h>
-#include <libxml/parser.h>
-#include <libxml/tree.h>
-
-#include "Fits.h"
-
-/**
-  Finds a column within this table
-  */
-static Column* findColumn(Table* table, const char* name) {
-
-    Column* column = NULL;
-
-    for (uint32_t i=0; i<table->numOfColumns; i++) {
-
-        if (strcmp(table->columns[i].pspsName, name) == 0) {
-            column = table->columns+i;
-            break;
-        }
-    }
-
-    if (!column) psError(PS_ERR_IO, false, "Could not find column '%s' in table '%s'", name, table->name);
-
-    return column;
-}
-
-/**
-  Finds a table from the array of tables
-  */
-static Table* findTable(Config* this, const char* name) {
-
-    Table* table = NULL;
-
-    for (uint32_t i=0; i<this->numOfTables; i++) {
-
-        if (strcmp(this->tables[i].name, name) == 0) {
-            table = this->tables+i;
-            break;
-        }
-    }
-
-    if (!table) psError(PS_ERR_IO, false, "Could not find table '%s'", name);
-
-    return table;
-}
-
-/**
-  Gets an attribute value from XML node
-  */
-static bool getAttribute(xmlNode* node, const char* attName, char* _value) {
-
-    xmlChar* value = xmlGetProp(node, (const xmlChar*)attName);
-    if (!value) return false;
-    sprintf(_value, "%s", value);
-    xmlFree(value);
-
-    return true;
-}
-
-/**
-  Creates a FITS binary table and populates it with defaults based on definition in schema XML
-  */
-static bool createTable(Table* table, Fits* fitsOut, const long nRows) {
-
-    if (!table) return false;
-    if (nRows < 1) return false;
-
-    long nCols = table->numOfColumns;
-
-    char** colNames = (char**)calloc(nCols, sizeof(char*));
-    char** colTypes = (char**)calloc(nCols, sizeof(char*));
-
-    uint32_t i = 0;
-    for (i=0;i<nCols;i++) colTypes[i] = (char*)calloc(5,sizeof(char));
-
-    i = 0;
-    for (uint32_t m=0; m<table->numOfColumns; m++) {
-
-        colNames[i] = table->columns[i].pspsName;
-
-        //        sprintf(colNames[i], table->columns[i].pspsName);
-
-        switch (table->columns[i].pspsType) {
-
-            case TBYTE: sprintf(colTypes[i],"1B");
-                        break;
-            case TSHORT: sprintf(colTypes[i],"1I");
-                         break;
-            case TLONG: sprintf(colTypes[i],"1J"); // TODO
-                        break;
-            case TLONGLONG: sprintf(colTypes[i],"1K");
-                            break;
-            case TFLOAT: sprintf(colTypes[i],"1E");
-                         break;
-            case TDOUBLE: sprintf(colTypes[i],"1D");
-                          break;
-            case TSTRING: sprintf(colTypes[i],"32A"); // TODO width?
-                          break;
-
-            default:
-                          break;
-        }
-
-        i++;
-    }
-
-    fitsOut->createBinaryTable(fitsOut, nRows, nCols, colNames, colTypes, table->name);
-
-    for (i=0;i<nCols;i++) free(colTypes[i]);
-    free(colTypes);
-    free(colNames);
-
-    // now insert defaults
-    int8_t* int8col = (int8_t*)calloc(nRows, sizeof(int8_t));
-    int16_t* int16col = (int16_t*)calloc(nRows, sizeof(int16_t));
-    long* longcol = (long*)calloc(nRows, sizeof(long));
-    float* floatcol = (float*)calloc(nRows, sizeof(float));
-    double* doublecol = (double*)calloc(nRows, sizeof(double));
-    char** strcol = (char**)calloc(nRows, sizeof(char**));
-    for (uint32_t i=0; i<nRows;i++)
-        strcol[i] = (char*)calloc(20,sizeof(char)); // TODO 20? size issue
-
-    uint32_t j;
-    int64_t tempLong;
-    double tempDouble;
-    char tempStr[20];
-
-    int col;
-    for (uint32_t i=0; i<table->numOfColumns; i++) {
-
-        col = i+1;
-
-        strcpy(tempStr,table->columns[i].defaultValue);
-        tempLong = atol(tempStr);
-        tempDouble = atof(tempStr);
-
-        switch (table->columns[i].pspsType) {
-
-            case TBYTE:
-                for(j=0;j<nRows;j++) int8col[j] = (int8_t)tempLong;
-                fitsOut->writeColumn(fitsOut, TBYTE, col, 1, 1, nRows, int8col);
-                break;
-            case TSHORT:
-                for(j=0;j<nRows;j++) int16col[j] = (int16_t)tempLong;
-                fitsOut->writeColumn(fitsOut, TSHORT, col, 1, 1, nRows, int16col);
-                break;
-            case TLONG:
-                for(j=0;j<nRows;j++) longcol[j] = (long)tempLong;
-                fitsOut->writeColumn(fitsOut, TLONG, col, 1, 1, nRows, longcol);
-                break;
-
-            case TLONGLONG:
-                for(j=0;j<nRows;j++) longcol[j] = tempLong;
-                fitsOut->writeColumn(fitsOut, TLONGLONG, col, 1, 1, nRows, longcol);
-                break;
-
-            case TFLOAT:
-                for(j=0;j<nRows;j++) floatcol[j] = (float)tempDouble;
-                fitsOut->writeColumn(fitsOut, TFLOAT, col, 1, 1, nRows, floatcol);
-                break;
-
-            case TDOUBLE:
-                for(j=0;j<nRows;j++) doublecol[j] = tempDouble;
-                fitsOut->writeColumn(fitsOut, TDOUBLE, col, 1, 1, nRows, doublecol);
-                break;
-
-            case TSTRING:
-                for(j=0;j<nRows;j++) strcpy(strcol[j], tempStr);
-                fitsOut->writeColumn(fitsOut, TSTRING, col, 1, 1, nRows, strcol);
-                break;
-
-            default:
-                break;
-        }
-    }
-
-    free(int8col);
-    free(int16col);
-    free(longcol);
-    free(floatcol);
-    free(doublecol);
-    for (uint32_t i=0; i<nRows;i++) free(strcol[i]);
-    free(strcol);
-
-    return true;
-}
-
-/*
-   Counts number of children with the provided name
-   */
-static int countChildren(xmlNode* rootNode, const char* name) {
-
-    int count = 0;
-    xmlNode* node = NULL;
-
-    for (node = rootNode->children; node; node = node->next) {
-
-        if (strcmp((const char*)node->name, name)==0) count++;
-    } 
-
-    return count;
-}
-
-/*
-   opens an XML file and returns the document
-   */
-static xmlDoc* openXmlFile(const char* path) {
-
-    xmlDoc* doc = xmlReadFile(path, NULL, 0);
-    if (doc == NULL) psError(PS_ERR_IO, false, "Unable to open XML file at %s", path);
-    return doc;
-}
-
-/*
-   closes an XML file 
-   */
-static bool closeXmlFile(xmlDoc* doc) {
-
-    xmlFreeDoc(doc);
-    xmlCleanupParser();
-
-    return true;
-}
-
-/**
-  Populates the provided table with data from XML
-  */
-static bool populateTable(Table* table, xmlNode* rootElement, Fits *fitsOut) {
-
-    char tempStr[100];
-    xmlNode* node = NULL;
-    xmlNode* tableNode = NULL;
-
-    // first check we have data for this table in XML file
-    for (node = rootElement->children; node; node = node->next) {
-        if (node->type == XML_ELEMENT_NODE) {
-
-            if (strcmp((const char*)node->name, "table")!=0) continue;
-            if (!getAttribute(node, "name", tempStr)) continue;
-            if (strcmp(tempStr, table->name)==0) {tableNode = node; break;}
-        }
-    }
-
-    if(!tableNode) {
-
-        psError(PS_ERR_IO,"Could not find table: %s", table->name);
-        return false;
-    }
-
-    // now count the number of rows
-    int nRows = countChildren(tableNode, "row");
-    if (nRows < 1) return false;
-    if (!createTable(table, fitsOut, nRows)) return false;
-
-    int rows=0;
-    int status;
-    char** strcol = (char**)calloc(1, sizeof(char**));
-    strcol[0] = (char*)calloc(32,sizeof(char)); // TODO 20? size issue
-
-    int8_t* bytecol = calloc(1, sizeof(uint8_t));
-    int16_t* shortcol = calloc(1, sizeof(uint16_t));
-    long* longcol = calloc(1, sizeof(long));
-    double* doublecol = calloc(1, sizeof(double));
-    float* floatcol = calloc(1, sizeof(float));
-
-    int col;
-
-    // now get rows
-    for (node = tableNode->children; node; node = node->next) {
-
-        if (strcmp((const char*)node->name, "row")!=0) continue;
-
-        rows++;
-
-        // get column data for this row
-        for (int i=0;i<table->numOfColumns;i++) {
-
-            col = i+1;
-
-            if (!getAttribute(node, table->columns[i].pspsName, tempStr)) continue;
-
-            strncpy(strcol[0], tempStr, 32);
-            status=0;
-            //psLogMsg("ippToPsps", PS_LOG_INFO, "Values %s - %ld - %f - %d", strcol[0], longcol[0], doublecol[0], bytecol[0]);
-            switch (table->columns[i].pspsType) {
-
-                case TBYTE:
-                    bytecol[0] = atoi(tempStr);
-                    fitsOut->writeColumn(fitsOut, table->columns[i].pspsType, col, rows, 1, 1, bytecol); 
-                    break;
-                case TSHORT:
-                    shortcol[0] = atoi(tempStr);
-                    fitsOut->writeColumn(fitsOut, table->columns[i].pspsType, col, rows, 1, 1, shortcol); 
-                    break;
-                case TLONG:
-                case TLONGLONG:
-                    longcol[0] = atol(tempStr);
-                    fitsOut->writeColumn(fitsOut, table->columns[i].pspsType, col, rows, 1, 1, longcol); 
-                    break;
-                case TFLOAT:
-                    floatcol[0] = atof(tempStr);
-                    fitsOut->writeColumn(fitsOut, table->columns[i].pspsType, col, rows, 1, 1, floatcol);
-                    break;
-                case TDOUBLE:
-                    doublecol[0] = atof(tempStr);
-                    fitsOut->writeColumn(fitsOut, table->columns[i].pspsType, col, rows, 1, 1, doublecol);
-                    break;
-                case TSTRING:
-                    fitsOut->writeColumn(fitsOut, table->columns[i].pspsType, col, rows, 1, 1, strcol); 
-                    break;
-
-            }
-            if (status) psError(PS_ERR_IO, false, "Unable to write value of %s to column %s in table %s", 
-                    tempStr, table->columns[i].pspsName, table->name);
-        }
-    }
-
-    free(bytecol);
-    free(shortcol);
-    free(longcol);
-    free(floatcol);
-    free(doublecol);
-    free(strcol[0]);
-    free(strcol);
-
-    return true;
-}
-
-/**
-  Loads a table description from XML
-  */
-static bool loadTableDescription(Table* table, xmlNode* tableNode) {
-
-    bool ret = true;
-    char tableName[100];
-    getAttribute(tableNode, "name", tableName);
-    strcpy(table->name, tableName);
-
-    // count how many columns we have coming in and allocate memory for them
-    table->numOfColumns = countChildren(tableNode, "column");
-    table->columns = calloc(table->numOfColumns, sizeof(Column));
-    //    psLogMsg("ippToPsps", PS_LOG_INFO, " Found '%d' columns", table->numOfColumns);
-
-    char buffer[200];
-    xmlNode* node;
-    int columnNum = 0;
-
-    for (node = tableNode->children; node; node = node->next) {
-
-        if (strcmp((const char*)node->name, "column") != 0) continue;
-
-        table->columns[columnNum].usingDefault = true;
-
-        // column name
-        getAttribute(node, "name", buffer);
-        sprintf(table->columns[columnNum].pspsName, buffer);
-
-        // column type
-        getAttribute(node, "type", buffer);
-        table->columns[columnNum].pspsType = Fits_getDataType(buffer);
-
-        // default value
-        getAttribute(node, "default", buffer);
-        sprintf(table->columns[columnNum].defaultValue, buffer);
-
-        // comment
-        getAttribute(node, "comment", buffer);
-        sprintf(table->columns[columnNum].comment, buffer);
-
-        # if 0
-        psLogMsg("ippToPsps", PS_LOG_INFO, "'%s'  name='%s' type='%d'  default='%s' comment='%s'", 
-                table->name,
-                table->columns[columnNum].pspsName, 
-                table->columns[columnNum].pspsType, 
-                table->columns[columnNum].defaultValue, 
-                table->columns[columnNum].comment);
-# endif
-        columnNum++;
-    }   
-
-
-    if (columnNum < 1) {
-
-        psError(PS_ERR_IO, false, "Found no columns for table '%s'", tableName);
-        ret = false;
-    }
-
-    if (columnNum != table->numOfColumns)
-        psError(PS_ERR_IO, false, "Mismatch between number of columns expected (%d) and those found (%d)", table->numOfColumns, columnNum);
-
-    return ret;
-}
-
-/**
-  Reads table shapes from XML file
-  */
-static bool loadTableDescriptions(Config* this) {
-
-    bool ret = true;
-
-    psString path = NULL;
-    psStringAppend(&path, "%s/tables.xml", this->configsPath);
-
-    xmlDoc* doc = openXmlFile(path);
-
-    if (doc == NULL) {
-
-        psFree(path);
-        return false;
-    }
-    psFree(path);
-
-    xmlNode* rootElement = xmlDocGetRootElement(doc);
-
-    if (strcmp((const char*)rootElement->name, "tableDescriptions")!=0) {
-
-        psError(PS_ERR_IO, false, "Root node of XML is not 'tableDescriptions', as it should be");
-        return false;
-    }
-
-    // count how many tables we have coming in and allocate memory for them
-    this->numOfTables = countChildren(rootElement, "table");
-    this->tables = calloc(this->numOfTables, sizeof(Table));
-    //    psLogMsg("ippToPsps", PS_LOG_INFO, " Found '%d' tables", this->numOfTables);
-
-    xmlNode* node = NULL;
-    Table* table = NULL;
-
-    int tableNum = 0;
-    // loop round all available table descriptions
-    for (node = rootElement->children; node; node = node->next) {
-        if (node->type == XML_ELEMENT_NODE) {
-
-            if (strcmp((const char*)node->name, "table")==0) {
-
-                table = this->tables+tableNum;
-
-                if (!loadTableDescription(table, node)) ret = false;
-                else tableNum++;
-            }
-        }
-    }
-
-    if (tableNum != this->numOfTables)
-        psError(PS_ERR_IO, false, "Mismatch between number of tables expected (%d) and those found (%d)", this->numOfTables, tableNum);
-
-    closeXmlFile(doc);
-
-    return ret;
-}
-
-/**
-  Loads mappings from XML for a particular table
-  */
-static bool loadTableMappings(Config* this, xmlNode* tableNode) {
-
-    bool ret = false;
-
-    xmlNode* node = NULL;
-
-    char tableName[100];
-    getAttribute(tableNode, "name", tableName);
-
-    Table* table = findTable(this, tableName);
-    Column* column = NULL;
-    if (!table) return false;
-
-    char buffer[100];
-    //psLogMsg("ippToPsps", PS_LOG_INFO, "Table '%s'", tableName);
-
-    // loop round all available mappings for this table
-    for (node = tableNode->children; node; node = node->next) {
-        if (node->type == XML_ELEMENT_NODE) {
-
-            if (strcmp((const char*)node->name, "map")==0) {
-
-                // column type
-                getAttribute(node, "pspsName", buffer);
-                column = findColumn(table, buffer);
-
-                if (!column) continue;
-
-                // IPP name
-                getAttribute(node, "ippName", buffer);
-                strcpy(column->ippName, buffer);
-
-                // IPP type
-                getAttribute(node, "ippType", buffer);
-                column->ippType = Fits_getDataType(buffer); 
-
-                column->usingDefault = false;
-
-                //psLogMsg("ippToPsps", PS_LOG_INFO, "...mapping PSPS:'%s' to '%s' '%d'", column->pspsName, column->ippName, column->ippColNum );
-            }
-        }
-    }
-
-    return ret;
-}
-
-/**
-  Reads table mappings from XML file
-  */
-static bool loadMappings(Config* this) {
-
-    bool ret = true;
-
-    psString path = NULL;
-    psStringAppend(&path, "%s/map.xml", this->configsPath);
-
-    xmlDoc* doc = openXmlFile(path);
-
-    if (doc == NULL) {
-        psFree(path);
-        return false;
-    }
-    psFree(path);
-
-    xmlNode* rootElement = xmlDocGetRootElement(doc);
-
-    if (strcmp((const char*)rootElement->name, "tabledata")!=0) {
-        psError(PS_ERR_IO, false, "Root node of XML is not 'tabledata', as it should be");
-        return false;
-    }
-
-    xmlNode* node = NULL;
-
-    // loop round all available tables
-    for (node = rootElement->children; node; node = node->next) {
-        if (node->type == XML_ELEMENT_NODE) {
-
-            if (strcmp((const char*)node->name, "table")==0) {
-
-                if (!loadTableMappings(this, node)) ret = false;
-            }
-        }
-    }
-
-    closeXmlFile(doc);
-
-    return ret;
-}
-
-/**
-  Populate the provided table with data from XML
-  */
-static bool populateFromFile(Config* this, Fits *fitsOut) {
-
-    bool ret = true;
-    psString path = NULL;
-    psStringAppend(&path, "%s/data.xml", this->configsPath);
-
-    xmlDoc* doc = openXmlFile(path);
-
-    if (doc == NULL) {
-        psFree(path);
-        return false;
-    }
-    psFree(path);
-
-    xmlNode* rootElement = xmlDocGetRootElement(doc);
-
-    if (strcmp((const char*)rootElement->name, "tabledata")!=0) {
-        psError(PS_ERR_IO, false, "Root node of XML is not 'tabledata', as it should be");
-        return false;
-    }
-
-    for (uint32_t i=0; i<this->numOfTables; i++) {
-        if (!populateTable(this->tables+i, rootElement, fitsOut)) {
-            ret = false;
-        }
-    }
-
-    closeXmlFile(doc);
-
-    return ret;
-}
-
-/**
-  Populate with data from another FITS table into this one
-  */
-static bool populateTableFromFits(
-        Table* table,
-        Fits *fitsIn, 
-        Fits *fitsOut,
-        const long nRows, 
-        const bool fromHeader) {
-
-    if (!table) return false;
-    if (!fitsIn) return false;
-
-    int8_t* int8col = (int8_t*)calloc(nRows, sizeof(int8_t));
-    int16_t* int16col = (int16_t*)calloc(nRows, sizeof(int16_t));
-    long* longcol = (long*)calloc(nRows, sizeof(long));
-    float* floatcol = (float*)calloc(nRows, sizeof(float));
-    double* doublecol = (double*)calloc(nRows, sizeof(double));
-    char** strcol = (char**)calloc(nRows, sizeof(char**));
-    for (uint32_t i=0; i<nRows;i++)
-        strcol[i] = (char*)calloc(50,sizeof(char)); // TODO 20? size issue
-
-    // first loop round all columns and get IPP col numbers for provided column names TODO only do once, first time in
-    if(!fromHeader) {
-
-        for (uint32_t i=0; i<table->numOfColumns; i++) {
-
-            if (strlen(table->columns[i].ippName) < 1) continue;
-
-            int dummy; // TODO getting wrong type for some reason
-            if (!fitsIn->getColumnMeta(fitsIn, table->columns[i].ippName, &table->columns[i].ippColNum, &dummy, &table->columns[i].ippRepeat)) return false;
-        }
-    }
-
-    int col;
-    for (uint32_t i=0; i<table->numOfColumns; i++) {
-
-        if (!table->columns[i].usingDefault) {
-
-            col = i+1;
-
-            switch (table->columns[i].ippType) {
-
-                case TBYTE:
-                    if (fromHeader) {
-                        fitsIn->getHeaderKeyValue(fitsIn, TBYTE, table->columns[i].ippName, &int8col[0]); 
-                    }
-                    else fitsIn->readColumn(fitsIn, TBYTE, table->columns[i].ippColNum, 1, 1, nRows, int8col);
-                    fitsOut->writeColumn(fitsOut, TBYTE, col, 1, 1, nRows, int8col);
-                    break;
-                case TSHORT:
-                    if (fromHeader) {
-                        fitsIn->getHeaderKeyValue(fitsIn, TSHORT, table->columns[i].ippName, &int16col[0]);
-                    }
-                    else fitsIn->readColumn(fitsIn, TSHORT, table->columns[i].ippColNum, 1, 1, nRows, int16col);
-                    fitsOut->writeColumn(fitsOut, TSHORT, col, 1, 1, nRows, int16col);
-                    break;
-                case TLONG:
-                    if (fromHeader) {
-                        fitsIn->getHeaderKeyValue(fitsIn, TLONG, table->columns[i].ippName, &longcol[0]);
-                    }
-                    else fitsIn->readColumn(fitsIn, TLONG, table->columns[i].ippColNum, 1, 1, nRows, longcol);
-                    fitsOut->writeColumn(fitsOut, TLONG, col, 1, 1, nRows, longcol);
-                    break;
-                case TLONGLONG:
-                    if (fromHeader) {
-                        fitsIn->getHeaderKeyValue(fitsIn, TLONGLONG, table->columns[i].ippName, &longcol[0]);
-                    }
-                    else fitsIn->readColumn(fitsIn, TLONGLONG, table->columns[i].ippColNum, 1, 1, nRows, longcol);
-                    fitsOut->writeColumn(fitsOut, TLONGLONG, col, 1, 1, nRows, longcol);
-                    break;
-                case TFLOAT:
-                    if (fromHeader) {
-                        fitsIn->getHeaderKeyValue(fitsIn, TFLOAT, table->columns[i].ippName,&floatcol[0]); 
-                    }
-                    else fitsIn->readColumn(fitsIn, TFLOAT, table->columns[i].ippColNum, 1, 1, nRows, floatcol);
-                    fitsOut->writeColumn(fitsOut, TFLOAT, col, 1, 1, nRows, floatcol);
-                    break;
-                case TDOUBLE:
-                    if (fromHeader) {
-                        fitsIn->getHeaderKeyValue(fitsIn, TDOUBLE, table->columns[i].ippName, &doublecol[0]);
-                    }
-                    else fitsIn->readColumn(fitsIn, TDOUBLE, table->columns[i].ippColNum, 1, 1, nRows, doublecol);
-                    fitsOut->writeColumn(fitsOut, TDOUBLE, col, 1, 1, nRows, doublecol);
-                    break;
-                case TSTRING:
-                    if (fromHeader) fitsIn->getHeaderKeyValue(fitsIn, TSTRING, table->columns[i].ippName, strcol[0]);
-                    else fitsIn->readColumn(fitsIn, TSTRING, table->columns[i].ippColNum, 1, 1, nRows, strcol);
-                    fitsOut->writeColumn(fitsOut, TSTRING, col, 1, 1, nRows, strcol);
-                    break;
-
-                default:
-                    psError(PS_ERR_IO, false, "Don't know IPP type (%d) for mapping from  '%d'  '%s' to '%s'", table->columns[i].ippType,
-                            table->columns[i].ippColNum, table->columns[i].ippName, table->columns[i].pspsName);
-                    break;
-            }
-        }
-    }
-
-    free(int8col);
-    free(int16col);
-    free(longcol);
-    free(floatcol);
-    free(doublecol);
-    for (uint32_t i=0; i<nRows;i++) free(strcol[i]);
-    free(strcol);
-
-    return true;
-}
-
-/**
-  Creates and populates a table
-  */
-static bool createAndPopulateTable(
-        Config* this, 
-        Fits* fitsIn,
-        Fits* fitsOut,
-        const long nRows,
-        const char* tableName,
-        const int fromHeader) {
-
-    Table* table = findTable(this, tableName);
-    if (!table) return false;
-
-    if(!createTable(table, fitsOut, nRows)) return false;
-    return populateTableFromFits(table, fitsIn, fitsOut, nRows, fromHeader);
-}
-
-/**
-  Destructor.
-  */
-static void destroy(Config* this) {
-
-    if (this == NULL) return;
-
-    // TODO check logic here
-    for (int i=0;i<this->numOfTables;i++)
-        free(this->tables[i].columns);
-
-    free(this->tables);
-    psFree(this->configsPath);
-    free(this);
-}
-
-/**
-  Constructor. Loads IPP -> PSPS mappings from an XML file
-  */
-Config* new_Config(const char* path) {
-
-    Config* this = (Config*)calloc(1, sizeof(Config));
-
-    this->configsPath = NULL;
-    psStringAppend(&this->configsPath, path);
-
-    // method pointers
-    this->createAndPopulateTable = createAndPopulateTable;
-    this->populateFromFile = populateFromFile;
-    this->destroy = destroy;
-
-    // load tables descriptions from XML
-    if (loadTableDescriptions(this)) {
-
-        // load any mappings we may have from XML        
-        loadMappings(this);
-    }
-
-    return this;
-}
-
Index: unk/ippToPsps/src/Config.h
===================================================================
--- /trunk/ippToPsps/src/Config.h	(revision 31024)
+++ 	(revision )
@@ -1,65 +1,0 @@
-/** @file Config.h
- *
- *  @brief ippToPsps
- *
- *  @ingroup ippToPsps
- *
- *  @author IfA
- *  Copyright 2011 Institute for Astronomy, University of Hawaii
- */
-
-#ifndef IPPTOPSPS_CONFIG_H
-#define IPPTOPSPS_CONFIG_H
-
-#include <psmodules.h>
-
-// column class
-typedef struct Column {
-
-    int ippColNum;
-    char ippName[100];
-    int ippType;
-    long ippRepeat;
-    char pspsName[100]; // TODO change to 'name'
-    int pspsType;
-    bool usingDefault;
-    char defaultValue[100];
-    char comment[300];
-
-} Column;
-
-// table class
-typedef struct Table {
-
-    char name[32];
-    Column* columns;
-    int numOfColumns;
-
-} Table;
-
-/**
-
-  Class encapsulating ... TODO
-
-*/
-typedef struct Config {
-
-    // fields
-    psString configsPath;
-    Table* tables;
-    int numOfTables;
-
-    // methods
-    bool (*createAndPopulateTable)();
-    bool (*populateFromFile)();
-
-    // destructor
-    void (*destroy)();
-
-} Config; 
-
-// constructor
-Config* new_Config(const char* path);
-
-#endif // IPPTOPSPS_CONFIG_H
-
Index: /trunk/ippToPsps/src/DetectionBatch.c
===================================================================
--- /trunk/ippToPsps/src/DetectionBatch.c	(revision 31024)
+++ /trunk/ippToPsps/src/DetectionBatch.c	(revision 31025)
@@ -59,5 +59,5 @@
 
 
-    this->base.config->createAndPopulateTable(this->base.config, fitsIn, this->base.fitsOut, 1, "FrameMeta", true);
+    this->base.fitsGenerator->createAndPopulateTable(this->base.fitsGenerator, fitsIn, this->base.fitsOut, 1, "FrameMeta", true);
 
     // FrameMeta values
@@ -212,5 +212,5 @@
 
             // create ImageMeta
-            this->base.config->createAndPopulateTable(this->base.config, fitsIn, this->base.fitsOut, 1, "ImageMeta", true);
+            this->base.fitsGenerator->createAndPopulateTable(this->base.fitsGenerator, fitsIn, this->base.fitsOut, 1, "ImageMeta", true);
             psfFwhm = (fwhmMaj+fwhmMin)/2;
             momentFwhm = (momentMaj+momentMin)/2;
@@ -339,5 +339,5 @@
 
                 // detections
-                this->base.config->createAndPopulateTable(this->base.config, fitsIn, this->base.fitsOut, nChipDetectionsIn, "Detection", false);
+                this->base.fitsGenerator->createAndPopulateTable(this->base.fitsGenerator, fitsIn, this->base.fitsOut, nChipDetectionsIn, "Detection", false);
                 this->base.fitsOut->writeColumn(this->base.fitsOut, TLONGLONG, DETECTION_OBJID, 1, 1, nChipDetectionsIn, objID);
                 this->base.fitsOut->writeColumn(this->base.fitsOut, TLONGLONG, DETECTION_DETECTID, 1, 1, nChipDetectionsIn, detectID);
@@ -356,5 +356,5 @@
 
                 // skinny object
-                this->base.config->createAndPopulateTable(this->base.config, fitsIn, this->base.fitsOut, nChipDetectionsIn, "SkinnyObject", false);
+                this->base.fitsGenerator->createAndPopulateTable(this->base.fitsGenerator, fitsIn, this->base.fitsOut, nChipDetectionsIn, "SkinnyObject", false);
                 this->base.fitsOut->writeColumn(this->base.fitsOut, TLONGLONG, SKINNYOBJECT_OBJID, 1, 1, nChipDetectionsIn, objID);
                 this->base.fitsOut->writeColumn(this->base.fitsOut, TLONGLONG, SKINNYOBJECT_IPPOBJID, 1, 1, nChipDetectionsIn, ippObjID);
@@ -363,5 +363,5 @@
 
                 // object calibration color
-                this->base.config->createAndPopulateTable(this->base.config, fitsIn, this->base.fitsOut, nChipDetectionsIn, "ObjectCalColor", false);
+                this->base.fitsGenerator->createAndPopulateTable(this->base.fitsGenerator, fitsIn, this->base.fitsOut, nChipDetectionsIn, "ObjectCalColor", false);
                 this->base.fitsOut->writeColumn(this->base.fitsOut, TLONGLONG, OBJECTCALCOLOR_OBJID, 1, 1, nChipDetectionsIn, objID);
                 this->base.fitsOut->writeColumn(this->base.fitsOut, TLONGLONG, OBJECTCALCOLOR_IPPOBJID, 1, 1, nChipDetectionsIn, ippObjID);
Index: /trunk/ippToPsps/src/Fits.h
===================================================================
--- /trunk/ippToPsps/src/Fits.h	(revision 31024)
+++ /trunk/ippToPsps/src/Fits.h	(revision 31025)
@@ -6,5 +6,5 @@
  *
  *  @author IfA
- *  Copyright 2009 Institute for Astronomy, University of Hawaii
+ *  Copyright 2011 Institute for Astronomy, University of Hawaii
  */
 
Index: /trunk/ippToPsps/src/FitsGenerator.c
===================================================================
--- /trunk/ippToPsps/src/FitsGenerator.c	(revision 31025)
+++ /trunk/ippToPsps/src/FitsGenerator.c	(revision 31025)
@@ -0,0 +1,756 @@
+/** @file FitsGenerator.c
+ *
+ *  @ingroup ippToPsps
+ *
+ *  @author IfA
+ *  Copyright 2011 Institute for Astronomy, University of Hawaii
+ */
+
+#include "FitsGenerator.h"
+#include <ctype.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+
+#include "Fits.h"
+
+/**
+  Finds a column within this table
+  */
+static Column* findColumn(Table* table, const char* name) {
+
+    Column* column = NULL;
+
+    for (uint32_t i=0; i<table->numOfColumns; i++) {
+
+        if (strcmp(table->columns[i].pspsName, name) == 0) {
+            column = table->columns+i;
+            break;
+        }
+    }
+
+    if (!column) psError(PS_ERR_IO, false, "Could not find column '%s' in table '%s'", name, table->name);
+
+    return column;
+}
+
+/**
+  Finds a table from the array of tables
+  */
+static Table* findTable(FitsGenerator* this, const char* name) {
+
+    Table* table = NULL;
+
+    for (uint32_t i=0; i<this->numOfTables; i++) {
+
+        if (strcmp(this->tables[i].name, name) == 0) {
+            table = this->tables+i;
+            break;
+        }
+    }
+
+    if (!table) psError(PS_ERR_IO, false, "Could not find table '%s'", name);
+
+    return table;
+}
+
+/**
+  Gets an attribute value from XML node
+  */
+static bool getAttribute(xmlNode* node, const char* attName, char* _value) {
+
+    xmlChar* value = xmlGetProp(node, (const xmlChar*)attName);
+    if (!value) return false;
+    sprintf(_value, "%s", value);
+    xmlFree(value);
+
+    return true;
+}
+
+/**
+  Creates a FITS binary table and populates it with defaults based on definition in schema XML
+  */
+static bool createTable(Table* table, Fits* fitsOut, const long nRows) {
+
+    if (!table) return false;
+    if (nRows < 1) return false;
+
+    long nCols = table->numOfColumns;
+
+    char** colNames = (char**)calloc(nCols, sizeof(char*));
+    char** colTypes = (char**)calloc(nCols, sizeof(char*));
+
+    uint32_t i = 0;
+    for (i=0;i<nCols;i++) colTypes[i] = (char*)calloc(5,sizeof(char));
+
+    i = 0;
+    for (uint32_t m=0; m<table->numOfColumns; m++) {
+
+        colNames[i] = table->columns[i].pspsName;
+
+        //        sprintf(colNames[i], table->columns[i].pspsName);
+
+        switch (table->columns[i].pspsType) {
+
+            case TBYTE: sprintf(colTypes[i],"1B");
+                        break;
+            case TSHORT: sprintf(colTypes[i],"1I");
+                         break;
+            case TLONG: sprintf(colTypes[i],"1J"); // TODO
+                        break;
+            case TLONGLONG: sprintf(colTypes[i],"1K");
+                            break;
+            case TFLOAT: sprintf(colTypes[i],"1E");
+                         break;
+            case TDOUBLE: sprintf(colTypes[i],"1D");
+                          break;
+            case TSTRING: sprintf(colTypes[i],"32A"); // TODO width?
+                          break;
+
+            default:
+                          break;
+        }
+
+        i++;
+    }
+
+    fitsOut->createBinaryTable(fitsOut, nRows, nCols, colNames, colTypes, table->name);
+
+    for (i=0;i<nCols;i++) free(colTypes[i]);
+    free(colTypes);
+    free(colNames);
+
+    // now insert defaults
+    int8_t* int8col = (int8_t*)calloc(nRows, sizeof(int8_t));
+    int16_t* int16col = (int16_t*)calloc(nRows, sizeof(int16_t));
+    long* longcol = (long*)calloc(nRows, sizeof(long));
+    float* floatcol = (float*)calloc(nRows, sizeof(float));
+    double* doublecol = (double*)calloc(nRows, sizeof(double));
+    char** strcol = (char**)calloc(nRows, sizeof(char**));
+    for (uint32_t i=0; i<nRows;i++)
+        strcol[i] = (char*)calloc(20,sizeof(char)); // TODO 20? size issue
+
+    uint32_t j;
+    int64_t tempLong;
+    double tempDouble;
+    char tempStr[20];
+
+    int col;
+    for (uint32_t i=0; i<table->numOfColumns; i++) {
+
+        col = i+1;
+
+        strcpy(tempStr,table->columns[i].defaultValue);
+        tempLong = atol(tempStr);
+        tempDouble = atof(tempStr);
+
+        switch (table->columns[i].pspsType) {
+
+            case TBYTE:
+                for(j=0;j<nRows;j++) int8col[j] = (int8_t)tempLong;
+                fitsOut->writeColumn(fitsOut, TBYTE, col, 1, 1, nRows, int8col);
+                break;
+            case TSHORT:
+                for(j=0;j<nRows;j++) int16col[j] = (int16_t)tempLong;
+                fitsOut->writeColumn(fitsOut, TSHORT, col, 1, 1, nRows, int16col);
+                break;
+            case TLONG:
+                for(j=0;j<nRows;j++) longcol[j] = (long)tempLong;
+                fitsOut->writeColumn(fitsOut, TLONG, col, 1, 1, nRows, longcol);
+                break;
+
+            case TLONGLONG:
+                for(j=0;j<nRows;j++) longcol[j] = tempLong;
+                fitsOut->writeColumn(fitsOut, TLONGLONG, col, 1, 1, nRows, longcol);
+                break;
+
+            case TFLOAT:
+                for(j=0;j<nRows;j++) floatcol[j] = (float)tempDouble;
+                fitsOut->writeColumn(fitsOut, TFLOAT, col, 1, 1, nRows, floatcol);
+                break;
+
+            case TDOUBLE:
+                for(j=0;j<nRows;j++) doublecol[j] = tempDouble;
+                fitsOut->writeColumn(fitsOut, TDOUBLE, col, 1, 1, nRows, doublecol);
+                break;
+
+            case TSTRING:
+                for(j=0;j<nRows;j++) strcpy(strcol[j], tempStr);
+                fitsOut->writeColumn(fitsOut, TSTRING, col, 1, 1, nRows, strcol);
+                break;
+
+            default:
+                break;
+        }
+    }
+
+    free(int8col);
+    free(int16col);
+    free(longcol);
+    free(floatcol);
+    free(doublecol);
+    for (uint32_t i=0; i<nRows;i++) free(strcol[i]);
+    free(strcol);
+
+    return true;
+}
+
+/*
+   Counts number of children with the provided name
+   */
+static int countChildren(xmlNode* rootNode, const char* name) {
+
+    int count = 0;
+    xmlNode* node = NULL;
+
+    for (node = rootNode->children; node; node = node->next) {
+
+        if (strcmp((const char*)node->name, name)==0) count++;
+    } 
+
+    return count;
+}
+
+/*
+   opens an XML file and returns the document
+   */
+static xmlDoc* openXmlFile(const char* path) {
+
+    xmlDoc* doc = xmlReadFile(path, NULL, 0);
+    if (doc == NULL) psError(PS_ERR_IO, false, "Unable to open XML file at %s", path);
+    return doc;
+}
+
+/*
+   closes an XML file 
+   */
+static bool closeXmlFile(xmlDoc* doc) {
+
+    xmlFreeDoc(doc);
+    xmlCleanupParser();
+
+    return true;
+}
+
+/**
+  Populates the provided table with data from XML
+  */
+static bool populateTable(Table* table, xmlNode* rootElement, Fits *fitsOut) {
+
+    char tempStr[100];
+    xmlNode* node = NULL;
+    xmlNode* tableNode = NULL;
+
+    // first check we have data for this table in XML file
+    for (node = rootElement->children; node; node = node->next) {
+        if (node->type == XML_ELEMENT_NODE) {
+
+            if (strcmp((const char*)node->name, "table")!=0) continue;
+            if (!getAttribute(node, "name", tempStr)) continue;
+            if (strcmp(tempStr, table->name)==0) {tableNode = node; break;}
+        }
+    }
+
+    if(!tableNode) {
+
+        psError(PS_ERR_IO,"Could not find table: %s", table->name);
+        return false;
+    }
+
+    // now count the number of rows
+    int nRows = countChildren(tableNode, "row");
+    if (nRows < 1) return false;
+    if (!createTable(table, fitsOut, nRows)) return false;
+
+    int rows=0;
+    int status;
+    char** strcol = (char**)calloc(1, sizeof(char**));
+    strcol[0] = (char*)calloc(32,sizeof(char)); // TODO 20? size issue
+
+    int8_t* bytecol = calloc(1, sizeof(uint8_t));
+    int16_t* shortcol = calloc(1, sizeof(uint16_t));
+    long* longcol = calloc(1, sizeof(long));
+    double* doublecol = calloc(1, sizeof(double));
+    float* floatcol = calloc(1, sizeof(float));
+
+    int col;
+
+    // now get rows
+    for (node = tableNode->children; node; node = node->next) {
+
+        if (strcmp((const char*)node->name, "row")!=0) continue;
+
+        rows++;
+
+        // get column data for this row
+        for (int i=0;i<table->numOfColumns;i++) {
+
+            col = i+1;
+
+            if (!getAttribute(node, table->columns[i].pspsName, tempStr)) continue;
+
+            strncpy(strcol[0], tempStr, 32);
+            status=0;
+            //psLogMsg("ippToPsps", PS_LOG_INFO, "Values %s - %ld - %f - %d", strcol[0], longcol[0], doublecol[0], bytecol[0]);
+            switch (table->columns[i].pspsType) {
+
+                case TBYTE:
+                    bytecol[0] = atoi(tempStr);
+                    fitsOut->writeColumn(fitsOut, table->columns[i].pspsType, col, rows, 1, 1, bytecol); 
+                    break;
+                case TSHORT:
+                    shortcol[0] = atoi(tempStr);
+                    fitsOut->writeColumn(fitsOut, table->columns[i].pspsType, col, rows, 1, 1, shortcol); 
+                    break;
+                case TLONG:
+                case TLONGLONG:
+                    longcol[0] = atol(tempStr);
+                    fitsOut->writeColumn(fitsOut, table->columns[i].pspsType, col, rows, 1, 1, longcol); 
+                    break;
+                case TFLOAT:
+                    floatcol[0] = atof(tempStr);
+                    fitsOut->writeColumn(fitsOut, table->columns[i].pspsType, col, rows, 1, 1, floatcol);
+                    break;
+                case TDOUBLE:
+                    doublecol[0] = atof(tempStr);
+                    fitsOut->writeColumn(fitsOut, table->columns[i].pspsType, col, rows, 1, 1, doublecol);
+                    break;
+                case TSTRING:
+                    fitsOut->writeColumn(fitsOut, table->columns[i].pspsType, col, rows, 1, 1, strcol); 
+                    break;
+
+            }
+            if (status) psError(PS_ERR_IO, false, "Unable to write value of %s to column %s in table %s", 
+                    tempStr, table->columns[i].pspsName, table->name);
+        }
+    }
+
+    free(bytecol);
+    free(shortcol);
+    free(longcol);
+    free(floatcol);
+    free(doublecol);
+    free(strcol[0]);
+    free(strcol);
+
+    return true;
+}
+
+/**
+  Loads a table description from XML
+  */
+static bool loadTableDescription(Table* table, xmlNode* tableNode) {
+
+    bool ret = true;
+    char tableName[100];
+    getAttribute(tableNode, "name", tableName);
+    strcpy(table->name, tableName);
+
+    // count how many columns we have coming in and allocate memory for them
+    table->numOfColumns = countChildren(tableNode, "column");
+    table->columns = calloc(table->numOfColumns, sizeof(Column));
+    //    psLogMsg("ippToPsps", PS_LOG_INFO, " Found '%d' columns", table->numOfColumns);
+
+    char buffer[200];
+    xmlNode* node;
+    int columnNum = 0;
+
+    for (node = tableNode->children; node; node = node->next) {
+
+        if (strcmp((const char*)node->name, "column") != 0) continue;
+
+        table->columns[columnNum].usingDefault = true;
+
+        // column name
+        getAttribute(node, "name", buffer);
+        sprintf(table->columns[columnNum].pspsName, buffer);
+
+        // column type
+        getAttribute(node, "type", buffer);
+        table->columns[columnNum].pspsType = Fits_getDataType(buffer);
+
+        // default value
+        getAttribute(node, "default", buffer);
+        sprintf(table->columns[columnNum].defaultValue, buffer);
+
+        // comment
+        getAttribute(node, "comment", buffer);
+        sprintf(table->columns[columnNum].comment, buffer);
+
+        # if 0
+        psLogMsg("ippToPsps", PS_LOG_INFO, "'%s'  name='%s' type='%d'  default='%s' comment='%s'", 
+                table->name,
+                table->columns[columnNum].pspsName, 
+                table->columns[columnNum].pspsType, 
+                table->columns[columnNum].defaultValue, 
+                table->columns[columnNum].comment);
+# endif
+        columnNum++;
+    }   
+
+
+    if (columnNum < 1) {
+
+        psError(PS_ERR_IO, false, "Found no columns for table '%s'", tableName);
+        ret = false;
+    }
+
+    if (columnNum != table->numOfColumns)
+        psError(PS_ERR_IO, false, "Mismatch between number of columns expected (%d) and those found (%d)", table->numOfColumns, columnNum);
+
+    return ret;
+}
+
+/**
+  Reads table shapes from XML file
+  */
+static bool loadTableDescriptions(FitsGenerator* this) {
+
+    bool ret = true;
+
+    psString path = NULL;
+    psStringAppend(&path, "%s/tables.xml", this->configsPath);
+
+    xmlDoc* doc = openXmlFile(path);
+
+    if (doc == NULL) {
+
+        psFree(path);
+        return false;
+    }
+    psFree(path);
+
+    xmlNode* rootElement = xmlDocGetRootElement(doc);
+
+    if (strcmp((const char*)rootElement->name, "tableDescriptions")!=0) {
+
+        psError(PS_ERR_IO, false, "Root node of XML is not 'tableDescriptions', as it should be");
+        return false;
+    }
+
+    // count how many tables we have coming in and allocate memory for them
+    this->numOfTables = countChildren(rootElement, "table");
+    this->tables = calloc(this->numOfTables, sizeof(Table));
+    //    psLogMsg("ippToPsps", PS_LOG_INFO, " Found '%d' tables", this->numOfTables);
+
+    xmlNode* node = NULL;
+    Table* table = NULL;
+
+    int tableNum = 0;
+    // loop round all available table descriptions
+    for (node = rootElement->children; node; node = node->next) {
+        if (node->type == XML_ELEMENT_NODE) {
+
+            if (strcmp((const char*)node->name, "table")==0) {
+
+                table = this->tables+tableNum;
+
+                if (!loadTableDescription(table, node)) ret = false;
+                else tableNum++;
+            }
+        }
+    }
+
+    if (tableNum != this->numOfTables)
+        psError(PS_ERR_IO, false, "Mismatch between number of tables expected (%d) and those found (%d)", this->numOfTables, tableNum);
+
+    closeXmlFile(doc);
+
+    return ret;
+}
+
+/**
+  Loads mappings from XML for a particular table
+  */
+static bool loadTableMappings(FitsGenerator* this, xmlNode* tableNode) {
+
+    bool ret = false;
+
+    xmlNode* node = NULL;
+
+    char tableName[100];
+    getAttribute(tableNode, "name", tableName);
+
+    Table* table = findTable(this, tableName);
+    Column* column = NULL;
+    if (!table) return false;
+
+    char buffer[100];
+    //psLogMsg("ippToPsps", PS_LOG_INFO, "Table '%s'", tableName);
+
+    // loop round all available mappings for this table
+    for (node = tableNode->children; node; node = node->next) {
+        if (node->type == XML_ELEMENT_NODE) {
+
+            if (strcmp((const char*)node->name, "map")==0) {
+
+                // column type
+                getAttribute(node, "pspsName", buffer);
+                column = findColumn(table, buffer);
+
+                if (!column) continue;
+
+                // IPP name
+                getAttribute(node, "ippName", buffer);
+                strcpy(column->ippName, buffer);
+
+                // IPP type
+                getAttribute(node, "ippType", buffer);
+                column->ippType = Fits_getDataType(buffer); 
+
+                column->usingDefault = false;
+
+                //psLogMsg("ippToPsps", PS_LOG_INFO, "...mapping PSPS:'%s' to '%s' '%d'", column->pspsName, column->ippName, column->ippColNum );
+            }
+        }
+    }
+
+    return ret;
+}
+
+/**
+  Reads table mappings from XML file
+  */
+static bool loadMappings(FitsGenerator* this) {
+
+    bool ret = true;
+
+    psString path = NULL;
+    psStringAppend(&path, "%s/map.xml", this->configsPath);
+
+    xmlDoc* doc = openXmlFile(path);
+
+    if (doc == NULL) {
+        psFree(path);
+        return false;
+    }
+    psFree(path);
+
+    xmlNode* rootElement = xmlDocGetRootElement(doc);
+
+    if (strcmp((const char*)rootElement->name, "tabledata")!=0) {
+        psError(PS_ERR_IO, false, "Root node of XML is not 'tabledata', as it should be");
+        return false;
+    }
+
+    xmlNode* node = NULL;
+
+    // loop round all available tables
+    for (node = rootElement->children; node; node = node->next) {
+        if (node->type == XML_ELEMENT_NODE) {
+
+            if (strcmp((const char*)node->name, "table")==0) {
+
+                if (!loadTableMappings(this, node)) ret = false;
+            }
+        }
+    }
+
+    closeXmlFile(doc);
+
+    return ret;
+}
+
+/**
+  Populate the provided table with data from XML
+  */
+static bool populateFromFile(FitsGenerator* this, Fits *fitsOut) {
+
+    bool ret = true;
+    psString path = NULL;
+    psStringAppend(&path, "%s/data.xml", this->configsPath);
+
+    xmlDoc* doc = openXmlFile(path);
+
+    if (doc == NULL) {
+        psFree(path);
+        return false;
+    }
+    psFree(path);
+
+    xmlNode* rootElement = xmlDocGetRootElement(doc);
+
+    if (strcmp((const char*)rootElement->name, "tabledata")!=0) {
+        psError(PS_ERR_IO, false, "Root node of XML is not 'tabledata', as it should be");
+        return false;
+    }
+
+    for (uint32_t i=0; i<this->numOfTables; i++) {
+        if (!populateTable(this->tables+i, rootElement, fitsOut)) {
+            ret = false;
+        }
+    }
+
+    closeXmlFile(doc);
+
+    return ret;
+}
+
+/**
+  Populate with data from another FITS table into this one
+  */
+static bool populateTableFromFits(
+        Table* table,
+        Fits *fitsIn, 
+        Fits *fitsOut,
+        const long nRows, 
+        const bool fromHeader) {
+
+    if (!table) return false;
+    if (!fitsIn) return false;
+
+    int8_t* int8col = (int8_t*)calloc(nRows, sizeof(int8_t));
+    int16_t* int16col = (int16_t*)calloc(nRows, sizeof(int16_t));
+    long* longcol = (long*)calloc(nRows, sizeof(long));
+    float* floatcol = (float*)calloc(nRows, sizeof(float));
+    double* doublecol = (double*)calloc(nRows, sizeof(double));
+    char** strcol = (char**)calloc(nRows, sizeof(char**));
+    for (uint32_t i=0; i<nRows;i++)
+        strcol[i] = (char*)calloc(50,sizeof(char)); // TODO 20? size issue
+
+    // first loop round all columns and get IPP col numbers for provided column names TODO only do once, first time in
+    if(!fromHeader) {
+
+        for (uint32_t i=0; i<table->numOfColumns; i++) {
+
+            if (strlen(table->columns[i].ippName) < 1) continue;
+
+            int dummy; // TODO getting wrong type for some reason
+            if (!fitsIn->getColumnMeta(fitsIn, table->columns[i].ippName, &table->columns[i].ippColNum, &dummy, &table->columns[i].ippRepeat)) return false;
+        }
+    }
+
+    int col;
+    for (uint32_t i=0; i<table->numOfColumns; i++) {
+
+        if (!table->columns[i].usingDefault) {
+
+            col = i+1;
+
+            switch (table->columns[i].ippType) {
+
+                case TBYTE:
+                    if (fromHeader) {
+                        fitsIn->getHeaderKeyValue(fitsIn, TBYTE, table->columns[i].ippName, &int8col[0]); 
+                    }
+                    else fitsIn->readColumn(fitsIn, TBYTE, table->columns[i].ippColNum, 1, 1, nRows, int8col);
+                    fitsOut->writeColumn(fitsOut, TBYTE, col, 1, 1, nRows, int8col);
+                    break;
+                case TSHORT:
+                    if (fromHeader) {
+                        fitsIn->getHeaderKeyValue(fitsIn, TSHORT, table->columns[i].ippName, &int16col[0]);
+                    }
+                    else fitsIn->readColumn(fitsIn, TSHORT, table->columns[i].ippColNum, 1, 1, nRows, int16col);
+                    fitsOut->writeColumn(fitsOut, TSHORT, col, 1, 1, nRows, int16col);
+                    break;
+                case TLONG:
+                    if (fromHeader) {
+                        fitsIn->getHeaderKeyValue(fitsIn, TLONG, table->columns[i].ippName, &longcol[0]);
+                    }
+                    else fitsIn->readColumn(fitsIn, TLONG, table->columns[i].ippColNum, 1, 1, nRows, longcol);
+                    fitsOut->writeColumn(fitsOut, TLONG, col, 1, 1, nRows, longcol);
+                    break;
+                case TLONGLONG:
+                    if (fromHeader) {
+                        fitsIn->getHeaderKeyValue(fitsIn, TLONGLONG, table->columns[i].ippName, &longcol[0]);
+                    }
+                    else fitsIn->readColumn(fitsIn, TLONGLONG, table->columns[i].ippColNum, 1, 1, nRows, longcol);
+                    fitsOut->writeColumn(fitsOut, TLONGLONG, col, 1, 1, nRows, longcol);
+                    break;
+                case TFLOAT:
+                    if (fromHeader) {
+                        fitsIn->getHeaderKeyValue(fitsIn, TFLOAT, table->columns[i].ippName,&floatcol[0]); 
+                    }
+                    else fitsIn->readColumn(fitsIn, TFLOAT, table->columns[i].ippColNum, 1, 1, nRows, floatcol);
+                    fitsOut->writeColumn(fitsOut, TFLOAT, col, 1, 1, nRows, floatcol);
+                    break;
+                case TDOUBLE:
+                    if (fromHeader) {
+                        fitsIn->getHeaderKeyValue(fitsIn, TDOUBLE, table->columns[i].ippName, &doublecol[0]);
+                    }
+                    else fitsIn->readColumn(fitsIn, TDOUBLE, table->columns[i].ippColNum, 1, 1, nRows, doublecol);
+                    fitsOut->writeColumn(fitsOut, TDOUBLE, col, 1, 1, nRows, doublecol);
+                    break;
+                case TSTRING:
+                    if (fromHeader) fitsIn->getHeaderKeyValue(fitsIn, TSTRING, table->columns[i].ippName, strcol[0]);
+                    else fitsIn->readColumn(fitsIn, TSTRING, table->columns[i].ippColNum, 1, 1, nRows, strcol);
+                    fitsOut->writeColumn(fitsOut, TSTRING, col, 1, 1, nRows, strcol);
+                    break;
+
+                default:
+                    psError(PS_ERR_IO, false, "Don't know IPP type (%d) for mapping from  '%d'  '%s' to '%s'", table->columns[i].ippType,
+                            table->columns[i].ippColNum, table->columns[i].ippName, table->columns[i].pspsName);
+                    break;
+            }
+        }
+    }
+
+    free(int8col);
+    free(int16col);
+    free(longcol);
+    free(floatcol);
+    free(doublecol);
+    for (uint32_t i=0; i<nRows;i++) free(strcol[i]);
+    free(strcol);
+
+    return true;
+}
+
+/**
+  Creates and populates a table
+  */
+static bool createAndPopulateTable(
+        FitsGenerator* this, 
+        Fits* fitsIn,
+        Fits* fitsOut,
+        const long nRows,
+        const char* tableName,
+        const int fromHeader) {
+
+    Table* table = findTable(this, tableName);
+    if (!table) return false;
+
+    if(!createTable(table, fitsOut, nRows)) return false;
+    return populateTableFromFits(table, fitsIn, fitsOut, nRows, fromHeader);
+}
+
+/**
+  Destructor.
+  */
+static void destroy(FitsGenerator* this) {
+
+    if (this == NULL) return;
+
+    // TODO check logic here
+    for (int i=0;i<this->numOfTables;i++)
+        free(this->tables[i].columns);
+
+    free(this->tables);
+    psFree(this->configsPath);
+    free(this);
+}
+
+/**
+  Constructor.
+  */
+FitsGenerator* new_FitsGenerator(const char* path) {
+
+    FitsGenerator* this = (FitsGenerator*)calloc(1, sizeof(FitsGenerator));
+
+    this->configsPath = NULL;
+    psStringAppend(&this->configsPath, path);
+
+    // method pointers
+    this->createAndPopulateTable = createAndPopulateTable;
+    this->populateFromFile = populateFromFile;
+    this->destroy = destroy;
+
+    // load tables descriptions from XML
+    if (loadTableDescriptions(this)) {
+
+        // load any mappings we may have from XML        
+        loadMappings(this);
+    }
+
+    return this;
+}
+
Index: /trunk/ippToPsps/src/FitsGenerator.h
===================================================================
--- /trunk/ippToPsps/src/FitsGenerator.h	(revision 31025)
+++ /trunk/ippToPsps/src/FitsGenerator.h	(revision 31025)
@@ -0,0 +1,69 @@
+/** @file FitsGenerator.h
+ *
+ *  @brief ippToPsps
+ *
+ *  @ingroup ippToPsps
+ *
+ *  @author IfA
+ *  Copyright 2011 Institute for Astronomy, University of Hawaii
+ */
+
+#ifndef IPPTOPSPS_FITSGENERATOR_H
+#define IPPTOPSPS_FITSGENERATOR_H
+
+#include <psmodules.h>
+
+// column class
+typedef struct Column {
+
+    int ippColNum;
+    char ippName[100];
+    int ippType;
+    long ippRepeat;
+    char pspsName[100]; // TODO change to 'name'
+    int pspsType;
+    bool usingDefault;
+    char defaultValue[100];
+    char comment[300];
+
+} Column;
+
+// table class
+typedef struct Table {
+
+    char name[32];
+    Column* columns;
+    int numOfColumns;
+
+} Table;
+
+/**
+
+  Class used for generating FITS files.
+
+  - Uses XML table definitions to create table shapes
+  - Uses XML map files to populate tables from another FITS files
+  - Uses XML data files to populate tables with set values
+
+*/
+typedef struct FitsGenerator {
+
+    // fields
+    psString configsPath;
+    Table* tables;
+    int numOfTables;
+
+    // methods
+    bool (*createAndPopulateTable)();
+    bool (*populateFromFile)();
+
+    // destructor
+    void (*destroy)();
+
+} FitsGenerator; 
+
+// constructor
+FitsGenerator* new_FitsGenerator(const char* path);
+
+#endif // IPPTOPSPS_FITSGENERATOR_H
+
Index: /trunk/ippToPsps/src/InitBatch.c
===================================================================
--- /trunk/ippToPsps/src/InitBatch.c	(revision 31024)
+++ /trunk/ippToPsps/src/InitBatch.c	(revision 31025)
@@ -18,5 +18,5 @@
     if (this->base.exitCode != PS_EXIT_SUCCESS) return this->base.exitCode;
 
-    if (!this->base.config->populateFromFile(this->base.config, this->base.fitsOut)) 
+    if (!this->base.fitsGenerator->populateFromFile(this->base.fitsGenerator, this->base.fitsOut)) 
         this->base.exitCode = PS_EXIT_CONFIG_ERROR;
     else this->base.exitCode = PS_EXIT_SUCCESS;
Index: /trunk/ippToPsps/src/Makefile.am
===================================================================
--- /trunk/ippToPsps/src/Makefile.am	(revision 31024)
+++ /trunk/ippToPsps/src/Makefile.am	(revision 31025)
@@ -33,5 +33,5 @@
 	Fits.c \
 	InitData.c \
-	Config.c
+	FitsGenerator.c
 
 # detectionbatch
@@ -44,5 +44,5 @@
 	Fits.c \
 	InitData.c \
-	Config.c
+	FitsGenerator.c
 
 # stackbatch
@@ -55,5 +55,5 @@
 	Fits.c \
 	InitData.c \
-	Config.c
+	FitsGenerator.c
 
 clean-local:
Index: /trunk/ippToPsps/src/StackBatch.c
===================================================================
--- /trunk/ippToPsps/src/StackBatch.c	(revision 31024)
+++ /trunk/ippToPsps/src/StackBatch.c	(revision 31025)
@@ -91,5 +91,5 @@
     if (numDetectionsOut > 0) {
 
-        this->base.config->createAndPopulateTable(this->base.config, fitsIn, this->base.fitsOut, nDet, "StackDetection", false);
+        this->base.fitsGenerator->createAndPopulateTable(this->base.fitsGenerator, fitsIn, this->base.fitsOut, nDet, "StackDetection", false);
         this->base.fitsOut->writeColumn(this->base.fitsOut, TLONG, STACKDETECTION_SKYCELLID, 1, 1, nDet, skycellIDs);
         this->base.fitsOut->writeColumn(this->base.fitsOut, TBYTE, STACKDETECTION_FILTERID, 1, 1, nDet, filterIDs);
@@ -186,5 +186,5 @@
 
     //int status = 0;
-    this->base.config->createAndPopulateTable(this->base.config, fitsIn, this->base.fitsOut, nDet, "StackApFlx", false);
+    this->base.fitsGenerator->createAndPopulateTable(this->base.fitsGenerator, fitsIn, this->base.fitsOut, nDet, "StackApFlx", false);
     this->base.fitsOut->writeColumn(this->base.fitsOut, TBYTE, STACKAPFLX_FILTERID, 1, 1, nDet, filterIDs);
     this->base.fitsOut->writeColumn(this->base.fitsOut, TBYTE, STACKAPFLX_SURVEYID, 1, 1, nDet, surveyIDs);
@@ -282,5 +282,5 @@
     }
 
-    this->base.config->createAndPopulateTable(this->base.config, fitsIn, this->base.fitsOut, nDet, "StackModelFit", false);
+    this->base.fitsGenerator->createAndPopulateTable(this->base.fitsGenerator, fitsIn, this->base.fitsOut, nDet, "StackModelFit", false);
     this->base.fitsOut->writeColumn(this->base.fitsOut, TBYTE, STACKMODELFIT_FILTERID, 1, 1, nDet, filterIDs);
     this->base.fitsOut->writeColumn(this->base.fitsOut, TBYTE, STACKMODELFIT_SURVEYID, 1, 1, nDet, surveyIDs);
@@ -302,5 +302,5 @@
         ) {
 
-    this->base.config->createAndPopulateTable(this->base.config, fitsIn, this->base.fitsOut, 3/*TODO*/, "StackToImage", false);
+    this->base.fitsGenerator->createAndPopulateTable(this->base.fitsGenerator, fitsIn, this->base.fitsOut, 3/*TODO*/, "StackToImage", false);
 
     return true;
@@ -333,5 +333,5 @@
 
     // write StackMeta
-    this->base.config->createAndPopulateTable(this->base.config, fitsIn, this->base.fitsOut, 1, "StackMeta", true);
+    this->base.fitsGenerator->createAndPopulateTable(this->base.fitsGenerator, fitsIn, this->base.fitsOut, 1, "StackMeta", true);
     this->base.fitsOut->writeColumn(this->base.fitsOut, TLONG, STACKMETA_SKYCELLID, 1, 1, 1, &this->skycellId);
     this->base.fitsOut->writeColumn(this->base.fitsOut, TBYTE, STACKMETA_FILTERID, 1, 1, 1, &filterID);
