Index: /trunk/psLib/src/types/psMetadata.c
===================================================================
--- /trunk/psLib/src/types/psMetadata.c	(revision 12531)
+++ /trunk/psLib/src/types/psMetadata.c	(revision 12532)
@@ -12,6 +12,6 @@
  *  @author Ross Harman, MHPCC
  *
- *  @version $Revision: 1.155 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2007-03-16 01:46:56 $
+ *  @version $Revision: 1.156 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2007-03-22 01:14:52 $
  *
  *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
@@ -463,6 +463,6 @@
         psMetadataItem *newItem = psMetadataItemCopy(inItem); // Copied item
         if (!psMetadataAddItem(out, newItem, PS_LIST_TAIL, flag)) {
-            psErrorStackPrint(stderr, "Error copying %s (%s) in the metadata\n", inItem->name,
-                              inItem->comment);
+            psError(PS_ERR_UNKNOWN, false, "Error copying %s (%s) in the metadata\n", 
+		    inItem->name, inItem->comment);
             if (outAlloced) {
                 psFree(out);
@@ -483,4 +483,42 @@
 
     return out;
+}
+
+// this function copies the input metadata to the output, raising an error
+// if any entries in 'in' a) do not exist in 'out' or b) have a different type
+bool p_psMetadataUpdate(const char *file,
+			unsigned int lineno,
+			const char *func,
+			psMetadata *out,
+			const psMetadata *in)
+{
+    PS_ASSERT_METADATA_NON_NULL(in, NULL);
+    PS_ASSERT_METADATA_NON_NULL(out, NULL);
+
+    psMetadataIterator *iter = psMetadataIteratorAlloc(in, PS_LIST_HEAD, NULL);
+    psMetadataItem *inItem = NULL;
+    while ((inItem = psMetadataGetAndIncrement(iter))) {
+        // Need to look for MULTI, which won't be picked up using the iterator.
+        psMetadataItem *multiCheckItem = psMetadataLookup(in, inItem->name);
+        unsigned int flag = PS_META_REPLACE | PS_META_REQUIRE_ENTRY | PS_META_REQUIRE_TYPE; // Flag to indicate MULTI; otherwise, replace
+        if (multiCheckItem->type == PS_DATA_METADATA_MULTI) {
+            psTrace("psLib.types", 10, "MULTI: %s (%s)\n", inItem->name, inItem->comment);
+            flag = PS_META_DUPLICATE_OK | PS_META_REQUIRE_ENTRY | PS_META_REQUIRE_TYPE;
+        }
+        psTrace("psLib.types", 5, "Copying %s (%s)...\n", inItem->name, inItem->comment);
+
+        // Copy the item and add it on
+        psMetadataItem *newItem = psMetadataItemCopy(inItem); // Copied item
+        if (!psMetadataAddItem(out, newItem, PS_LIST_TAIL, flag)) {
+            psError(PS_ERR_UNKNOWN, false, "Error copying %s (%s) in the metadata\n", 
+		    inItem->name, inItem->comment);
+	    psFree(newItem);
+	    psFree(iter);
+	    return false;
+        }
+        psFree(newItem);                // Drop reference
+    }
+    psFree(iter);
+    return true;
 }
 
@@ -572,4 +610,9 @@
         } else if ((flags & PS_META_REPLACE) != 0) {
             // replace entry instead of creating a duplicate entry.
+
+	    if ((flags & PS_META_REQUIRE_TYPE) && (existingEntry->type != item->type)) {
+		psError (PS_ERR_UNKNOWN, true, _("existing item does not match type for item requiring matching type"));
+		return false;
+	    }
 
             // remove the existing entry from metadata
@@ -601,4 +644,8 @@
     } else {
         // OK, this is a new item.
+	if (flags & PS_META_REQUIRE_ENTRY) {
+	    psError (PS_ERR_UNKNOWN, true, _("no matching item found for item requiring existing entry"));
+	    return false;
+	}
 
         // Node doesn't exist - Add new metadata item to metadata collection's hash
Index: /trunk/psLib/src/types/psMetadata.h
===================================================================
--- /trunk/psLib/src/types/psMetadata.h	(revision 12531)
+++ /trunk/psLib/src/types/psMetadata.h	(revision 12532)
@@ -9,6 +9,6 @@
 *  @author Ross Harman, MHPCC
 *
-*  @version $Revision: 1.100 $ $Name: not supported by cvs2svn $
-*  @date $Date: 2007-03-17 02:38:53 $
+*  @version $Revision: 1.101 $ $Name: not supported by cvs2svn $
+*  @date $Date: 2007-03-22 01:14:52 $
 *
 *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
@@ -61,5 +61,7 @@
     PS_META_NO_REPLACE = 0x2000000,    ///< duplicate entry is silently skipped
     PS_META_DUPLICATE_OK = 0x4000000,  ///< allow duplicate entries
-    PS_META_NULL = 0x8000000           ///< psMetadataItem.data is a NULL value
+    PS_META_NULL = 0x8000000,           ///< psMetadataItem.data is a NULL value
+    PS_META_REQUIRE_ENTRY = 0x10000000,	///< require pre-existing entry with same name
+    PS_META_REQUIRE_TYPE = 0x20000000	///< require pre-existing entry to have same type
 } psMetadataFlags;
 
@@ -480,4 +482,29 @@
 
 
+/** Updates an existing psMetadata collection with elements from a metadata collection
+ *
+ *  Creates a new copy of all the psMetadataItems in the psMetadata collection 'in' and places
+ *  them in out.  all items in 'in' must already be in 'out' and be of the same type.
+ *
+ *  @return psMetadata*:        the copy of the psMetadata container.
+ */
+#ifdef DOXYGEN
+bool psMetadataUpdate(
+    psMetadata *out,                   ///< output Metadata container for copying.
+    const psMetadata *in               ///< Metadata collection to be copied.
+    );
+#else // ifdef DOXYGEN
+bool p_psMetadataUpdate(
+    const char *file,                   ///< File of caller
+    unsigned int lineno,                ///< Line number of caller
+    const char *func,                   ///< Function name of caller
+    psMetadata *out,                    ///< output Metadata container for copying.
+    const psMetadata *in                ///< Metadata collection to be copied.
+    );
+#define psMetadataUpdate(out, in) \
+      p_psMetadataUpdate(__FILE__, __LINE__, __func__, out, in)
+#endif // ifdef DOXYGEN
+
+
 /** Supplements a metadata with an item from another metadata.
  *
Index: /trunk/psLib/test/types/.cvsignore
===================================================================
--- /trunk/psLib/test/types/.cvsignore	(revision 12531)
+++ /trunk/psLib/test/types/.cvsignore	(revision 12532)
@@ -74,2 +74,4 @@
 tap_psMetadata_printing
 tap_psPixels_all
+
+tap_psMetadataUpdate
Index: /trunk/psLib/test/types/Makefile.am
===================================================================
--- /trunk/psLib/test/types/Makefile.am	(revision 12531)
+++ /trunk/psLib/test/types/Makefile.am	(revision 12532)
@@ -18,4 +18,5 @@
 	tap_psMetadataItemCompare \
 	tap_psMetadataItemParse \
+	tap_psMetadataUpdate \
 	tap_psMetadata_printing \
 	tap_psMetadata_copying \
Index: /trunk/psLib/test/types/tap_psMetadataUpdate.c
===================================================================
--- /trunk/psLib/test/types/tap_psMetadataUpdate.c	(revision 12532)
+++ /trunk/psLib/test/types/tap_psMetadataUpdate.c	(revision 12532)
@@ -0,0 +1,140 @@
+/**
+*  C Implementation: tap_psMetadataUpdate
+*
+* Description: Tests for psMetadataUpdate, psMetadataItemAdd for PS_META_REQUIRE_ENTRY and
+* PS_META_REQUIRE_TYPE
+*
+* Author: Eugene Magnier
+* Copyright: See COPYING file that comes with this distribution
+*
+*/
+
+#include <pslib.h>
+#include <string.h>
+
+#include "tap.h"
+#include "pstap.h"
+
+int main(void)
+{
+    plan_tests(16);
+
+    note("psMetadataUpdate Tests");
+
+    {
+        psMemId id = psMemGetId();
+
+	psMetadata *md = psMetadataAlloc();
+	psMetadataAddS32 (md, PS_LIST_TAIL, "TEST1", 0, "", 1);
+	bool status = psMetadataAddF32 (md, PS_LIST_TAIL, "TEST1", PS_META_REPLACE | PS_META_REQUIRE_ENTRY, "", 1);
+	ok (status, "PS_META_REQUIRE_ENTRY : psMetadataAdd should not fail if item already exists");
+	psFree (md);
+        ok(!psMemCheckLeaks (id, NULL, NULL, false), "no memory leaks");
+    }
+
+    {
+        psMemId id = psMemGetId();
+
+	psMetadata *md = psMetadataAlloc();
+	psMetadataAddS32 (md, PS_LIST_TAIL, "TEST1", 0, "", 1);
+	bool status = psMetadataAddF32 (md, PS_LIST_TAIL, "TEST2", PS_META_REPLACE | PS_META_REQUIRE_ENTRY, "", 1);
+	ok (!status, "PS_META_REQUIRE_ENTRY : psMetadataAdd should fail if item does not already exist");
+	psFree (md);
+        ok(!psMemCheckLeaks (id, NULL, NULL, false), "no memory leaks");
+    }
+
+    {
+        psMemId id = psMemGetId();
+
+	psMetadata *md = psMetadataAlloc();
+	psMetadataAddS32 (md, PS_LIST_TAIL, "TEST1", 0, "", 1);
+	bool status = psMetadataAddF32 (md, PS_LIST_TAIL, "TEST2", PS_META_REPLACE | PS_META_REQUIRE_TYPE, "", 1);
+	ok (status, "PS_META_REQUIRE_TYPE : psMetadataAdd should not fail if item does not already exist");
+	psFree (md);
+        ok(!psMemCheckLeaks (id, NULL, NULL, false), "no memory leaks");
+    }
+
+    {
+        psMemId id = psMemGetId();
+
+	psMetadata *md = psMetadataAlloc();
+	psMetadataAddS32 (md, PS_LIST_TAIL, "TEST1", 0, "", 1);
+	bool status = psMetadataAddS32 (md, PS_LIST_TAIL, "TEST1", PS_META_REPLACE | PS_META_REQUIRE_TYPE, "", 1);
+	ok (status, "PS_META_REQUIRE_TYPE : psMetadataAdd should not fail if existing item has the same type");
+	psFree (md);
+        ok(!psMemCheckLeaks (id, NULL, NULL, false), "no memory leaks");
+    }
+
+    {
+        psMemId id = psMemGetId();
+
+	psMetadata *md = psMetadataAlloc();
+	psMetadataAddS32 (md, PS_LIST_TAIL, "TEST1", 0, "", 1);
+	bool status = psMetadataAddF32 (md, PS_LIST_TAIL, "TEST1", PS_META_REPLACE | PS_META_REQUIRE_TYPE, "", 1);
+	ok (!status, "PS_META_REQUIRE_TYPE : psMetadataAdd should fail if existing item does not match type");
+	psFree (md);
+        ok(!psMemCheckLeaks (id, NULL, NULL, false), "no memory leaks");
+    }
+
+    {
+        psMemId id = psMemGetId();
+
+	psMetadata *input = psMetadataAlloc();
+	psMetadata *output = psMetadataAlloc();
+
+	psMetadataAddS32 (input, PS_LIST_TAIL, "TEST1", 0, "", 2);
+	psMetadataAddS32 (input, PS_LIST_TAIL, "TEST2", 0, "", 2);
+	psMetadataAddS32 (input, PS_LIST_TAIL, "TEST3", 0, "", 2);
+
+	psMetadataAddS32 (output, PS_LIST_TAIL, "TEST1", 0, "", 1);
+	psMetadataAddS32 (output, PS_LIST_TAIL, "TEST2", 0, "", 1);
+	psMetadataAddS32 (output, PS_LIST_TAIL, "TEST3", 0, "", 1);
+
+	bool status = psMetadataUpdate (output, input);
+	ok (status, "psMetadataUpdate should not fail if items all exist and match type");
+	psFree (input);
+	psFree (output);
+        ok(!psMemCheckLeaks (id, NULL, NULL, false), "no memory leaks");
+    }
+
+    {
+        psMemId id = psMemGetId();
+
+	psMetadata *input = psMetadataAlloc();
+	psMetadata *output = psMetadataAlloc();
+
+	psMetadataAddS32 (input, PS_LIST_TAIL, "TEST1", 0, "", 2);
+	psMetadataAddS32 (input, PS_LIST_TAIL, "TEST2", 0, "", 2);
+	psMetadataAddS32 (input, PS_LIST_TAIL, "TEST3", 0, "", 2);
+
+	psMetadataAddS32 (output, PS_LIST_TAIL, "TEST1", 0, "", 1);
+	psMetadataAddS32 (output, PS_LIST_TAIL, "TEST3", 0, "", 1);
+
+	bool status = psMetadataUpdate (output, input);
+	ok (!status, "psMetadataUpdate should fail if any input items do not exist in output");
+	psFree (input);
+	psFree (output);
+        ok(!psMemCheckLeaks (id, NULL, NULL, false), "no memory leaks");
+    }
+
+    {
+        psMemId id = psMemGetId();
+
+	psMetadata *input = psMetadataAlloc();
+	psMetadata *output = psMetadataAlloc();
+
+	psMetadataAddS32 (input, PS_LIST_TAIL, "TEST1", 0, "", 2);
+	psMetadataAddS32 (input, PS_LIST_TAIL, "TEST2", 0, "", 2);
+	psMetadataAddS32 (input, PS_LIST_TAIL, "TEST3", 0, "", 2);
+
+	psMetadataAddS32 (output, PS_LIST_TAIL, "TEST1", 0, "", 1);
+	psMetadataAddF32 (output, PS_LIST_TAIL, "TEST2", 0, "", 1);
+	psMetadataAddS32 (output, PS_LIST_TAIL, "TEST3", 0, "", 1);
+
+	bool status = psMetadataUpdate (output, input);
+	ok (!status, "psMetadataUpdate should fail if any input items do not match type in output");
+	psFree (input);
+	psFree (output);
+        ok(!psMemCheckLeaks (id, NULL, NULL, false), "no memory leaks");
+    }
+}
