Index: branches/pap/psLib/src/imageops/psImageConvolve.c
===================================================================
--- branches/pap/psLib/src/imageops/psImageConvolve.c	(revision 27732)
+++ branches/pap/psLib/src/imageops/psImageConvolve.c	(revision 28003)
@@ -37,7 +37,7 @@
 
 
+
 static bool threaded = false;           // Run image convolution threaded?
-
-
+static pthread_mutex_t threadMutex = PTHREAD_MUTEX_INITIALIZER;
 
 
@@ -871,14 +871,13 @@
             psFree(job);
         }
+        if (!psThreadPoolWait(true)) {
+            psError(PS_ERR_UNKNOWN, false, "Error waiting for threads.");
+            psFree(gaussNorm);
+            psFree(out);
+            return NULL;
+        }
     } else if (!imageSmoothMaskPixels(out, image, mask, maskVal, x, y,
                                       gaussNorm, minGauss, size, 0, num)) {
         psError(PS_ERR_UNKNOWN, false, "Unable to smooth pixels.");
-        psFree(gaussNorm);
-        psFree(out);
-        return NULL;
-    }
-
-    if (threaded && !psThreadPoolWait(true)) {
-        psError(PS_ERR_UNKNOWN, false, "Error waiting for threads.");
         psFree(gaussNorm);
         psFree(out);
@@ -1192,35 +1191,48 @@
           psImage *calcMask = psImageAlloc(numRows, numCols, PS_TYPE_IMAGE_MASK); /* Mask for calculation image; BW */
 
-          /** Smooth in X direction **/
-          for (int rowStart = 0; rowStart < numRows; rowStart+=scanRows) {
-              int rowStop = PS_MIN (rowStart + scanRows, numRows);
-
-              // allocate a job, construct the arguments for this job
-              psThreadJob *job = psThreadJobAlloc("PSLIB_IMAGE_SMOOTHMASK_SCANROWS");
-              psArrayAdd(job->args, 1, calculation);
-              psArrayAdd(job->args, 1, calcMask);
-              psArrayAdd(job->args, 1, (psImage *) image); // cast away const
-              psArrayAdd(job->args, 1, (psImage *) mask); // cast away const
-              PS_ARRAY_ADD_SCALAR(job->args, maskVal,  PS_TYPE_IMAGE_MASK);
-              psArrayAdd(job->args, 1, gaussNorm);
-              PS_ARRAY_ADD_SCALAR(job->args, minGauss, PS_TYPE_F32);
-              PS_ARRAY_ADD_SCALAR(job->args, size,     PS_TYPE_S32);
-              PS_ARRAY_ADD_SCALAR(job->args, rowStart, PS_TYPE_S32);
-              PS_ARRAY_ADD_SCALAR(job->args, rowStop,  PS_TYPE_S32);
-              // -> psImageSmoothMask_ScanRows_F32 (calculation, calcMask, image, mask, maskVal, gauss, minGauss, size, rowStart, rowStop);
-
-              // if threading is not active, we simply run the job and return
-              if (!psThreadJobAddPending(job)) {
+          if (threaded) {
+              /** Smooth in X direction **/
+              for (int rowStart = 0; rowStart < numRows; rowStart+=scanRows) {
+                  int rowStop = PS_MIN (rowStart + scanRows, numRows);
+
+                  // allocate a job, construct the arguments for this job
+                  psThreadJob *job = psThreadJobAlloc("PSLIB_IMAGE_SMOOTHMASK_SCANROWS");
+                  psArrayAdd(job->args, 1, calculation);
+                  psArrayAdd(job->args, 1, calcMask);
+                  psArrayAdd(job->args, 1, (psImage *) image); // cast away const
+                  psArrayAdd(job->args, 1, (psImage *) mask); // cast away const
+                  PS_ARRAY_ADD_SCALAR(job->args, maskVal,  PS_TYPE_IMAGE_MASK);
+                  psArrayAdd(job->args, 1, gaussNorm);
+                  PS_ARRAY_ADD_SCALAR(job->args, minGauss, PS_TYPE_F32);
+                  PS_ARRAY_ADD_SCALAR(job->args, size,     PS_TYPE_S32);
+                  PS_ARRAY_ADD_SCALAR(job->args, rowStart, PS_TYPE_S32);
+                  PS_ARRAY_ADD_SCALAR(job->args, rowStop,  PS_TYPE_S32);
+                  // -> psImageSmoothMask_ScanRows_F32 (calculation, calcMask, image, mask, maskVal, gauss, minGauss, size, rowStart, rowStop);
+
+                  // if threading is not active, we simply run the job and return
+                  if (!psThreadJobAddPending(job)) {
+                      psError(PS_ERR_UNKNOWN, false, "Unable to smooth image");
+                      psFree(job);
+                      psFree(calculation);
+                      psFree(calcMask);
+                      psFree(gaussNorm);
+                      return false;
+                  }
+                  psFree(job);
+              }
+              // wait here for the threaded jobs to finish (NOP if threading is not active)
+              if (!psThreadPoolWait(true)) {
                   psError(PS_ERR_UNKNOWN, false, "Unable to smooth image");
-                  psFree(job);
+                  psFree(calculation);
+                  psFree(calcMask);
+                  psFree(gaussNorm);
                   return false;
               }
-              psFree(job);
-
-          }
-
-          // wait here for the threaded jobs to finish (NOP if threading is not active)
-          if (!psThreadPoolWait(true)) {
+          } else if (!psImageSmoothMask_ScanRows_F32(calculation, calcMask, image, mask, maskVal,
+                                                     gaussNorm, minGauss, size, 0, numRows)) {
               psError(PS_ERR_UNKNOWN, false, "Unable to smooth image");
+              psFree(calculation);
+              psFree(calcMask);
+              psFree(gaussNorm);
               return false;
           }
@@ -1229,34 +1241,50 @@
 
           /** Smooth in Y direction  **/
-          for (int colStart = 0; colStart < numCols; colStart+=scanCols) {
-              int colStop = PS_MIN (colStart + scanCols, numCols);
-
-              // allocate a job, construct the arguments for this job
-              psThreadJob *job = psThreadJobAlloc("PSLIB_IMAGE_SMOOTHMASK_SCANCOLS");
-              psArrayAdd(job->args, 1, output);
-              psArrayAdd(job->args, 1, calculation);
-              psArrayAdd(job->args, 1, calcMask);
-              PS_ARRAY_ADD_SCALAR(job->args, maskVal,  PS_TYPE_IMAGE_MASK);
-              psArrayAdd(job->args, 1, gaussNorm);
-              PS_ARRAY_ADD_SCALAR(job->args, minGauss, PS_TYPE_F32);
-              PS_ARRAY_ADD_SCALAR(job->args, size,     PS_TYPE_S32);
-              PS_ARRAY_ADD_SCALAR(job->args, colStart, PS_TYPE_S32);
-              PS_ARRAY_ADD_SCALAR(job->args, colStop,  PS_TYPE_S32);
-              // -> psImageSmoothMask_ScanCols_F32 (output, calculation, calcMask, maskVal, gauss, minGauss, size, colStart, colStop);
-
-              // if threading is not active, we simply run the job and return
-              if (!psThreadJobAddPending(job)) {
+          if (threaded) {
+              for (int colStart = 0; colStart < numCols; colStart+=scanCols) {
+                  int colStop = PS_MIN (colStart + scanCols, numCols);
+
+                  // allocate a job, construct the arguments for this job
+                  psThreadJob *job = psThreadJobAlloc("PSLIB_IMAGE_SMOOTHMASK_SCANCOLS");
+                  psArrayAdd(job->args, 1, output);
+                  psArrayAdd(job->args, 1, calculation);
+                  psArrayAdd(job->args, 1, calcMask);
+                  PS_ARRAY_ADD_SCALAR(job->args, maskVal,  PS_TYPE_IMAGE_MASK);
+                  psArrayAdd(job->args, 1, gaussNorm);
+                  PS_ARRAY_ADD_SCALAR(job->args, minGauss, PS_TYPE_F32);
+                  PS_ARRAY_ADD_SCALAR(job->args, size,     PS_TYPE_S32);
+                  PS_ARRAY_ADD_SCALAR(job->args, colStart, PS_TYPE_S32);
+                  PS_ARRAY_ADD_SCALAR(job->args, colStop,  PS_TYPE_S32);
+                  // -> psImageSmoothMask_ScanCols_F32 (output, calculation, calcMask, maskVal, gauss, minGauss, size, colStart, colStop);
+
+                  // if threading is not active, we simply run the job and return
+                  if (!psThreadJobAddPending(job)) {
+                      psError(PS_ERR_UNKNOWN, false, "Unable to smooth image");
+                      psFree(job);
+                      psFree(calculation);
+                      psFree(calcMask);
+                      psFree(gaussNorm);
+                      return false;
+                  }
+                  psFree(job);
+              }
+
+              // wait here for the threaded jobs to finish (NOP if threading is not active)
+              if (!psThreadPoolWait(true)) {
                   psError(PS_ERR_UNKNOWN, false, "Unable to smooth image");
-                  psFree(job);
+                  psFree(calculation);
+                  psFree(calcMask);
+                  psFree(gaussNorm);
                   return false;
               }
-              psFree(job);
-          }
-
-          // wait here for the threaded jobs to finish (NOP if threading is not active)
-          if (!psThreadPoolWait(true)) {
+          } else if (!psImageSmoothMask_ScanCols_F32(output, calculation, calcMask, maskVal,
+                                                     gaussNorm, minGauss, size, 0, numCols)) {
               psError(PS_ERR_UNKNOWN, false, "Unable to smooth image");
+              psFree(calculation);
+              psFree(calcMask);
+              psFree(gaussNorm);
               return false;
           }
+
           psFree(calculation);
           psFree(calcMask);
@@ -1559,13 +1587,12 @@
             psFree(job);
         }
+        if (!psThreadPoolWait(true)) {
+            psError(PS_ERR_UNKNOWN, false, "Error waiting for threads.");
+            psFree(conv);
+            psFree(out);
+            return NULL;
+        }
     } else if (!imageConvolveMaskColumns(conv, mask, 0, numRows, maskVal, xMin, xMax)) {
         psError(PS_ERR_UNKNOWN, false, "Unable to convolve mask columns.");
-        psFree(conv);
-        psFree(out);
-        return NULL;
-    }
-
-    if (threaded && !psThreadPoolWait(true)) {
-        psError(PS_ERR_UNKNOWN, false, "Error waiting for threads.");
         psFree(conv);
         psFree(out);
@@ -1597,13 +1624,12 @@
             psFree(job);
         }
+        if (!psThreadPoolWait(true)) {
+            psError(PS_ERR_UNKNOWN, false, "Error waiting for threads.");
+            psFree(conv);
+            psFree(out);
+            return NULL;
+        }
     } else if (!imageConvolveMaskRows(out, conv, 0, numCols, setVal, yMin, yMax)) {
         psError(PS_ERR_UNKNOWN, false, "Unable to convolve mask columns.");
-        psFree(conv);
-        psFree(out);
-        return NULL;
-    }
-
-    if (threaded && !psThreadPoolWait(true)) {
-        psError(PS_ERR_UNKNOWN, false, "Error waiting for threads.");
         psFree(conv);
         psFree(out);
@@ -1679,4 +1705,5 @@
 bool psImageConvolveSetThreads(bool set)
 {
+    pthread_mutex_lock(&threadMutex);
     bool old = threaded;                // Old value
     if (set && !threaded) {
@@ -1711,4 +1738,5 @@
     }
     threaded = set;
+    pthread_mutex_unlock(&threadMutex);
     return old;
 }
Index: branches/pap/psLib/src/mathtypes/psImage.h
===================================================================
--- branches/pap/psLib/src/mathtypes/psImage.h	(revision 27732)
+++ branches/pap/psLib/src/mathtypes/psImage.h	(revision 28003)
@@ -66,4 +66,5 @@
 #define P_PSIMAGE_SET_ROW0(img,r0) {*(int*)&img->row0 = r0;}
 #define P_PSIMAGE_SET_TYPE(img,t) {*(psMathType*)&img->type = t;}
+#define P_PSIMAGE_GET_TYPE(img) ((img)->type->type)
 
 /** Create an image of the specified size and type.
Index: branches/pap/psLib/src/types/psLookupTable.c
===================================================================
--- branches/pap/psLib/src/types/psLookupTable.c	(revision 27732)
+++ branches/pap/psLib/src/types/psLookupTable.c	(revision 28003)
@@ -31,4 +31,6 @@
 #include "psString.h"
 #include "psError.h"
+#include "psString.h"
+#include "psSlurp.h"
 #include "psLookupTable.h"
 
@@ -153,5 +155,7 @@
         char *end = NULL; \
         ps##TYPE value = FUNC(strValue, &end, 0); \
-        if (*end != '\0' && !isspace(*end)) { \
+        if (*end != '\0' && *end != '\n' && !isspace(*end)) { \
+            psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Characters left over after parsing %s: %s", \
+                strValue, end); \
             *status = PS_PARSE_ERROR_VALUE; \
         } \
@@ -164,5 +168,7 @@
         char *end = NULL; \
         ps##TYPE value = FUNC(strValue, &end); \
-        if (*end != '\0' && !isspace(*end)) { \
+        if (*end != '\0' && *end != '\n' && !isspace(*end)) { \
+            psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Characters left over after parsing %s: %s", \
+                strValue, end); \
             *status = PS_PARSE_ERROR_VALUE; \
         } \
@@ -244,175 +250,132 @@
 }
 
-psArray *psVectorsReadFromFile(const char *filename,
-                               const char *format)
+psArray *psVectorsReadFromFile(const char *filename, const char *format)
 {
     PS_ASSERT_STRING_NON_EMPTY(filename, NULL);
     PS_ASSERT_STRING_NON_EMPTY(format, NULL);
 
-    psArray*          outputArray = NULL;
-    psVector*         colVector   = NULL;
-    char*             strValue    = NULL;
-    char*             strNum      = NULL;
-    char*             line        = NULL;
-    char*             linePtr     = NULL;
-    int               numCols     = 0;
-    int               numRows     = 0;
-    FILE*             fp          = NULL;
-    const char*       tempFormat  = NULL;
-    psParseErrorType  parseStatus = PS_PARSE_SUCCESS;
-
-    // Create temp pointer which can then be used several times
-    tempFormat = format;
-
-    // Create output array and set array elements to zero
-    outputArray = psArrayAllocEmpty(INITIAL_NUM);
-
-    // Parse the format string to determine how many vectors
-    // and whether the format string is valid
-    while ((strValue = getToken((char**)&tempFormat, " \t", &parseStatus))) {
-
-        // Check for %d format sub string
+    psArray *outputArray = psArrayAllocEmpty(INITIAL_NUM); // Array of vectors to return
+    psParseErrorType parseStatus = PS_PARSE_SUCCESS; // Status of parsing
+
+    // Parse the format string to determine how many vectors and whether the format string is valid
+    const char *tempFormat = format;    // Pointer into format
+    psString strValue;                  // Format of interest
+    int numCols = 0;                    // Number of columns found in format
+    while ((strValue = getToken((char**)&tempFormat, " \t", &parseStatus)) &&
+           parseStatus == PS_PARSE_SUCCESS) {
+        if (strstr(strValue,"\%*") != 0) {
+            // Don't increase number of columns
+            continue;
+        }
+        psElemType type;                // Type specified
         if (strcmp(strValue,"\%d") == 0 ) {
-            numCols++;
-            colVector = psVectorAlloc(1,PS_TYPE_S32);
-            outputArray = psArrayAdd(outputArray, ARRAY_STRIDE, colVector);
-            psFree(colVector);
+            type = PS_TYPE_S32;
         } else if (strcmp(strValue,"\%ld") == 0) {
-            numCols++;
-            colVector = psVectorAlloc(1,PS_TYPE_S64);
-            outputArray = psArrayAdd(outputArray, ARRAY_STRIDE, colVector);
-            psFree(colVector);
+            type = PS_TYPE_S64;
         } else if (strcmp(strValue,"\%f") == 0) {
-            numCols++;
-            colVector = psVectorAlloc(1,PS_TYPE_F32);
-            outputArray = psArrayAdd(outputArray, ARRAY_STRIDE, colVector);
-            psFree(colVector);
+            type = PS_TYPE_F32;
         } else if (strcmp(strValue,"\%lf") == 0) {
-            numCols++;
-            colVector = psVectorAlloc(1,PS_TYPE_F64);
-            outputArray = psArrayAdd(outputArray, ARRAY_STRIDE, colVector);
-            psFree(colVector);
-        } else if (strstr(strValue,"\%*") != 0) {
-            // Don't increase number of columns
+            type = PS_TYPE_F64;
         } else {
-            psError(PS_ERR_BAD_PARAMETER_VALUE, true,
-                    "Invalid format specifier");
+            psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Invalid format specifier: %s", strValue);
             psFree(strValue);
-            numCols = 0;
-            break;
-        }
+            psFree(outputArray);
+            return NULL;
+        }
+        psVector *colVector = psVectorAllocEmpty(1, type); // Vector for type
+        outputArray = psArrayAdd(outputArray, ARRAY_STRIDE, colVector);
+        psFree(colVector);
+        numCols++;
         psFree(strValue);
+    }
+    if (parseStatus != PS_PARSE_SUCCESS) {
+        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Failed to parse format at column %d: %s",
+                numCols, strValue);
+        psFree(strValue);
+        psFree(outputArray);
+        return NULL;
+    }
+
+    if (numCols == 0) {
+        // Format string parse error detected
+        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Format string was not parsed sucessfully");
+        psFree(outputArray);
+        return NULL;
     }
 
     // If the format string was parsed successfully and return numCols the
     // prepare to open file and read values
-    if (numCols > 0) {
-
-        // Open specified file
-        if ((fp=fopen(filename, "r")) == NULL) {
-            psError(PS_ERR_BAD_PARAMETER_VALUE, true, _("Failed to open file %s."),
-                    filename);
-            psFree(outputArray);
-            return NULL;
-        } else {
-            // Initialize array index
-            int arrayIndex = 0;
-
-            // 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) &&
-                    (parseStatus == PS_PARSE_SUCCESS))   {
-
-                // Copy pointer to line for parsing
-                linePtr = line;
-
-                // If line is not a comment or blank, then extract data
-                if (!ignoreLine(linePtr)) {
-                    numRows++;
-
-                    // Copy format pointer for parsing
-                    tempFormat = format;
-                    arrayIndex = 0;
-                    parseStatus = PS_PARSE_SUCCESS;
-
-                    // Loop through format and line strings to get values in text table file
-                    while ((strValue=getToken((char**)&tempFormat," \t",&parseStatus))
-                            && (strNum=getToken((char**)&linePtr," \t",&parseStatus)) ) {
-                        // Set column vector
-                        colVector = outputArray->data[arrayIndex];
-
-                        // Set column entries based on format string defining the type
-                        if (strcmp(strValue,"\%d") == 0 ) {
-                            colVector = psVectorRecycle(colVector, numRows,
-                                                        colVector->type.type);
-                            parseValue(colVector,numRows-1,strNum,&parseStatus);
-                            arrayIndex++;
-                        } else if (strcmp(strValue,"\%ld") == 0) {
-                            colVector = psVectorRecycle(colVector, numRows,
-                                                        colVector->type.type);
-                            parseValue(colVector,numRows-1,strNum,&parseStatus);
-                            arrayIndex++;
-                        } else if (strcmp(strValue,"\%f") == 0) {
-                            colVector = psVectorRecycle(colVector, numRows,
-                                                        colVector->type.type);
-                            parseValue(colVector,numRows-1,strNum,&parseStatus);
-                            arrayIndex++;
-                        } else if (strcmp(strValue,"\%lf") == 0) {
-                            colVector = psVectorRecycle(colVector, numRows,
-                                                        colVector->type.type);
-                            parseValue(colVector,numRows-1,strNum,&parseStatus);
-                            arrayIndex++;
-                        } else if (strstr(strValue,"\%*") != 0) {
-                            // Don't increase number of columns
-                        }
-                        psFree(strValue);
-                        psFree(strNum);
-
-                        // If the file line was not parsed successful report
-                        // error and return NULL
-                        if (parseStatus != PS_PARSE_SUCCESS) {
-                            psError(PS_ERR_UNKNOWN, true,
-                                    "Parsing text file failed.");
-                            fclose(fp);
-                            psFree(outputArray);
-                            psFree(line);
-                            return NULL;
-                        }
-                    }
-                    if (strValue != NULL && strNum == NULL) {
-                        psError(PS_ERR_UNKNOWN, true,
-                                "Parsing text file failed - missing table value(s).");
-                        fclose(fp);
-                        psFree(outputArray);
-                        psFree(line);
-                        psFree(strValue);
-                        return NULL;
-                    }
-                }  // ignore line
+
+    psString file = psSlurpFilename(filename); // Contents of file
+    if (!file) {
+        psError(psErrorCodeLast(), false, "Unable to read file of vectors");
+        psFree(outputArray);
+        return NULL;
+    }
+
+    psArray *lines = psStringSplitArray(file, "\n", false); // Lines of file
+    psFree(file);
+    long numRows = 0;                                  // Number of rows
+    for (long i = 0; i < lines->n; i++) {
+        psString line = lines->data[i]; // Line of interest
+        if (ignoreLine(line)) {
+            continue;
+        }
+        numRows++;
+
+        char *linePtr = line;           // Pointer into line
+
+        // Copy format pointer for parsing
+        const char *tempFormat = format; // Pointer into format
+        long arrayIndex = 0;            // Index in array
+        parseStatus = PS_PARSE_SUCCESS;
+
+        // Loop through format and line strings to get values in text table file
+        char *strNum;                   // Number within line
+        while ((strValue=getToken((char**)&tempFormat," \t",&parseStatus)) &&
+               (strNum=getToken((char**)&linePtr," \t",&parseStatus)) &&
+               parseStatus == PS_PARSE_SUCCESS) {
+            if (strstr(strValue,"\%*") != 0) {
+                continue;
             }
 
-            //Return NULL for an empty table
-            if (numRows == 0) {
-                psError(PS_ERR_UNKNOWN, true,
-                        "Parsing text file failed - input table is empty.");
-                fclose(fp);
+            // Set column vector
+            psVector *colVector = outputArray->data[arrayIndex]; // Column vector of interest
+
+            outputArray->data[arrayIndex] = colVector = psVectorRecycle(colVector, numRows,
+                                                                        colVector->type.type);
+            parseValue(colVector, numRows - 1, strNum, &parseStatus);
+            arrayIndex++;
+
+            if (parseStatus != PS_PARSE_SUCCESS) {
+                psError(PS_ERR_UNKNOWN, false, "Parsing text file failed: %s as %s", strNum, strValue);
                 psFree(outputArray);
-                psFree(line);
+                psFree(lines);
+                psFree(strNum);
+                psFree(strValue);
                 return NULL;
             }
-
-            // Read on the lines in the file - close file pointer
-            fclose(fp);
-            psFree(line);
-        }
-    } else {
-        // Format string parse error detected
-        psError(PS_ERR_UNKNOWN, true,
-                "Format string was not parsed sucessfully");
+            psFree(strValue);
+            psFree(strNum);
+
+        }
+        if (strValue != NULL && strNum == NULL) {
+            psError(PS_ERR_UNKNOWN, true,
+                    "Parsing text file failed - missing table value(s).");
+            psFree(outputArray);
+            psFree(lines);
+            psFree(strValue);
+            return NULL;
+        }
+    }
+    if (parseStatus != PS_PARSE_SUCCESS) {
+        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Failed to parse format at column %d: %s",
+                numCols, strValue);
+        psFree(strValue);
         psFree(outputArray);
         return NULL;
     }
+
+    psFree(lines);
 
     // Return populated array
