Index: trunk/psLib/src/collections/psList.h
===================================================================
--- trunk/psLib/src/collections/psList.h	(revision 3341)
+++ trunk/psLib/src/collections/psList.h	(revision 3381)
@@ -10,6 +10,6 @@
  *  @ingroup LinkedList
  *
- *  @version $Revision: 1.21 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2005-02-17 19:26:23 $
+ *  @version $Revision: 1.22 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2005-03-07 20:58:50 $
  *
  *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
@@ -174,6 +174,6 @@
 /** Position the specified iterator to the next item in list.
  *
- *  @return psPtr       the data item at the new iterator position or NULL if the
- *                      iterator goes past the end of the list.
+ *  @return psPtr       the data item at the original iterator position or NULL if the
+ *                      iterator went past the end of the list.
  */
 psPtr psListGetAndIncrement(
@@ -183,6 +183,6 @@
 /** Position the specified iterator to the previous item in list.
  *
- *  @return psPtr       the data item at the new iterator position or NULL if the
- *                      iterator goes past the beginning of the list.
+ *  @return psPtr       the data item at the original iterator position or NULL if the
+ *                      iterator went past the beginning of the list.
  */
 psPtr psListGetAndDecrement(
Index: trunk/psLib/src/collections/psMetadata.c
===================================================================
--- trunk/psLib/src/collections/psMetadata.c	(revision 3341)
+++ trunk/psLib/src/collections/psMetadata.c	(revision 3381)
@@ -12,6 +12,6 @@
 *  @author Ross Harman, MHPCC
 *
-*  @version $Revision: 1.53 $ $Name: not supported by cvs2svn $
-*  @date $Date: 2005-02-28 23:34:10 $
+*  @version $Revision: 1.54 $ $Name: not supported by cvs2svn $
+*  @date $Date: 2005-03-07 20:58:50 $
 *
 *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
@@ -85,4 +85,13 @@
 }
 
+static void metadataIteratorFree(psMetadataIterator* iter)
+{
+    if (iter == NULL) {
+        return;
+    }
+    psFree(iter->iter);
+    regfree(iter->preg);
+}
+
 static void metadataFree(psMetadata* metadata)
 {
@@ -158,5 +167,5 @@
 
     // Set metadata item type
-    metadataItem->type = type;
+    metadataItem->type = type & PS_METADATA_TYPE_MASK;
 
     // Allocate and set metadata item name
@@ -165,5 +174,5 @@
 
     // Set metadata item value
-    switch(type) {
+    switch(metadataItem->type) {
     case PS_META_BOOL:
         metadataItem->data.B = (psBool)va_arg(argPtr, psS32);
@@ -190,4 +199,5 @@
     case PS_META_ASTROM:
     case PS_META_UNKNOWN:
+    case PS_META_MULTI:
         // Copy of input data not performed due to variability of data types
         metadataItem->data.V = psMemIncrRefCounter(va_arg(argPtr, psPtr));
@@ -223,5 +233,5 @@
 }
 
-psBool psMetadataAddItem(psMetadata *md, psMetadataItem *metadataItem, psS32 location)
+psBool psMetadataAddItem(psMetadata *md, psMetadataItem *metadataItem, psS32 location, psS32 flags)
 {
     char * key = NULL;
@@ -229,6 +239,4 @@
     psList *mdList = NULL;
     psMetadataItem *existingEntry = NULL;
-    psMetadataItem *newFolderEntry = NULL;
-    psMetadataType newType;
 
     PS_PTR_CHECK_NULL(md,NULL);
@@ -238,5 +246,4 @@
     PS_PTR_CHECK_NULL(metadataItem->name,NULL);
 
-    newType = metadataItem->type;
     mdTable = md->table;
     mdList = md->list;
@@ -245,72 +252,56 @@
     // See if key is already in table
     existingEntry = (psMetadataItem*)psHashLookup(mdTable, key);
+
+    // how the item is added to the hash depends on flags & prior existence
     if(existingEntry != NULL) {
-
-        if(existingEntry->type == PS_META_LIST) {
-
-            if(existingEntry->data.list == NULL) {
-                existingEntry->data.list = psListAlloc(NULL);
+        if ((flags & PS_META_DUPLICATE_OK) != 0) {
+            // duplicate entries allowed - add another entry.
+            if (existingEntry->type != PS_META_MULTI) {
+                // first duplicate, transfer the hash's old entry into a
+                // list of entries with the type PS_META_MULTI.
+
+                // add entry to a list and dereference the local pointer
+                psList* newList = psListAlloc(existingEntry);
+
+                existingEntry = psMetadataItemAlloc(key,
+                                                    PS_META_MULTI,
+                                                    "",
+                                                    newList);
+                psHashRemove(mdTable,key); // take out the old entry
+                psHashAdd(mdTable, key, existingEntry); // put in the new entry
+
+                // free local references of newly allocated items.
+                psFree(newList);
+                psFree(existingEntry);
+
             }
 
-            // Add leaf node to existing folder node
-            if(!psListAdd(existingEntry->data.list, PS_LIST_TAIL, metadataItem)) {
-                psError(PS_ERR_UNKNOWN, false, PS_ERRORTEXT_psMetadata_ADD_LIST_FAILED, metadataItem->name);
+            // add to the hash's list of duplicate entries
+            if (! psListAdd(existingEntry->data.list, PS_LIST_TAIL, metadataItem) ) {
+                psError(PS_ERR_UNKNOWN,false,PS_ERRORTEXT_psMetadata_ADD_COLLECTION_FAILED,key);
                 return false;
             }
-        } else if(existingEntry->type != PS_META_LIST && newType!= PS_META_LIST) {
-
-            // Leaf node replaces another leaf. Make new folder node and add leaves.
-            newFolderEntry = psMetadataItemAlloc(key, PS_META_LIST, NULL, NULL);
-            newFolderEntry->data.list = psListAlloc(NULL);
-
-            if(!psListAdd(newFolderEntry->data.list, PS_LIST_TAIL, existingEntry)) {
-                psError(PS_ERR_UNKNOWN,false, PS_ERRORTEXT_psMetadata_ADD_LIST_FAILED,key);
-                psFree(newFolderEntry);
-                return false;
-            }
-
-            if(!psListAdd(newFolderEntry->data.list, PS_LIST_TAIL, metadataItem)) {
-                psError(PS_ERR_UNKNOWN,false, PS_ERRORTEXT_psMetadata_ADD_LIST_FAILED,key);
-                psFree(newFolderEntry);
-                return false;
-            }
-
-            if(!psHashRemove(mdTable, key)) {
-                psError(PS_ERR_UNKNOWN,false,PS_ERRORTEXT_psMetadata_REMOVE_TABLE_FAILED,key);
-                psFree(newFolderEntry);
-                return false;
-            }
-
-            if(!psHashAdd(mdTable, key, newFolderEntry)) {
-                psError(PS_ERR_UNKNOWN,false,PS_ERRORTEXT_psMetadata_ADD_TABLE_FAILED,key);
-                psFree(newFolderEntry);
-                return false;
-            }
-
-            // Remove local reference to new folder node
-            psMemDecrRefCounter(newFolderEntry);
-        } else {
-
-            // Folder node replaces leaf or folder node - Put old node into new folder and remove from table
-            if(metadataItem->data.list == NULL) {
-                metadataItem->data.list = psListAlloc(NULL);
-            }
-
-            if(!psListAdd(metadataItem->data.list, PS_LIST_TAIL, existingEntry)) {
-                psError(PS_ERR_UNKNOWN,false,PS_ERRORTEXT_psMetadata_ADD_LIST_FAILED,key);
-                return false;
-            }
-
-            if(!psHashRemove(mdTable, key)) {
-                psError(PS_ERR_UNKNOWN,false,PS_ERRORTEXT_psMetadata_REMOVE_TABLE_FAILED,key);
-                return false;
-            }
-
+            // (added to list below)
+
+        } else if ((flags & PS_META_REPLACE) != 0) {
+            // replace entry instead of creating a duplicate entry.
+
+            // remove the existing entry from metadata
+            psListRemoveData(mdList, existingEntry);
+            psHashRemove(mdTable, key);
+
+            // treat as if new (added to list below)
             if(!psHashAdd(mdTable, key, metadataItem)) {
                 psError(PS_ERR_UNKNOWN,false,PS_ERRORTEXT_psMetadata_ADD_TABLE_FAILED,key);
                 return false;
             }
+        } else {
+            // default is to error on duplicate entry.
+            psError(PS_ERR_BAD_PARAMETER_VALUE, true,
+                    PS_ERRORTEXT_psMetadata_DUPLICATE_NOT_ALLOWED);
+            return false;
         }
     } else {
+        // OK, this is a new item.
 
         // Node doesn't exist - Add new metadata item to metadata collection's hash
@@ -321,11 +312,7 @@
     }
 
-    // Add items to metadata collection's list, even if they have the same metadata item names. Folder nodes
-    // (PS_META_LIST metadata items) are not added, since the metadata list is flat.
-    if(metadataItem->type != PS_META_LIST) {
-        if(!psListAdd(mdList, location, metadataItem)) {
-            psError(PS_ERR_UNKNOWN,false,PS_ERRORTEXT_psMetadata_ADD_COLLECTION_FAILED,key);
-            return false;
-        }
+    if(!psListAdd(mdList, location, metadataItem)) {
+        psError(PS_ERR_UNKNOWN,false,PS_ERRORTEXT_psMetadata_ADD_COLLECTION_FAILED,key);
+        return false;
     }
 
@@ -333,15 +320,24 @@
 }
 
-psBool psMetadataAdd(psMetadata *md, psS32 where, const char *name,
-                     psMetadataType type, const char *comment, ...)
+psBool psMetadataAdd(psMetadata *md, psS32 location, const char *name,
+                     psS32 type, const char *comment, ...)
 {
     va_list argPtr;
+
+    va_start(argPtr, comment);
+    psBool result = psMetadataAddV(md,location,name,type,comment,argPtr);
+    va_end(argPtr);
+
+    return result;
+}
+
+psBool psMetadataAddV(psMetadata *md, psS32 location, const char *name,
+                      psS32 type, const char *comment, va_list list)
+{
     psMetadataItem* metadataItem = NULL;
 
-    va_start(argPtr, comment);
-    metadataItem = psMetadataItemAllocV(name, type, comment, argPtr);
-    va_end(argPtr);
-
-    if (!psMetadataAddItem(md, metadataItem, where)) {
+    metadataItem = psMetadataItemAllocV(name, type & PS_METADATA_TYPE_MASK, comment, list);
+
+    if (!psMetadataAddItem(md, metadataItem, location, type & PS_METADATA_FLAGS_MASK)) {
         psError(PS_ERR_UNKNOWN,false,PS_ERRORTEXT_psMetadata_ADD_FAILED);
         psFree(metadataItem);
@@ -373,51 +369,72 @@
 psBool psMetadataRemove(psMetadata *md, psS32 where, const char *key)
 {
-    psList* mdList = NULL;
-    psHash* mdTable = NULL;
-    psMetadataItem* entry = NULL;
-
-
     PS_PTR_CHECK_NULL(md,NULL);
+
+    PS_PTR_CHECK_NULL(md->list,NULL);
+    psList* mdList = md->list;
+
     PS_PTR_CHECK_NULL(md->table,NULL);
-    PS_PTR_CHECK_NULL(md->list,NULL);
-
-    mdList = md->list;
-    mdTable = md->table;
+    psHash* mdTable = md->table;
 
     // Select removal by key or index
     if (key != NULL) {
-
         // Remove by key name
-        entry = (psMetadataItem*)psHashLookup(mdTable, key);
+        psMetadataItem* entry = psHashLookup(mdTable,key);
         if (entry == NULL) {
-            psError(PS_ERR_BAD_PARAMETER_VALUE, true, PS_ERRORTEXT_psMetadata_FIND_FAILED, key);
+            psError(PS_ERR_UNKNOWN, false, PS_ERRORTEXT_psMetadata_REMOVE_TABLE_FAILED, key);
             return false;
         }
-
+        if (entry->type == PS_META_MULTI) {
+            psMetadataItem* listItem;
+            psListIterator* iter = psListIteratorAlloc(
+                                       entry->data.list,
+                                       PS_LIST_HEAD,true);
+            while ((listItem=psListGetAndIncrement(iter)) != NULL) {
+                psListRemoveData(mdList, listItem);
+            }
+            psFree(iter);
+            psHashRemove(mdTable,key);
+
+        } else {
+            psListRemoveData(mdList, entry);
+            psHashRemove(mdTable, key);
+        }
     } else {
-
         // Remove by index
-        entry = psListGet(mdList, where);
+        psMetadataItem* entry = psListGet(mdList, where);
         if (entry == NULL) {
             psError(PS_ERR_BAD_PARAMETER_VALUE, true, PS_ERRORTEXT_psMetadata_FIND_INDEX_FAILED, where);
             return false;
         }
-
         key = entry->name;
-        if(key == NULL) {
+
+        if (key == NULL) {
             psError(PS_ERR_BAD_PARAMETER_VALUE, true, PS_ERRORTEXT_psMetadata_REMOVE_LIST_INDEX_FAILED, where);
             return false;
         }
-    }
-
-    if (!psListRemoveData(mdList, entry)) {
-        psError(PS_ERR_UNKNOWN, false, PS_ERRORTEXT_psMetadata_REMOVE_LIST_FAILED, key);
-        return false;
-    }
-
-    // Remove entry from metadata collection's table
-    if (!psHashRemove(mdTable, key)) {
-        psError(PS_ERR_UNKNOWN, false, PS_ERRORTEXT_psMetadata_REMOVE_TABLE_FAILED, key);
-        return false;
+
+        psMetadataItem* tableItem = psHashLookup(mdTable, key);
+        if (tableItem == NULL) {
+            psError(PS_ERR_UNKNOWN, false, PS_ERRORTEXT_psMetadata_REMOVE_TABLE_FAILED, key);
+            return false;
+        }
+
+        if (tableItem->type == PS_META_MULTI) {
+            // multiple entries with same key, remove just the specified one
+            psListRemoveData(tableItem->data.list, entry);
+            if (psListGet(tableItem->data.list,PS_LIST_HEAD) == NULL) {
+                // list is empty, so let's clear the whole entry now.
+                if (!psHashRemove(mdTable, key)) {
+                    psError(PS_ERR_UNKNOWN, false, PS_ERRORTEXT_psMetadata_REMOVE_TABLE_FAILED, key);
+                    return false;
+                }
+            }
+        } else {
+            if (!psHashRemove(mdTable, key)) {
+                psError(PS_ERR_UNKNOWN, false, PS_ERRORTEXT_psMetadata_REMOVE_TABLE_FAILED, key);
+                return false;
+            }
+        }
+        psListRemove(mdList, where);
     }
 
@@ -455,4 +472,8 @@
         }
         return NULL;
+    }
+    if (metadataItem->type == PS_META_MULTI) {
+        // if multiple keys found, use the first.
+        metadataItem = (psMetadataItem*)((metadataItem->data.list)->head);
     }
 
@@ -486,4 +507,8 @@
         } \
         return 0; \
+    } \
+    if (metadataItem->type == PS_META_MULTI) { \
+        /* if multiple keys found, use the first. */ \
+        metadataItem = (psMetadataItem*)((metadataItem->data.list)->head); \
     } \
     \
@@ -535,2 +560,145 @@
     return entry;
 }
+
+psMetadataIterator* psMetadataIteratorAlloc(psMetadata* md,
+        int location,
+        const char* regex)
+{
+    PS_PTR_CHECK_NULL(md,NULL);
+    PS_PTR_CHECK_NULL(md->list,NULL);
+
+    psMetadataIterator* newIter = psAlloc(sizeof(psMetadataIterator));
+    newIter->preg = NULL;
+    newIter->iter = NULL;
+
+    // Set deallocator
+    p_psMemSetDeallocator(newIter, (psFreeFcn) metadataIteratorFree);
+
+    if (regex == NULL) {
+        newIter->iter = psListIteratorAlloc(md->list, location, false);
+        return newIter;
+    } else {
+        int regRtn = regcomp(newIter->preg,regex,0);
+        if (regRtn != 0) {
+            char errMsg[256];
+            regerror(regRtn, newIter->preg, errMsg, 256);
+            regfree(newIter->preg);
+            psError(PS_ERR_BAD_PARAMETER_VALUE, true,
+                    PS_ERRORTEXT_psMetadata_REGEX_INVALID,
+                    errMsg);
+            psFree(newIter);
+            return NULL;
+        }
+    }
+
+    psMetadataIteratorSet(newIter, location); // XXX: do we error if no match is found?
+
+    return newIter;
+}
+
+psBool psMetadataIteratorSet(psMetadataIterator* iterator,
+                             int location)
+{
+    int match;
+    psMetadataItem* cursor;
+
+    PS_PTR_CHECK_NULL(iterator,NULL);
+
+    psListIterator* iter = iterator->iter;
+    PS_PTR_CHECK_NULL(iterator->iter,NULL);
+
+    regex_t* preg = iterator->preg;
+
+    // handle trivial case where no regex subsetting is required.
+    if (preg == NULL) {
+        return psListIteratorSet(iter,location);
+    }
+
+    if (location < 0) {
+        // match from the tail
+        match = 0;
+        psListIteratorSet(iter,PS_LIST_TAIL);
+        while ( (cursor=(psMetadataItem*)iter->cursor) != NULL) {
+            if (regexec(preg, cursor->name, 0, NULL, 0) == 0) {
+                // this key is a match
+                match--;
+                if (match == location) {
+                    break;
+                }
+            }
+            (void)psListGetAndDecrement(iter);
+        }
+        return (match == location);
+    }
+
+    // find the n-th match from the head
+    match = -1;
+    psListIteratorSet(iter,PS_LIST_HEAD);
+    while ( (cursor=(psMetadataItem*)iter->cursor) != NULL) {
+        if (regexec(preg, cursor->name, 0, NULL, 0) == 0) {
+            // this key is a match
+            match++;
+            if (match == location) {
+                break;
+            }
+        }
+        (void)psListGetAndIncrement(iter);
+    }
+    return (match == location);
+}
+
+psMetadataItem* psMetadataGetAndIncrement(psMetadataIterator* iterator)
+{
+    psMetadataItem* oldValue;
+
+    PS_PTR_CHECK_NULL(iterator,NULL);
+
+    psListIterator* iter = iterator->iter;
+    PS_PTR_CHECK_NULL(iterator->iter,NULL);
+
+    regex_t* preg = iterator->preg;
+
+    // handle trivial case where no regex subsetting is required.
+    if (preg == NULL) {
+        return (psMetadataItem*)psListGetAndIncrement(iter);
+    }
+
+    oldValue = (psMetadataItem*)iter->cursor;
+
+    while (psListGetAndIncrement(iter) != NULL) {
+        if (iter->cursor != NULL &&
+                regexec(preg, ((psMetadataItem*)iter->cursor)->name, 0, NULL, 0) == 0) {
+            // this key is a match
+            break;
+        }
+    }
+    return oldValue;
+}
+
+psMetadataItem* psMetadataGetAndDecrement(psMetadataIterator* iterator)
+{
+    psMetadataItem* oldValue;
+
+    PS_PTR_CHECK_NULL(iterator,NULL);
+
+    psListIterator* iter = iterator->iter;
+    PS_PTR_CHECK_NULL(iterator->iter,NULL);
+
+    regex_t* preg = iterator->preg;
+
+    // handle trivial case where no regex subsetting is required.
+    if (preg == NULL) {
+        return (psMetadataItem*)psListGetAndDecrement(iter);
+    }
+
+    oldValue = (psMetadataItem*)iter->cursor;
+
+    while (psListGetAndDecrement(iter) != NULL) {
+        if (iter->cursor != NULL &&
+                regexec(preg, ((psMetadataItem*)iter->cursor)->name, 0, NULL, 0) == 0) {
+            // this key is a match
+            break;
+        }
+    }
+    return oldValue;
+}
Index: trunk/psLib/src/collections/psMetadata.h
===================================================================
--- trunk/psLib/src/collections/psMetadata.h	(revision 3341)
+++ trunk/psLib/src/collections/psMetadata.h	(revision 3381)
@@ -11,6 +11,6 @@
 *  @author Ross Harman, MHPCC
 *
-*  @version $Revision: 1.38 $ $Name: not supported by cvs2svn $
-*  @date $Date: 2005-02-28 23:34:10 $
+*  @version $Revision: 1.39 $ $Name: not supported by cvs2svn $
+*  @date $Date: 2005-03-07 20:58:50 $
 *
 *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
@@ -21,4 +21,6 @@
 #include <stdarg.h>
 #include <stdio.h>
+#include <sys/types.h>
+#include <regex.h>
 
 #include "psHash.h"
@@ -35,8 +37,8 @@
  */
 typedef enum {
-    PS_META_S32,                       ///< Primitive data.
-    PS_META_F32,                       ///< Primitive data.
-    PS_META_F64,                       ///< Primitive data.
-    PS_META_BOOL,                       ///< Primitive data.
+    PS_META_S32,                       ///< psS32 primitive data.
+    PS_META_F32,                       ///< psF32 primitive data.
+    PS_META_F64,                       ///< psF64 primitive data.
+    PS_META_BOOL,                      ///< psBool primitive data.
     PS_META_LIST,                      ///< List data (Stored as item.data.list).
     PS_META_STR,                       ///< String data (Stored as item.data.V).
@@ -49,4 +51,5 @@
     PS_META_ASTROM,                    ///< Astrometric coefficients (Stored as item.data.V).
     PS_META_UNKNOWN,                   ///< Other data (Stored as item.data.V).
+    PS_META_MULTI,                     ///< Used internally, do not create an metadata item of this type.
     PS_META_NTYPE                      ///< Number of types. Must be last.
 } psMetadataType;
@@ -72,6 +75,10 @@
 typedef enum {
     PS_META_DEFAULT = 0,               ///< default behaviour (duplicate entry is an error)
-    PS_META_REPLACE = 0x10000          ///< allow entry to be replaced
+    PS_META_REPLACE = 0x1000000,       ///< allow entry to be replaced
+    PS_META_DUPLICATE_OK = 0x2000000   ///< allow duplicate entries
 } psMetadataFlags;
+
+#define PS_METADATA_FLAGS_MASK 0xFF000000
+#define PS_METADATA_TYPE_MASK 0x00FFFFFF
 
 /** Metadata data structure.
@@ -88,4 +95,16 @@
 }
 psMetadata;
+
+/** Metadata iterator
+ *
+ *  Iterator for metadata.
+ */
+typedef struct
+{
+    psListIterator* iter;              ///< iterator for the psMetadata's psList
+    regex_t* preg;                     ///< the subsetting regular expression
+}
+psMetadataIterator;
+
 
 /** Metadata item data structure.
@@ -134,32 +153,67 @@
 );
 
+/** Create a metadata item with specified string data.
+ *
+ *  Returns a fill psMetadataItem ready for insertion into the psMetadata
+ *  struct.
+ *
+ * @return psMetadataItem* : Pointer metadata item.
+ */
 psMetadataItem* psMetadataItemAllocStr(
-    const char* name,
-    const char* comment,
-    const char* value
-);
-
+    const char* name,                  ///< Name of metadata item.
+    const char* comment,               ///< Comment for metadata item.
+    const char* value                  ///< the value of the metadata item.
+);
+
+/** Create a metadata item with specified psF32 data.
+ *
+ *  Returns a fill psMetadataItem ready for insertion into the psMetadata
+ *  struct.
+ *
+ * @return psMetadataItem* : Pointer metadata item.
+ */
 psMetadataItem* psMetadataItemAllocF32(
-    const char* name,
-    const char* comment,
-    psF32 value
-);
-
+    const char* name,                  ///< Name of metadata item.
+    const char* comment,               ///< Comment for metadata item.
+    psF32 value                        ///< the value of the metadata item.
+);
+
+/** Create a metadata item with specified psF64 data.
+ *
+ *  Returns a fill psMetadataItem ready for insertion into the psMetadata
+ *  struct.
+ *
+ * @return psMetadataItem* : Pointer metadata item.
+ */
 psMetadataItem* psMetadataItemAllocF64(
-    const char* name,
-    const char* comment,
-    psF64 value
-);
-
+    const char* name,                  ///< Name of metadata item.
+    const char* comment,               ///< Comment for metadata item.
+    psF64 value                        ///< the value of the metadata item.
+);
+
+/** Create a metadata item with specified psS32 data.
+ *
+ *  Returns a fill psMetadataItem ready for insertion into the psMetadata
+ *  struct.
+ *
+ * @return psMetadataItem* : Pointer metadata item.
+ */
 psMetadataItem* psMetadataItemAllocS32(
-    const char* name,
-    const char* comment,
-    psS32 value
-);
-
+    const char* name,                  ///< Name of metadata item.
+    const char* comment,               ///< Comment for metadata item.
+    psS32 value                        ///< the value of the metadata item.
+);
+
+/** Create a metadata item with specified psBool data.
+ *
+ *  Returns a fill psMetadataItem ready for insertion into the psMetadata
+ *  struct.
+ *
+ * @return psMetadataItem* : Pointer metadata item.
+ */
 psMetadataItem* psMetadataItemAllocBool(
-    const char* name,
-    const char* comment,
-    psBool value
+    const char* name,                  ///< Name of metadata item.
+    const char* comment,               ///< Comment for metadata item.
+    psBool value                       ///< the value of the metadata item.
 );
 
@@ -207,5 +261,6 @@
     psMetadata*  md,                   ///< Metadata collection to insert metadat item.
     psMetadataItem*  item,             ///< Metadata item to be added.
-    psS32 location                     ///< Location to be added.
+    psS32 location,                    ///< Location to be added.
+    psS32 flags                        ///< Options flag mask, see psMetadataFlags enum
 );
 
@@ -218,30 +273,47 @@
 psBool psMetadataAdd(
     psMetadata* md,                    ///< Metadata collection to insert metadat item.
-    psS32 where,                       ///< Location to be added.
+    psS32 location,                    ///< Location to be added.
     const char *name,                  ///< Name of metadata item.
-    psMetadataType type,               ///< Type of metadata item.
+    int type,                          ///< Type of metadata item (psMetadataType) and options (psMetadataFlags)
     const char *comment,               ///< Comment for metadata item.
     ...                                ///< Arguments for name formatting and metadata item data.
 );
 
-psBool psMetadataAddS32(psMetadata* md, psS32 where, const char* name,
+#ifndef SWIG
+/** Create and add a metadata item to metadata collection.
+ *
+ * Creates a new metadata item add to the metadata collection.
+ *
+ * @return bool: True for success, false for failure.
+ */
+psBool psMetadataAddV(
+    psMetadata* md,                    ///< Metadata collection to insert metadat item.
+    psS32 location,                    ///< Location to be added.
+    const char *name,                  ///< Name of metadata item.
+    int type,                          ///< Type of metadata item (psMetadataType) and options (psMetadataFlags)
+    const char *comment,               ///< Comment for metadata item.
+    va_list list                       ///< Arguments for name formatting and metadata item data.
+);
+#endif
+
+psBool psMetadataAddS32(psMetadata* md, psS32 location, const char* name,
                         const char* comment, psS32 value);
-psBool psMetadataAddF32(psMetadata* md, psS32 where, const char* name,
+psBool psMetadataAddF32(psMetadata* md, psS32 location, const char* name,
                         const char* comment, psF32 value);
-psBool psMetadataAddF64(psMetadata* md, psS32 where, const char* name,
+psBool psMetadataAddF64(psMetadata* md, psS32 location, const char* name,
                         const char* comment, psF64 value);
-psBool psMetadataAddList(psMetadata* md, psS32 where, const char* name,
+psBool psMetadataAddList(psMetadata* md, psS32 location, const char* name,
                          const char* comment, psList* value);
-psBool psMetadataAddStr(psMetadata* md, psS32 where, const char* name,
+psBool psMetadataAddStr(psMetadata* md, psS32 location, const char* name,
                         const char* comment, const char* value);
-psBool psMetadataAddVector(psMetadata* md, psS32 where, const char* name,
+psBool psMetadataAddVector(psMetadata* md, psS32 location, const char* name,
                            const char* comment, psVector* value);
-psBool psMetadataAddImage(psMetadata* md, psS32 where, const char* name,
+psBool psMetadataAddImage(psMetadata* md, psS32 location, const char* name,
                           const char* comment, psImage* value);
-psBool psMetadataAddHash(psMetadata* md, psS32 where, const char* name,
+psBool psMetadataAddHash(psMetadata* md, psS32 location, const char* name,
                          const char* comment, psHash* value);
-psBool psMetadataAddLookupTable(psMetadata* md, psS32 where, const char* name,
+psBool psMetadataAddLookupTable(psMetadata* md, psS32 location, const char* name,
                                 const char* comment, psLookupTable* value);
-psBool psMetadataAddUnknown(psMetadata* md, psS32 where, const char* name,
+psBool psMetadataAddUnknown(psMetadata* md, psS32 location, const char* name,
                             const char* comment, psPtr value);
 
@@ -340,5 +412,5 @@
  * @return void* : Value of metadata item.
  */
-void* psMetadataLookupPtr(
+psPtr psMetadataLookupPtr(
     psBool *status,                    ///< Status of lookup.
     psMetadata* md,                    ///< Metadata collection to lookup metadata item.
@@ -354,6 +426,53 @@
  */
 psMetadataItem* psMetadataGet(
-    psMetadata*  md,           ///< Metadata collection to insert metadat item.
-    psS32 where                ///< Location to be retrieved.
+    psMetadata*  md,                   ///< Metadata collection to insert metadat item.
+    psS32 location                     ///< Location to be retrieved.
+);
+
+/** Creates a psMetadataIterator to iterate over the specified psMetadata.
+ *
+ *  Supports the subsetting of the metadata via keyword using regular
+ *  expression.  If no regular expression is specified, iteration
+ *  over the entire psMetadata is performed.
+ *
+ *  @return psMetadataIterator*        a new psMetadataIterator, of NULL if error occurred
+ */
+psMetadataIterator* psMetadataIteratorAlloc(
+    psMetadata* md,                    ///< the psMetadata to iterate with
+    int location,                      ///< the initial starting point (after subsetting).
+    const char* regex
+    ///< A regular expression for subsetting the psMetadata.  If NULL, no
+    ///< subsetting is performed.
+);
+
+/** Set the iterator of the psMetadat to a given position.  If location is
+ *  invalid the iterator position is not changed.
+ *
+ *  @return psBool        TRUE if iterator successfully set, otherwise FALSE.
+*/
+psBool psMetadataIteratorSet(
+    psMetadataIterator* iterator,      ///< psMetadata iterator
+    int location                       ///< index number, PS_LIST_HEAD, or PS_LIST_TAIL
+);
+
+/** Position the specified iterator to the next matching item in psMetadata,
+ *  given the regular expression of the iterator
+ *
+ *  @return psPtr       the psMetadataItem at the original iterator position
+ *                      or NULL if the iterator went past the end of the list.
+ */
+psMetadataItem* psMetadataGetAndIncrement(
+    psMetadataIterator* iterator           ///< iterator to move
+);
+
+/** Position the specified iterator to the previous matching item in psMetadata,
+ *  given the regular expression of the iterator
+ *
+ *  @return psPtr       the psMetadataItem at the original iterator position
+ *                      or NULL if the iterator went past the beginning of the
+ *                      list.
+ */
+psMetadataItem* psMetadataGetAndDecrement(
+    psMetadataIterator* iterator           ///< iterator to move
 );
 
Index: trunk/psLib/src/collections/psMetadataIO.c
===================================================================
--- trunk/psLib/src/collections/psMetadataIO.c	(revision 3341)
+++ trunk/psLib/src/collections/psMetadataIO.c	(revision 3381)
@@ -9,6 +9,6 @@
 *  @author Ross Harman, MHPCC
 *
-*  @version $Revision: 1.21 $ $Name: not supported by cvs2svn $
-*  @date $Date: 2005-02-28 23:34:10 $
+*  @version $Revision: 1.22 $ $Name: not supported by cvs2svn $
+*  @date $Date: 2005-03-07 20:58:50 $
 *
 *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
@@ -410,18 +410,22 @@
         switch (keyType) {
         case 'I':
-            success = psMetadataAdd(output, PS_LIST_TAIL, keyName, PS_META_S32,
+            success = psMetadataAdd(output, PS_LIST_TAIL, keyName,
+                                    PS_META_S32 | PS_META_DUPLICATE_OK,
                                     keyComment, atoi(keyValue));
             break;
         case 'F':
-            success = psMetadataAdd(output, PS_LIST_TAIL, keyName, PS_META_F64,
+            success = psMetadataAdd(output, PS_LIST_TAIL, keyName,
+                                    PS_META_F64 | PS_META_DUPLICATE_OK,
                                     keyComment, atof(keyValue));
             break;
         case 'C':
-            success = psMetadataAdd(output, PS_LIST_TAIL, keyName, PS_META_STR,
+            success = psMetadataAdd(output, PS_LIST_TAIL, keyName,
+                                    PS_META_STR | PS_META_DUPLICATE_OK,
                                     keyComment, keyValue);
             break;
         case 'L':
             tempBool = (keyValue[0] == 'T') ? 1 : 0;
-            success = psMetadataAdd(output, PS_LIST_TAIL, keyName, PS_META_BOOL,
+            success = psMetadataAdd(output, PS_LIST_TAIL, keyName,
+                                    PS_META_BOOL | PS_META_DUPLICATE_OK,
                                     keyComment, tempBool);
             break;
@@ -456,9 +460,9 @@
     psF64 tempDbl = 0.0;
     psS32 tempInt = 0.0;
-    psMetadataItem *metadataItem = NULL;
     psVector *tempVec = NULL;
     FILE *fp = NULL;
     psMetadataType mdType;
-
+    psMetadataFlags flags;
+    psBool addStatus;
 
     // Check for nulls
@@ -516,4 +520,6 @@
             }
 
+            flags = (overwrite) ? PS_META_REPLACE : PS_META_DEFAULT;
+
             // Get the metadata item type
             strType = getToken(&linePtr, " ", &status);
@@ -524,21 +530,27 @@
                         fileName);
                 continue;
-            } else if(!strncmp(strType, "*", 1)) {
-                mdType = PS_META_LIST;
-            } else if(!strncmp(strType, "STR", 3)) {
-                mdType = PS_META_STR;
-            } else if(!strncmp(strType, "BOOL", 4)) {
-                mdType = PS_META_BOOL;
-            } else if(!strncmp(strType, "S32", 3)) {
-                mdType = PS_META_S32;
-            } else if(!strncmp(strType, "F32", 3)) {
-                mdType = PS_META_F32;
-            } else if(!strncmp(strType, "F64", 3)) {
-                mdType = PS_META_F64;
             } else {
-                (*nFail)++;
-                psError(PS_ERR_IO, true, PS_ERRORTEXT_psMetadataIO_FILE_TYPE_INVALID, strType, lineCount,
-                        fileName);
-                continue;
+                char* tempStrType = strType;
+                if(*strType == '*') {
+                    flags = PS_META_DUPLICATE_OK;
+                    tempStrType = strType+1;
+                }
+
+                if(!strncmp(tempStrType, "STR", 3)) {
+                    mdType = PS_META_STR;
+                } else if(!strncmp(tempStrType, "BOOL", 4)) {
+                    mdType = PS_META_BOOL;
+                } else if(!strncmp(tempStrType, "S32", 3)) {
+                    mdType = PS_META_S32;
+                } else if(!strncmp(tempStrType, "F32", 3)) {
+                    mdType = PS_META_F32;
+                } else if(!strncmp(tempStrType, "F64", 3)) {
+                    mdType = PS_META_F64;
+                } else {
+                    (*nFail)++;
+                    psError(PS_ERR_IO, true, PS_ERRORTEXT_psMetadataIO_FILE_TYPE_INVALID, strType, lineCount,
+                            fileName);
+                    continue;
+                }
             }
 
@@ -548,17 +560,22 @@
             }
 
-            // Get the metadata item value if there is one. Lines with * don't have values.
-            if(mdType != PS_META_LIST) {
-                strValue = getToken(&linePtr, "#", &status);
-                if(strValue==NULL) {
-                    (*nFail)++;
-                    status = 0;
-                    psError(PS_ERR_IO, true, PS_ERRORTEXT_psMetadataIO_FILE_ELEMENT_NULL, "value", lineCount,
-                            fileName);
-                    continue;
-                }
-            }
-
-            // Get the metadata item value if there is one. Not all lines will have comments, so NULL is ok.
+            // Get the metadata item value if there is one.
+            strValue = getToken(&linePtr, "#", &status);
+            if(status) {
+                (*nFail)++;
+                status = 0;
+                psError(PS_ERR_IO, true, PS_ERRORTEXT_psMetadataIO_FILE_ELEMENT_NULL, "comment", lineCount,
+                        fileName);
+                continue;
+            }
+            if(strValue==NULL) {
+                (*nFail)++;
+                status = 0;
+                psError(PS_ERR_IO, true, PS_ERRORTEXT_psMetadataIO_FILE_ELEMENT_NULL, "value", lineCount,
+                        fileName);
+                continue;
+            }
+
+            // Not all lines will have comments, so NULL is ok.
             strComment = getToken(&linePtr,"~", &status);
             if(status) {
@@ -570,33 +587,17 @@
             }
 
-            /* If metadata item is found, is not a folder node, and overwrite is allowed, then remove existing
-            and allow switch/case below to add new item. If overwrite is false, then report error. If found
-            item is folder node, then psMetadataAdd will automatically add a new child. */
-            metadataItem = psMetadataLookup(md, strName);
-            if(metadataItem != NULL) {
-                if(metadataItem->type!=PS_META_LIST) {
-                    if(overwrite) {
-                        psMetadataRemove(md, INT_MIN, strName);
-                    } else {
-                        (*nFail)++;
-                        psError(PS_ERR_IO, true, PS_ERRORTEXT_psMetadataIO_OVERWRITE_ITEM, strName, lineCount,
-                                fileName);
-                        continue;
-                    }
-                }
-            }
-
             // Create and add metadata item to metadata and parse values
             switch (mdType) {
-            case PS_META_LIST:
-                psMetadataAdd(md, PS_LIST_TAIL, strName, mdType, NULL, NULL);
-                break;
             case PS_META_STR:
-                psMetadataAdd(md, PS_LIST_TAIL, strName, mdType, strComment, strValue);
+                addStatus = psMetadataAdd(md, PS_LIST_TAIL, strName,
+                                          mdType | flags,
+                                          strComment, strValue);
                 break;
             case PS_META_VEC:
                 tempVec = parseVector(strValue, vecType, &status);
                 if(!status) {
-                    psMetadataAdd(md, PS_LIST_TAIL, strName+1, mdType, strComment, tempVec);
+                    addStatus = psMetadataAdd(md, PS_LIST_TAIL, strName+1,
+                                              mdType | flags,
+                                              strComment, tempVec);
                 } else {
                     status = 0;
@@ -611,5 +612,7 @@
                 tempBool = parseBool(strValue, &status);
                 if(!status) {
-                    psMetadataAdd(md, PS_LIST_TAIL, strName, mdType, strComment, tempBool);
+                    addStatus = psMetadataAdd(md, PS_LIST_TAIL, strName,
+                                              mdType | flags,
+                                              strComment, tempBool);
                 } else {
                     status = 0;
@@ -623,5 +626,7 @@
                 tempInt = (psS32)parseValue(strValue, &status);
                 if(!status) {
-                    psMetadataAdd(md, PS_LIST_TAIL, strName, mdType, strComment, tempInt);
+                    addStatus = psMetadataAdd(md, PS_LIST_TAIL, strName,
+                                              mdType | flags,
+                                              strComment, tempInt);
                 } else {
                     status = 0;
@@ -636,5 +641,7 @@
                 tempDbl = parseValue(strValue, &status);
                 if(!status) {
-                    psMetadataAdd(md, PS_LIST_TAIL, strName, mdType, strComment, tempDbl);
+                    addStatus = psMetadataAdd(md, PS_LIST_TAIL, strName,
+                                              mdType | flags,
+                                              strComment, tempDbl);
                 } else {
                     status = 0;
@@ -652,4 +659,10 @@
                 continue;
             } // switch
+            if (! addStatus) {
+                (*nFail)++;
+                psError(PS_ERR_IO, true, PS_ERRORTEXT_psMetadataIO_OVERWRITE_ITEM, strName, lineCount,
+                        fileName);
+            }
+
         } // if ignoreLine
     } // while loop
@@ -725,5 +738,7 @@
     // Add attributes to metadata
 
-    psMetadataAdd(md, PS_LIST_TAIL, "htAtts", PS_META_HASH, NULL, htAtts);
+    psMetadataAdd(md, PS_LIST_TAIL, "htAtts",
+                  PS_META_HASH | PS_META_DUPLICATE_OK,
+                  NULL, htAtts);
 
     psFree(psTagName);
@@ -828,13 +843,19 @@
     switch(mdType) {
     case PS_META_LIST:
-        psMetadataAdd(md, PS_LIST_TAIL, strName, mdType, NULL, NULL);
+        psMetadataAdd(md, PS_LIST_TAIL, strName,
+                      mdType | PS_META_DUPLICATE_OK,
+                      NULL, NULL);
         break;
     case PS_META_STR:
-        psMetadataAdd(md, PS_LIST_TAIL, strName, mdType, NULL, strValue);
+        psMetadataAdd(md, PS_LIST_TAIL, strName,
+                      mdType | PS_META_DUPLICATE_OK,
+                      NULL, strValue);
         break;
     case PS_META_BOOL:
         tempBool = parseBool((char*)strValue, &status);
         if(!status) {
-            psMetadataAdd(md, PS_LIST_TAIL, strName, mdType, NULL, tempBool);
+            psMetadataAdd(md, PS_LIST_TAIL, strName,
+                          mdType | PS_META_DUPLICATE_OK,
+                          NULL, tempBool);
         } else {
             status = 0;
@@ -846,5 +867,7 @@
         tempInt = (psS32)parseValue((char*)strValue, &status);
         if(!status) {
-            psMetadataAdd(md, PS_LIST_TAIL, strName, mdType, NULL, tempInt);
+            psMetadataAdd(md, PS_LIST_TAIL, strName,
+                          mdType | PS_META_DUPLICATE_OK,
+                          NULL, tempInt);
         } else {
             status = 0;
@@ -857,5 +880,7 @@
         tempDbl = parseValue((char*)strValue, &status);
         if(!status) {
-            psMetadataAdd(md, PS_LIST_TAIL, strName, mdType, NULL, tempDbl);
+            psMetadataAdd(md, PS_LIST_TAIL, strName,
+                          mdType | PS_META_DUPLICATE_OK,
+                          NULL, tempDbl);
         } else {
             status = 0;
@@ -966,5 +991,7 @@
     vec = parseVector((char*)strValue, pType, &status);
     if(!status) {
-        psMetadataAdd(md, PS_LIST_TAIL, strName+1, PS_META_VEC, NULL, vec);
+        psMetadataAdd(md, PS_LIST_TAIL, strName+1,
+                      PS_META_VEC | PS_META_DUPLICATE_OK,
+                      NULL, vec);
     } else {
         psError(PS_ERR_IO, true, PS_ERRORTEXT_psMetadataIO_PARSE_FAILED, strValue, strName, strType,
Index: trunk/psLib/src/collections/psMetadataIO.h
===================================================================
--- trunk/psLib/src/collections/psMetadataIO.h	(revision 3341)
+++ trunk/psLib/src/collections/psMetadataIO.h	(revision 3381)
@@ -1,20 +1,20 @@
 /** @file  psMetadataIO.h
-*
-*  @brief Contains metadata input/output functions.
-*
-*  This file defines functions to read and write metadata to/from an external file.
-*
-*  @ingroup Metadata
-*
-*  @author Ross Harman, MHPCC
-*
-*  @version $Revision: 1.8 $ $Name: not supported by cvs2svn $
-*  @date $Date: 2005-02-17 19:26:23 $
-*
-*  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
-*/
+ *
+ *  @brief Contains metadata input/output functions.
+ *
+ *  This file defines functions to read and write metadata to/from an external file.
+ *
+ *  @ingroup Metadata
+ *
+ *  @author Ross Harman, MHPCC
+ *  @author Robert DeSonia, MHPCC
+ *
+ *  @version $Revision: 1.9 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2005-03-07 20:58:50 $
+ *
+ *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
+ */
 #ifndef PS_METADATAIO_H
 #define PS_METADATAIO_H
-
 
 /// @addtogroup Metadata
