Index: trunk/doc/draft/metadata.tex
===================================================================
--- trunk/doc/draft/metadata.tex	(revision 130)
+++ trunk/doc/draft/metadata.tex	(revision 179)
@@ -59,5 +59,6 @@
 \section{Metadata Representation}
 
-We propose that an item of metadata be represented as a C structure:
+We propose that an item of metadata be represented as a C structure with at least the following
+fields:
 \begin{verbatim}
 /*
@@ -75,6 +76,5 @@
     } val;                              // value of metadata
     char *comment;                      // optional comment ("", not NULL)
-
-} psMetaData;
+} psMetaDataItem;
 \end{verbatim}
 
@@ -89,5 +89,5 @@
 
 The possible types of metadata are identified by the enumerated type
-\code{psMetaDataType} (see also table \ref{tabMetaDataTypes}):
+\code{psMetaDataType} (see also table \ref{tabMetaDataTypes}); the initial defined values are:
 \begin{verbatim}
 /*
@@ -95,5 +95,5 @@
  */
 typedef enum {                          // type of val is:
-    psMetaFloat = 0,                    // float (.f)
+    psMetaFloat,                        // float (.f)
     psMetaInt,                          // int (.i)
     psMetaStr,                          // string (.v)
@@ -129,31 +129,51 @@
 \section{Collections of Metadata}
 
-We also need to support a container class for metadata.  We propose
-using the standard \PS{} doubly-linked list type \code{psDlist}
-(see \href{file:utils#psDlist}{utils.pdf} for details). For example:
-\begin{verbatim}
-    psDlist *list = psDlistNew(NULL);   // list of metadata
-
-    psDlistAppend(list, psMetaDataNew("const.ten", psMetaInt, &ten, NULL, 0));
-    psDlistAppend(list, psMetaDataNew("const.sqrt2", psMetaFloat, &sqrt2,
-                                      "square root of two", 0));
-    psDlistAppend(list, psMetaDataNew("lang.hello", psMetaStr, "Bonjour",
-                                      "French", 0));
-    /*
-     * Print all metadata to stdout
-     */
-    (void)psDlistGet(list, psDlistTail); // initialise iterator
-    while ((ms = psDlistGet(list, psDlistPrev)) != NULL) {
-        psMetaDataPrint(stdout, ms);
-    }
-    /*
-     * Clean up
-     */
-    psDlistDel(list, (void (*)(void *))psMetaDataDel);
+\begin{verbatim}
+typedef struct {
+    psDlist *list;			// list of psMetaDataItem
+    psHash *table;			// hash table of the same metadata
+} psMetaDataSet;
+\end{verbatim}
+
+The type \code{psMetaDataSet} is a container class for metadata. Note that there are
+in fact \emph{two} representations of the metadata (each \code{psMetaDataItem} appears
+on both).
+
+We are using the standard \PS{} doubly-linked list types \code{psDlist} and  \code{psHash}
+(see \href{file:utils#psDlist}{utils.pdf:psDlist} and \href{file:utils#psHash}{utils.pdf:psHash} for details).
+For example:
+\begin{verbatim}
+    for (int i = 0; i < 10; i += 5) {
+        float sqrti = sqrt(i);
+        psMetaDataAppend(ms, psMetaDataItemAlloc(PS_META_INT, &i, NULL, "const.%d", i));
+        psMetaDataAppend(ms, psMetaDataItemAlloc(PS_META_FLOAT, &sqrti, "square root", "const.sqrt%d", i));
+    }
+    psMetaDataAppend(ms, psMetaDataItemAlloc(PS_META_STR, "Bonjour", "French", "lang.hello"));
+    /*
+     * Remove a key
+     */
+    psMetaDataItemFree(psMetaDataRemove(ms, "lang.hello"));
+    /*
+     * Print all metadata
+     */
+    fprintf(stdout, "------\n");
+    psMetaDataSetIterator(ms);
+    while ((meta = psMetaDataGetNext(ms, NULL)) != NULL) {
+        psMetaDataItemPrint(stdout, meta, "");
+    }
+    /*
+     * Look up a key by name
+     */
+    fprintf(stdout, "------\n");
+    fprintf(stdout, "Looking up by name:\n");
+    meta = psMetaDataLookup(ms, "const.5");
+    if (meta != NULL) {
+        psMetaDataItemPrint(stdout, meta, "");
+    }
 \end{verbatim}
 
 \section{Naming convention for MetaData}
 
-The \code{psMetaData} struct includes a name.  This name should be of
+The \code{psMetaDataItem} struct includes a name.  This name should be of
 the form \code{name1.name2.name3$\cdots$}, e.g.\hfil\break
 \null\qquad\qquad\code{IPP.phase1.ota12.biassec}.
@@ -163,4 +183,64 @@
 all metadata names in use throughout the project.
 
+\subsection{Support for Multiple Values for a Given Name}
+
+\begin{verbatim}
+    psMetaDataAppend(ms, psMetaDataItemAlloc(PS_META_STR | PS_META_NON_UNIQUE,
+                                           "Bonjour", "French", "lang.hello"));
+    psMetaDataAppend(ms, psMetaDataItemAlloc(PS_META_STR | PS_META_NON_UNIQUE,
+                                           "Aloha", "Hawaiian", "lang.hello"));
+    psMetaDataAppend(ms, psMetaDataItemAlloc(PS_META_STR | PS_META_NON_UNIQUE,
+                                           "Good Morning", "English", "lang.hello"));
+    /*
+     * Print all metadata starting "lang"
+     */
+    psMetaDataSetIterator(ms);
+    while ((meta = psMetaDataGetNext(ms, "lang")) != NULL) {
+        psMetaDataItemPrint(stdout, meta, "");
+    }
+\end{verbatim}
+
+It is an unfortunate fact that certain metadata keywords (such as \code{COMMENT} in a FITS header)
+may be repeated with different values.  The \code{psMetaDataAppend} routine is required
+to check that all metadata names are unique unless the type is qualified as \code{PS_META_NON_UNIQUE};
+in this case a unique integer will be added to each name that you specify. In this case,
+you may either delete individual element separately or as a complete set:
+\begin{verbatim}
+psMetaDataItemFree(psMetaDataRemove(ms, "lang.hello.0"));
+psMetaDataItemFree(psMetaDataRemove(ms, "lang.hello"));
+\end{verbatim}
+
+\appendix
+\section{MetaData APIs}
+
+\begin{verbatim}
+psMetaDataItem *psMetaDataItemAlloc(
+    psMetaDataType type,		// type of this piece of metadata
+    const void *val,			// value of new item
+    					// N.b. a pointer even if the item
+    					// is of type e.g. int
+    const char *comment,		// comment associated with item
+    const char *name,			// name of new item of metadata (may be an sprintf format)
+    ...);				// possible arguments for name format
+
+void psMetaDataItemFree(psMetaDataItem *ms); // piece of metadata to destroy
+
+psMetaDataSet *psMetaDataSetAlloc(void);	  // make a new set of metadata
+void psMetaDataSetDel(psMetaDataSet *ms); // destroy a set of metadata
+
+/*****************************************************************************/
+/*
+ * Utilities
+ */
+psMetaDataItem *psMetaDataAppend(psMetaDataSet *restrict ms, psMetaDataItem *restrict item);
+psMetaDataItem *psMetaDataRemove(psMetaDataSet *restrict ms, const char *restrict key);
+
+void psMetaDataSetIterator(psMetaDataSet *ms);
+psMetaDataItem *psMetaDataGetNext(psMetaDataSet *ms);
+psMetaDataItem *psMetaDataLookup(const psMetaDataSet *ms, const char *key);
+
+void psMetaDataItemPrint(FILE *fd,		// file descriptor to write to
+			 const psMetaDataItem *ms); // item of metadata to print
+\end{verbatim}
 
 \bibliographystyle{plain}
