Index: trunk/psLib/src/types/psMetadataConfig.c
===================================================================
--- trunk/psLib/src/types/psMetadataConfig.c	(revision 12440)
+++ trunk/psLib/src/types/psMetadataConfig.c	(revision 12441)
@@ -10,6 +10,6 @@
 *  @author Eric Van Alst, MHPCC
 *
-*  @version $Revision: 1.130 $ $Name: not supported by cvs2svn $
-*  @date $Date: 2007-03-14 02:37:34 $
+*  @version $Revision: 1.131 $ $Name: not supported by cvs2svn $
+*  @date $Date: 2007-03-15 02:19:09 $
 *
 *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
@@ -67,8 +67,10 @@
 static psMetadata* setMetadataItem(psMetadata* template, char* linePtr)
 ;
-static bool parseLine(psArray* levelArray, char*  linePtr,
-                      psS32 lineCount, bool overwrite);
+static bool parseLine(psArray* levelArray,
+                      char* linePtr,
+                      bool overwrite,
+                      bool *notBlank);
 static bool parseMetadataItem(char* keyName, psArray* levelArray,
-                              char* linePtr, psS32 lineCount, psMetadataFlags flags);
+                              char* linePtr, psMetadataFlags flags);
 static psString formatMetadataItem(psMetadataItem *item);
 static psArray *p_psMetadataKeyArray(psMetadata *md);
@@ -76,15 +78,12 @@
                          psArray* levelArray,
                          char* linePtr,
-                         psS32 lineCount,
                          psMetadataFlags flags);
 static bool parseType(char* keyName,
                       psArray* levelArray,
                       char* linePtr,
-                      psS32 lineCount,
                       psMetadataFlags flags);
 static bool parseMetadataEnd(char* keyName,
                              psArray* levelArray,
                              char* linePtr,
-                             psS32 lineCount,
                              psMetadataFlags flags);
 
@@ -672,5 +671,4 @@
                        psArray* levelArray,
                        char* linePtr,
-                       psS32 lineCount,
                        psMetadataFlags flags)
 {
@@ -679,5 +677,4 @@
     psDataType           mdType        = PS_DATA_UNKNOWN;
     psElemType           vectorType    = PS_TYPE_S8;
-    char*                strType       = NULL;
     char*                strValue      = NULL;
     char*                strComment    = NULL;
@@ -699,125 +696,121 @@
     psTimeType timeType = PS_TIME_TAI;
 
+    long level = psArrayLength(levelArray) - 1;
+
     // Get the metadata item type
-    strType = getToken(&linePtr, " ", &status,true);
-
-    long level = psArrayLength(levelArray) - 1;
+    char *strType = getToken(&linePtr, " ", &status,true);
 
     // Check for no type
-    if(strType==NULL) {
-        psError(PS_ERR_IO, true,
-                _("Failed to read a metadata %s on line %u."), "type",lineCount);
-        returnValue = false;
+    if (strType == NULL) {
+        psError(PS_ERR_IO, true, _("Failed to read a metadata type."));
+        return false;
+    }
+
+    // Set metadata type based on type token
+    // Check if the keyName specifies a vector and if so use strType token to
+    // find vector type
+    if (*keyName == '@') {
+        mdType = PS_DATA_VECTOR;
+        // Get the type of vector
+        if(!strncmp(strType, "U8", 2)) {
+            vectorType = PS_TYPE_U8;
+        } else if (!strncmp(strType,"U16",3)) {
+            vectorType = PS_TYPE_U16;
+        } else if (!strncmp(strType,"U32",3)) {
+            vectorType = PS_TYPE_U32;
+        } else if (!strncmp(strType,"U64",3)) {
+            vectorType = PS_TYPE_U64;
+        } else if (!strncmp(strType,"S8",2)) {
+            vectorType = PS_TYPE_S8;
+        } else if (!strncmp(strType,"S16",3)) {
+            vectorType = PS_TYPE_S16;
+        } else if (!strncmp(strType,"S32",3)) {
+            vectorType = PS_TYPE_S32;
+        } else if (!strncmp(strType,"S64",3)) {
+            vectorType = PS_TYPE_S64;
+        } else if (!strncmp(strType,"F32",3)) {
+            vectorType = PS_TYPE_F32;
+        } else if (!strncmp(strType,"F64",3)) {
+            vectorType = PS_TYPE_F64;
+        } else {
+            psError(PS_ERR_IO, true,
+                    _("Failed to parse the value '%s' of metadata item %s, type %s, "),
+                      "", keyName,  strType);
+            psFree(strType);
+            return false;
+        }
+    } else if(!strncmp(strType, "STR", 3)) {
+        mdType = PS_DATA_STRING;
+    } else if(!strncmp(strType, "BOOL", 4)) {
+        mdType = PS_DATA_BOOL;
+    } else if(!strncmp(strType, "S8", 2)) {
+        mdType = PS_DATA_S8;
+    } else if(!strncmp(strType, "S16", 3)) {
+        mdType = PS_DATA_S16;
+    } else if(!strncmp(strType, "S32", 3)) {
+        mdType = PS_DATA_S32;
+    } else if(!strncmp(strType, "S64", 3)) {
+        mdType = PS_DATA_S64;
+    } else if(!strncmp(strType, "U8", 2)) {
+        mdType = PS_DATA_U8;
+    } else if(!strncmp(strType, "U16", 3)) {
+        mdType = PS_DATA_U16;
+    } else if(!strncmp(strType, "U32", 3)) {
+        mdType = PS_DATA_U32;
+    } else if(!strncmp(strType, "U64", 3)) {
+        mdType = PS_DATA_U64;
+    } else if(!strncmp(strType, "F32", 3)) {
+        mdType = PS_DATA_F32;
+    } else if(!strncmp(strType, "F64", 3)) {
+        mdType = PS_DATA_F64;
+    } else if(!strncmp(strType, "MULTI", 5)) {
+        mdType = PS_DATA_METADATA_MULTI;
+    } else if(!strncmp(strType, "METADATA", 8)) {
+        mdType = PS_DATA_METADATA;
+    } else if( !strncmp(strType, "UTC", 3) || !strncmp(strType, "TAI", 3)
+               || !strncmp(strType, "UT1", 3) || !strncmp(strType, "TT", 3)) {
+        mdType = PS_DATA_TIME;
     } else {
-
-        // Set metadata type based on type token
-
-        // Check if the keyName specifies a vector and if so use strType token to find vector type
-        if(*keyName == '@') {
-            mdType = PS_DATA_VECTOR;
-            // Get the type of vector
-            if(!strncmp(strType, "U8", 2)) {
-                vectorType = PS_TYPE_U8;
-            } else if (!strncmp(strType,"U16",3)) {
-                vectorType = PS_TYPE_U16;
-            } else if (!strncmp(strType,"U32",3)) {
-                vectorType = PS_TYPE_U32;
-            } else if (!strncmp(strType,"U64",3)) {
-                vectorType = PS_TYPE_U64;
-            } else if (!strncmp(strType,"S8",2)) {
-                vectorType = PS_TYPE_S8;
-            } else if (!strncmp(strType,"S16",3)) {
-                vectorType = PS_TYPE_S16;
-            } else if (!strncmp(strType,"S32",3)) {
-                vectorType = PS_TYPE_S32;
-            } else if (!strncmp(strType,"S64",3)) {
-                vectorType = PS_TYPE_S64;
-            } else if (!strncmp(strType,"F32",3)) {
-                vectorType = PS_TYPE_F32;
-            } else if (!strncmp(strType,"F64",3)) {
-                vectorType = PS_TYPE_F64;
-            } else {
-                psError(PS_ERR_IO, true,
-                        _("Failed to parse the value '%s' of metadata item %s, type %s, "
-                          "on line %u."), "", keyName,  strType, lineCount);
-                psFree(strType);
-                return false;
-            }
-        } else if(!strncmp(strType, "STR", 3)) {
-            mdType = PS_DATA_STRING;
-        } else if(!strncmp(strType, "BOOL", 4)) {
-            mdType = PS_DATA_BOOL;
-        } else if(!strncmp(strType, "S8", 2)) {
-            mdType = PS_DATA_S8;
-        } else if(!strncmp(strType, "S16", 3)) {
-            mdType = PS_DATA_S16;
-        } else if(!strncmp(strType, "S32", 3)) {
-            mdType = PS_DATA_S32;
-        } else if(!strncmp(strType, "S64", 3)) {
-            mdType = PS_DATA_S64;
-        } else if(!strncmp(strType, "U8", 2)) {
-            mdType = PS_DATA_U8;
-        } else if(!strncmp(strType, "U16", 3)) {
-            mdType = PS_DATA_U16;
-        } else if(!strncmp(strType, "U32", 3)) {
-            mdType = PS_DATA_U32;
-        } else if(!strncmp(strType, "U64", 3)) {
-            mdType = PS_DATA_U64;
-        } else if(!strncmp(strType, "F32", 3)) {
-            mdType = PS_DATA_F32;
-        } else if(!strncmp(strType, "F64", 3)) {
-            mdType = PS_DATA_F64;
-        } else if(!strncmp(strType, "MULTI", 5)) {
-            mdType = PS_DATA_METADATA_MULTI;
-        } else if(!strncmp(strType, "METADATA", 8)) {
-            mdType = PS_DATA_METADATA;
-        } else if( !strncmp(strType, "UTC", 3) || !strncmp(strType, "TAI", 3)
-                   || !strncmp(strType, "UT1", 3) || !strncmp(strType, "TT", 3)) {
-            mdType = PS_DATA_TIME;
-        } else {
-            // Search through user types
-            typeArray = ((p_psParseLevelInfo*)(levelArray->data[level]))->typeArray;
-            templateArray = ((p_psParseLevelInfo*)(levelArray->data[level]))->templateArray;
-            for(psS32 k = 0; k < typeArray->n; k++) {
-                if(strcmp(strType,(char*)typeArray->data[k]) == 0) {
-                    tempMeta = setMetadataItem((psMetadata*)templateArray->data[k],linePtr);
-                    if(tempMeta != NULL) {
-                        // Add metadata item
-                        md = ((p_psParseLevelInfo*)(levelArray->data[level]))->metadata;
-                        addStatus = psMetadataAdd(md,PS_LIST_TAIL,keyName,
-                                                  PS_DATA_METADATA | flags,"",tempMeta);
-                        // Check for add failure
-                        if (! addStatus) {
-                            psError(PS_ERR_IO, true,
-                                    _("Duplicate Metadata item, %s, found on line %u.  "
-                                      "Overwrite not allowed."),
-                                    keyName, lineCount);
-                            psFree(strType);
-                            psFree(tempMeta);
-                            return false;
-                        }
+        // Search through user types
+        typeArray = ((p_psParseLevelInfo*)(levelArray->data[level]))->typeArray;
+        templateArray = ((p_psParseLevelInfo*)(levelArray->data[level]))->templateArray;
+        for(psS32 k = 0; k < typeArray->n; k++) {
+            if(strcmp(strType,(char*)typeArray->data[k]) == 0) {
+                tempMeta = setMetadataItem((psMetadata*)templateArray->data[k],linePtr);
+                if(tempMeta != NULL) {
+                    // Add metadata item
+                    md = ((p_psParseLevelInfo*)(levelArray->data[level]))->metadata;
+                    addStatus = psMetadataAdd(md,PS_LIST_TAIL,keyName,
+                                              PS_DATA_METADATA | flags,"",tempMeta);
+                    // Check for add failure
+                    if (! addStatus) {
+                        psError(PS_ERR_IO, true,
+                                _("Duplicate Metadata item, %s, found.  "
+                                  "Overwrite not allowed."),
+                                keyName);
+                        psFree(strType);
                         psFree(tempMeta);
-                    } else {
-                        // Metadata type read error
-                        psError(PS_ERR_IO,true,
-                                _("Failed to read a metadata %s on line %u."),
-                                keyName, lineCount);
-                        psFree(strType);
                         return false;
                     }
-                    typeFound = true;
-                    break;
+                    psFree(tempMeta);
+                } else {
+                    // Metadata type read error
+                    psError(PS_ERR_IO,true,
+                            _("Failed to read a metadata %s."), keyName);
+                    psFree(strType);
+                    return false;
                 }
-            }
-            if(!typeFound) {
-                psError(PS_ERR_IO, true,
-                        _("Metadata type '%s', found on line %u, is invalid."),
-                        strType, lineCount);
-                psFree(strType);
-                return false;
-            } else {
-                psFree(strType);
-                return true;
-            }
+                typeFound = true;
+                break;
+            }
+        }
+        if(!typeFound) {
+            psError(PS_ERR_IO, true,
+                    _("Metadata type '%s' is invalid."), strType);
+            psFree(strType);
+            return false;
+        } else {
+            psFree(strType);
+            return true;
         }
     }
@@ -830,6 +823,5 @@
 
         if(status) {
-            psError(PS_ERR_IO, true,
-                    _("Failed to read a metadata %s on line %u."), "value", lineCount);
+            psError(PS_ERR_IO, true, _("Failed to read a metadata value."));
             psFree(strType);
             psFree(strValue);
@@ -838,6 +830,5 @@
 
         if(strValue==NULL) {
-            psError(PS_ERR_IO, true,
-                    _("Failed to read a metadata %s on line %u."), "value", lineCount);
+            psError(PS_ERR_IO, true, _("Failed to read a metadata value."));
             psFree(strType);
             psFree(strValue);
@@ -850,6 +841,5 @@
         strComment = getToken(&linePtr, "", &status, true);
         if(status) {
-            psError(PS_ERR_IO, true,
-                    _("Failed to read a metadata %s on line %u."), "comment", lineCount);
+            psError(PS_ERR_IO, true, _("Failed to read a metadata comment"));
             psFree(strType);
             psFree(strValue);
@@ -876,6 +866,6 @@
         } else {
             psError(PS_ERR_IO, true,
-                    _("Failed to parse the value '%s' of metadata item %s, type %s, "
-                      "on line %u."), strValue, keyName, strType, lineCount);
+                    _("Failed to parse the value '%s' of metadata item %s, type %s."),
+                      strValue, keyName, strType);
             returnValue = false;
         }
@@ -890,6 +880,6 @@
         } else {
             psError(PS_ERR_IO, true,
-                    _("Failed to parse the value '%s' of metadata item %s, type %s, "
-                      "on line %u."), strValue, keyName, strType, lineCount);
+                    _("Failed to parse the value '%s' of metadata item %s, type %s."),
+                      strValue, keyName, strType);
             returnValue = false;
         }
@@ -902,6 +892,6 @@
         } else {
             psError(PS_ERR_IO, true,
-                    _("Failed to parse the value '%s' of metadata item %s, type %s, on line %u."),
-                    strValue, keyName, strType, lineCount);
+                    _("Failed to parse the value '%s' of metadata item %s, type %s."), 
+                    strValue, keyName, strType);
             returnValue = false;
         }
@@ -914,6 +904,6 @@
         } else {
             psError(PS_ERR_IO, true,
-                    _("Failed to parse the value '%s' of metadata item %s, type %s, on line %u."),
-                    strValue, keyName, strType, lineCount);
+                    _("Failed to parse the value '%s' of metadata item %s, type %s."),
+                    strValue, keyName, strType);
             returnValue = false;
         }
@@ -926,6 +916,6 @@
         } else {
             psError(PS_ERR_IO, true,
-                    _("Failed to parse the value '%s' of metadata item %s, type %s, on line %u."),
-                    strValue, keyName, strType, lineCount);
+                    _("Failed to parse the value '%s' of metadata item %s, type %s."),
+                    strValue, keyName, strType);
             returnValue = false;
         }
@@ -938,6 +928,6 @@
         } else {
             psError(PS_ERR_IO, true,
-                    _("Failed to parse the value '%s' of metadata item %s, type %s, on line %u."),
-                    strValue, keyName, strType, lineCount);
+                    _("Failed to parse the value '%s' of metadata item %s, type %s."),
+                    strValue, keyName, strType);
             returnValue = false;
         }
@@ -950,6 +940,6 @@
         } else {
             psError(PS_ERR_IO, true,
-                    _("Failed to parse the value '%s' of metadata item %s, type %s, on line %u."),
-                    strValue, keyName, strType, lineCount);
+                    _("Failed to parse the value '%s' of metadata item %s, type %s."),
+                    strValue, keyName, strType);
             returnValue = false;
         }
@@ -962,6 +952,6 @@
         } else {
             psError(PS_ERR_IO, true,
-                    _("Failed to parse the value '%s' of metadata item %s, type %s, on line %u."),
-                    strValue, keyName, strType, lineCount);
+                    _("Failed to parse the value '%s' of metadata item %s, type %s."),
+                    strValue, keyName, strType);
             returnValue = false;
         }
@@ -974,6 +964,6 @@
         } else {
             psError(PS_ERR_IO, true,
-                    _("Failed to parse the value '%s' of metadata item %s, type %s, on line %u."),
-                    strValue, keyName, strType, lineCount);
+                    _("Failed to parse the value '%s' of metadata item %s, type %s."),
+                    strValue, keyName, strType);
             returnValue = false;
         }
@@ -986,6 +976,6 @@
         } else {
             psError(PS_ERR_IO, true,
-                    _("Failed to parse the value '%s' of metadata item %s, type %s, on line %u."),
-                    strValue, keyName, strType, lineCount);
+                    _("Failed to parse the value '%s' of metadata item %s, type %s."),
+                    strValue, keyName, strType);
             returnValue = false;
         }
@@ -1009,6 +999,6 @@
         } else {
             psError(PS_ERR_IO, true,
-                    _("Failed to parse the value '%s' of metadata item %s, type %s, on line %u."),
-                    strValue, keyName, strType, lineCount);
+                    _("Failed to parse the value '%s' of metadata item %s, type %s."),
+                    strValue, keyName, strType);
             returnValue = false;
         }
@@ -1023,6 +1013,6 @@
         } else {
             psError(PS_ERR_IO, true,
-                    _("Failed to parse the value '%s' of metadata item %s, type %s, on line %u."),
-                    strValue, keyName, strType, lineCount);
+                    _("Failed to parse the value '%s' of metadata item %s, type %s."),
+                    strValue, keyName, strType);
             returnValue = false;
         }
@@ -1035,6 +1025,5 @@
         for(psS32 k=0; k < nonUniqueKeys->n; k++) {
             if(strcmp(keyName,(char*)nonUniqueKeys->data[k]) == 0) {
-                psError(PS_ERR_IO,true,_("Duplicate MULTI specifier on line %u."),
-                        lineCount);
+                psError(PS_ERR_IO,true,_("Duplicate MULTI specifier."));
                 psFree(strType);
                 return false;
@@ -1047,4 +1036,16 @@
         break;
     case PS_DATA_METADATA: {
+            // check to see if this keyname already exists and is allowed as a
+            // MULTI.  If we don't do this check first, it's possible that we
+            // can create a new "scope" yet fail to add the new metdata.
+            psMetadataItem *item = psMetadataLookup (md, keyName);
+            if ((item != NULL) &&
+                    ((item->type != PS_DATA_METADATA_MULTI) &&
+                    ((flags & PS_META_REPLACE) == 0))
+            ) {
+                psError(PS_ERR_IO, true, _("Duplicate Metadata declaration: %s is not allowed without 'overwrite' or MULTI specifier."), keyName);
+                break;
+            }
+            
             // create the nested metadata
             psMetadata *newScope = psMetadataAlloc();
@@ -1053,19 +1054,26 @@
             nextLevelInfo = p_psParseLevelInfoAlloc();
 
-            // switch to the scope to the new metadata
-            nextLevelInfo->metadata = newScope;
-
-            // Add next level to levelArray
-            levelArray = psArrayAdd(levelArray, 0, nextLevelInfo);
-            psFree(nextLevelInfo);
-
+
+            // try to add the new metdata to the current one
             addStatus = psMetadataAdd(md, PS_LIST_TAIL, keyName,
                                       mdType | flags,
                                       strComment, newScope);
+
+            if (addStatus) {
+                // switch to the scope to the new metadata
+                nextLevelInfo->metadata = psMemIncrRefCounter(newScope);
+
+                // Add next level to levelArray
+                levelArray = psArrayAdd(levelArray, 0, nextLevelInfo);
+            }
+
+            psFree(nextLevelInfo);
+            psFree(newScope);
+
             break;
         }
     default:
         psError(PS_ERR_IO, true,
-                _("Metadata of unknown type found on line %u."), lineCount);
+                _("Metadata of unknown type found."));
         break;
     }
@@ -1083,8 +1091,8 @@
 }
 
-bool parseLine(psArray* levelArray,
-               char* linePtr,
-               psS32 lineCount,
-               bool overwrite)
+static bool parseLine(psArray* levelArray,
+                      char* linePtr,
+                      bool overwrite,
+                      bool *notBlank)
 {
     psMetadataFlags     flags  = PS_META_DEFAULT;
@@ -1098,6 +1106,12 @@
     if (ignoreLine(linePtr)) {
         // do nothing and return
+        if (notBlank) {
+            *notBlank = false;
+        }
         return true;
     }
+
+    // even if it's a "bad line" we know it can't be "blank" after this point 
+    *notBlank = true;
 
     // Check for more than one '@' in a line
@@ -1106,5 +1120,5 @@
     if (repeatedChars(linePtr, '@') > 1) {
         psError(PS_ERR_IO, true,
-                _("More than one '@' character not allowed.  Found on line %u."), lineCount);
+                _("More than one '@' character is not allowed"));
         return false;
     }
@@ -1114,6 +1128,5 @@
     char *keyName = getToken(&linePtr, " ", &status, true);
     if (status) {
-        psError(PS_ERR_IO, true,
-                _("Failed to read item key name on line %u."), lineCount);
+        psError(PS_ERR_IO, true, _("Failed to read item key name on line"));
         psFree(keyName);
         return false;
@@ -1122,13 +1135,13 @@
     // Check for special keyName values "TYPE", "END"
     if (strcmp(keyName, "END") == 0) {
-        if (!parseMetadataEnd(keyName, levelArray, linePtr, lineCount, flags)) {
+        if (!parseMetadataEnd(keyName, levelArray, linePtr, flags)) {
             goto FAIL;
         }
     } else if (strcmp(keyName,"TYPE") == 0 ) {
-        if (!parseType(keyName, levelArray, linePtr, lineCount, flags)) {
+        if (!parseType(keyName, levelArray, linePtr, flags)) {
             goto FAIL;
         }
     } else {
-        if (!parseGeneric(keyName, levelArray, linePtr, lineCount, flags)) {
+        if (!parseGeneric(keyName, levelArray, linePtr, flags)) {
             goto FAIL;
         }
@@ -1140,6 +1153,5 @@
 
 FAIL:
-    psError(PS_ERR_UNKNOWN, false,
-            _("Failed to parse line %u: %s."), lineCount, linePtr);
+    psError(PS_ERR_UNKNOWN, false, _("Failed to parse line"));
     psFree(keyName);
     return false;
@@ -1149,5 +1161,4 @@
                          psArray* levelArray,
                          char* linePtr,
-                         psS32 lineCount,
                          psMetadataFlags flags)
 {
@@ -1169,5 +1180,5 @@
 
     // Parse metadataItem
-    if (!parseMetadataItem(keyName, levelArray, linePtr, lineCount, flags)) {
+    if (!parseMetadataItem(keyName, levelArray, linePtr, flags)) {
         return false;
     }
@@ -1179,5 +1190,4 @@
                       psArray* levelArray,
                       char* linePtr,
-                      psS32 lineCount,
                       psMetadataFlags flags)
 {
@@ -1192,11 +1202,9 @@
     char *strType = getToken(&linePtr, " ", &status, true);
     if(!strType) {
-        psError(PS_ERR_IO,true,
-                _("Failed to read item type on line %u."), lineCount);
+        psError(PS_ERR_IO,true, _("Failed to read item type."));
         return false;
     }
     if (status) {
-        psError(PS_ERR_IO, true,
-                _("Failed to read item type on line %u."), lineCount);
+        psError(PS_ERR_IO, true, _("Failed to read item type."));
         psFree(strType);
         return false;
@@ -1206,7 +1214,5 @@
     psMetadata *tempTemplate = getMetadataType(linePtr);
     if (!tempTemplate) {
-        psError(PS_ERR_IO,true,
-                _("Metadata type '%s', found on line %u, is invalid."),
-                strType,lineCount);
+        psError(PS_ERR_IO,true, _("Metadata type '%s' is invalid."), strType);
         psFree(strType);
         return false;
@@ -1221,6 +1227,5 @@
         if (strcmp(strType, (char*)typeArray->data[k]) == 0) {
             psError(PS_ERR_IO,true,
-                    _("Specified type, %s, on line %u is already defined."),
-                    strType, lineCount);
+                    _("Specified type %s is already defined."), strType);
             psFree(tempTemplate);
             psFree(strType);
@@ -1244,5 +1249,4 @@
                              psArray* levelArray,
                              char* linePtr,
-                             psS32 lineCount,
                              psMetadataFlags flags)
 {
@@ -1379,11 +1383,11 @@
         return NULL;
     }
+
+    // accept completely empty strings
+    // nFail == 0 / nPass == 0 - OK
     if (psListLength(doc) == 0) {
-        psError(PS_ERR_UNKNOWN, false, "string contained no lines");
+        psTrace("psLib.types", PS_LOG_INFO, "string contained no lines");
         psFree(doc);
-        if (allocedMD) {
-            psFree(md);
-        }
-        return NULL;
+        return md;
     }
 
@@ -1401,19 +1405,22 @@
     psErrorClear();
 
+    // line type counts
+    long nLines = 0;                // all lines
+    long nGood  = 0;                // valid lines excluding blank/comment
+    long nBad   = 0;                // invalid lines
+
     // While loop to parse the file
-    long lineCount = 0;
     char *line = NULL;
     psListIterator *iter = psListIteratorAlloc(doc, 0, false);
     while ((line = psListGetAndIncrement(iter))) {
-        lineCount++; // indexed from 1
-
-        if (!parseLine(parseLevelInfoArray, line, lineCount,
-                       overwrite)) {
-            if (nFail != NULL) {
-                (*nFail)++;
-            } else {
-                psError(PS_ERR_BAD_PARAMETER_VALUE, false, "Error parsing line: %s", line);
-            }
-            psTrace("psLib.types", 4, "Error parsing line: %s", line);
+        nLines++; // indexed from 1
+
+        bool notBlank = false;
+        if (!parseLine(parseLevelInfoArray, line, overwrite, &notBlank)) {
+            nBad++;
+            psError(PS_ERR_BAD_PARAMETER_VALUE, false, "Error parsing line #%lu : %s", nLines, line);
+        } else if (notBlank) {
+        // do not count blank/comment lines as "good" lines
+            nGood++;
         }
     }
@@ -1425,4 +1432,18 @@
     psFree(parseLevelInfoArray);
 
+    // nFail > 0 / nPass == 0 - NULL
+    if ((nBad > 0) && (nGood == 0)) {
+        psError(PS_ERR_UNKNOWN, false, "string contained no data lines and %ld bad lines", nBad);
+        psFree(md);
+        return NULL;
+    }
+
+    // pass back the number of failed lines
+    if (nFail) {
+        *nFail = nBad;
+    }
+
+    // nFail == 0 / nPass > 0
+    // nFail > 0 / nPass > 0
     return md;
 }
Index: trunk/psLib/test/types/metaconf.in
===================================================================
--- trunk/psLib/test/types/metaconf.in	(revision 12440)
+++ trunk/psLib/test/types/metaconf.in	(revision 12441)
@@ -1,29 +1,20 @@
+#
+# Good lines
+#
+
 item1            BOOL      T                # I am a boolean
-item1            BOOL      F                # I am a boolean2
 item2            S32       55               # I am int
 item3            F32       3.14
 item4            F64       6.28             # I am float
-item4-1          F64       6.28 1           # I am float
 item5            STR       GNIRTS           # I am a string
-item6            S32       10 1
-item6-1          S32       ~
 item7            S64       555
-item7-1          S64       555 x
 item8            S8        3
-item8            S8        5
-item8-1          S8        5 1
 itemu1           U16       2
-itemu1-1         U16       2 1
 itemu2           U32       55
-itemu2-1         U32       55 1
-itemu3-1         U8        1 2
 itemu3           U8        1
 itemu4           U64       1634
-itemu4-1         U64       1634 1
 item9            BOOL      F                # I am a boolean2
 item10           S16       16
-item10-1         S16       16 16
 @vector1  S8  1 2 3 4 5   # I am a vector
-@vector1-1 S8 % #
 @vector2  S16 1 2 3 4 5
 @vector3  S32 1 2 3 4 5
@@ -35,15 +26,10 @@
 @vector9  F32 1.0 2.3 3.1 4.5 5.0   # I am a vector
 @vector10 F64 1.0 2.0 3.0 4.0 5.0
-@vector11 C64 1.0 2.0 3.0 4.0 5.0
-@@@vector12 F64 1.0 2.0 3.0 4.0 5.0
 time01           TT        1970-01-01T00:16:39Z  # I am time
 time02           UTC       NULL     # I am time2
-
-ps1  S32  NAN
 
 f32 MULTI
 f32              S32       666              # f32_1
 f32              S32       665              # f32_2
-f32 MULTI
 
 f32 METADATA
@@ -54,7 +40,4 @@
 meta1 METADATA
     itemS32   S32       666              # f32_1
-END
-meta1 METADATA
-    M2   S32       666
 END
 
@@ -68,18 +51,40 @@
    ITEM03           F64       666.666          # I AM DOUBLE
 END
-
-     TYPE  C32  3
-     TYPE  C32  3
-     TYPE PS_TYPE_C32 2                 #
-newC32      C32 7i+5
-newC32      PS_TYPE_C32 7i+5
 #item11           C32       16+2i            # I am Complex
 
 TYPE PS_TYPE_DD D
+DD2     PS_TYPE_DD   ""
+     TYPE  C32  3
+newC32      C32 7i+5
+
+#
+# Bad lines : 28 (-1 for the GOOD line in meta1) & 3 valid duplicates
+#
+item1            BOOL      F                # duplicate
+item8            S8        5                # duplicate
+item4-1          F64       6.28 1           # I am float
+item6            S32       10 1
+item6-1          S32       ~
+item7-1          S64       555 x
+item8-1          S8        5 1
+itemu1-1         U16       2 1
+itemu2-1         U32       55 1
+itemu3-1         U8        1 2
+itemu4-1         U64       1634 1
+item10-1         S16       16 16
+@vector1-1 S8 % #
+@@@vector12 F64 1.0 2.0 3.0 4.0 5.0
+@vector11 C64 1.0 2.0 3.0 4.0 5.0
+meta1 METADATA                              # duplicate
+    M2   S32       666  # this line is "GOOD" but parsed in the top level
+END
 newDD   PS_TYPE_DD
-DD2     PS_TYPE_DD   ""
-
 TYPE            1
 TYPE
 TYPE         #  # 1
+     TYPE  C32  3
+     TYPE PS_TYPE_C32 2                 #
+newC32      PS_TYPE_C32 7i+5        # duplicate but with borken type
+ps1  S32  NAN
+f32 MULTI
 \n
Index: trunk/psLib/test/types/table3.dat
===================================================================
--- trunk/psLib/test/types/table3.dat	(revision 12440)
+++ trunk/psLib/test/types/table3.dat	(revision 12441)
@@ -1,3 +1,4 @@
-#  Table with valid types and index-values
+#
+# This file is not valid metdataconfig syntax
 #
 #psF32     psU16    psU32     psU64    psS8    psS16    psS32    psS64    psU8   psF64
Index: trunk/psLib/test/types/tap_psMetadataConfig_input.c
===================================================================
--- trunk/psLib/test/types/tap_psMetadataConfig_input.c	(revision 12440)
+++ trunk/psLib/test/types/tap_psMetadataConfig_input.c	(revision 12441)
@@ -19,139 +19,127 @@
 #include "pstap.h"
 
-static void testMetaConfigRead(void);
-static void testMetaConfigParse(void);
-
-
 int main(void)
 {
+    plan_tests(42);
+
     psLogSetFormat("HLNM");
-    plan_tests(39);
-
-    note("Tests for psMetadataConfig Input Functions");
-    testMetaConfigRead();
-    testMetaConfigParse();
-}
-
-void testMetaConfigRead(void)
-{
-    note("  >>>Test 1:  psMetadataConfigRead");
-
-    //Return NULL for NULL filename input
+//    psTraceSetLevel("err", 10);
+
+
+    // Return NULL for NULL filename input
     {
         unsigned int nfail = 0;
         psMetadata *out = psMetadataConfigRead(NULL, &nfail, NULL, false);
-        ok( out == NULL,
-            "psMetadataConfigRead: return NULL for NULL filename input.");
-    }
-    //Return NULL for invalid filename input
+
+        ok(out == NULL, "return NULL for NULL filename input.");
+    }
+
+    // Return NULL for invalid filename input
     {
         unsigned int nfail = 0;
         psMetadata *out = psMetadataConfigRead(NULL, &nfail, ".", false);
-        ok( out == NULL,
-            "psMetadataConfigRead: return NULL for invalid filename input.");
-    }
-    //Return NULL for missing file input
+
+        ok(out == NULL, "return NULL for invalid filename input.");
+    }
+
+    // Return NULL for missing file input
     {
         unsigned int nfail = 0;
         psMetadata *out = psMetadataConfigRead(NULL, &nfail, "table4.dat", false);
-        ok( out == NULL,
-            "psMetadataConfigRead: return NULL for missing file input.");
-    }
-    //Return empty metadata for read-only file with invalid syntax
+        ok(out == NULL, "return NULL for missing file input.");
+    }
+
+    // Return NULL for read-only file with comments, bad syntax, and no good
+    // lines
     {
         unsigned int nfail = 0;
         psMetadata *out = psMetadataConfigRead(NULL, &nfail, "table3.dat", false);
-        ok( out != NULL && out->list->n == 0,
-            "psMetadataConfigRead: return empty metadata for file"
-            " with invalid syntax.");
-        psFree(out);
-    }
-    //Return true for valid inputs - overwrite = false
+        ok(out == NULL, "return NULL for all bad syntax");
+        is_int(nfail, 0, "correct nfail");
+
+        psFree(out);
+    }
+
+    // Return true for valid inputs - overwrite = false
     {
         unsigned int nfail = 0;
         psMetadata *out = psMetadataConfigRead(NULL, &nfail, "metaconf.in", false);
-        psMetadataItem *tempItem = psMetadataGet(out, PS_LIST_HEAD);
-
-        //XXX: Josh, please review the "metaconf.in" in this directory and ensure that
-        //the number of failed lines, which we test next, should indeed be 26.
-        ok(out != NULL && nfail == 26,
-            "psMetadataConfigRead: return correct metadata for valid inputs (nfail was %d)", nfail);
-        skip_start(tempItem == NULL, 6,
-                     "Skipping 1 tests because metadata container is empty!");
-        ok_str(tempItem->name, "item1",
-               "psMetadataConfigRead: return correct metadataItem name from "
-               "returned metadata.");
-        ok(tempItem->type == PS_DATA_BOOL && tempItem->data.B == true,
-            "psMetadataConfigRead: return correct metadataItem data from "
-            "returned metadata.");
-        ok_str(tempItem->comment, "I am a boolean",
-                "psMetadataConfigRead: return correct metadataItem comment from "
-                "returned metadata.");
+
+        ok(out != NULL, "return metadata for valid input");
+        is_int(nfail, 27, "return correct nFail count");
+
+        skip_start(out == NULL, 8,
+                     "Skipping 1 tests because metadata container is empty!");
+
+        // look at the first item
+        psMetadataItem *tempItem = psMetadataGet(out, PS_LIST_HEAD);
+        // XXX shouldn't assume tempItem isn't NULL
+        ok_str(tempItem->name, "item1", "metadataItem name");
+        ok(tempItem->type == PS_DATA_BOOL, "metadataItem type");
+        is_bool(tempItem->data.B, true, "metdataItem value");
+        ok_str(tempItem->comment, "I am a boolean", "metadataItem comment.");
+
+        // look at the last item
         tempItem = psMetadataGet(out, PS_LIST_TAIL);
-        ok_str(tempItem->name, "DD2",
-                "psMetadataConfigRead: return correct metadataItem name from returned metadata");
-        ok(tempItem->type == PS_DATA_METADATA &&
-            ((psMetadata*)(tempItem->data.V))->list->n == 1
-            && strlen(tempItem->comment) == 0,
-            "psMetadataConfigRead: return correct metadataItem data from "
-            "returned metadata.");
-        skip_end();
-        // psMetadataConfigWrite(out, "mdc-overwrite_false.txt");
-        psFree(out);
-    }
-
-    //Return true for valid inputs - overwrite = true
+        // XXX shouldn't assume tempItem isn't NULL
+        ok_str(tempItem->name, "M2", "metadataItem name");
+        ok(tempItem->type == PS_DATA_S32, "metdataItem type");
+        is_int(tempItem->data.S32, 666, "metdataItem value");
+        ok_str(tempItem->comment, "this line is \"GOOD\" but parsed in the top level", "metadataItem comment.");
+
+        skip_end();
+        psFree(out);
+    }
+
+    // Return true for valid inputs - overwrite = true
     {
         unsigned int nfail = 0;
         psMetadata *out = psMetadataConfigRead(NULL, &nfail, "metaconf.in", true);
-        psMetadataItem *tempItem = psMetadataGet(out, PS_LIST_HEAD);
-        //XXX: Josh, please review the "metaconf.in" in this directory and ensure that
-        //the number of failed lines, which we test next, should indeed be 23.
-        ok( out != NULL  && nfail == 23,
-            "psMetadataConfigRead: return correct metadata for valid inputs (nfail was %d).", nfail);
-        skip_start(  tempItem == NULL, 6,
-                     "Skipping 1 tests because metadata container is empty!");
-        ok_str( tempItem->name, "item1",
-                "psMetadataConfigRead: return correct metadataItem name from "
-                "returned metadata.");
-        ok( tempItem->type == PS_DATA_BOOL && tempItem->data.B == false,
-            "psMetadataConfigRead: return correct metadataItem data from "
-            "returned metadata.");
-        ok_str( tempItem->comment, "I am a boolean2",
-                "psMetadataConfigRead: return correct metadataItem comment from "
-                "returned metadata.");
+//        psMetadataConfigPrint(stdout, out);
+
+        ok(out != NULL, "return metadata for valid input");
+        is_int(nfail, 23, "return correct nFail count");
+
+        skip_start(out == NULL, 7,
+                     "Skipping 1 tests because metadata container is empty!");
+
+        // look at the first item
+        psMetadataItem *tempItem = psMetadataGet(out, PS_LIST_HEAD);
+        // XXX shouldn't assume tempItem isn't NULL
+        // note that item1 gets added to the "tail" of the metdata was it's
+        // replaced
+        ok_str(tempItem->name, "item2", "metadataItem name");
+        ok(tempItem->type == PS_DATA_S32, "metdataItem type");
+        is_bool(tempItem->data.S32, 55, "metadataItem value");
+        ok_str(tempItem->comment, "I am int", "metadataItem value");
+
+        // look at the last item
         tempItem = psMetadataGet(out, PS_LIST_TAIL);
-        ok_str( tempItem->name, "DD2",
-                "psMetadataConfigRead: return correct metadataItem name from "
-                "returned metadata.");
-        ok( tempItem->type == PS_DATA_METADATA &&
-            ((psMetadata*)(tempItem->data.V))->list->n == 1
-            && strlen(tempItem->comment) == 0,
-            "psMetadataConfigRead: return correct metadataItem data from "
-            "returned metadata.");
-        skip_end();
-        // psMetadataConfigWrite(out, "mdc-overwrite_true.txt");
-        psFree(out);
-    }
-
-    //Check for Memory leaks
+        // XXX shouldn't assume tempItem isn't NULL
+        // meta1 is from "the bad section"
+        ok_str(tempItem->name, "meta1", "metadataItem name");
+        ok(tempItem->type == PS_DATA_METADATA, "metadataItem type");
+
+        ok_str(tempItem->comment, "", "metadataItem comment");
+
+        skip_end();
+        psFree(out);
+    }
+
+    // Check for Memory leaks
     checkMem();
-}
-
-void testMetaConfigParse(void)
-{
-    note("  >>>Test 2: psMetadataConfigParse");
-
-    //Return NULL for NULL string input
+
+    // Return NULL for NULL string input
     {
         psMemId id = psMemGetId();
         unsigned int nfail = 0;
         psMetadata *out = psMetadataConfigParse(NULL, &nfail, NULL, false);
-        ok(out == NULL,
-           "psMetadataConfigParse: return NULL for NULL string input.");
-        ok(!psMemCheckLeaks (id, NULL, NULL, false), "no memory leaks");
-    }
-
-    //Return empty metadata for incorrect string input
+
+        ok(out == NULL, "psMetadataConfigParse: return NULL for NULL string input.");
+
+        ok(!psMemCheckLeaks (id, NULL, NULL, false), "no memory leaks");
+    }
+
+    // Return empty metadata for incorrect string input
     {
         psMemId id = psMemGetId();
@@ -167,5 +155,5 @@
     }
 
-    //Return correct metadata for correct string input - S32
+    // Return correct metadata for correct string input - S32
     {
         psMemId id = psMemGetId();
@@ -188,5 +176,5 @@
     }
 
-    //Return correct metadata for correct string input - F64
+    // Return correct metadata for correct string input - F64
     {
         psMemId id = psMemGetId();
@@ -213,5 +201,5 @@
     }
 
-    //Return correct metadata for string with duplicate entry - S8
+    // Return correct metadata for string with duplicate entry - S8
     {
         psMemId id = psMemGetId();
