Index: /trunk/psLib/src/dataIO/Makefile
===================================================================
--- /trunk/psLib/src/dataIO/Makefile	(revision 2302)
+++ /trunk/psLib/src/dataIO/Makefile	(revision 2302)
@@ -0,0 +1,59 @@
+ifndef prefix
+    export prefix=$(shell cd ../..;pwd)
+endif
+
+TARGET_STATIC  = libpslib.a
+include ../Makefile.Globals
+CFLAGS := $(CFLAGS_RELOC) -I. -I../sysUtils -I../collections -I../dataManip \
+    -I.. -I../image -I../astronomy -DSER7_FILE="\"$(SER7_FILE)\"" -DTAIUTC_FILE="\"$(TAIUTC_FILE)\""
+
+SRC_OBJS = psLookupTable.o
+
+OBJS = $(addprefix makedir/,$(SRC_OBJS))
+
+HEADERS = $(SRC_OBJS:.o=.h)
+
+all: $(TARGET_STATIC)
+
+#psAstronomyErrors.h: psAstronomyErrors.dat
+#	perl ../parseErrorCodes.pl --data=$? $@
+
+
+# Rule to make static library
+
+libpslib.a:     $(OBJS)
+# The ar option -r is to add/replace object and -s is to create
+# a symbol table in the archive
+	$(AR) rcs ../$@ $(OBJS)
+
+# Define PHONY target "install" which will install necessary files
+install: $(TARGET_STATIC)
+	install $(HEADERS) $(includedir)
+
+# Define PHONY target "distclean" which will cleanup the distribution
+distclean:      clean
+	$(RM) ../$(TARGET_STATIC)
+
+# Define PHONY target "clean" which will cleanup the development area
+clean:
+	@echo "    Deleting intermediate files for 'fileUtils'"
+	$(RM) $(OBJS) *.lint $(SRC_OBJS:.o=.i)
+
+cleandep:
+	$(RM) $(OBJS:.o=.d)
+
+%.lint: %.c
+	splint +posixlib -exportlocal -realcompare $(INCLUDE_GLOBAL) $? > $@; cat $@
+
+%.i: %.c
+	$(CC) -E $(CFLAGS) -o $@ $<
+
+makedir/%.o: %.c
+	$(CC) -c $(CFLAGS) -o $@ $<
+
+makedir/%.d: %.c
+	$(CC) -MM $(CFLAGS) $< > $@.tmp
+	sed 's|\($*\)\.o[ :]*|\1.o $@ : |g' $@.tmp > $@
+	$(RM) -f $@.tmp
+
+include $(OBJS:.o=.d)
Index: /trunk/psLib/src/dataIO/psFileUtilsErrors.dat
===================================================================
--- /trunk/psLib/src/dataIO/psFileUtilsErrors.dat	(revision 2302)
+++ /trunk/psLib/src/dataIO/psFileUtilsErrors.dat	(revision 2302)
@@ -0,0 +1,16 @@
+#
+#  This file is used to generate psFileUtilsErrors.h content
+#
+#  Format is:
+#  ERRORNAME(one word)    ERROR_TEXT
+#
+#  N.B. in code, the ERRORNAME appears as PS_ERRORTEXT_ERRORNAME
+####################################################################
+psLookupTable_FILE_NOT_FOUND           Failed to open file %s.
+psLookupTable_PARSE_VALUE              Unable to parse string, %s on line %d.
+psLookupTable_PARSE_TYPE               Unable to parse type, %s on line %d.
+psLookupTable_PARSE_GENERAL            Unable to read lookup table item, %s on line %d 
+psLookupTable_INTERPOLATE_HIGH         High index too big, %d.
+psLookupTable_INTERPOLATE_LOW          Low index too small, %d.
+psLookupTable_DIVIDE_BY_ZERO           Divide by zero error during interpolation.
+psLookupTable_INVALID_TYPE             Invalid psLookupType, %d;
Index: /trunk/psLib/src/dataIO/psFileUtilsErrors.h
===================================================================
--- /trunk/psLib/src/dataIO/psFileUtilsErrors.h	(revision 2302)
+++ /trunk/psLib/src/dataIO/psFileUtilsErrors.h	(revision 2302)
@@ -0,0 +1,42 @@
+/** @file  psAstronomyErrors.h
+ *
+ *  @brief Contains the error text for the astronomy functions
+ *
+ *  @ingroup ErrorHandling
+ *
+ *  @author Robert DeSonia, MHPCC
+ *
+ *  @version $Revision: 1.1 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2004-11-09 00:38:14 $
+ *
+ *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
+ */
+
+#ifndef PS_SYSUTILS_ERRORS_H
+#define PS_SYSUTILS_ERRORS_H
+
+/* N.B., lines between '//~Start' and '//~End' are automatic generated from
+ * the template following the '//~Start'.  The template is used to generate
+ * the other lines by, for each error text in psAstronomyErrors.dat, the following
+ * substitutions are made:
+ *     $1  The error text macro name (first word in the psAstronomyErrors.dat lines)
+ *     $2  The error text (rest of the line in psAstronomyErrors.dat)
+ *     $n  The order of the source line in psAstronomyErrors.dat (comments excluded)
+ * 
+ * DO NOT EDIT THE LINES BETWEEN //~Start and //~End!  ANY CHANGES WILL BE OVERWRITTEN.
+ */
+
+#define PS_ERRORNAME_DOMAIN "psLib.astronomy."
+
+//~Start #define PS_ERRORTEXT_$1 "$2"
+#define PS_ERRORTEXT_psLookupTable_FILE_NOT_FOUND "Failed to open file %s."
+#define PS_ERRORTEXT_psLookupTable_PARSE_VALUE "Unable to parse string, %s on line %d."
+#define PS_ERRORTEXT_psLookupTable_PARSE_TYPE "Unable to parse type, %s on line %d."
+#define PS_ERRORTEXT_psLookupTable_PARSE_GENERAL "Unable to read lookup table item, %s on line %d "
+#define PS_ERRORTEXT_psLookupTable_INTERPOLATE_HIGH "High index too big, %d."
+#define PS_ERRORTEXT_psLookupTable_INTERPOLATE_LOW "Low index too small, %d."
+#define PS_ERRORTEXT_psLookupTable_DIVIDE_BY_ZERO "Divide by zero error during interpolation."
+#define PS_ERRORTEXT_psLookupTable_INVALID_TYPE "Invalid psLookupType, %d;"
+//~End
+
+#endif
Index: /trunk/psLib/src/dataIO/psLookupTable.c
===================================================================
--- /trunk/psLib/src/dataIO/psLookupTable.c	(revision 2301)
+++ /trunk/psLib/src/dataIO/psLookupTable.c	(revision 2302)
@@ -8,28 +8,654 @@
 *  @author Ross Harman, MHPCC
 *
-*  @version $Revision: 1.1 $ $Name: not supported by cvs2svn $
-*  @date $Date: 2004-10-26 00:36:50 $
+*  @version $Revision: 1.2 $ $Name: not supported by cvs2svn $
+*  @date $Date: 2004-11-09 00:38:14 $
 *
 *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
 */
-
-#include "psLookupTable.c"
-
-
-psLookupTable* psLookupTableAlloc(psU64 numRows, psU64 numCols)
-{
-}
-
-psLookupTable* psLookupTableRead(char *fileName)
-{
-}
-
-psF64 psLookupTableInterpolate(psLookupTable *table, psF64 index, psMaskType *status)
-{
-}
-
-psVector* psLookupTableInterpolate(psLookupTable *table, psF64 index, psMaskType *status)
-{
-}
-
-#endif
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <math.h>
+
+#include "psMemory.h"
+#include "psString.h"
+#include "psError.h"
+#include "psLookupTable.h"
+#include "psFileUtilsErrors.h"
+#include "psConstants.h"
+
+/******************************************************************************/
+/*  DEFINE STATEMENTS                                                         */
+/******************************************************************************/
+
+/** Maximum size of a string */
+#define MAX_STRING_LENGTH 256
+
+/******************************************************************************/
+/*  TYPE DEFINITIONS                                                          */
+/******************************************************************************/
+
+// None
+
+/*****************************************************************************/
+/*  GLOBAL VARIABLES                                                         */
+/*****************************************************************************/
+
+// None
+
+/*****************************************************************************/
+/*  FILE STATIC VARIABLES                                                    */
+/*****************************************************************************/
+
+// None
+
+/*****************************************************************************/
+/*  FUNCTION IMPLEMENTATION - LOCAL                                          */
+/*****************************************************************************/
+
+static bool ignoreLine(char *inString);
+static char *cleanString(char *inString, int sLen);
+static char* getToken(char **inString, char *delimiter, psParseErrorType *status);
+static psU8 parseU8(char *inString, psParseErrorType *status);
+static psS8 parseS8(char *inString, psParseErrorType *status);
+static psU16 parseU16(char *inString, psParseErrorType *status);
+static psS16 parseS16(char *inString, psParseErrorType *status);
+static psU32 parseU32(char *inString, psParseErrorType *status);
+static psS32 parseS32(char *inString, psParseErrorType *status);
+static psU64 parseU64(char *inString, psParseErrorType *status);
+static psS64 parseS64(char *inString, psParseErrorType *status);
+static psF32 parseF32(char *inString, psParseErrorType *status);
+static psF64 parseF64(char *inString, psParseErrorType *status);
+static void parseValue(psVector *vec, psU64 index, char* strValue, psParseErrorType *status);
+static void lookupTableFree(psLookupTable* table);
+
+/** Determines if a line is blank (whitespace only) or a commentline. It returns true if so. The input string
+ *  must be null terminated. */
+static bool ignoreLine(char *inString)
+{
+    while(*inString!='\0' && *inString!='#') {
+        if(!isspace(*inString)) {
+            return false;
+        }
+        inString++;
+    }
+
+    return true;
+}
+
+
+/** Removes leading and trailing whitespace and # characters from a string. The cleaned string is a new null
+ *  terminated copy of the original input string. */
+static char *cleanString(char *inString, int sLen)
+{
+    char *ptrB = NULL;
+    char *ptrE = NULL;
+    char *cleaned = NULL;
+
+
+    ptrB = inString;
+
+    /* Skip over leading # or whitespace */
+    while (isspace(*ptrB) || *ptrB=='#') {
+        ptrB++;
+    }
+
+    /* Skip over trailing whitespace, null terminators, and # characters */
+    ptrE = inString + sLen;
+    while(isspace(*ptrE) || *ptrE=='\0' || *ptrE=='#') {
+        ptrE--;
+    }
+
+    // Length, sLen, does not include '\0'
+    sLen = ptrE - ptrB + 1;
+
+    // Adds '\0' to end of string and +1 to sLen
+    cleaned = psStringNCopy(ptrB, sLen);
+
+    return cleaned;
+}
+
+
+/** Returns cleaned token based on delimiter, but not including delimiter. Also changes the pointer location
+ * the beginning of the string. Tokens are newly allocated null terminated strings. */
+static char* getToken(char **inString, char *delimiter, psParseErrorType *status)
+{
+    char *cleanToken = NULL;
+    int sLen = 0;
+
+
+    // Skip over leading whitespace
+    while(isspace(**inString)) {
+        (*inString)++;
+    }
+
+    // Length of token, not including delimiter
+    sLen = strcspn(*inString, delimiter);
+    if(sLen) {
+
+        // Create new, cleaned, and null terminated token
+        cleanToken = cleanString(*inString, sLen);
+
+        // Move to end of token
+        (*inString) += sLen;
+    } else if(**inString!='\0' && sLen==0) {
+        *status = PS_PARSE_ERROR_GENERAL;
+    }
+
+    return cleanToken;
+}
+
+/** Returns single parsed value as a psU8. The input string must be cleaned and null terminated. */
+static psU8 parseU8(char *inString, psParseErrorType *status)
+{
+    char *end = NULL;
+    psU8 value = 0.0;
+
+
+    value = (psU8)strtoul(inString, &end, 0);
+    if(*end != '\0') {
+        *status = PS_PARSE_ERROR_VALUE;
+    } else if(inString==end) {
+        *status = PS_PARSE_ERROR_VALUE;
+    }
+
+    return value;
+}
+
+/** Returns single parsed value as a psS8. The input string must be cleaned and null terminated. */
+static psS8 parseS8(char *inString, psParseErrorType *status)
+{
+    char *end = NULL;
+    psS8 value = 0.0;
+
+
+    value = (psS8)strtol(inString, &end, 0);
+    if(*end != '\0') {
+        *status = PS_PARSE_ERROR_VALUE;
+    } else if(inString==end) {
+        *status = PS_PARSE_ERROR_VALUE;
+    }
+
+    return value;
+}
+
+/** Returns single parsed value as a psU16. The input string must be cleaned and null terminated. */
+static psU16 parseU16(char *inString, psParseErrorType *status)
+{
+    char *end = NULL;
+    psU16 value = 0.0;
+
+
+    value = (psU16)strtoul(inString, &end, 0);
+    if(*end != '\0') {
+        *status = PS_PARSE_ERROR_VALUE;
+    } else if(inString==end) {
+        *status = PS_PARSE_ERROR_VALUE;
+    }
+
+    return value;
+}
+
+/** Returns single parsed value as a psS16. The input string must be cleaned and null terminated. */
+static psS16 parseS16(char *inString, psParseErrorType *status)
+{
+    char *end = NULL;
+    psS16 value = 0.0;
+
+
+    value = (psS16)strtol(inString, &end, 0);
+    if(*end != '\0') {
+        *status = PS_PARSE_ERROR_VALUE;
+    } else if(inString==end) {
+        *status = PS_PARSE_ERROR_VALUE;
+    }
+
+    return value;
+}
+
+/** Returns single parsed value as a psU32. The input string must be cleaned and null terminated. */
+static psU32 parseU32(char *inString, psParseErrorType *status)
+{
+    char *end = NULL;
+    psU32 value = 0.0;
+
+
+    value = (psU32)strtoul(inString, &end, 0);
+    if(*end != '\0') {
+        *status = PS_PARSE_ERROR_VALUE;
+    } else if(inString==end) {
+        *status = PS_PARSE_ERROR_VALUE;
+    }
+
+    return value;
+}
+
+/** Returns single parsed value as a psS32. The input string must be cleaned and null terminated. */
+static psS32 parseS32(char *inString, psParseErrorType *status)
+{
+    char *end = NULL;
+    psS32 value = 0.0;
+
+
+    value = (psS32)strtol(inString, &end, 0);
+    if(*end != '\0') {
+        *status = PS_PARSE_ERROR_VALUE;
+    } else if(inString==end) {
+        *status = PS_PARSE_ERROR_VALUE;
+    }
+
+    return value;
+}
+
+/** Returns single parsed value as a psU64. The input string must be cleaned and null terminated. */
+static psU64 parseU64(char *inString, psParseErrorType *status)
+{
+    char *end = NULL;
+    psU64 value = 0.0;
+
+
+    value = (psU64)strtoull(inString, &end, 0);
+    if(*end != '\0') {
+        *status = PS_PARSE_ERROR_VALUE;
+    } else if(inString==end) {
+        *status = PS_PARSE_ERROR_VALUE;
+    }
+
+    return value;
+}
+
+/** Returns single parsed value as a psS64. The input string must be cleaned and null terminated. */
+static psS64 parseS64(char *inString, psParseErrorType *status)
+{
+    char *end = NULL;
+    psS64 value = 0.0;
+
+
+    value = (psS64)strtoll(inString, &end, 0);
+    if(*end != '\0') {
+        *status = PS_PARSE_ERROR_VALUE;
+    } else if(inString==end) {
+        *status = PS_PARSE_ERROR_VALUE;
+    }
+
+    return value;
+}
+
+/** Returns single parsed value as a psF32. The input string must be cleaned and null terminated. */
+static psF32 parseF32(char *inString, psParseErrorType *status)
+{
+    char *end = NULL;
+    psF32 value = 0.0;
+
+
+    value = (psF32)strtof(inString, &end);
+    if(*end != '\0') {
+        *status = PS_PARSE_ERROR_VALUE;
+    } else if(inString==end) {
+        *status = PS_PARSE_ERROR_VALUE;
+    }
+
+    return value;
+}
+
+/** Returns single parsed value as a psF64. The input string must be cleaned and null terminated. */
+static psF64 parseF64(char *inString, psParseErrorType *status)
+{
+    char *end = NULL;
+    psF64 value = 0.0;
+
+
+    value = (psF64)strtod(inString, &end);
+    if(*end != '\0') {
+        *status = PS_PARSE_ERROR_VALUE;
+    } else if(inString==end) {
+        *status = PS_PARSE_ERROR_VALUE;
+    }
+
+    return value;
+}
+
+/** Returns single parsed value as a double precision number. The input string must be cleaned and null
+ * terminated. */
+static void parseValue(psVector *vec, psU64 index, char* strValue, psParseErrorType *status)
+{
+    psElemType type;
+
+
+    if(vec == NULL) {
+        *status = 1;
+        return;
+    }
+
+    type = vec->type.type;
+
+    switch(type) {
+    case PS_TYPE_U8:
+        vec->data.U8[index] = parseU8(strValue, status);
+        break;
+    case PS_TYPE_S8:
+        vec->data.S8[index] = parseS8(strValue, status);
+        break;
+    case PS_TYPE_U16:
+        vec->data.U16[index] = parseU16(strValue, status);
+        break;
+    case PS_TYPE_S16:
+        vec->data.S16[index] = parseS16(strValue, status);
+        break;
+    case PS_TYPE_U32:
+        vec->data.U32[index] = parseU32(strValue, status);
+        break;
+    case PS_TYPE_S32:
+        vec->data.S32[index] = parseS32(strValue, status);
+        break;
+    case PS_TYPE_U64:
+        vec->data.U64[index] = parseU64(strValue, status);
+        break;
+    case PS_TYPE_S64:
+        vec->data.S64[index] = parseS64(strValue, status);
+        break;
+    case PS_TYPE_F32:
+        vec->data.F32[index] = parseF32(strValue, status);
+        break;
+    case PS_TYPE_F64:
+        vec->data.F64[index] = parseF64(strValue, status);
+        break;
+    default:
+        *status = PS_PARSE_ERROR_TYPE;
+    }
+
+    return;
+}
+
+static psParseErrorType printError(psU64 lineCount, char* badText, psParseErrorType status)
+{
+    switch(status) {
+    case PS_PARSE_ERROR_VALUE:
+        psError(PS_ERR_BAD_PARAMETER_VALUE, true, PS_ERRORTEXT_psLookupTable_PARSE_VALUE, badText, lineCount);
+        break;
+    case PS_PARSE_ERROR_TYPE:
+        psError(PS_ERR_BAD_PARAMETER_VALUE, true, PS_ERRORTEXT_psLookupTable_PARSE_TYPE, badText, lineCount);
+        break;
+    case PS_PARSE_ERROR_GENERAL:
+        psError(PS_ERR_BAD_PARAMETER_VALUE, true, PS_ERRORTEXT_psLookupTable_PARSE_GENERAL, badText, lineCount);
+        break;
+    default:
+        psError(PS_ERR_BAD_PARAMETER_VALUE, true, PS_ERRORTEXT_psLookupTable_INVALID_TYPE, badText, lineCount);
+    }
+
+    return PS_LOOKUP_SUCCESS;
+}
+
+static void lookupTableFree(psLookupTable* table)
+{
+    if (table == NULL) {
+        return;
+    }
+
+    psFree(table->values);
+    psFree(table->index);
+    psFree((char*)table->fileName);
+}
+
+/*****************************************************************************/
+/* FUNCTION IMPLEMENTATION - PUBLIC                                          */
+/*****************************************************************************/
+
+psLookupTable* psLookupTableAlloc(const char *fileName, psF64 validFrom, psF64 validTo)
+{
+    psLookupTable *outTable = NULL;
+
+
+    // Can't read table if you don't know its name
+    PS_PTR_CHECK_NULL(fileName,NULL);
+
+    // Allocate lookup table
+    outTable = (psLookupTable*)psAlloc(sizeof(psLookupTable));
+
+    // Set deallocator
+    p_psMemSetDeallocator(outTable, (psFreeFcn)lookupTableFree);
+
+    // Allocate and set metadata item comment
+    outTable->fileName = psStringCopy(fileName);
+
+    // Number of table rows and columns. Automatically resized by table read.
+    outTable->numRows = 0;
+    outTable->numCols = 0;
+
+    // Valid ranges. Automatically set by table read if both zero.
+    outTable->validFrom = validFrom;
+    outTable->validTo = validTo;
+
+    // Vector of independent index values. Filled by table read.
+    outTable->index = NULL;
+
+    // Array of dependent table values corresponding to index values. Filled by table read.
+    outTable->values = NULL;
+
+    return outTable;
+}
+
+psLookupTable* psLookupTableRead(psLookupTable *table)
+{
+    bool typeLine = true;
+    char *line = NULL;
+    char *strType = NULL;
+    char *strValue = NULL;
+    char *linePtr = NULL;
+    psParseErrorType status = PS_PARSE_SUCCESS;
+    psU64 lineCount = 0;
+    psU64 numRows = 0;
+    psU64 numCols = 0;
+    psU64 failedLines = 0;
+    FILE *fp = NULL;
+    psElemType elemType;
+    psVector *indexVec = NULL;
+    psVector *valuesVec = NULL;
+    psArray *values = NULL;
+
+
+    // Error checks
+    PS_PTR_CHECK_NULL(table,NULL);
+    PS_PTR_CHECK_NULL(table->fileName,NULL);
+    if((fp=fopen(table->fileName, "r")) == NULL) {
+        psError(PS_ERR_BAD_PARAMETER_VALUE, true, PS_ERRORTEXT_psLookupTable_FILE_NOT_FOUND, table->fileName);
+        return NULL;
+    }
+
+    indexVec = table->index;
+    values = table->values;
+
+    // Create reusable line for continuous read
+    line = (char*)psAlloc(MAX_STRING_LENGTH*sizeof(char));
+
+    // Loop through file to get numRows, numCols, and column data types
+    while(fgets(line, MAX_STRING_LENGTH, fp) != NULL) {
+
+        // Initialize variables for new line
+        linePtr = line;
+        lineCount++;
+
+        // If line is not a comment or blank, then extract data
+        if(!ignoreLine(linePtr)) {
+
+            if(typeLine == true) {
+
+                // Determine column types from first line in data file after comments
+                while((strType=getToken(&linePtr, " ", &status)) != NULL) {
+                    numCols++;
+                    typeLine = false;
+                    if(!strncmp(strType, "psU8", 4)) {
+                        elemType = PS_TYPE_U8;
+                    } else if(!strncmp(strType, "psS8", 4)) {
+                        elemType = PS_TYPE_S8;
+                    } else if(!strncmp(strType, "psU16", 5)) {
+                        elemType = PS_TYPE_U16;
+                    } else if(!strncmp(strType, "psS16", 5)) {
+                        elemType = PS_TYPE_S16;
+                    } else if(!strncmp(strType, "psU32", 5)) {
+                        elemType = PS_TYPE_U32;
+                    } else if(!strncmp(strType, "psS32", 5)) {
+                        elemType = PS_TYPE_S32;
+                    } else if(!strncmp(strType, "psU64", 5)) {
+                        elemType = PS_TYPE_U64;
+                    } else if(!strncmp(strType, "psS64", 5)) {
+                        elemType = PS_TYPE_S64;
+                    } else if(!strncmp(strType, "psF32", 5)) {
+                        elemType = PS_TYPE_F32;
+                    } else if(!strncmp(strType, "psF64", 5)) {
+                        elemType = PS_TYPE_F64;
+                    } else {
+                        status = PS_PARSE_ERROR_TYPE;
+                    }
+
+                    // Realloc number of columns as you go
+                    if(numCols == 1) {
+                        indexVec = psVectorAlloc(0, elemType);
+                    } else {
+                        values = psArrayRealloc(values, numCols-1);
+                        values->n = values->nalloc;
+                        values->data[numCols-2] = psVectorAlloc(0, elemType);
+                    }
+
+                    if(status) {
+                        status = printError(lineCount, strValue, status);
+                        failedLines++;
+                    }
+                    psFree(strType);
+                }
+            } else {
+
+                // Parse and add values to all columns
+                numRows++;
+                numCols = 0;
+                while((strValue=getToken(&linePtr, " ", &status)) != NULL) {
+                    numCols++;
+
+                    // Realloc number of rows as you go
+                    if(numCols == 1) {
+                        indexVec = psVectorRecycle(indexVec, numRows, indexVec->type.type);
+                        parseValue(indexVec, numRows-1, strValue, &status);
+                    } else {
+                        valuesVec = values->data[numCols-2];
+                        valuesVec = psVectorRecycle(valuesVec, numRows, valuesVec->type.type);
+                        parseValue(valuesVec, numRows-1, strValue, &status);
+                    }
+
+                    if(status) {
+                        status = printError(lineCount, strValue, status);
+                        failedLines++;
+                    }
+                    psFree(strValue);
+                } // end while
+            } // end else
+        } // if ignoreLine
+    } // end while
+
+    psFree(line);
+
+    // Set table for return
+    table->numRows = numRows;
+    table->numCols = numCols-1;
+    table->index = indexVec;
+    table->values = values;
+
+    fclose(fp);
+
+    return table;
+}
+
+psF64 psLookupTableInterpolate(psLookupTable *table, psF64 index, psU64 column, psLookupStatusType *status)
+{
+    psU64 hiIdx = 0;
+    psU64 loIdx = 0;
+    psU64 numRows = 0;
+    psU64 numCols = 0;
+    psF64 out = 0.0;
+    psF64 denom = 0.0;
+    psVector *indexVec = NULL;
+    psVector *valuesVec = NULL;
+    psArray *values = NULL;
+
+
+    // Error checks
+    PS_PTR_CHECK_NULL(table,0.0);
+    indexVec = table->index;
+    values = table->values;
+    numRows = table->numRows;
+    numCols = table->numCols;
+    PS_PTR_CHECK_NULL(indexVec,0.0);
+    PS_PTR_CHECK_NULL(values,0.0);
+    PS_INT_CHECK_EQUALS(numRows, 0,0.0);
+    PS_INT_CHECK_EQUALS(numCols, 0,0.0);
+    PS_INT_CHECK_RANGE(column, 0, numCols-1, 0.0);
+
+
+    valuesVec = (psVector*)values->data[column];
+    PS_PTR_CHECK_NULL(indexVec,0.0);
+
+    if(index<indexVec->data.F64[0] || index<table->validFrom) {
+
+        // Index value past top of table
+        *status = PS_LOOKUP_PAST_TOP;
+        return valuesVec->data.F64[0];
+    } else if(index>indexVec->data.F64[numRows-1] || index>table->validTo) {
+
+        // Index value past bottom of table
+        *status = PS_LOOKUP_PAST_BOTTOM;
+        return valuesVec->data.F64[numRows-1];
+    } else {
+
+        // Interpolation
+        while(index > indexVec->data.F64[hiIdx]) {
+            hiIdx++;
+            if(hiIdx >= numRows) {
+                psError(PS_ERR_BAD_PARAMETER_VALUE, true, PS_ERRORTEXT_psLookupTable_INTERPOLATE_HIGH, hiIdx);
+                return 0.0;
+            }
+        }
+
+        loIdx = hiIdx--;
+        if(loIdx < 0) {
+            psError(PS_ERR_BAD_PARAMETER_VALUE, true, PS_ERRORTEXT_psLookupTable_INTERPOLATE_LOW, loIdx);
+            return 0.0;
+        }
+
+        denom = indexVec->data.F64[hiIdx] - indexVec->data.F64[loIdx];
+        if(fabs(denom) < FLT_EPSILON) {
+            psError(PS_ERR_BAD_PARAMETER_VALUE, true, PS_ERRORTEXT_psLookupTable_DIVIDE_BY_ZERO);
+            return 0.0;
+        } else {
+            out = valuesVec->data.F64[loIdx]+(valuesVec->data.F64[hiIdx]-valuesVec->data.F64[loIdx])
+                  *(index-indexVec->data.F64[loIdx])/denom;
+        }
+    }
+
+    return out;
+}
+
+psVector* psLookupTableInterpolateAll(psLookupTable *table, psF64 index, psVector *stats)
+{
+    psU64 i = 0;
+    psU64 numCols = 0;
+    psVector *outVector = NULL;
+    psLookupStatusType status = PS_LOOKUP_SUCCESS;
+
+
+    // Error checks
+    PS_PTR_CHECK_NULL(table,NULL);
+    PS_PTR_CHECK_NULL(stats,NULL);
+    numCols = table->numCols;
+    PS_INT_CHECK_EQUALS(numCols, 0,NULL);
+
+    outVector = psVectorAlloc(numCols, PS_TYPE_F64);
+
+    // Fill vectors with results and status of results
+    for(i=0; i<numCols; i++) {
+        outVector->data.F64[i] = psLookupTableInterpolate(table, index, i, &status);
+        stats->data.U32[i] = status;
+    }
+
+    return outVector;
+}
+
Index: /trunk/psLib/src/dataIO/psLookupTable.h
===================================================================
--- /trunk/psLib/src/dataIO/psLookupTable.h	(revision 2301)
+++ /trunk/psLib/src/dataIO/psLookupTable.h	(revision 2302)
@@ -7,6 +7,6 @@
 *  @author Ross Harman, MHPCC
 *
-*  @version $Revision: 1.1 $ $Name: not supported by cvs2svn $
-*  @date $Date: 2004-10-26 00:37:15 $
+*  @version $Revision: 1.2 $ $Name: not supported by cvs2svn $
+*  @date $Date: 2004-11-09 00:38:14 $
 *
 *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
@@ -15,4 +15,8 @@
 #ifndef PS_LOOKUPTABLE_H
 #define PS_LOOKUPTABLE_H
+
+#include "psType.h"
+#include "psVector.h"
+#include "psArray.h"
 
 
@@ -24,20 +28,36 @@
 typedef struct
 {
+    const char *fileName;              ///< Name of file with table
+    psU64 numRows;                     ///< Number of table rows
+    psU64 numCols;                     ///< Number of table columns
+    psF64 validFrom;                   ///< Lower bound for rable read
+    psF64 validTo;                     ///< Upper bound for table read
     psVector *index;                   ///< Vector of independent index values
-    psArray *values;                   ///< Array of dependent table values corresponding to index values.
+    psArray *values;                   ///< Array of dependent table values corresponding to index values
 }
 psLookupTable;
 
 
-/** Lookup error conditions
+/** Lookup table lookup status and error conditions
  *
- *  Success and failure conditions for table lookups.
+ *  Success, failure, and status conditions for table lookups.
  */
 typedef enum {
-    PS_LOOKUP_SUCCESS = 0x000,         ///< Table lookup succeeded.
-    PS_LOOKUP_TOP     = 0x0001,        ///< Lookup off top of table.
-    PS_LOOKUP_BOTTOM  = 0x0002,        ///< Lookup off bottom of table.
-    PS_LOOKUP_ERROR   = 0x0003,        ///< Any other type of lookup error.
-} psLookupErrorType;
+    PS_LOOKUP_SUCCESS             = 0x0000,        ///< Table lookup succeeded
+    PS_LOOKUP_PAST_TOP            = 0x0101,        ///< Lookup off top of table
+    PS_LOOKUP_PAST_BOTTOM         = 0x0102,        ///< Lookup off bottom of table
+    PS_LOOKUP_ERROR               = 0x0104         ///< Any other type of lookup error
+} psLookupStatusType;
+
+/** Lookup table parse status and error conditions
+ *
+ *  Success, failure, and status conditions for table parsing.
+ */
+typedef enum {
+    PS_PARSE_SUCCESS              = 0x0000,        ///< Table lookup succeeded
+    PS_PARSE_ERROR_TYPE           = 0x0101,        ///< Error parsing type
+    PS_PARSE_ERROR_VALUE          = 0x0102,        ///< Error parsing numerical value
+    PS_PARSE_ERROR_GENERAL        = 0x0104         ///< Any other type of lookup error
+}psParseErrorType;
 
 /** Allocator for psLookupTable struct
@@ -48,6 +68,7 @@
  */
 psLookupTable* psLookupTableAlloc(
-    psU64 numRows,                  ///< Number of rows
-    psU64 numCols                   ///< number of columns
+    const char *fileName,           ///< Name of file to read
+    psF64 validFrom,                ///< Lower bound for rable read
+    psF64 validTo                   ///< Upper bound for table read
 );
 
@@ -59,5 +80,5 @@
  */
 psLookupTable* psLookupTableRead(
-    char *fileName                  ///< Name of file to read
+    psLookupTable *table            ///< Table to read
 );
 
@@ -67,10 +88,11 @@
  *  conditions.
  *
- *  @return psLookupTable*     New psLookupTable struct.
+ *  @return psLookupTable*     New psLookupTable struct
  */
 psF64 psLookupTableInterpolate(
     psLookupTable *table,           ///< Table with data
     psF64 index,                    ///< Value to be interpolated
-    psMaskType *status              ///< Status of lookup.
+    psU64 column,                   ///< Column in table to be interpolated
+    psLookupStatusType *status      ///< Status of lookup
 );
 
@@ -80,10 +102,10 @@
  *  conditions.
  *
- *  @return psLookupTable*     New psLookupTable struct.
+ *  @return psLookupTable*     New psLookupTable struct
  */
-psVector* psLookupTableInterpolate(
+psVector* psLookupTableInterpolateAll(
     psLookupTable *table,           ///< Table with data
     psF64 index,                    ///< Value to be interpolated
-    psMaskType *status              ///< Status of lookup.
+    psVector *stats                 ///< Vector of status for each lookup
 );
 
Index: /trunk/psLib/src/fileUtils/Makefile
===================================================================
--- /trunk/psLib/src/fileUtils/Makefile	(revision 2302)
+++ /trunk/psLib/src/fileUtils/Makefile	(revision 2302)
@@ -0,0 +1,59 @@
+ifndef prefix
+    export prefix=$(shell cd ../..;pwd)
+endif
+
+TARGET_STATIC  = libpslib.a
+include ../Makefile.Globals
+CFLAGS := $(CFLAGS_RELOC) -I. -I../sysUtils -I../collections -I../dataManip \
+    -I.. -I../image -I../astronomy -DSER7_FILE="\"$(SER7_FILE)\"" -DTAIUTC_FILE="\"$(TAIUTC_FILE)\""
+
+SRC_OBJS = psLookupTable.o
+
+OBJS = $(addprefix makedir/,$(SRC_OBJS))
+
+HEADERS = $(SRC_OBJS:.o=.h)
+
+all: $(TARGET_STATIC)
+
+#psAstronomyErrors.h: psAstronomyErrors.dat
+#	perl ../parseErrorCodes.pl --data=$? $@
+
+
+# Rule to make static library
+
+libpslib.a:     $(OBJS)
+# The ar option -r is to add/replace object and -s is to create
+# a symbol table in the archive
+	$(AR) rcs ../$@ $(OBJS)
+
+# Define PHONY target "install" which will install necessary files
+install: $(TARGET_STATIC)
+	install $(HEADERS) $(includedir)
+
+# Define PHONY target "distclean" which will cleanup the distribution
+distclean:      clean
+	$(RM) ../$(TARGET_STATIC)
+
+# Define PHONY target "clean" which will cleanup the development area
+clean:
+	@echo "    Deleting intermediate files for 'fileUtils'"
+	$(RM) $(OBJS) *.lint $(SRC_OBJS:.o=.i)
+
+cleandep:
+	$(RM) $(OBJS:.o=.d)
+
+%.lint: %.c
+	splint +posixlib -exportlocal -realcompare $(INCLUDE_GLOBAL) $? > $@; cat $@
+
+%.i: %.c
+	$(CC) -E $(CFLAGS) -o $@ $<
+
+makedir/%.o: %.c
+	$(CC) -c $(CFLAGS) -o $@ $<
+
+makedir/%.d: %.c
+	$(CC) -MM $(CFLAGS) $< > $@.tmp
+	sed 's|\($*\)\.o[ :]*|\1.o $@ : |g' $@.tmp > $@
+	$(RM) -f $@.tmp
+
+include $(OBJS:.o=.d)
Index: /trunk/psLib/src/fileUtils/psFileUtilsErrors.dat
===================================================================
--- /trunk/psLib/src/fileUtils/psFileUtilsErrors.dat	(revision 2302)
+++ /trunk/psLib/src/fileUtils/psFileUtilsErrors.dat	(revision 2302)
@@ -0,0 +1,16 @@
+#
+#  This file is used to generate psFileUtilsErrors.h content
+#
+#  Format is:
+#  ERRORNAME(one word)    ERROR_TEXT
+#
+#  N.B. in code, the ERRORNAME appears as PS_ERRORTEXT_ERRORNAME
+####################################################################
+psLookupTable_FILE_NOT_FOUND           Failed to open file %s.
+psLookupTable_PARSE_VALUE              Unable to parse string, %s on line %d.
+psLookupTable_PARSE_TYPE               Unable to parse type, %s on line %d.
+psLookupTable_PARSE_GENERAL            Unable to read lookup table item, %s on line %d 
+psLookupTable_INTERPOLATE_HIGH         High index too big, %d.
+psLookupTable_INTERPOLATE_LOW          Low index too small, %d.
+psLookupTable_DIVIDE_BY_ZERO           Divide by zero error during interpolation.
+psLookupTable_INVALID_TYPE             Invalid psLookupType, %d;
Index: /trunk/psLib/src/fileUtils/psFileUtilsErrors.h
===================================================================
--- /trunk/psLib/src/fileUtils/psFileUtilsErrors.h	(revision 2302)
+++ /trunk/psLib/src/fileUtils/psFileUtilsErrors.h	(revision 2302)
@@ -0,0 +1,42 @@
+/** @file  psAstronomyErrors.h
+ *
+ *  @brief Contains the error text for the astronomy functions
+ *
+ *  @ingroup ErrorHandling
+ *
+ *  @author Robert DeSonia, MHPCC
+ *
+ *  @version $Revision: 1.1 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2004-11-09 00:38:14 $
+ *
+ *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
+ */
+
+#ifndef PS_SYSUTILS_ERRORS_H
+#define PS_SYSUTILS_ERRORS_H
+
+/* N.B., lines between '//~Start' and '//~End' are automatic generated from
+ * the template following the '//~Start'.  The template is used to generate
+ * the other lines by, for each error text in psAstronomyErrors.dat, the following
+ * substitutions are made:
+ *     $1  The error text macro name (first word in the psAstronomyErrors.dat lines)
+ *     $2  The error text (rest of the line in psAstronomyErrors.dat)
+ *     $n  The order of the source line in psAstronomyErrors.dat (comments excluded)
+ * 
+ * DO NOT EDIT THE LINES BETWEEN //~Start and //~End!  ANY CHANGES WILL BE OVERWRITTEN.
+ */
+
+#define PS_ERRORNAME_DOMAIN "psLib.astronomy."
+
+//~Start #define PS_ERRORTEXT_$1 "$2"
+#define PS_ERRORTEXT_psLookupTable_FILE_NOT_FOUND "Failed to open file %s."
+#define PS_ERRORTEXT_psLookupTable_PARSE_VALUE "Unable to parse string, %s on line %d."
+#define PS_ERRORTEXT_psLookupTable_PARSE_TYPE "Unable to parse type, %s on line %d."
+#define PS_ERRORTEXT_psLookupTable_PARSE_GENERAL "Unable to read lookup table item, %s on line %d "
+#define PS_ERRORTEXT_psLookupTable_INTERPOLATE_HIGH "High index too big, %d."
+#define PS_ERRORTEXT_psLookupTable_INTERPOLATE_LOW "Low index too small, %d."
+#define PS_ERRORTEXT_psLookupTable_DIVIDE_BY_ZERO "Divide by zero error during interpolation."
+#define PS_ERRORTEXT_psLookupTable_INVALID_TYPE "Invalid psLookupType, %d;"
+//~End
+
+#endif
Index: /trunk/psLib/src/fileUtils/psLookupTable.c
===================================================================
--- /trunk/psLib/src/fileUtils/psLookupTable.c	(revision 2301)
+++ /trunk/psLib/src/fileUtils/psLookupTable.c	(revision 2302)
@@ -8,28 +8,654 @@
 *  @author Ross Harman, MHPCC
 *
-*  @version $Revision: 1.1 $ $Name: not supported by cvs2svn $
-*  @date $Date: 2004-10-26 00:36:50 $
+*  @version $Revision: 1.2 $ $Name: not supported by cvs2svn $
+*  @date $Date: 2004-11-09 00:38:14 $
 *
 *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
 */
-
-#include "psLookupTable.c"
-
-
-psLookupTable* psLookupTableAlloc(psU64 numRows, psU64 numCols)
-{
-}
-
-psLookupTable* psLookupTableRead(char *fileName)
-{
-}
-
-psF64 psLookupTableInterpolate(psLookupTable *table, psF64 index, psMaskType *status)
-{
-}
-
-psVector* psLookupTableInterpolate(psLookupTable *table, psF64 index, psMaskType *status)
-{
-}
-
-#endif
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <math.h>
+
+#include "psMemory.h"
+#include "psString.h"
+#include "psError.h"
+#include "psLookupTable.h"
+#include "psFileUtilsErrors.h"
+#include "psConstants.h"
+
+/******************************************************************************/
+/*  DEFINE STATEMENTS                                                         */
+/******************************************************************************/
+
+/** Maximum size of a string */
+#define MAX_STRING_LENGTH 256
+
+/******************************************************************************/
+/*  TYPE DEFINITIONS                                                          */
+/******************************************************************************/
+
+// None
+
+/*****************************************************************************/
+/*  GLOBAL VARIABLES                                                         */
+/*****************************************************************************/
+
+// None
+
+/*****************************************************************************/
+/*  FILE STATIC VARIABLES                                                    */
+/*****************************************************************************/
+
+// None
+
+/*****************************************************************************/
+/*  FUNCTION IMPLEMENTATION - LOCAL                                          */
+/*****************************************************************************/
+
+static bool ignoreLine(char *inString);
+static char *cleanString(char *inString, int sLen);
+static char* getToken(char **inString, char *delimiter, psParseErrorType *status);
+static psU8 parseU8(char *inString, psParseErrorType *status);
+static psS8 parseS8(char *inString, psParseErrorType *status);
+static psU16 parseU16(char *inString, psParseErrorType *status);
+static psS16 parseS16(char *inString, psParseErrorType *status);
+static psU32 parseU32(char *inString, psParseErrorType *status);
+static psS32 parseS32(char *inString, psParseErrorType *status);
+static psU64 parseU64(char *inString, psParseErrorType *status);
+static psS64 parseS64(char *inString, psParseErrorType *status);
+static psF32 parseF32(char *inString, psParseErrorType *status);
+static psF64 parseF64(char *inString, psParseErrorType *status);
+static void parseValue(psVector *vec, psU64 index, char* strValue, psParseErrorType *status);
+static void lookupTableFree(psLookupTable* table);
+
+/** Determines if a line is blank (whitespace only) or a commentline. It returns true if so. The input string
+ *  must be null terminated. */
+static bool ignoreLine(char *inString)
+{
+    while(*inString!='\0' && *inString!='#') {
+        if(!isspace(*inString)) {
+            return false;
+        }
+        inString++;
+    }
+
+    return true;
+}
+
+
+/** Removes leading and trailing whitespace and # characters from a string. The cleaned string is a new null
+ *  terminated copy of the original input string. */
+static char *cleanString(char *inString, int sLen)
+{
+    char *ptrB = NULL;
+    char *ptrE = NULL;
+    char *cleaned = NULL;
+
+
+    ptrB = inString;
+
+    /* Skip over leading # or whitespace */
+    while (isspace(*ptrB) || *ptrB=='#') {
+        ptrB++;
+    }
+
+    /* Skip over trailing whitespace, null terminators, and # characters */
+    ptrE = inString + sLen;
+    while(isspace(*ptrE) || *ptrE=='\0' || *ptrE=='#') {
+        ptrE--;
+    }
+
+    // Length, sLen, does not include '\0'
+    sLen = ptrE - ptrB + 1;
+
+    // Adds '\0' to end of string and +1 to sLen
+    cleaned = psStringNCopy(ptrB, sLen);
+
+    return cleaned;
+}
+
+
+/** Returns cleaned token based on delimiter, but not including delimiter. Also changes the pointer location
+ * the beginning of the string. Tokens are newly allocated null terminated strings. */
+static char* getToken(char **inString, char *delimiter, psParseErrorType *status)
+{
+    char *cleanToken = NULL;
+    int sLen = 0;
+
+
+    // Skip over leading whitespace
+    while(isspace(**inString)) {
+        (*inString)++;
+    }
+
+    // Length of token, not including delimiter
+    sLen = strcspn(*inString, delimiter);
+    if(sLen) {
+
+        // Create new, cleaned, and null terminated token
+        cleanToken = cleanString(*inString, sLen);
+
+        // Move to end of token
+        (*inString) += sLen;
+    } else if(**inString!='\0' && sLen==0) {
+        *status = PS_PARSE_ERROR_GENERAL;
+    }
+
+    return cleanToken;
+}
+
+/** Returns single parsed value as a psU8. The input string must be cleaned and null terminated. */
+static psU8 parseU8(char *inString, psParseErrorType *status)
+{
+    char *end = NULL;
+    psU8 value = 0.0;
+
+
+    value = (psU8)strtoul(inString, &end, 0);
+    if(*end != '\0') {
+        *status = PS_PARSE_ERROR_VALUE;
+    } else if(inString==end) {
+        *status = PS_PARSE_ERROR_VALUE;
+    }
+
+    return value;
+}
+
+/** Returns single parsed value as a psS8. The input string must be cleaned and null terminated. */
+static psS8 parseS8(char *inString, psParseErrorType *status)
+{
+    char *end = NULL;
+    psS8 value = 0.0;
+
+
+    value = (psS8)strtol(inString, &end, 0);
+    if(*end != '\0') {
+        *status = PS_PARSE_ERROR_VALUE;
+    } else if(inString==end) {
+        *status = PS_PARSE_ERROR_VALUE;
+    }
+
+    return value;
+}
+
+/** Returns single parsed value as a psU16. The input string must be cleaned and null terminated. */
+static psU16 parseU16(char *inString, psParseErrorType *status)
+{
+    char *end = NULL;
+    psU16 value = 0.0;
+
+
+    value = (psU16)strtoul(inString, &end, 0);
+    if(*end != '\0') {
+        *status = PS_PARSE_ERROR_VALUE;
+    } else if(inString==end) {
+        *status = PS_PARSE_ERROR_VALUE;
+    }
+
+    return value;
+}
+
+/** Returns single parsed value as a psS16. The input string must be cleaned and null terminated. */
+static psS16 parseS16(char *inString, psParseErrorType *status)
+{
+    char *end = NULL;
+    psS16 value = 0.0;
+
+
+    value = (psS16)strtol(inString, &end, 0);
+    if(*end != '\0') {
+        *status = PS_PARSE_ERROR_VALUE;
+    } else if(inString==end) {
+        *status = PS_PARSE_ERROR_VALUE;
+    }
+
+    return value;
+}
+
+/** Returns single parsed value as a psU32. The input string must be cleaned and null terminated. */
+static psU32 parseU32(char *inString, psParseErrorType *status)
+{
+    char *end = NULL;
+    psU32 value = 0.0;
+
+
+    value = (psU32)strtoul(inString, &end, 0);
+    if(*end != '\0') {
+        *status = PS_PARSE_ERROR_VALUE;
+    } else if(inString==end) {
+        *status = PS_PARSE_ERROR_VALUE;
+    }
+
+    return value;
+}
+
+/** Returns single parsed value as a psS32. The input string must be cleaned and null terminated. */
+static psS32 parseS32(char *inString, psParseErrorType *status)
+{
+    char *end = NULL;
+    psS32 value = 0.0;
+
+
+    value = (psS32)strtol(inString, &end, 0);
+    if(*end != '\0') {
+        *status = PS_PARSE_ERROR_VALUE;
+    } else if(inString==end) {
+        *status = PS_PARSE_ERROR_VALUE;
+    }
+
+    return value;
+}
+
+/** Returns single parsed value as a psU64. The input string must be cleaned and null terminated. */
+static psU64 parseU64(char *inString, psParseErrorType *status)
+{
+    char *end = NULL;
+    psU64 value = 0.0;
+
+
+    value = (psU64)strtoull(inString, &end, 0);
+    if(*end != '\0') {
+        *status = PS_PARSE_ERROR_VALUE;
+    } else if(inString==end) {
+        *status = PS_PARSE_ERROR_VALUE;
+    }
+
+    return value;
+}
+
+/** Returns single parsed value as a psS64. The input string must be cleaned and null terminated. */
+static psS64 parseS64(char *inString, psParseErrorType *status)
+{
+    char *end = NULL;
+    psS64 value = 0.0;
+
+
+    value = (psS64)strtoll(inString, &end, 0);
+    if(*end != '\0') {
+        *status = PS_PARSE_ERROR_VALUE;
+    } else if(inString==end) {
+        *status = PS_PARSE_ERROR_VALUE;
+    }
+
+    return value;
+}
+
+/** Returns single parsed value as a psF32. The input string must be cleaned and null terminated. */
+static psF32 parseF32(char *inString, psParseErrorType *status)
+{
+    char *end = NULL;
+    psF32 value = 0.0;
+
+
+    value = (psF32)strtof(inString, &end);
+    if(*end != '\0') {
+        *status = PS_PARSE_ERROR_VALUE;
+    } else if(inString==end) {
+        *status = PS_PARSE_ERROR_VALUE;
+    }
+
+    return value;
+}
+
+/** Returns single parsed value as a psF64. The input string must be cleaned and null terminated. */
+static psF64 parseF64(char *inString, psParseErrorType *status)
+{
+    char *end = NULL;
+    psF64 value = 0.0;
+
+
+    value = (psF64)strtod(inString, &end);
+    if(*end != '\0') {
+        *status = PS_PARSE_ERROR_VALUE;
+    } else if(inString==end) {
+        *status = PS_PARSE_ERROR_VALUE;
+    }
+
+    return value;
+}
+
+/** Returns single parsed value as a double precision number. The input string must be cleaned and null
+ * terminated. */
+static void parseValue(psVector *vec, psU64 index, char* strValue, psParseErrorType *status)
+{
+    psElemType type;
+
+
+    if(vec == NULL) {
+        *status = 1;
+        return;
+    }
+
+    type = vec->type.type;
+
+    switch(type) {
+    case PS_TYPE_U8:
+        vec->data.U8[index] = parseU8(strValue, status);
+        break;
+    case PS_TYPE_S8:
+        vec->data.S8[index] = parseS8(strValue, status);
+        break;
+    case PS_TYPE_U16:
+        vec->data.U16[index] = parseU16(strValue, status);
+        break;
+    case PS_TYPE_S16:
+        vec->data.S16[index] = parseS16(strValue, status);
+        break;
+    case PS_TYPE_U32:
+        vec->data.U32[index] = parseU32(strValue, status);
+        break;
+    case PS_TYPE_S32:
+        vec->data.S32[index] = parseS32(strValue, status);
+        break;
+    case PS_TYPE_U64:
+        vec->data.U64[index] = parseU64(strValue, status);
+        break;
+    case PS_TYPE_S64:
+        vec->data.S64[index] = parseS64(strValue, status);
+        break;
+    case PS_TYPE_F32:
+        vec->data.F32[index] = parseF32(strValue, status);
+        break;
+    case PS_TYPE_F64:
+        vec->data.F64[index] = parseF64(strValue, status);
+        break;
+    default:
+        *status = PS_PARSE_ERROR_TYPE;
+    }
+
+    return;
+}
+
+static psParseErrorType printError(psU64 lineCount, char* badText, psParseErrorType status)
+{
+    switch(status) {
+    case PS_PARSE_ERROR_VALUE:
+        psError(PS_ERR_BAD_PARAMETER_VALUE, true, PS_ERRORTEXT_psLookupTable_PARSE_VALUE, badText, lineCount);
+        break;
+    case PS_PARSE_ERROR_TYPE:
+        psError(PS_ERR_BAD_PARAMETER_VALUE, true, PS_ERRORTEXT_psLookupTable_PARSE_TYPE, badText, lineCount);
+        break;
+    case PS_PARSE_ERROR_GENERAL:
+        psError(PS_ERR_BAD_PARAMETER_VALUE, true, PS_ERRORTEXT_psLookupTable_PARSE_GENERAL, badText, lineCount);
+        break;
+    default:
+        psError(PS_ERR_BAD_PARAMETER_VALUE, true, PS_ERRORTEXT_psLookupTable_INVALID_TYPE, badText, lineCount);
+    }
+
+    return PS_LOOKUP_SUCCESS;
+}
+
+static void lookupTableFree(psLookupTable* table)
+{
+    if (table == NULL) {
+        return;
+    }
+
+    psFree(table->values);
+    psFree(table->index);
+    psFree((char*)table->fileName);
+}
+
+/*****************************************************************************/
+/* FUNCTION IMPLEMENTATION - PUBLIC                                          */
+/*****************************************************************************/
+
+psLookupTable* psLookupTableAlloc(const char *fileName, psF64 validFrom, psF64 validTo)
+{
+    psLookupTable *outTable = NULL;
+
+
+    // Can't read table if you don't know its name
+    PS_PTR_CHECK_NULL(fileName,NULL);
+
+    // Allocate lookup table
+    outTable = (psLookupTable*)psAlloc(sizeof(psLookupTable));
+
+    // Set deallocator
+    p_psMemSetDeallocator(outTable, (psFreeFcn)lookupTableFree);
+
+    // Allocate and set metadata item comment
+    outTable->fileName = psStringCopy(fileName);
+
+    // Number of table rows and columns. Automatically resized by table read.
+    outTable->numRows = 0;
+    outTable->numCols = 0;
+
+    // Valid ranges. Automatically set by table read if both zero.
+    outTable->validFrom = validFrom;
+    outTable->validTo = validTo;
+
+    // Vector of independent index values. Filled by table read.
+    outTable->index = NULL;
+
+    // Array of dependent table values corresponding to index values. Filled by table read.
+    outTable->values = NULL;
+
+    return outTable;
+}
+
+psLookupTable* psLookupTableRead(psLookupTable *table)
+{
+    bool typeLine = true;
+    char *line = NULL;
+    char *strType = NULL;
+    char *strValue = NULL;
+    char *linePtr = NULL;
+    psParseErrorType status = PS_PARSE_SUCCESS;
+    psU64 lineCount = 0;
+    psU64 numRows = 0;
+    psU64 numCols = 0;
+    psU64 failedLines = 0;
+    FILE *fp = NULL;
+    psElemType elemType;
+    psVector *indexVec = NULL;
+    psVector *valuesVec = NULL;
+    psArray *values = NULL;
+
+
+    // Error checks
+    PS_PTR_CHECK_NULL(table,NULL);
+    PS_PTR_CHECK_NULL(table->fileName,NULL);
+    if((fp=fopen(table->fileName, "r")) == NULL) {
+        psError(PS_ERR_BAD_PARAMETER_VALUE, true, PS_ERRORTEXT_psLookupTable_FILE_NOT_FOUND, table->fileName);
+        return NULL;
+    }
+
+    indexVec = table->index;
+    values = table->values;
+
+    // Create reusable line for continuous read
+    line = (char*)psAlloc(MAX_STRING_LENGTH*sizeof(char));
+
+    // Loop through file to get numRows, numCols, and column data types
+    while(fgets(line, MAX_STRING_LENGTH, fp) != NULL) {
+
+        // Initialize variables for new line
+        linePtr = line;
+        lineCount++;
+
+        // If line is not a comment or blank, then extract data
+        if(!ignoreLine(linePtr)) {
+
+            if(typeLine == true) {
+
+                // Determine column types from first line in data file after comments
+                while((strType=getToken(&linePtr, " ", &status)) != NULL) {
+                    numCols++;
+                    typeLine = false;
+                    if(!strncmp(strType, "psU8", 4)) {
+                        elemType = PS_TYPE_U8;
+                    } else if(!strncmp(strType, "psS8", 4)) {
+                        elemType = PS_TYPE_S8;
+                    } else if(!strncmp(strType, "psU16", 5)) {
+                        elemType = PS_TYPE_U16;
+                    } else if(!strncmp(strType, "psS16", 5)) {
+                        elemType = PS_TYPE_S16;
+                    } else if(!strncmp(strType, "psU32", 5)) {
+                        elemType = PS_TYPE_U32;
+                    } else if(!strncmp(strType, "psS32", 5)) {
+                        elemType = PS_TYPE_S32;
+                    } else if(!strncmp(strType, "psU64", 5)) {
+                        elemType = PS_TYPE_U64;
+                    } else if(!strncmp(strType, "psS64", 5)) {
+                        elemType = PS_TYPE_S64;
+                    } else if(!strncmp(strType, "psF32", 5)) {
+                        elemType = PS_TYPE_F32;
+                    } else if(!strncmp(strType, "psF64", 5)) {
+                        elemType = PS_TYPE_F64;
+                    } else {
+                        status = PS_PARSE_ERROR_TYPE;
+                    }
+
+                    // Realloc number of columns as you go
+                    if(numCols == 1) {
+                        indexVec = psVectorAlloc(0, elemType);
+                    } else {
+                        values = psArrayRealloc(values, numCols-1);
+                        values->n = values->nalloc;
+                        values->data[numCols-2] = psVectorAlloc(0, elemType);
+                    }
+
+                    if(status) {
+                        status = printError(lineCount, strValue, status);
+                        failedLines++;
+                    }
+                    psFree(strType);
+                }
+            } else {
+
+                // Parse and add values to all columns
+                numRows++;
+                numCols = 0;
+                while((strValue=getToken(&linePtr, " ", &status)) != NULL) {
+                    numCols++;
+
+                    // Realloc number of rows as you go
+                    if(numCols == 1) {
+                        indexVec = psVectorRecycle(indexVec, numRows, indexVec->type.type);
+                        parseValue(indexVec, numRows-1, strValue, &status);
+                    } else {
+                        valuesVec = values->data[numCols-2];
+                        valuesVec = psVectorRecycle(valuesVec, numRows, valuesVec->type.type);
+                        parseValue(valuesVec, numRows-1, strValue, &status);
+                    }
+
+                    if(status) {
+                        status = printError(lineCount, strValue, status);
+                        failedLines++;
+                    }
+                    psFree(strValue);
+                } // end while
+            } // end else
+        } // if ignoreLine
+    } // end while
+
+    psFree(line);
+
+    // Set table for return
+    table->numRows = numRows;
+    table->numCols = numCols-1;
+    table->index = indexVec;
+    table->values = values;
+
+    fclose(fp);
+
+    return table;
+}
+
+psF64 psLookupTableInterpolate(psLookupTable *table, psF64 index, psU64 column, psLookupStatusType *status)
+{
+    psU64 hiIdx = 0;
+    psU64 loIdx = 0;
+    psU64 numRows = 0;
+    psU64 numCols = 0;
+    psF64 out = 0.0;
+    psF64 denom = 0.0;
+    psVector *indexVec = NULL;
+    psVector *valuesVec = NULL;
+    psArray *values = NULL;
+
+
+    // Error checks
+    PS_PTR_CHECK_NULL(table,0.0);
+    indexVec = table->index;
+    values = table->values;
+    numRows = table->numRows;
+    numCols = table->numCols;
+    PS_PTR_CHECK_NULL(indexVec,0.0);
+    PS_PTR_CHECK_NULL(values,0.0);
+    PS_INT_CHECK_EQUALS(numRows, 0,0.0);
+    PS_INT_CHECK_EQUALS(numCols, 0,0.0);
+    PS_INT_CHECK_RANGE(column, 0, numCols-1, 0.0);
+
+
+    valuesVec = (psVector*)values->data[column];
+    PS_PTR_CHECK_NULL(indexVec,0.0);
+
+    if(index<indexVec->data.F64[0] || index<table->validFrom) {
+
+        // Index value past top of table
+        *status = PS_LOOKUP_PAST_TOP;
+        return valuesVec->data.F64[0];
+    } else if(index>indexVec->data.F64[numRows-1] || index>table->validTo) {
+
+        // Index value past bottom of table
+        *status = PS_LOOKUP_PAST_BOTTOM;
+        return valuesVec->data.F64[numRows-1];
+    } else {
+
+        // Interpolation
+        while(index > indexVec->data.F64[hiIdx]) {
+            hiIdx++;
+            if(hiIdx >= numRows) {
+                psError(PS_ERR_BAD_PARAMETER_VALUE, true, PS_ERRORTEXT_psLookupTable_INTERPOLATE_HIGH, hiIdx);
+                return 0.0;
+            }
+        }
+
+        loIdx = hiIdx--;
+        if(loIdx < 0) {
+            psError(PS_ERR_BAD_PARAMETER_VALUE, true, PS_ERRORTEXT_psLookupTable_INTERPOLATE_LOW, loIdx);
+            return 0.0;
+        }
+
+        denom = indexVec->data.F64[hiIdx] - indexVec->data.F64[loIdx];
+        if(fabs(denom) < FLT_EPSILON) {
+            psError(PS_ERR_BAD_PARAMETER_VALUE, true, PS_ERRORTEXT_psLookupTable_DIVIDE_BY_ZERO);
+            return 0.0;
+        } else {
+            out = valuesVec->data.F64[loIdx]+(valuesVec->data.F64[hiIdx]-valuesVec->data.F64[loIdx])
+                  *(index-indexVec->data.F64[loIdx])/denom;
+        }
+    }
+
+    return out;
+}
+
+psVector* psLookupTableInterpolateAll(psLookupTable *table, psF64 index, psVector *stats)
+{
+    psU64 i = 0;
+    psU64 numCols = 0;
+    psVector *outVector = NULL;
+    psLookupStatusType status = PS_LOOKUP_SUCCESS;
+
+
+    // Error checks
+    PS_PTR_CHECK_NULL(table,NULL);
+    PS_PTR_CHECK_NULL(stats,NULL);
+    numCols = table->numCols;
+    PS_INT_CHECK_EQUALS(numCols, 0,NULL);
+
+    outVector = psVectorAlloc(numCols, PS_TYPE_F64);
+
+    // Fill vectors with results and status of results
+    for(i=0; i<numCols; i++) {
+        outVector->data.F64[i] = psLookupTableInterpolate(table, index, i, &status);
+        stats->data.U32[i] = status;
+    }
+
+    return outVector;
+}
+
Index: /trunk/psLib/src/fileUtils/psLookupTable.h
===================================================================
--- /trunk/psLib/src/fileUtils/psLookupTable.h	(revision 2301)
+++ /trunk/psLib/src/fileUtils/psLookupTable.h	(revision 2302)
@@ -7,6 +7,6 @@
 *  @author Ross Harman, MHPCC
 *
-*  @version $Revision: 1.1 $ $Name: not supported by cvs2svn $
-*  @date $Date: 2004-10-26 00:37:15 $
+*  @version $Revision: 1.2 $ $Name: not supported by cvs2svn $
+*  @date $Date: 2004-11-09 00:38:14 $
 *
 *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
@@ -15,4 +15,8 @@
 #ifndef PS_LOOKUPTABLE_H
 #define PS_LOOKUPTABLE_H
+
+#include "psType.h"
+#include "psVector.h"
+#include "psArray.h"
 
 
@@ -24,20 +28,36 @@
 typedef struct
 {
+    const char *fileName;              ///< Name of file with table
+    psU64 numRows;                     ///< Number of table rows
+    psU64 numCols;                     ///< Number of table columns
+    psF64 validFrom;                   ///< Lower bound for rable read
+    psF64 validTo;                     ///< Upper bound for table read
     psVector *index;                   ///< Vector of independent index values
-    psArray *values;                   ///< Array of dependent table values corresponding to index values.
+    psArray *values;                   ///< Array of dependent table values corresponding to index values
 }
 psLookupTable;
 
 
-/** Lookup error conditions
+/** Lookup table lookup status and error conditions
  *
- *  Success and failure conditions for table lookups.
+ *  Success, failure, and status conditions for table lookups.
  */
 typedef enum {
-    PS_LOOKUP_SUCCESS = 0x000,         ///< Table lookup succeeded.
-    PS_LOOKUP_TOP     = 0x0001,        ///< Lookup off top of table.
-    PS_LOOKUP_BOTTOM  = 0x0002,        ///< Lookup off bottom of table.
-    PS_LOOKUP_ERROR   = 0x0003,        ///< Any other type of lookup error.
-} psLookupErrorType;
+    PS_LOOKUP_SUCCESS             = 0x0000,        ///< Table lookup succeeded
+    PS_LOOKUP_PAST_TOP            = 0x0101,        ///< Lookup off top of table
+    PS_LOOKUP_PAST_BOTTOM         = 0x0102,        ///< Lookup off bottom of table
+    PS_LOOKUP_ERROR               = 0x0104         ///< Any other type of lookup error
+} psLookupStatusType;
+
+/** Lookup table parse status and error conditions
+ *
+ *  Success, failure, and status conditions for table parsing.
+ */
+typedef enum {
+    PS_PARSE_SUCCESS              = 0x0000,        ///< Table lookup succeeded
+    PS_PARSE_ERROR_TYPE           = 0x0101,        ///< Error parsing type
+    PS_PARSE_ERROR_VALUE          = 0x0102,        ///< Error parsing numerical value
+    PS_PARSE_ERROR_GENERAL        = 0x0104         ///< Any other type of lookup error
+}psParseErrorType;
 
 /** Allocator for psLookupTable struct
@@ -48,6 +68,7 @@
  */
 psLookupTable* psLookupTableAlloc(
-    psU64 numRows,                  ///< Number of rows
-    psU64 numCols                   ///< number of columns
+    const char *fileName,           ///< Name of file to read
+    psF64 validFrom,                ///< Lower bound for rable read
+    psF64 validTo                   ///< Upper bound for table read
 );
 
@@ -59,5 +80,5 @@
  */
 psLookupTable* psLookupTableRead(
-    char *fileName                  ///< Name of file to read
+    psLookupTable *table            ///< Table to read
 );
 
@@ -67,10 +88,11 @@
  *  conditions.
  *
- *  @return psLookupTable*     New psLookupTable struct.
+ *  @return psLookupTable*     New psLookupTable struct
  */
 psF64 psLookupTableInterpolate(
     psLookupTable *table,           ///< Table with data
     psF64 index,                    ///< Value to be interpolated
-    psMaskType *status              ///< Status of lookup.
+    psU64 column,                   ///< Column in table to be interpolated
+    psLookupStatusType *status      ///< Status of lookup
 );
 
@@ -80,10 +102,10 @@
  *  conditions.
  *
- *  @return psLookupTable*     New psLookupTable struct.
+ *  @return psLookupTable*     New psLookupTable struct
  */
-psVector* psLookupTableInterpolate(
+psVector* psLookupTableInterpolateAll(
     psLookupTable *table,           ///< Table with data
     psF64 index,                    ///< Value to be interpolated
-    psMaskType *status              ///< Status of lookup.
+    psVector *stats                 ///< Vector of status for each lookup
 );
 
Index: /trunk/psLib/src/types/psLookupTable.c
===================================================================
--- /trunk/psLib/src/types/psLookupTable.c	(revision 2301)
+++ /trunk/psLib/src/types/psLookupTable.c	(revision 2302)
@@ -8,28 +8,654 @@
 *  @author Ross Harman, MHPCC
 *
-*  @version $Revision: 1.1 $ $Name: not supported by cvs2svn $
-*  @date $Date: 2004-10-26 00:36:50 $
+*  @version $Revision: 1.2 $ $Name: not supported by cvs2svn $
+*  @date $Date: 2004-11-09 00:38:14 $
 *
 *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
 */
-
-#include "psLookupTable.c"
-
-
-psLookupTable* psLookupTableAlloc(psU64 numRows, psU64 numCols)
-{
-}
-
-psLookupTable* psLookupTableRead(char *fileName)
-{
-}
-
-psF64 psLookupTableInterpolate(psLookupTable *table, psF64 index, psMaskType *status)
-{
-}
-
-psVector* psLookupTableInterpolate(psLookupTable *table, psF64 index, psMaskType *status)
-{
-}
-
-#endif
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <math.h>
+
+#include "psMemory.h"
+#include "psString.h"
+#include "psError.h"
+#include "psLookupTable.h"
+#include "psFileUtilsErrors.h"
+#include "psConstants.h"
+
+/******************************************************************************/
+/*  DEFINE STATEMENTS                                                         */
+/******************************************************************************/
+
+/** Maximum size of a string */
+#define MAX_STRING_LENGTH 256
+
+/******************************************************************************/
+/*  TYPE DEFINITIONS                                                          */
+/******************************************************************************/
+
+// None
+
+/*****************************************************************************/
+/*  GLOBAL VARIABLES                                                         */
+/*****************************************************************************/
+
+// None
+
+/*****************************************************************************/
+/*  FILE STATIC VARIABLES                                                    */
+/*****************************************************************************/
+
+// None
+
+/*****************************************************************************/
+/*  FUNCTION IMPLEMENTATION - LOCAL                                          */
+/*****************************************************************************/
+
+static bool ignoreLine(char *inString);
+static char *cleanString(char *inString, int sLen);
+static char* getToken(char **inString, char *delimiter, psParseErrorType *status);
+static psU8 parseU8(char *inString, psParseErrorType *status);
+static psS8 parseS8(char *inString, psParseErrorType *status);
+static psU16 parseU16(char *inString, psParseErrorType *status);
+static psS16 parseS16(char *inString, psParseErrorType *status);
+static psU32 parseU32(char *inString, psParseErrorType *status);
+static psS32 parseS32(char *inString, psParseErrorType *status);
+static psU64 parseU64(char *inString, psParseErrorType *status);
+static psS64 parseS64(char *inString, psParseErrorType *status);
+static psF32 parseF32(char *inString, psParseErrorType *status);
+static psF64 parseF64(char *inString, psParseErrorType *status);
+static void parseValue(psVector *vec, psU64 index, char* strValue, psParseErrorType *status);
+static void lookupTableFree(psLookupTable* table);
+
+/** Determines if a line is blank (whitespace only) or a commentline. It returns true if so. The input string
+ *  must be null terminated. */
+static bool ignoreLine(char *inString)
+{
+    while(*inString!='\0' && *inString!='#') {
+        if(!isspace(*inString)) {
+            return false;
+        }
+        inString++;
+    }
+
+    return true;
+}
+
+
+/** Removes leading and trailing whitespace and # characters from a string. The cleaned string is a new null
+ *  terminated copy of the original input string. */
+static char *cleanString(char *inString, int sLen)
+{
+    char *ptrB = NULL;
+    char *ptrE = NULL;
+    char *cleaned = NULL;
+
+
+    ptrB = inString;
+
+    /* Skip over leading # or whitespace */
+    while (isspace(*ptrB) || *ptrB=='#') {
+        ptrB++;
+    }
+
+    /* Skip over trailing whitespace, null terminators, and # characters */
+    ptrE = inString + sLen;
+    while(isspace(*ptrE) || *ptrE=='\0' || *ptrE=='#') {
+        ptrE--;
+    }
+
+    // Length, sLen, does not include '\0'
+    sLen = ptrE - ptrB + 1;
+
+    // Adds '\0' to end of string and +1 to sLen
+    cleaned = psStringNCopy(ptrB, sLen);
+
+    return cleaned;
+}
+
+
+/** Returns cleaned token based on delimiter, but not including delimiter. Also changes the pointer location
+ * the beginning of the string. Tokens are newly allocated null terminated strings. */
+static char* getToken(char **inString, char *delimiter, psParseErrorType *status)
+{
+    char *cleanToken = NULL;
+    int sLen = 0;
+
+
+    // Skip over leading whitespace
+    while(isspace(**inString)) {
+        (*inString)++;
+    }
+
+    // Length of token, not including delimiter
+    sLen = strcspn(*inString, delimiter);
+    if(sLen) {
+
+        // Create new, cleaned, and null terminated token
+        cleanToken = cleanString(*inString, sLen);
+
+        // Move to end of token
+        (*inString) += sLen;
+    } else if(**inString!='\0' && sLen==0) {
+        *status = PS_PARSE_ERROR_GENERAL;
+    }
+
+    return cleanToken;
+}
+
+/** Returns single parsed value as a psU8. The input string must be cleaned and null terminated. */
+static psU8 parseU8(char *inString, psParseErrorType *status)
+{
+    char *end = NULL;
+    psU8 value = 0.0;
+
+
+    value = (psU8)strtoul(inString, &end, 0);
+    if(*end != '\0') {
+        *status = PS_PARSE_ERROR_VALUE;
+    } else if(inString==end) {
+        *status = PS_PARSE_ERROR_VALUE;
+    }
+
+    return value;
+}
+
+/** Returns single parsed value as a psS8. The input string must be cleaned and null terminated. */
+static psS8 parseS8(char *inString, psParseErrorType *status)
+{
+    char *end = NULL;
+    psS8 value = 0.0;
+
+
+    value = (psS8)strtol(inString, &end, 0);
+    if(*end != '\0') {
+        *status = PS_PARSE_ERROR_VALUE;
+    } else if(inString==end) {
+        *status = PS_PARSE_ERROR_VALUE;
+    }
+
+    return value;
+}
+
+/** Returns single parsed value as a psU16. The input string must be cleaned and null terminated. */
+static psU16 parseU16(char *inString, psParseErrorType *status)
+{
+    char *end = NULL;
+    psU16 value = 0.0;
+
+
+    value = (psU16)strtoul(inString, &end, 0);
+    if(*end != '\0') {
+        *status = PS_PARSE_ERROR_VALUE;
+    } else if(inString==end) {
+        *status = PS_PARSE_ERROR_VALUE;
+    }
+
+    return value;
+}
+
+/** Returns single parsed value as a psS16. The input string must be cleaned and null terminated. */
+static psS16 parseS16(char *inString, psParseErrorType *status)
+{
+    char *end = NULL;
+    psS16 value = 0.0;
+
+
+    value = (psS16)strtol(inString, &end, 0);
+    if(*end != '\0') {
+        *status = PS_PARSE_ERROR_VALUE;
+    } else if(inString==end) {
+        *status = PS_PARSE_ERROR_VALUE;
+    }
+
+    return value;
+}
+
+/** Returns single parsed value as a psU32. The input string must be cleaned and null terminated. */
+static psU32 parseU32(char *inString, psParseErrorType *status)
+{
+    char *end = NULL;
+    psU32 value = 0.0;
+
+
+    value = (psU32)strtoul(inString, &end, 0);
+    if(*end != '\0') {
+        *status = PS_PARSE_ERROR_VALUE;
+    } else if(inString==end) {
+        *status = PS_PARSE_ERROR_VALUE;
+    }
+
+    return value;
+}
+
+/** Returns single parsed value as a psS32. The input string must be cleaned and null terminated. */
+static psS32 parseS32(char *inString, psParseErrorType *status)
+{
+    char *end = NULL;
+    psS32 value = 0.0;
+
+
+    value = (psS32)strtol(inString, &end, 0);
+    if(*end != '\0') {
+        *status = PS_PARSE_ERROR_VALUE;
+    } else if(inString==end) {
+        *status = PS_PARSE_ERROR_VALUE;
+    }
+
+    return value;
+}
+
+/** Returns single parsed value as a psU64. The input string must be cleaned and null terminated. */
+static psU64 parseU64(char *inString, psParseErrorType *status)
+{
+    char *end = NULL;
+    psU64 value = 0.0;
+
+
+    value = (psU64)strtoull(inString, &end, 0);
+    if(*end != '\0') {
+        *status = PS_PARSE_ERROR_VALUE;
+    } else if(inString==end) {
+        *status = PS_PARSE_ERROR_VALUE;
+    }
+
+    return value;
+}
+
+/** Returns single parsed value as a psS64. The input string must be cleaned and null terminated. */
+static psS64 parseS64(char *inString, psParseErrorType *status)
+{
+    char *end = NULL;
+    psS64 value = 0.0;
+
+
+    value = (psS64)strtoll(inString, &end, 0);
+    if(*end != '\0') {
+        *status = PS_PARSE_ERROR_VALUE;
+    } else if(inString==end) {
+        *status = PS_PARSE_ERROR_VALUE;
+    }
+
+    return value;
+}
+
+/** Returns single parsed value as a psF32. The input string must be cleaned and null terminated. */
+static psF32 parseF32(char *inString, psParseErrorType *status)
+{
+    char *end = NULL;
+    psF32 value = 0.0;
+
+
+    value = (psF32)strtof(inString, &end);
+    if(*end != '\0') {
+        *status = PS_PARSE_ERROR_VALUE;
+    } else if(inString==end) {
+        *status = PS_PARSE_ERROR_VALUE;
+    }
+
+    return value;
+}
+
+/** Returns single parsed value as a psF64. The input string must be cleaned and null terminated. */
+static psF64 parseF64(char *inString, psParseErrorType *status)
+{
+    char *end = NULL;
+    psF64 value = 0.0;
+
+
+    value = (psF64)strtod(inString, &end);
+    if(*end != '\0') {
+        *status = PS_PARSE_ERROR_VALUE;
+    } else if(inString==end) {
+        *status = PS_PARSE_ERROR_VALUE;
+    }
+
+    return value;
+}
+
+/** Returns single parsed value as a double precision number. The input string must be cleaned and null
+ * terminated. */
+static void parseValue(psVector *vec, psU64 index, char* strValue, psParseErrorType *status)
+{
+    psElemType type;
+
+
+    if(vec == NULL) {
+        *status = 1;
+        return;
+    }
+
+    type = vec->type.type;
+
+    switch(type) {
+    case PS_TYPE_U8:
+        vec->data.U8[index] = parseU8(strValue, status);
+        break;
+    case PS_TYPE_S8:
+        vec->data.S8[index] = parseS8(strValue, status);
+        break;
+    case PS_TYPE_U16:
+        vec->data.U16[index] = parseU16(strValue, status);
+        break;
+    case PS_TYPE_S16:
+        vec->data.S16[index] = parseS16(strValue, status);
+        break;
+    case PS_TYPE_U32:
+        vec->data.U32[index] = parseU32(strValue, status);
+        break;
+    case PS_TYPE_S32:
+        vec->data.S32[index] = parseS32(strValue, status);
+        break;
+    case PS_TYPE_U64:
+        vec->data.U64[index] = parseU64(strValue, status);
+        break;
+    case PS_TYPE_S64:
+        vec->data.S64[index] = parseS64(strValue, status);
+        break;
+    case PS_TYPE_F32:
+        vec->data.F32[index] = parseF32(strValue, status);
+        break;
+    case PS_TYPE_F64:
+        vec->data.F64[index] = parseF64(strValue, status);
+        break;
+    default:
+        *status = PS_PARSE_ERROR_TYPE;
+    }
+
+    return;
+}
+
+static psParseErrorType printError(psU64 lineCount, char* badText, psParseErrorType status)
+{
+    switch(status) {
+    case PS_PARSE_ERROR_VALUE:
+        psError(PS_ERR_BAD_PARAMETER_VALUE, true, PS_ERRORTEXT_psLookupTable_PARSE_VALUE, badText, lineCount);
+        break;
+    case PS_PARSE_ERROR_TYPE:
+        psError(PS_ERR_BAD_PARAMETER_VALUE, true, PS_ERRORTEXT_psLookupTable_PARSE_TYPE, badText, lineCount);
+        break;
+    case PS_PARSE_ERROR_GENERAL:
+        psError(PS_ERR_BAD_PARAMETER_VALUE, true, PS_ERRORTEXT_psLookupTable_PARSE_GENERAL, badText, lineCount);
+        break;
+    default:
+        psError(PS_ERR_BAD_PARAMETER_VALUE, true, PS_ERRORTEXT_psLookupTable_INVALID_TYPE, badText, lineCount);
+    }
+
+    return PS_LOOKUP_SUCCESS;
+}
+
+static void lookupTableFree(psLookupTable* table)
+{
+    if (table == NULL) {
+        return;
+    }
+
+    psFree(table->values);
+    psFree(table->index);
+    psFree((char*)table->fileName);
+}
+
+/*****************************************************************************/
+/* FUNCTION IMPLEMENTATION - PUBLIC                                          */
+/*****************************************************************************/
+
+psLookupTable* psLookupTableAlloc(const char *fileName, psF64 validFrom, psF64 validTo)
+{
+    psLookupTable *outTable = NULL;
+
+
+    // Can't read table if you don't know its name
+    PS_PTR_CHECK_NULL(fileName,NULL);
+
+    // Allocate lookup table
+    outTable = (psLookupTable*)psAlloc(sizeof(psLookupTable));
+
+    // Set deallocator
+    p_psMemSetDeallocator(outTable, (psFreeFcn)lookupTableFree);
+
+    // Allocate and set metadata item comment
+    outTable->fileName = psStringCopy(fileName);
+
+    // Number of table rows and columns. Automatically resized by table read.
+    outTable->numRows = 0;
+    outTable->numCols = 0;
+
+    // Valid ranges. Automatically set by table read if both zero.
+    outTable->validFrom = validFrom;
+    outTable->validTo = validTo;
+
+    // Vector of independent index values. Filled by table read.
+    outTable->index = NULL;
+
+    // Array of dependent table values corresponding to index values. Filled by table read.
+    outTable->values = NULL;
+
+    return outTable;
+}
+
+psLookupTable* psLookupTableRead(psLookupTable *table)
+{
+    bool typeLine = true;
+    char *line = NULL;
+    char *strType = NULL;
+    char *strValue = NULL;
+    char *linePtr = NULL;
+    psParseErrorType status = PS_PARSE_SUCCESS;
+    psU64 lineCount = 0;
+    psU64 numRows = 0;
+    psU64 numCols = 0;
+    psU64 failedLines = 0;
+    FILE *fp = NULL;
+    psElemType elemType;
+    psVector *indexVec = NULL;
+    psVector *valuesVec = NULL;
+    psArray *values = NULL;
+
+
+    // Error checks
+    PS_PTR_CHECK_NULL(table,NULL);
+    PS_PTR_CHECK_NULL(table->fileName,NULL);
+    if((fp=fopen(table->fileName, "r")) == NULL) {
+        psError(PS_ERR_BAD_PARAMETER_VALUE, true, PS_ERRORTEXT_psLookupTable_FILE_NOT_FOUND, table->fileName);
+        return NULL;
+    }
+
+    indexVec = table->index;
+    values = table->values;
+
+    // Create reusable line for continuous read
+    line = (char*)psAlloc(MAX_STRING_LENGTH*sizeof(char));
+
+    // Loop through file to get numRows, numCols, and column data types
+    while(fgets(line, MAX_STRING_LENGTH, fp) != NULL) {
+
+        // Initialize variables for new line
+        linePtr = line;
+        lineCount++;
+
+        // If line is not a comment or blank, then extract data
+        if(!ignoreLine(linePtr)) {
+
+            if(typeLine == true) {
+
+                // Determine column types from first line in data file after comments
+                while((strType=getToken(&linePtr, " ", &status)) != NULL) {
+                    numCols++;
+                    typeLine = false;
+                    if(!strncmp(strType, "psU8", 4)) {
+                        elemType = PS_TYPE_U8;
+                    } else if(!strncmp(strType, "psS8", 4)) {
+                        elemType = PS_TYPE_S8;
+                    } else if(!strncmp(strType, "psU16", 5)) {
+                        elemType = PS_TYPE_U16;
+                    } else if(!strncmp(strType, "psS16", 5)) {
+                        elemType = PS_TYPE_S16;
+                    } else if(!strncmp(strType, "psU32", 5)) {
+                        elemType = PS_TYPE_U32;
+                    } else if(!strncmp(strType, "psS32", 5)) {
+                        elemType = PS_TYPE_S32;
+                    } else if(!strncmp(strType, "psU64", 5)) {
+                        elemType = PS_TYPE_U64;
+                    } else if(!strncmp(strType, "psS64", 5)) {
+                        elemType = PS_TYPE_S64;
+                    } else if(!strncmp(strType, "psF32", 5)) {
+                        elemType = PS_TYPE_F32;
+                    } else if(!strncmp(strType, "psF64", 5)) {
+                        elemType = PS_TYPE_F64;
+                    } else {
+                        status = PS_PARSE_ERROR_TYPE;
+                    }
+
+                    // Realloc number of columns as you go
+                    if(numCols == 1) {
+                        indexVec = psVectorAlloc(0, elemType);
+                    } else {
+                        values = psArrayRealloc(values, numCols-1);
+                        values->n = values->nalloc;
+                        values->data[numCols-2] = psVectorAlloc(0, elemType);
+                    }
+
+                    if(status) {
+                        status = printError(lineCount, strValue, status);
+                        failedLines++;
+                    }
+                    psFree(strType);
+                }
+            } else {
+
+                // Parse and add values to all columns
+                numRows++;
+                numCols = 0;
+                while((strValue=getToken(&linePtr, " ", &status)) != NULL) {
+                    numCols++;
+
+                    // Realloc number of rows as you go
+                    if(numCols == 1) {
+                        indexVec = psVectorRecycle(indexVec, numRows, indexVec->type.type);
+                        parseValue(indexVec, numRows-1, strValue, &status);
+                    } else {
+                        valuesVec = values->data[numCols-2];
+                        valuesVec = psVectorRecycle(valuesVec, numRows, valuesVec->type.type);
+                        parseValue(valuesVec, numRows-1, strValue, &status);
+                    }
+
+                    if(status) {
+                        status = printError(lineCount, strValue, status);
+                        failedLines++;
+                    }
+                    psFree(strValue);
+                } // end while
+            } // end else
+        } // if ignoreLine
+    } // end while
+
+    psFree(line);
+
+    // Set table for return
+    table->numRows = numRows;
+    table->numCols = numCols-1;
+    table->index = indexVec;
+    table->values = values;
+
+    fclose(fp);
+
+    return table;
+}
+
+psF64 psLookupTableInterpolate(psLookupTable *table, psF64 index, psU64 column, psLookupStatusType *status)
+{
+    psU64 hiIdx = 0;
+    psU64 loIdx = 0;
+    psU64 numRows = 0;
+    psU64 numCols = 0;
+    psF64 out = 0.0;
+    psF64 denom = 0.0;
+    psVector *indexVec = NULL;
+    psVector *valuesVec = NULL;
+    psArray *values = NULL;
+
+
+    // Error checks
+    PS_PTR_CHECK_NULL(table,0.0);
+    indexVec = table->index;
+    values = table->values;
+    numRows = table->numRows;
+    numCols = table->numCols;
+    PS_PTR_CHECK_NULL(indexVec,0.0);
+    PS_PTR_CHECK_NULL(values,0.0);
+    PS_INT_CHECK_EQUALS(numRows, 0,0.0);
+    PS_INT_CHECK_EQUALS(numCols, 0,0.0);
+    PS_INT_CHECK_RANGE(column, 0, numCols-1, 0.0);
+
+
+    valuesVec = (psVector*)values->data[column];
+    PS_PTR_CHECK_NULL(indexVec,0.0);
+
+    if(index<indexVec->data.F64[0] || index<table->validFrom) {
+
+        // Index value past top of table
+        *status = PS_LOOKUP_PAST_TOP;
+        return valuesVec->data.F64[0];
+    } else if(index>indexVec->data.F64[numRows-1] || index>table->validTo) {
+
+        // Index value past bottom of table
+        *status = PS_LOOKUP_PAST_BOTTOM;
+        return valuesVec->data.F64[numRows-1];
+    } else {
+
+        // Interpolation
+        while(index > indexVec->data.F64[hiIdx]) {
+            hiIdx++;
+            if(hiIdx >= numRows) {
+                psError(PS_ERR_BAD_PARAMETER_VALUE, true, PS_ERRORTEXT_psLookupTable_INTERPOLATE_HIGH, hiIdx);
+                return 0.0;
+            }
+        }
+
+        loIdx = hiIdx--;
+        if(loIdx < 0) {
+            psError(PS_ERR_BAD_PARAMETER_VALUE, true, PS_ERRORTEXT_psLookupTable_INTERPOLATE_LOW, loIdx);
+            return 0.0;
+        }
+
+        denom = indexVec->data.F64[hiIdx] - indexVec->data.F64[loIdx];
+        if(fabs(denom) < FLT_EPSILON) {
+            psError(PS_ERR_BAD_PARAMETER_VALUE, true, PS_ERRORTEXT_psLookupTable_DIVIDE_BY_ZERO);
+            return 0.0;
+        } else {
+            out = valuesVec->data.F64[loIdx]+(valuesVec->data.F64[hiIdx]-valuesVec->data.F64[loIdx])
+                  *(index-indexVec->data.F64[loIdx])/denom;
+        }
+    }
+
+    return out;
+}
+
+psVector* psLookupTableInterpolateAll(psLookupTable *table, psF64 index, psVector *stats)
+{
+    psU64 i = 0;
+    psU64 numCols = 0;
+    psVector *outVector = NULL;
+    psLookupStatusType status = PS_LOOKUP_SUCCESS;
+
+
+    // Error checks
+    PS_PTR_CHECK_NULL(table,NULL);
+    PS_PTR_CHECK_NULL(stats,NULL);
+    numCols = table->numCols;
+    PS_INT_CHECK_EQUALS(numCols, 0,NULL);
+
+    outVector = psVectorAlloc(numCols, PS_TYPE_F64);
+
+    // Fill vectors with results and status of results
+    for(i=0; i<numCols; i++) {
+        outVector->data.F64[i] = psLookupTableInterpolate(table, index, i, &status);
+        stats->data.U32[i] = status;
+    }
+
+    return outVector;
+}
+
Index: /trunk/psLib/src/types/psLookupTable.h
===================================================================
--- /trunk/psLib/src/types/psLookupTable.h	(revision 2301)
+++ /trunk/psLib/src/types/psLookupTable.h	(revision 2302)
@@ -7,6 +7,6 @@
 *  @author Ross Harman, MHPCC
 *
-*  @version $Revision: 1.1 $ $Name: not supported by cvs2svn $
-*  @date $Date: 2004-10-26 00:37:15 $
+*  @version $Revision: 1.2 $ $Name: not supported by cvs2svn $
+*  @date $Date: 2004-11-09 00:38:14 $
 *
 *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
@@ -15,4 +15,8 @@
 #ifndef PS_LOOKUPTABLE_H
 #define PS_LOOKUPTABLE_H
+
+#include "psType.h"
+#include "psVector.h"
+#include "psArray.h"
 
 
@@ -24,20 +28,36 @@
 typedef struct
 {
+    const char *fileName;              ///< Name of file with table
+    psU64 numRows;                     ///< Number of table rows
+    psU64 numCols;                     ///< Number of table columns
+    psF64 validFrom;                   ///< Lower bound for rable read
+    psF64 validTo;                     ///< Upper bound for table read
     psVector *index;                   ///< Vector of independent index values
-    psArray *values;                   ///< Array of dependent table values corresponding to index values.
+    psArray *values;                   ///< Array of dependent table values corresponding to index values
 }
 psLookupTable;
 
 
-/** Lookup error conditions
+/** Lookup table lookup status and error conditions
  *
- *  Success and failure conditions for table lookups.
+ *  Success, failure, and status conditions for table lookups.
  */
 typedef enum {
-    PS_LOOKUP_SUCCESS = 0x000,         ///< Table lookup succeeded.
-    PS_LOOKUP_TOP     = 0x0001,        ///< Lookup off top of table.
-    PS_LOOKUP_BOTTOM  = 0x0002,        ///< Lookup off bottom of table.
-    PS_LOOKUP_ERROR   = 0x0003,        ///< Any other type of lookup error.
-} psLookupErrorType;
+    PS_LOOKUP_SUCCESS             = 0x0000,        ///< Table lookup succeeded
+    PS_LOOKUP_PAST_TOP            = 0x0101,        ///< Lookup off top of table
+    PS_LOOKUP_PAST_BOTTOM         = 0x0102,        ///< Lookup off bottom of table
+    PS_LOOKUP_ERROR               = 0x0104         ///< Any other type of lookup error
+} psLookupStatusType;
+
+/** Lookup table parse status and error conditions
+ *
+ *  Success, failure, and status conditions for table parsing.
+ */
+typedef enum {
+    PS_PARSE_SUCCESS              = 0x0000,        ///< Table lookup succeeded
+    PS_PARSE_ERROR_TYPE           = 0x0101,        ///< Error parsing type
+    PS_PARSE_ERROR_VALUE          = 0x0102,        ///< Error parsing numerical value
+    PS_PARSE_ERROR_GENERAL        = 0x0104         ///< Any other type of lookup error
+}psParseErrorType;
 
 /** Allocator for psLookupTable struct
@@ -48,6 +68,7 @@
  */
 psLookupTable* psLookupTableAlloc(
-    psU64 numRows,                  ///< Number of rows
-    psU64 numCols                   ///< number of columns
+    const char *fileName,           ///< Name of file to read
+    psF64 validFrom,                ///< Lower bound for rable read
+    psF64 validTo                   ///< Upper bound for table read
 );
 
@@ -59,5 +80,5 @@
  */
 psLookupTable* psLookupTableRead(
-    char *fileName                  ///< Name of file to read
+    psLookupTable *table            ///< Table to read
 );
 
@@ -67,10 +88,11 @@
  *  conditions.
  *
- *  @return psLookupTable*     New psLookupTable struct.
+ *  @return psLookupTable*     New psLookupTable struct
  */
 psF64 psLookupTableInterpolate(
     psLookupTable *table,           ///< Table with data
     psF64 index,                    ///< Value to be interpolated
-    psMaskType *status              ///< Status of lookup.
+    psU64 column,                   ///< Column in table to be interpolated
+    psLookupStatusType *status      ///< Status of lookup
 );
 
@@ -80,10 +102,10 @@
  *  conditions.
  *
- *  @return psLookupTable*     New psLookupTable struct.
+ *  @return psLookupTable*     New psLookupTable struct
  */
-psVector* psLookupTableInterpolate(
+psVector* psLookupTableInterpolateAll(
     psLookupTable *table,           ///< Table with data
     psF64 index,                    ///< Value to be interpolated
-    psMaskType *status              ///< Status of lookup.
+    psVector *stats                 ///< Vector of status for each lookup
 );
 
