Index: trunk/doc/pslib/psLibSDRS.tex
===================================================================
--- trunk/doc/pslib/psLibSDRS.tex	(revision 4165)
+++ trunk/doc/pslib/psLibSDRS.tex	(revision 4166)
@@ -1,3 +1,3 @@
-%%% $Id: psLibSDRS.tex,v 1.269 2005-06-09 00:35:55 price Exp $
+%%% $Id: psLibSDRS.tex,v 1.270 2005-06-09 00:40:48 eugene Exp $
 \documentclass[panstarrs,spec]{panstarrs}
 
@@ -1512,4 +1512,12 @@
 given \code{type}.
 
+\begin{prototype}
+int psVectorInit(psVector *image, ...);
+\end{prototype}
+
+\code{psVectorInit} shall initialize the vector with the given value.
+The input data is cast to match the vector datatype, allowing for
+integers to be preserved.
+
 \subsection{Simple Images}
 
@@ -1573,4 +1581,6 @@
 dimensionality must be 2.  
 
+\subsubsection{Support Functions}
+
 \begin{prototype}
 psImage* psImageRecycle(
@@ -1588,9 +1598,66 @@
 
 \begin{prototype}
-int psImageFreeChildren(psImage* image);
+int psImageFreeChildren(psImage *image);
 \end{prototype}
 
 \code{psImageFreeChildren} shall free all child images of the given
 \code{image}.
+
+\begin{prototype}
+int psImageInit(psImage *image, ...);
+\end{prototype}
+
+\code{psImageInit} shall initialize the image with the given value.
+The input data is cast to match the image datatype, allowing for
+integers to be preserved.
+
+\subsubsection{Image Regions}
+
+In many places, we need to refer to a rectangular area.  We define a
+structure to represent a rectangle:
+\begin{datatype}
+typedef struct {
+  float x0;
+  float x1;
+  float y0;
+  float y1;
+} psRegion;
+\end{datatype}
+This structure is used in psLib as an abbreviation for the four
+floats, and is defined statically.  Functions which accept or return a
+\code{psRegion} shall do so by value, not by pointer.
+
+We define two functions to set and return the value of a
+\code{psRegion}.  The first defines the region by the corner
+coordinates.  The second function converts the IRAF description of a
+region in the form \code{[x0:x1,y0:y1]}, used for header entries such
+as \code{BIASSEC}, into the corresponding \code{psRegion} structure
+(any values that do not parse correctly shall be returned as
+\code{NaN}).  We also define a function that converts a
+\code{psRegion} to the corresponding IRAF description.
+
+\begin{prototype}
+psRegion psRegionSet(float x0, float x1, float y0, float y1);
+psRegion psRegionFromString(const char *region);
+char *psRegionToString(const psRegion region);
+\end{prototype}
+
+All functions which use a psRegion must interpret the definition of
+$(x0,y0)$ and $(x1,y1)$ in the same way. The coordinate $(x0,y0)$
+defines the starting pixel in the region.  The coordinate $(x1,y1)$
+defines the outer bound of the region.  The size of the region is
+$(x1-x0,y1-y1)$.  If either $x1$ or $y1$ is less than or equal to 0,
+the value is added to the image dimensions ($Nx + x1$).  Thus a region
+\code{[0:0,0:0]} refers to the full image array, while
+\code{[0:-10,0:-20]} trims the last 10 columns and the last 20 rows.
+
+\begin{prototype}
+psRegion psRegionForImage (psImage *image, psRegion in);
+\end{prototype}
+
+An image region defined with negative upper limits may be rationalized
+for the bounds of a specific image with \code{psRegionForImage}.  The
+output of this function is a region with negative upper limits
+replaced by their corrected value appropriate to the given image.
 
 \subsection{Math Casting}
@@ -2102,4 +2169,1256 @@
 
 \pagebreak 
+
+\subsection{BitSets}
+
+BitSets are required in order to turn options on and off.  We require
+the capability to have a bitset of arbitrary length (i.e., not limited
+by the length of a \code{long}, say).  The \code{psBitSet} structure
+is defined below.  Note that the entry \code{bits} is an array of type
+\code{char} storing the bits as bits of each byte in the array, with 8
+bits available for each byte in the array.  Also note that the
+constructor is passed the number of required bits, which implies that
+\code{ceil(n/8)} bytes must be allocated.  The bitset structure is
+define by:
+\begin{datatype}
+typedef struct {
+    long n;                             ///< Number of chars that form the bitset
+    char *bits;                         ///< The bits
+} psBitSet;
+\end{datatype}
+
+We also require the corresponding constructor and destructor:
+\begin{prototype}
+psBitSet *psBitSetAlloc(long nalloc);
+\end{prototype}
+where \code{n} is the requested number of bits.
+
+Several basic operations on bitsets are required:
+\begin{itemize}
+\item Set a bit;
+\item Check if a bit is set; and
+\item \code{OR}, \code{AND} and \code{XOR} two bitsets.
+\item \code{NOT} a bitset.
+\end{itemize}
+The corresponding APIs are defined below:
+
+\begin{prototype}
+psBitSet *psBitSetSet(psBitSet *bitSet, long bit);
+psBitSet* psBitSetClear(psBitSet *bitSet, long bit);
+psBitSet *psBitSetOp(psBitSet *outBitSet, const psBitSet *inBitSet1, const char *operator, const psBitSet *inBitSet2);
+psBitSet *psBitSetNot(psBitSet *outBitSet, const psBitSet *inBitSet);
+bool psBitSetTest(const psBitSet *bitSet, long bit);
+char *psBitSetToString(const psBitSet* bitSet);
+\end{prototype}
+
+\code{psBitSetSet} sets the specified \code{bit} in the
+\code{psBitSet}, and returns the updated bitset.  The input bitset
+will be modified.
+
+\code{psBitSetClear} clears the specified \code{bit} in the \code{bitSet}
+and returns the updated bitset.  The input bitset will be modified.
+
+\code{psBitSetOp} returns the \code{psBitSet} that is the result of
+performing the specified \code{operator} (one of \code{"AND"},
+\code{"OR"}, or \code{"XOR"}) on \code{inBitSet1} and \code{inBitSet2}.
+If the output bitset \code{outBitSet} is \code{NULL}, it is created by
+the function.
+
+\code{psBitSetNot} applies a unary \code{NOT} to a bitset, placing the
+answer in the bitset \code{out}, or creating a new bitset if
+\code{out} is \code{NULL}.
+
+\code{psBitSetTest} returns a true value if the specified \code{bit}
+is set; otherwise, it returns a false value.
+
+Finally, \code{psBitSetToString} returns a string representation of
+the specified \code{bits}.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\section{Rich Data Structures and I/O}
+
+\subsection{Metadata}
+\label{sec:metadata}
+
+\subsubsection{Conceptual Overview}
+
+Within PSLib, we provide a data structure to carry metadata and
+mechanisms to manipulate the metadata.  Metadata is a general concept
+that requires some discussion.  In any data analysis task, the
+ensemble of all possible data may be divided into two or three
+classes: there is the specific data of interest, there is data which
+is related or critical but not the primary data of interest, and there
+is all of the other data which may or may not be interesting.  For
+example, consider a simple 2D image obtained of a galaxy from a CCD
+camera on a telescope.  If you want to study the galaxy, the specific
+data of interest is the collection of pixels.  There are a variety of
+other pieces of data which are closely related and crucial to
+understanding the data in those pixels, such as the dimensions of the
+image, the coordinate system, the time of the image, the exposure
+time, and so forth.  Other data may be known which may be less
+critical to understanding the image, but which may be interesting or
+desired at a later date.  For example, the observer who took the
+image, the filter manufacturer, the humidity at the telescope, etc.
+
+Formally, all of the related data which describe the principal data of
+interest are metadata.  Note that which piece is the metadata and
+which is the data may depend on the context.  If you are examining the
+pixels in an image, the coordinate and flux of an object may be part
+of the metadata.  However, if you are analyzing a collection of
+objects extracted from an image, you may consider then pixel data
+simply part of the metadata associated with the list of objects.  
+
+There are various ways to handle metadata vs data within a programming
+environment.  In C, it is convenient to use structures to group
+associated data together.  One possibility is to define the metadata
+as part of the associated data structure.  For example, the image data
+structure would have elements for all possible associated measurement.
+This approach is both cumbersome (because of the large number metadata
+types), impractical (because the full range of necessary metadata is
+difficult to know in advance) and inflexible (because any change in
+the collection of metadata requires addition of new structure elements
+and recompilation).  
+
+An alternative is to place the metadata in a generic container and use
+lookup mechanisms to extract the appropriate metadata when needed.  An
+example of this is would be a text-based FITS header for an image read
+into a flat text buffer.  In this implementation, metadata lookup
+functions could return the current value of, for example, NAXIS1 (the
+number of columns of the image) by scanning through the header buffer.
+This method has the benefits of flexibility and simplicity of
+programming interface, but it has the disadvantage that all metadata
+is accessed though this lookup mechanism.  This may make the code less
+readable and it may slow down the access.  
+
+PSLib implements an intermediate solution to this problem.  We specify
+a flexible, generic metadata container and access methods.  Data types
+which require association with a general collection of metadata should
+include an entry of this metadata type.  However, a subset of metadata
+concepts which are basic and frequently required may be placed in the
+coded structure elements.  This approach allows the code to refer to
+the basic metadata concepts as part of the data structure (ie,
+\code{image.nx}), but also allows us to provide access to any
+arbitrary metadata which may be generated.  As a practical matter, the
+choice of which entries are only in the metadata and which are part of
+the explicit structure elements is rather subjective.  Any data
+elements which are frequently used should be put in the structure;
+those which are only infrequently needed should be left in the generic
+metadata.
+
+There are some points of caution which must be noted.  Any
+manipulation of the data should be reflected in the metadata where
+appropriate.  This is always an issue of concern.  For example,
+consider an image of dimensions \code{nx, ny}.  If a function extracts
+a subraster, it must change the values of \code{nx, ny} to match the
+new dimensions.  What should it do to the corresponding metadata?
+Clearly, it should change the corresponding value which defines
+\code{nX, nY}.  However, it is not quite so simple: there may be other
+metadata values which depend on those values.  These must also be
+changed appropriately.  What if the metadata element points to a
+copy of the metadata which may be shared by other representations of
+the image?  These must be treated differently because the change would
+invalidate those other references.  Care must be taken, therefore,
+when writing functions which operate on the data to consider all of
+the relevant metadata entries which must also be updated. 
+
+A related issue is the definition of metadata names.  Entries in a
+structure have the advantage of being hardwired: every instance of
+that structure will have the same name for the same entry.  This is
+not necessarily the case with a more flexible metadata container.  The
+image exposure time is a notorious example in astronomy.  Different
+observatories use different header keywords (ie, metadata names) for
+the same concept of the exposure time (\code{EXPTIME},
+\code{EXPOSURE}, \code{OPENTIME}, \code{INTTIME}, etc).  Any system
+which operates on these metadata needs to address the issue of
+identifying these names.  This issue seems like an argument for
+hardwiring metadata in the structure, but in fact it does not present
+such a strong case.  If the metadata are hardwired, some function will
+still have to know how to interpret the various names to populate the
+structure.  The concept can still be localized with generic metadata
+containers by including abstract metadata names within the code which
+are tied to the various implementations-specific metadata names.
+
+\subsubsection{Metadata Representation}
+
+\begin{figure}
+\psfig{file=Metadata,width=6.5in}
+\caption{Metadata Structures\label{fig:metadata}}
+\end{figure}
+
+This section addresses the question of how \PS{} metadata should be
+represented in memory, not how it should be represented on disk.
+
+We define an item of metadata with the following structure:
+\filbreak
+\begin{datatype}
+typedef struct {
+    const psS32 id;                     ///< unique ID for this item
+    char *name;                         ///< Name of item
+    psMetadataType type;                ///< type of this item
+    const union {
+        psS32 S32;                      ///< integer data
+        psF32 F32;                      ///< floating-point data
+        psF64 F64;                      ///< double-precision data
+        psList *list;                   ///< psList entry
+        psMetadata *md;                 ///< psMetadata entry
+        psPtr V;                        ///< other type
+    } data;                             ///< value of metadata
+    char *comment;                      ///< optional comment ("", not NULL)
+} psMetadataItem;
+\end{datatype}
+
+The \code{id} is a unique identifier for this item of metadata;
+experience shows that such tags are useful.  The entry \code{name}
+specifies the name of the metadata item.  The value of the metadata is
+given by the union \code{data}, and may be of type \code{psS32},
+\code{psF32}, \code{psF64}, or an arbitrary rich structure pointed at
+by the \code{void} pointer \code{V}.  A character string comment
+associated with this metadata item may be stored in the element
+\code{comment}. The \code{type} entry specifies how to interpret the
+type of the data being represented, given by the enumerated type
+\code{psMetadataType}:
+%
+\filbreak
+\begin{datatype}
+typedef enum {                         ///< type of item.data is:
+    PS_META_S32  = PS_TYPE_S32,        ///< psS32 primitive data.
+    PS_META_F32  = PS_TYPE_F32,        ///< psF32 primitive data.
+    PS_META_F64  = PS_TYPE_F64,        ///< psF64 primitive data.
+    PS_META_BOOL = PS_TYPE_BOOL,       ///< psBool primitive data.
+    PS_META_LIST = 0x10000,            ///< List data (Stored as item.data.list).
+    PS_META_STR,                       ///< String data (Stored as item.data.V).
+    PS_META_META,                      ///< Metadata (Stored as item.data.md).
+    PS_META_VEC,                       ///< Vector data (Stored as item.data.V).
+    PS_META_IMG,                       ///< Image data (Stored as item.data.V).
+    PS_META_HASH,                      ///< Hash data (Stored as item.data.V).
+    PS_META_LOOKUPTABLE,               ///< Lookup table data (Stored as item.data.V).
+    PS_META_JPEG,                      ///< JPEG data (Stored as item.data.V).
+    PS_META_PNG,                       ///< PNG data (Stored as item.data.V).
+    PS_META_ASTROM,                    ///< Astrometric coefficients (Stored as item.data.V).
+    PS_META_TIME,                      ///< psTime object (Stored as item.data.V).
+    PS_META_UNKNOWN,                   ///< Other data (Stored as item.data.V).
+    PS_META_MULTI                      ///< Used internally, do not create a metadata item of this type.
+} psMetadataType;
+\end{datatype}
+The macro \code{PS_META_IS_PRIMITIVE(psMetadataType.type)} returns
+true if the type is one of the primitive data types (S32, F64, etc).
+In such a case, the data value is directly available.  Otherwise, a
+pointer to the data is available.
+
+A collection of metadata is represented by the \code{psMetadata} structure:
+\begin{datatype}
+typedef struct {
+    psList *list;                       ///< list of psMetadataItem
+    psHash *hash;                       ///< hash table of the same metadata
+} psMetadata;
+\end{datatype}
+The type \code{psMetadata} is a container class for metadata. Note
+that there are in fact \emph{two} representations of the metadata
+(each \code{psMetadataItem} appears on both).  The first
+representation employs a doubly-linked list that allows the order of
+the metadata to be preserved (e.g., if FITS headers are read in a
+particular order, they should be written in the same order).  The
+second representation employs a hash table which allows fast look-up
+given a specific metadata keyword.
+
+Certain metadata names (such as the FITS keywords \code{COMMENT} and
+\code{HISTORY} in a FITS header) may be repeated with different
+values.  In such a case, the \code{psMetadata.list} structure contains
+the entries in their original sequence with duplicate keys.  The
+\code{psMetadata.hash} entries, which are required to have unique
+keys, would have a single entry with the keyword of the repeated key,
+with the value of \code{psMetadataType} set to \code{PS_META_MULTI},
+and the \code{psMetadataItem.data} element pointing to a \code{psList}
+containing the actual entries.  If \code{psMetadataItemAlloc} is
+called with the type set to \code{PS_META_MULTI}, such a repeated key
+is created.  In this case, the data value passed to
+\code{psMetadataItemAlloc} (the quantity in ellipsis) must be
+\code{NULL}.  An empty \code{psMetadataItem} with the given keyword is
+created to hold future entries of that keyword.
+
+As a convenience to the user, the following type-specific functions are
+also defined:
+\begin{prototype}
+psMetadataItem* psMetadataItemAllocStr(const char* name, const char* comment, const char* value);
+psMetadataItem* psMetadataItemAllocF32(const char* name, const char* comment, psF32 value);
+psMetadataItem* psMetadataItemAllocF64(const char* name, const char* comment, psF64 value);
+psMetadataItem* psMetadataItemAllocS32(const char* name, const char* comment, psS32 value);
+psMetadataItem* psMetadataItemAllocBool(const char* name, const char* comment, bool value);
+psMetadataItem* psMetadataItemAllocPtr(const char* name, psMetadataType type, const char* comment, psPtr value);
+\end{prototype}
+
+\subsubsection{Metadata APIs}
+
+\begin{prototype}
+psMetadata *psMetadataAlloc(void);
+\end{prototype}
+
+The constructor for the collection of metadata, \code{psMetadata},
+simply returns an empty metadata container (employing the constructors
+for the doubly-linked list and hash table).  The destructor needs to
+free each of the \code{psMetadataItem}s.
+
+\begin{prototype}
+psMetadataItem *psMetadataItemAlloc(const char *name, psMetadataType type, const char *comment, ...);
+psMetadataItem *psMetadataItemAllocV(const char *name, psMetadataType type, const char *comment, va_list list);
+\end{prototype}
+
+The allocator for \code{psMetadataItem} returns a full
+\code{psMetadataItem} ready for insertion into the \code{psMetadata}.
+The \code{name} entry specifies the name to use for this metadata
+item, and may include \code{sprintf}-type formating codes.  The
+\code{comment} entry is a fixed string which is used for the comment
+associated with this metadata item.  The metadata data and the
+arguments to the \code{name} formatting codes are passed, in that
+order (metadata pointer first), to \code{psMetadataItemAlloc} as
+arguments following the comment string.  The data must be a pointer
+for any data types which are stored in the element \code{data.void},
+while other data types are passed as numeric values.  The argument
+list must be interpreted appropriately by the \code{va_list} operators
+in the function.
+
+\begin{prototype}
+bool psMetadataAddItem(psMetadata *md, const psMetadataItem *item, psS32 location, psS32 flags);
+bool psMetadataAdd(psMetadata *md, int location, const char *name, int format, const char *comment, ...);
+bool psMetadataAddV(psMetadata *md, int location, const char *name, int format, const char *comment,
+                    va_list list);
+\end{prototype}
+
+Items may be added to the metadata in one of two ways --- firstly, an
+item may be added by appending a \code{psMetadataItem} which has
+already been created; and secondly by directly providing the data to
+be appended.  In both cases, the return value defines the success
+(\code{true}) or failure of the operation.  The second function,
+\code{psMetadataAdd} takes a pointer or value which is interpreted by
+the function using variadic argument interpretation.  The third
+version is the \code{va_list} version of the second function.  All
+three functions take a parameter, \code{location}, which specifies
+where in the list to place the element, following the conventions for
+the \code{psList}.  The entry \code{mode} for \code{psMetadataAddItem}
+is a bit mask constructed by OR-ing the allowed option flags (eg,
+\code{PS_META_REPLACE}) which specify minor variations on the
+behavior.  The \code{format} entry, which specifies both the metadata
+type and the optional flags, is constructed by bit-wise OR-ing the
+appropriate \code{psMetadataType} and allowed option flags.  Care
+should be taken not to leak memory when appending an item for which
+the key already exists in the metadata (and is not
+\code{PS_META_MULTI}).
+%
+
+\begin{datatype}
+typedef enum {                          ///< option flags for psMetadata functions
+    PS_META_DEFAULT         = 0,        ///< default behavior (0x0000) for use in mode above
+    PS_META_REPLACE         = 0x1000000 ///< allow entry to be replaced
+    PS_META_DUPLICATE_OK    = 0x2000000 ///< allow duplicate entries
+    PS_META_NULL            = 0x4000000 ///< psMetadataItem.data is a NULL value
+} psMetadataFlags;
+\end{datatype}
+
+The functions above take option flags which modify the behavior when
+metadata items are added to the metadata list.  These flags must be
+bit-exclusive of those used above for the \code{psMetadataTypes}.  The
+flags have the following meanings: 
+
+\code{PS_META_DEFAULT}: This is the zero bit mask, to allow the
+default behavior for \code{psMetadataAddItem} above.  If this is OR-ed
+with a \code{psMetadataType}, the result is as if no OR-ing took
+place.
+
+\code{PS_META_REPLACE}: Replace an existing, unique entry. If the
+given metadata item exists in the metadata collection, and is not of
+type \code{PS_META_MULTI}, then the item replaces the existing entry.
+
+\code{PS_META_DUPLICATE_OK}: Allow the new metadata item key to be a
+duplicate (ie, \code{PS_META_MULTI}).  If an existing item with the
+same key is already \code{PS_META_MULTI}, the new item is added to the
+\code{PS_META_MULTI} list.  If the existing item is not
+\code{PS_META_MULTI}, a \code{PS_META_MULTI} list is created to
+contain both the existing item and the new item.  The original entry's
+location on the psMetadata.list must be maintained.
+
+\code{PS_META_NULL}:  Indicates that \code{psMetadataItem.data} should be
+ignored and that the the current value is ``NULL'' or undefined.  The
+\code{psMetadataItem} must have a proper \code{type} set and it's \code{data}
+field shall have a valid value.  e.g. A \code{type} of \code{PS_META_STR} would
+require that 's \code{data} is set to \code{NULL}.
+
+There are several of cases to handle for duplication of an existing
+key by a new key, some identified above.  The following situations
+must also be handled:
+
+If the new key already exists, but is not \code{PS_META_MULTI}, and
+the new item is not flagged as either \code{PS_META_DUPLICATE_OK} or
+\code{PS_META_REPLACE}, an error is raised.  
+
+If the new key already exists, and the existing item is
+\code{PS_META_MULTI}, the new item is added to the MULTI list.  Note
+that if the new item is also of type \code{PS_META_MULTI}, no action
+is taken, but a successful exit status is returned (the action of
+adding a \code{PS_META_MULTI} item to the metadata is equivalent to
+setting that key to be tagged as \code{PS_META_MULTI}.  If it is
+{\em already} \code{PS_META_MULTI}, this effect has already been
+achieved).  
+
+An example of code to use these metadata APIs to generate the
+structure seen in Figure~\ref{fig:metadata} is given below.
+
+\begin{verbatim}
+md = psMetadataAlloc();
+
+psMetadataAdd(md, PS_LIST_TAIL, "SIMPLE",   PS_META_BOOL, "basic fits",            TRUE);
+psMetadataAdd(md, PS_LIST_TAIL, "BLANK",    PS_META_S32,  "invalid pixel data",    -32768);
+psMetadataAdd(md, PS_LIST_TAIL, "DATE-OBS", PS_META_STR,  "observing date UT", "   2004-6-16");
+psMetadataAdd(md, PS_LIST_TAIL, "COMMENT",  PS_META_LIST, "head of comment block", NULL);
+psMetadataAdd(md, PS_LIST_TAIL, "COMMENT",  PS_META_STR,  "",                      "DATA");
+psMetadataAdd(md, PS_LIST_TAIL, "COMMENT",  PS_META_STR,  "",                      "PARAMS"); 
+psMetadataAdd(md, PS_LIST_TAIL, "EXPTIME",  PS_META_F32,  "exposure time (sec)",   1.05);
+psMetadataAdd(md, PS_LIST_TAIL, "COMMENT",  PS_META_STR,  "",                      "FOO");
+
+cell = psMetadataAlloc();
+psMetadataAdd(cell, PS_LIST_TAIL, "EXTNAME",  PS_META_STR,  "",                    "CCD00");
+psMetadataAdd(cell, PS_LIST_TAIL, "BIASNAME", PS_META_STR,  "",                    "BSEC-00");
+psMetadataAdd(cell, PS_LIST_TAIL, "CHIP",     PS_META_STR,  "",                    "CHIP.00");
+psMetadataAdd(md,   PS_LIST_TAIL, "CELL.00",  PS_META_META, "",                    cell);
+
+cell = psMetadataAlloc();
+psMetadataAdd(cell, PS_LIST_TAIL, "EXTNAME",  PS_META_STR,  "",                    "CCD01");
+psMetadataAdd(cell, PS_LIST_TAIL, "BIASNAME", PS_META_STR,  "",                    "BSEC-01");
+psMetadataAdd(cell, PS_LIST_TAIL, "CHIP",     PS_META_STR,  "",                    "CHIP.01");
+psMetadataAdd(md,   PS_LIST_TAIL, "CELL.01",  PS_META_META, "",                    cell);
+\end{verbatim}
+
+The following code shows how to use the APIs to replace one of these values:
+\begin{verbatim}
+psMetadataAdd(md, PS_LIST_TAIL, "EXPTIME",  PS_META_F32 | PS_REPLACE,  "new exposure time (sec)",   2.05);
+\end{verbatim}
+
+As a convenience to the user, the following type-specific functions
+are specified:
+\begin{prototype}
+bool psMetadataAddStr(psMetadata* md, psS32 location, const char* name, const char* comment,
+                        const char* value);
+bool psMetadataAddS32(psMetadata* md, psS32 location, const char* name, const char* comment, psS32 value);
+bool psMetadataAddF32(psMetadata* md, psS32 location, const char* name, const char* comment, psF32 value);
+bool psMetadataAddF64(psMetadata* md, psS32 location, const char* name, const char* comment, psF64 value);
+bool psMetadataAddBool(psMetadata* md, psS32 location, const char* name, const char* comment, bool value);
+bool psMetadataAddPtr(psMetadata* md, psS32 location, const char* name, psMetadataType type,
+                        const char* comment, psPtr value);
+\end{prototype}
+
+
+Items may be removed from the metadata by specifying a key or a
+location in the list.  If the value of \code{name} is \code{NULL}, the
+value of \code{location} is used.  If the value of \code{name} is not
+\code{NULL}, then \code{location} must be set to
+\code{PS_LIST_UNKNOWN}.  If the key matches a metadata item, the item
+is removed from the metadata and \code{true} is returned; otherwise,
+\code{false} is returned.  If the key is not unique, then \emph{all}
+items corresponding to the key are removed, and \code{true} is
+returned.
+%
+\begin{prototype}
+bool psMetadataRemove(psMetadata *md, int location, const char *key);
+\end{prototype}
+
+Items may be found within the metadata by providing a key.  In the
+event that the key is non-unique, the first item is returned.
+\begin{prototype}
+psMetadataItem *psMetadataLookup(const psMetadata *md, const char *key);
+\end{prototype}
+
+Several utility functions are provided for simple cases.  These
+functions perform the effort of casting the data to the appropriate
+type.  The numerical functions shall return 0.0 if their key is not
+found.  If the pointer value of \code{status} is not \code{NULL}, it
+is set to reflect the success or failure of the lookup.
+\begin{prototype}
+psPtr psMetadataLookupStr(bool *status, const psMetadata *md, const char *key);
+psS32 psMetadataLookupS32(bool *status, const psMetadata *md, const char *key);
+psF32 psMetadataLookupF32(bool *status, const psMetadata *md, const char *key);
+psF64 psMetadataLookupF64(bool *status, const psMetadata *md, const char *key);
+bool psMetadataLookupBool(bool *status, const psMetadata *md, const char *key);
+psPtr psMetadataLookupPtr(bool *status, const psMetadata *md, const char *key);
+\end{prototype}
+
+Items may be retrieved from the metadata by their entry position.  The
+value of which specifies the desired entry in the fashion of
+\code{psList}.
+\begin{prototype}
+psMetadataItem *psMetadataGet(const psMetadata *md, int location);
+\end{prototype}
+
+The metadata list component may be iterated over by using a
+\code{psMetadataIterator} in a fashion equivalent to the
+\code{psListIterator}:
+\begin{datatype}
+typedef struct {
+    psListIterator* iter;              ///< iterator for the psMetadata's psList
+    regex_t* regex;                     ///< the subsetting regular expression
+} psMetadataIterator;
+\end{datatype}
+
+The iterator may be set to a location in the \code{psMetadata} list,
+and the user may get the previous or next item in the list relative to
+that location.  \code{psMetadataGetNext} has the ability to match the
+key using a POSIX \code{regex}, e.g., if the user only wants to
+iterate through \code{IPP.machines.sky} and doesn't want to bother
+with \code{IPP.machines.detector}.  The iterator should iterate over
+every item in the metadata list, even those that are contained in a
+\code{PS_META_LIST}.  The value \code{iterator} specifies the iterator
+to be used.  In setting the iterator, the position of the iterator is
+defined by \code{location}, which follows the conventions of the
+\code{psList} iterators.
+\begin{prototype}
+psMetadataIterator *psMetadataIteratorAlloc(psMetadata *md, int location, const char *regex);
+bool psMetadataIteratorSet(psMetadataIterator *iterator, int location);
+psMetadataItem *psMetadataGetAndIncrement(psMetadataIterator *iterator);
+psMetadataItem *psMetadataGetAndDecrement(psMetadataIterator *iterator);
+\end{prototype}
+
+Metadata items may be printed to an open file descriptor based on a
+provided format.  The format string is an sprintf format statement
+with exactly one \% formatting command.  If the metadata item type is
+a numeric type, this formatting command must also be numeric, and type
+conversion performed to the value to match the format type.  If the
+metadata item type is a string, the formatting command must also be
+for a string (\%s type of command).  If the metadata type is any other
+data type, printing is not allowed.
+\begin{prototype}
+bool psMetadataItemPrint(FILE *fd, const char *format, const psMetadataItem *item);
+\end{prototype}
+
+\subsubsection{Configuration files}
+\label{sec:configspec}
+
+It will be necessary for the \PS{} system, in order to load
+pre-defined settings, to parse a configuration file into a
+\code{psMetadata} structure.  This shall be performed by the
+function \code{psMetadataConfigParse}, as described below.
+
+\begin{prototype}
+psMetadata *psMetadataConfigParse(psMetadata *md, int *nFail, const char *filename, bool overwrite);
+\end{prototype}
+
+Given a metadata container, \code{md}, and the name of a configuration
+file, \code{filename}, \code{psMetadataConfigParse} shall parse the
+configuration file, placing the contained key/type/value/comment quads
+into the metadata, and returning a pointer to the metadata structure.
+The number of lines that failed to parse is returned in \code{nFail}.
+Multiple specifications of a key that haven't been declared (see
+below) are overwritten if and only if \code{overwrite} is \code{true}.
+If the metadata container is \code{NULL}, it shall be allocated.  
+
+On error, the function shall return \code{NULL}.
+
+It is also useful to be able to convert a \code{psMetadata} structure into the
+Configuration File format for debugging purposes and to enable persistent
+configuration.
+
+\begin{prototype}
+char *psMetadataConfigFormat(psMetadata *md);
+bool psMetadataConfigWrite(psMetadata *md, const char *filename);
+\end{prototype}
+
+The \code{psMetadataConfigFormat} function converts a \code{psMetadata}
+structure (including any nested \code{psMetadata}) into a Configuration File
+formatted string.  A \code{NULL} shall be returned on error.  The
+\code{psMetadataConfigWrite} behaves the same as \code{psMetadataConfigFormat}
+except that the string is written out to \code{filename}.  \code{false} is
+returned on failure.
+
+\paragraph{Comments}
+
+The configuration file shall consist of plain text with
+key/type/value/comment quads on separate lines.  Blank lines,
+including those consisting solely of whitespace (both spaces and
+tabs), shall be ignored, as shall lines that commence with the comment
+character (a hash mark, \code{#}), either immediately at the start of
+the line, or preceded by whitespace.  The key/type/value/comment quads
+shall all lie on a single line, separated by whitespace.
+
+The key shall be first, possibly preceded on the line by whitespace
+which should not form part of the key.
+
+\paragraph{NULL values}
+
+The ``value'' of a quad may be declare to be undefined with the \code{NULL}
+keyword.  \code{NULL} is allowed to co-exist with a ``comment'' and may be
+surrounded by whitespace.  Any non-whitespace character will cause of the
+``value'' to be interpreted as a string.
+
+\begin{verbatim}
+foo     STR     NULL    # string with a NULL value
+bar     STR     NULL a  # string with a value of "NULL a"
+\end{verbatim}
+
+\paragraph{Types}
+\subparagraph{Scalar \& Vector}
+
+Next, to assist the casting of the value, shall be a string identifying the
+type of the value, which shall correspond to one of the simple types supported
+in \code{psMetadata}: \code{STRING,BOOL,S32,F32,F64}; \code{STR} may be used to
+abbreviate \code{STRING}; valid time types are \code{UTC,UT1,TAI,TT}.
+
+\tbd{May, in the future, require more types, including U8,S16,C64,
+which will also necessitate updating the definition of psMetadata.}
+
+The value shall follow the type: strings may consist of multiple words, and
+shall have all leading and trailing whitespace removed; booleans shall simply
+be either \code{T} or \code{F}.  Time type values will be in the ISO8601
+compatible format of "YYYY-MM-DDTHH:MM:SS,sZ".  When parsed, time types shall
+be represented as a \code{psTime} object.
+
+Following the value may be an optional comment, preceded by a comment
+character (a hash mark, \code{#}), which in the case of a string
+value, serves to mark the end of the value, and for other types serves
+to identify the comment to the reader.  Only one comment character may
+be present on any single line (i.e., neither strings nor comments are
+permitted to contain the comment character).  The comment may consist
+of multiple words, and shall have leading and trailing whitespace
+removed.
+
+One wrinkle is the specification of vectors.  Keys for which the value
+is to be parsed as a vector shall be preceded immediately by a
+``vector symbol'', which we choose to be the ``at'' sign, \code{@}.
+In this case, the type shall be interpreted as the type for the
+vector, which may be any of the signed or unsigned integer or floating
+point types (\code{U8,U16,U32,U64,S8,S16,S32,S32,S64,F32,F64}) but not
+the complex floating point types; and the value shall consist of
+multiple numbers, separated either by a comma or whitespace.  These
+values shall populate a \code{psVector} of the appropriate type in the
+order in which they appear in the configuration file.
+
+\tbd{May add complex types, likely to be specified with values such as
+  1.23+4.56i in the future.}
+
+\tbd{May add null, Not-a-Number (NaN), de-normalized, underflow, overflow,
+and/or +/-infinity values for selected types.}
+
+\subparagraph{MULTI}
+
+An additional hurdle is the specification of keys that may be non-unique (such
+as the \code{COMMENT} keyword in a FITS header).  These keys shall be specified
+in the configuration file as non-unique with a \code{MULTI} declaration.  In
+the form \code{[keyword] MULTI}.  No other data may be provided on this line,
+though a comment, preceded by the comment marker, is valid.  A warning shall
+be produced when a key which has not been specified to be non-unique is
+repeated; in this case, the former value shall be overwritten if
+\code{overwrite} is \code{true}, otherwise the line shall be ignored and
+counted as one that could not be parsed.  It should be noted that non-unique
+keys may be of mixed type (even the \code{TYPE} and \code{METADATA} complex
+types). For example:
+\begin{verbatim}
+comment     MULTI   # a comment
+comment     STR     some string
+comment     F32     1.23456
+comment     BOOL    T
+\end{verbatim}
+
+If a line does not conform to the rules laid out here, a warning shall
+be generated, it shall be ignored and counted as a line that could not
+be parsed.  The total number of lines that were not able to be parsed
+(including those that were ignored because \code{overwrite} is
+\code{false}, and any other parsing problems, but not including blank
+lines and comment lines) shall be returned by the function in the
+argument \code{nFail}.
+
+Here are some examples of lines of a valid configuration file:
+\filbreak
+\begin{verbatim}
+Double     F64     1.23456789      # This is a comment
+Float    F32 0.98765 # This is a comment too
+String  STR This is the string that forms the value #comment
+
+ # This is a comment line and is to be ignored
+boolean     BOOL    T # The value of `boolean' is `true'
+
+@primes U8  2,3 5 7,11,13 17 #   These are prime numbers
+
+comment MULTI # The rest of this line is ignored, but `comment' is set to be non-unique
+comment STR This
+comment STR     is
+comment STR       a
+comment STR        non-unique
+comment STR                  key
+Float F64 1.23456 # This generates a warning, and, if `overwrite' is `false', is ignored
+\end{verbatim}
+
+Of course, a real configuration file should look much nicer to humans
+than the above example, but PSLib must be able to parse such ugly
+files.
+
+\paragraph{Complex Types}
+\subparagraph{TYPE}
+
+We support a modest tree structure by defining a reserved keyword \code{TYPE}.
+Any line in the config file which starts with the word \code{TYPE} shall be
+interpreted as defining a new valid type.  The defined type name follows the
+word \code{TYPE}, and is in turn followed by an arbitrary number of words.
+These words are to be interpreted as the names of an embedded \code{psMetadata}
+entry, where the values are given on any line which (following the \code{TYPE}
+definition) employs the new type name.  For example, a new type may be defined
+as:
+\begin{verbatim}
+TYPE      CELL   EXTNAME   BIASSEC  CHIP
+CELL.00   CELL   CCD00     BSEC-00  CHIP.00
+CELL.01   CELL   CCD01     BSEC-01  CHIP.00
+\end{verbatim}
+
+When \code{psMetadataConfigParse} encounters the \code{TYPE} line, it
+should construct a \code{psMetadata} container and fill it with
+\code{psMetadataItems} having the names \code{EXTNAME, BIASSEC, CHIP},
+with type \code{PS_META_STR}, but data allocated.  When it next
+encounters an entry of type \code{CELL}, it should then use the given
+name (e.g., \code{CELL.00}) for the \code{psMetadataItem}, and copy
+the \code{psMetadata} data onto the \code{psMetadataItem.data.md}
+entry, filling in the values from the rest of the line (\code{CCD00,
+BSEC-00, CHIP.00}).  This hierarchical structure is illustrated in
+Figure~\ref{fig:metadata}.
+
+\subparagraph{METADATA}
+
+Another way to form a tree-like structure is to directly define a
+\code{psMetadata} entry using a sequence of successive lines to define the
+values of the \code{psMetadataItem} entries.  The initial line defines the new
+\code{psMetadata} entry and its name.  The following lines have the same format
+as the other metadata config file entries.  The sequence is terminated with a
+line with a single word \code{END}.  For example, a metadata entry may be
+defined as:
+\begin{verbatim}
+CELL      METADATA
+ EXTNAME   STR   CCD00
+ BIASSEC   STR   BSEC-00
+ CHIP      STR   CHIP.00
+ NCELL     S32   24
+END
+\end{verbatim}
+
+\paragraph{Scoping Rules}
+
+A simple set of ``Scoping Rules'' are required to properly parse a
+configuration file.  ``Scope'' refers to the current ``level'' of
+\code{METADATA} that a statement appears in.  Statements that are not contained
+in a nested \code{METADATA} are said to be in the ``Top level scope''.  Each
+level of nested \code{METADATA} statements create a new ``lower level scope''.
+
+\begin{itemize}
+\item 
+Variable names are unique only to the current level of scope.
+
+\item
+non-unique keywords (\code{MULTI}) apply only to the current scope.  i.e. They
+are invalid in ``higher'' or ``lower'' level scopes.
+
+\item
+\code{TYPE} declarations apply only to the current scope.
+
+\item
+\code{METADATA} declarations must begin and end in the same scope.  i.e.  They
+may not be declared and end in two different nested METADATA and the same
+depth.
+\end{itemize}
+
+A series of test inputs is contained in
+\S\ref{sec:configtest}.
+
+\subsection{XML Functions}
+
+Within Pan-STARRS, we will use XML documents as a transport mechanism
+to carry data between programs and between IPP and other subsystems.
+Configuration information may be stored as well as XML documents, in
+addition to the text format discussed in the discussion on Metadata.
+XML is an extremely variable document format, and it is not currently
+the intention of PSLib to provide a complete PSLib version of XML
+operations.  Rather, a limited number of operations are defined to
+convert specific data structures to an appropriate XML document.  To
+maximize the simplicity of the XML APIs, we will use the convention
+that a single XML document to be parsed by PSLib shall contain only a
+single data structure.  Each of the XML APIs therefore take as input a
+reference to a complete XML document and return a PSLib data
+structure, or take a PSLib data structure and return a complete XML
+document.
+
+We start by defining a PSLib wrapper type which is a pointer to an XML
+document in memory.  We wrap the \code{libxml2} version of an XML
+document pointer for now:
+\begin{datatype}
+typedef xmlDocPtr psXMLDoc;
+\end{datatype}
+
+\begin{prototype}
+psXMLDoc *psXMLDocAlloc(void);
+\end{prototype}
+
+The next pair of functions convert a \code{psMetadata} data structure
+to a complete \code{psXMLDoc} (in memory) and vice versa:
+\begin{prototype}
+psXMLDoc *psMetadataToXMLDoc(const psMetadata *md);
+psMetadata *psXMLDocToMetadata(const psXMLDoc *doc);
+\end{prototype}
+
+The next pair of functions loads the data in a named file into a
+complete \code{psXMLDoc} (in memory) and write out the \code{psXMLDoc}
+to a named file:
+\begin{prototype}
+psXMLDoc *psXMLParseFile(const char *filename);
+int psXMLDocToFile(const psXMLDoc *doc, const char *filename);
+\end{prototype}
+
+The next pair of functions accepts a block of memory and parses it
+into a complete \code{psXMLDoc} (also in memory), and vice versa:
+\begin{prototype}
+psXMLDoc *psXMLParseMem(const char *buffer, int size);
+int psXMLDocToMem(const psXMLDoc *doc, char *buffer);
+\end{prototype}
+
+The next pair of functions read from and write to a file descriptor.
+The first converts the incoming data to a complete \code{psXMLDoc}
+(also in memory), the second writes the \code{psXMLDoc} to the file
+descriptor:
+\begin{prototype}
+psXMLDoc *psXMLParseFD(int fd);
+int psXMLDocToFD(const psXMLDoc *doc, int fd);
+\end{prototype}
+
+\subsection{Database Functions}
+
+Many of the applications that PSLib will be used for will require
+access to a simple relational database.  PSLib includes generic
+database-independent interface mechanisms as part of its API set.  The
+most important aspect of PSLib's database support is to abstract as
+much database specific complexity as is feasible.  As almost all RDBMS
+provide at least a simple transactional model, commit and rollback
+support should be provided.
+
+Currently, only support for MySQL 4.1.x is required but other backends
+may be added as options in the future.  As a particular example which
+has implications for the database interaction model, support for
+SQLite may be required in the future.  Currently, the choice of
+backend database interface may be made as a compile option.  Details
+of the specified APIs in the discussion below refer to the relevant
+MySQL functions.
+
+Database errors must be trapped and placed onto the psError stack.
+The complete error message should be retrieved with the database's
+error function.
+
+\subsubsection{Managing the Database Connection}
+
+We specify a database handle which carries the information about the
+database connection:
+
+\begin{datatype}
+    typedef struct {
+        MYSQL *mysql;
+    } psDB;
+\end{datatype}
+
+The following collection of functions provides basic database functionality:
+
+\begin{prototype}
+    // wraps mysql_init() & mysql_real_connect()
+    psDB *psDBInit(const char *host, const char *user, const char *passwd, const char *dbname);
+
+    // wraps mysql_close()
+    void psDBCleanup(psDB *dbh);
+
+    // wraps mysql_create_db()
+    bool psDBCreate(psDB *dbh, const char *dbname);
+
+    // wraps mysql_select_db()
+    bool psDBChange(psDB *dbh, const char *dbname);
+
+    // wraps mysql_drop_db()
+    bool psDBDrop(psDB *dbh, const char *dbname);
+\end{prototype}
+
+For MySQL support, \code{psDBInit()} wraps \code{mysql_init()} and
+\code{mysql_real_connect()} in order to initialize a psDB structure and
+establish a database connection.  A null pointer should be returned on
+failure.
+
+When implementing support for SQLite, or other DB which is purely
+file-based, the \code{host}, \code{user}, and \code{passwd} arguments
+would be ignored while \code{dbname} would specify the path to the
+SQLite db file.
+
+\subsubsection{Interacting with Database Tables}
+
+The functions in this section perform high level interactions with the
+database tables.  All of them should behave ``atomically'' with
+respect to the state of the database.  Specifically, all interactions
+with the database should be done as a part of a transaction that is
+rolled-back on failure and committed only after all queries used by
+the API have been run.  In general, this API set attempts to treat a
+database table as a 2D matrix where columns can be represented by a
+\code{psVector} and rows as a \code{psMetadata} type.  A
+\code{psMetadata} collection is also used to define the columns of a
+table and as part of the query restrictions.
+
+\begin{prototype}
+    bool psDBCreateTable(psDB *dbh, const char *tableName, const psMetadata *md);
+\end{prototype}
+
+This function generates and executes the SQL needed to create a table
+named \code{tableName}, with the column names and datatypes as
+described in \code{md}.  Each data item in the \code{psMetadata}
+collection represents a single table field.  The name of the field is
+given by the name of the \code{psMetadataItem} and the data type is
+given by the \code{psMetadataItem.type} entry.  A lookup table should
+be used to convert from PSLib types into MySQL compatible SQL data
+types.  For example, a \code{PS_META_STR} would map to an SQL99
+varchar.  If the value of \code{type} is \code{PS_META_STR} then the
+\code{psMetadataItem.data} element is set to a string with the length
+for the field written as a text string.  The value of the
+\code{psMetadataItem.data} element is unused for the
+\code{PS_META_PRIMITIVE} types.  Other metadata types beyond
+\code{PS_META_STR} and \code{PS_META_PRIMITIVE} are not allowed in a
+table definition metadata collection.
+
+Database indexes can be specified by setting the \code{comment} field to
+``\code{Primary Key}'' or ``\code{Key}''.  ``Auto-incrementing'' columns may be
+specified by setting the \code{comment} field to ``\code{AUTO_INCREMENT}''.
+Indexes and auto-increments maybe be combined in the same \code{comment}.  They
+must be separated by optional whitespace, a comma, and then more optional
+whitespace.  The \code{comment} field is otherwise ignored.
+
+\begin{prototype}
+    bool psDBDropTable(psDB *dbh, const char *tableName);
+\end{prototype}
+
+This function deletes the specified table.
+
+\begin{prototype}
+    bool p_psDBRunQuery(psDB *dbh, const char *query);
+\end{prototype}
+
+This function will execute a string as a raw SQL query.  No additional
+processing of the string or abstraction of the underlying database's SQL
+dialect is provided.
+
+\begin{prototype}
+    psArray *psDBSelectColumn(psDB *dbh, const char *tableName, const char *col, unsigned long limit);
+    psVector *psDBSelectColumnNum(psDB *dbh, const char *tableName, const char *col, psElemType type, unsigned long limit);
+\end{prototype}
+
+These functions generates and executes the SQL needed to select an entire
+column from a table or up to \code{limit} rows from it.  If \code{limit} is 0,
+the entire range is returned.  The database response is processed and a
+\code{psArray} of strings is returned.  The Num version of the function returns
+the data in a \code{psVector}, data cast to \code{type}.  It returns an error
+(NULL) if the requested field is not a numerical type.
+
+\begin{prototype}
+    psArray *psDBSelectRows(psDB *dbh, const char *tableName, psMetadata *where, unsigned long limit);
+\end{prototype}
+
+This function returns rows from the specified table which match
+the restrictions given by \code{where}.  The restrictions are
+specified as field / value pairs.  The \code{psMetadata} collection
+where must consist of valid database fields, though the database query
+checking functions may be used to validate the fields as part of the
+query.  If \code{where} is \code{NULL}, then there are no restrictions
+on the rows selected.  The selected rows are returned as a
+\code{psArray} of \code{psMetadata} values, one per row. 
+
+\begin{prototype}
+    bool psDBInsertOneRow(psDB *dbh, const char *tableName, const psMetadata *row);
+\end{prototype}
+
+Insert the data from \code{row} into \code{tableName}.  It should be noted in
+the API reference that if fields are specified in \code{row} that do not exist
+in \code{tablename}, the insert will fail.
+
+\begin{prototype}
+    bool psDBInsertRows(psDB *dbh, const char *tableName, const psArray *rowSet);
+\end{prototype}
+
+Similar to \code{psDBInsertOneRow()}, this function inserts many rows at once
+and is atomic for the complete set of rows.
+
+\begin{prototype}
+    psArray *psDBDumpRows(psDB *dbh, const char *tableName);
+\end{prototype}
+
+Fetch all rows as an psArray of psMetadata.
+
+\begin{prototype}
+    psMetadata *psDBDumpCols(psDB *dbh, const char *tableName);
+\end{prototype}
+
+Fetch all columns, as either a psVector or a psArray depending on whether or not
+the column is numeric, and return them in a psMetadata structure where
+psMetadataItem.name contains the column's name.
+
+\begin{prototype}
+psS64 psDBUpdateRows(psDB *dbh, const char *tableName, const psMetadata *where, const psMetadata *values);
+\end{prototype}
+
+Update the columns contained in \code{values} in the row(s) that have a field
+with the value indicated by \code{where} (note that this is only allows very
+limited use of SQL99's ``where'' semantics).  The number of rows modified is
+returned.  A negative value is return to indicate an error. If there are
+multiple psMetadataItems in \code{where} then each item should be considered as
+an additional constraint.  e.g.  ``where foo = x and where bar = y''
+
+\begin{prototype}
+    psS64 psDBDeleteRows(psDB *dbh, const char *tableName, const psMetadata *where);
+\end{prototype}
+
+Delete the rows that are matched by \code{where} using the same semantics for
+\code{where} as in psDBUpdateRow().  A negative value is returned to indicate an
+error.
+
+\subsection{FITS I/O Functions}
+
+We need a variety of I/O functions between the disk and certain of our
+PSLib data structures.  We need the ability to access FITS headers,
+images and tables (both ASCII and Binary).  We define here the FITS
+I/O functions, all of which are currently specified as wrappers to
+functions within CFITSIO.  CFITSIO provides a wide range of utilities
+which we do not feel are particularly appropriate as part of a generic
+I/O library, such as assumptions about names which change the data
+interpretation, etc.  We are defining our calls to avoid the hidden
+'features'.  The CFITSIO functions which are wrapped should in general
+be the most basic versions.
+
+\begin{datatype}
+typedef struct {
+    fitsfile fd;
+} psFits;
+\end{datatype}
+We begin by defining a datatype to wrap the CFITSIO \code{fitsfile}
+structure.  This is necessary to allow repeated access to the data in
+a file without multiple open commands (which are expensive).
+
+\subsubsection{FITS File Manipulations}
+
+\begin{prototype}
+psFits *psFitsOpen(const char *filename);
+\end{prototype}
+
+Opens a FITS file and positions the pointer to the PHU.
+
+\begin{prototype}
+bool psFitsClose(psFits *fits);
+\end{prototype}
+
+Closes a FITS file.
+
+\begin{prototype}
+bool psFitsMoveExtName(const psFits *fits, const char *extname);
+\end{prototype}
+
+Positions the pointer to the beginning of the specified
+\code{extname}.  If the \code{extname} does not exist, the function
+shall fail.  
+
+\begin{prototype}
+bool psFitsMoveExtNum(const psFits* fits, int extnum, bool relative);
+\end{prototype}
+
+Moves the pointer to the beginning of the specified HDU number.  If
+\code{relative} is TRUE, \code{extnum} represents the number of HDUs
+relative to the current HDU.  The PHU is entry number 0, while the
+extended data segments start at number 1.
+
+\begin{prototype}
+int psFitsGetExtNum(const psFits* fits);
+\end{prototype}
+
+Returns the current HDU number (i.e., file position).  
+
+\begin{prototype}
+int psFitsGetSize(const psFits* fits);
+\end{prototype}
+
+Returns the number of HDUs in the file.
+
+\begin{datatype}
+typedef enum {
+    PS_FITS_TYPE_NONE,
+    PS_FITS_TYPE_IMAGE,
+    PS_FITS_TYPE_BINARY_TABLE,
+    PS_FITS_TYPE_ASCII_TABLE,
+    PS_FITS_TYPE_ANY
+} psFitsType;
+\end{datatype}
+
+\begin{prototype}
+psFitsType psFitsGetExtType(const psFits* fits);
+\end{prototype}
+
+Gets the current HDU's type (table or image).
+
+\begin{prototype}
+char *psFitsGetExtName(const psFits* fits);
+bool psFitsSetExtName(psFits* fits, const char* name);
+\end{prototype}
+
+\code{psFitsGetExtName} shall return the name of the current extension
+for the given \code{fits} file (as specified by the \code{EXTNAME}
+header).  \code{psFitsSetExtName} shall change the name of the current
+extension for the given \code{fits} file to \code{name}, returning
+\code{true} upon success and \code{false} otherwise.
+
+\subsubsection{FITS Header I/O Functions}
+
+\begin{prototype}
+psMetadata *psFitsReadHeader(psMetadata *out, const psFits *fits);
+\end{prototype}
+Read header data into a \code{psMetadata} structure.  The data is read
+from the current HDU pointed at by the \code{psFits *fits} entry.  If
+\code{out} is \code{NULL}, a new psMetadata is created.
+
+\begin{prototype}
+psMetadata *psFitsReadHeaderSet(const psFits *fits);
+\end{prototype}
+Load a complete set of headers from the \code{psFits} file pointer.
+This function loads the headers from all extensions into a
+\code{psMetadata} collection, each entry of which is a pointer to a
+\code{psMetadata} structure containing the header data.  The metadata
+entry names are the \code{EXTNAME} values for each header (with the
+value of \code{PHU} for the primary header unit).  At the start of the
+operation, the file pointer is rewound to the beginning of the file.
+At the end, it is positioned where it started when the function was
+called.
+
+\begin{prototype}
+bool psFitsWriteHeader(const psMetadata *output, psFits *fits);
+\end{prototype}
+Write metadata into the header of a FITS image file.  The header is
+written at the current HDU.
+
+\subsubsection{FITS Image I/O Functions}
+
+\begin{prototype}
+psImage *psFitsReadImage(psImage *out, const psFits *fits, psRegion region, int z);
+\end{prototype}
+Read an image or subimage from the \code{psFits} file pointer.  This
+function is a wrapper to the CFITSIO library function.  The input
+parameters allow a full image or a subimage to be read.  The region to
+be read is specified by \code{region}.  A negative value for either of
+\code{region.x1} or \code{region.y1} specifies the size of the region
+to be read counting down from the end of the array.  
+
+If the native image is a cube, the value of z specifies the requested
+slice of the image.  This function must call \code{psError} and return
+\code{NULL} if any of the specified parameters are out of range for
+the data in the image file, or if the image on disk is zero- or
+one-dimensional.  This function need only read images of the native
+FITS image types (\code{psU8}, \code{psS16}, \code{psS32},
+\code{psF32}, \code{psF64}).  The user is expected to convert the data
+type as needed with \code{psImageCopy}.
+ 
+\begin{prototype}
+bool psFitsUpdateImage(psFits *fits, const psImage *input, psRegion region, int z);
+\end{prototype}
+Write an image section to the open \code{psFits} file pointer.  This
+operation may write a portion of an image over the existing bytes of
+an existing image.  Care must be taken to interpret \code{region},
+which specified the output pixels to be written / over-written.  If
+the combination of \code{region} and the size of \code{psImage *input}
+implies writing pixels outside the existing data area of the image,
+the function shall return an error (ie, if \code{region.x0 + image.nx
+>= NAXIS1}, \code{region.y0 + image.ny >= NAXIS2}, or \code{z >=
+NAXIS3}).  This function will only write images of the native FITS
+image types (\code{psU8}, \code{psS16}, \code{psS32}, \code{psF32},
+\code{psF64}).  The user is expected to convert the data type as
+needed with \code{psImageCopy}.  The return value must be 0 for a
+successful operation and 1 for an error.
+
+\begin{prototype}
+bool psFitsWriteImage(psFits *fits, const psMetadata *header, const psImage *input, int depth);
+\end{prototype}
+Create a new image based on the dimensions specified for the image and
+the requested depth.  The header and image data segments are written
+in the file at the current position of the \code{psFits} pointer.
+This function will only write images of the native FITS image types
+(\code{psU8}, \code{psS16}, \code{psS32}, \code{psF32}, \code{psF64}).
+The user is expected to convert the data type as needed with
+\code{psImageCopy}.  The return value must be 0 for a successful
+operation and 1 for an error.
+
+\subsubsection{FITS Table I/O Functions}
+
+\begin{prototype}
+psMetadata *psFitsReadTableRow(const psFits *fits, int row);
+\end{prototype}
+This function reads a single row of the table in the extension pointed
+at by the \code{psFits} file pointer.  The row number to be read is
+given by \code{row}.  The result is returned as a \code{psMetadata}
+collection with elements of the appropriate types and keys
+corresponding to the table column names.  The function must apply the
+needed byte-swapping on the data in the row based on the description
+of the table data in the table header.  \tbr{we may need to be more
+flexible here: if we call this function repeatedly, it would be more
+efficient to pass the corresponding header or keep it somewhere (and
+the file pointer location, for that matter).}
+
+\begin{prototype}
+void *psFitsReadTableRowRaw(size_t *size, const psFits *fits, int row);
+\end{prototype}
+This function reads a single row of the table in the extension pointed
+at by the \code{psFits} file pointer.  The row number to be read is
+given by \code{row}.  The result is returned as collection of
+\code{size} bytes allocated by the function.  The function must
+apply the needed byte-swapping on the data in the row based on the
+description of the table data in the table header.  \tbr{we may need
+to be more flexible here: if we call this function repeatedly, it
+would be more efficient to pass the corresponding header or keep it
+somewhere (and the file pointer location, for that matter).}
+
+\begin{prototype}
+psArray *psFitsReadTableColumn(const psFits *fits, const char *colname);
+\end{prototype}
+This function reads a single column of the table in the extension
+pointed at by the \code{psFits} file pointer.  The column is specified
+by the FITS table column key given by \code{row}.  The result is
+returned as a \code{psArray}, with the data from one row of the table
+column per array element.
+
+\begin{prototype}
+psVector *psFitsReadTableColumnNum(const psFits *fits, const char *colname);
+\end{prototype}
+This function reads a single column of the table in the extension
+pointed at by the \code{psFits} file pointer.  The column is specified
+by the FITS table column key given by \code{row} and must be of a
+numeric data type.  The result is returned as a \code{psVector} of the
+appropriate data type, with the data from one row of the table column
+per array element.
+
+\begin{prototype}
+psArray *psFitsReadTableRaw(size_t *size, const psFits *fits);
+\end{prototype}
+This function reads the entire data block from a table into the a
+\code{psArray}, with one element of the array per row.  The number of
+bytes per row is returned in \code{size}.  The function must apply
+the needed byte-swapping on the data in each row based on the
+description of the table data in the table header.
+
+\begin{prototype}
+psArray *psFitsReadTable (psFits *fits);
+\end{prototype}
+This function reads the entire data block from a table into the a
+\code{psArray}, with one element of the array per row.  Each row is
+stored as a \code{psMetadata} collection as described above for
+\code{psFitsReadTableRow}. 
+
+\begin{prototype}
+bool psFitsWriteTable(psFits* fits, const psMetadata *header, const psArray* table); 
+\end{prototype}
+Accepts a \code{psArray} of \code{psMetadata} and writes it to the
+current HDU.  If the current HDU is not a table type, this will fail
+and return FALSE.
+
+\begin{prototype}
+bool psFitsUpdateTable(psFits* fits, const psMetadata* data, int row); 
+\end{prototype}
+Writes the \code{psMetadata} data to a FITS table at the specified row
+in the current HDU.  If the current HDU is not a table type, this will
+fail and return FALSE.  
+
+\pagebreak
 \section{Data manipulation}
 
@@ -2117,71 +3436,4 @@
 \item Minimization and fitting routines.
 \end{itemize}
-
-\subsection{BitSets}
-
-BitSets are required in order to turn options on and off.  We require
-the capability to have a bitset of arbitrary length (i.e., not limited
-by the length of a \code{long}, say).  The \code{psBitSet} structure
-is defined below.  Note that the entry \code{bits} is an array of type
-\code{char} storing the bits as bits of each byte in the array, with 8
-bits available for each byte in the array.  Also note that the
-constructor is passed the number of required bits, which implies that
-\code{ceil(n/8)} bytes must be allocated.  The bitset structure is
-define by:
-\begin{datatype}
-typedef struct {
-    long n;                             ///< Number of chars that form the bitset
-    char *bits;                         ///< The bits
-} psBitSet;
-\end{datatype}
-
-We also require the corresponding constructor and destructor:
-\begin{prototype}
-psBitSet *psBitSetAlloc(long nalloc);
-\end{prototype}
-where \code{n} is the requested number of bits.
-
-Several basic operations on bitsets are required:
-\begin{itemize}
-\item Set a bit;
-\item Check if a bit is set; and
-\item \code{OR}, \code{AND} and \code{XOR} two bitsets.
-\item \code{NOT} a bitset.
-\end{itemize}
-The corresponding APIs are defined below:
-
-\begin{prototype}
-psBitSet *psBitSetSet(psBitSet *bitSet, long bit);
-psBitSet* psBitSetClear(psBitSet *bitSet, long bit);
-psBitSet *psBitSetOp(psBitSet *outBitSet, const psBitSet *inBitSet1, const char *operator, const psBitSet *inBitSet2);
-psBitSet *psBitSetNot(psBitSet *outBitSet, const psBitSet *inBitSet);
-bool psBitSetTest(const psBitSet *bitSet, long bit);
-char *psBitSetToString(const psBitSet* bitSet);
-\end{prototype}
-
-\code{psBitSetSet} sets the specified \code{bit} in the
-\code{psBitSet}, and returns the updated bitset.  The input bitset
-will be modified.
-
-\code{psBitSetClear} clears the specified \code{bit} in the \code{bitSet}
-and returns the updated bitset.  The input bitset will be modified.
-
-\code{psBitSetOp} returns the \code{psBitSet} that is the result of
-performing the specified \code{operator} (one of \code{"AND"},
-\code{"OR"}, or \code{"XOR"}) on \code{inBitSet1} and \code{inBitSet2}.
-If the output bitset \code{outBitSet} is \code{NULL}, it is created by
-the function.
-
-\code{psBitSetNot} applies a unary \code{NOT} to a bitset, placing the
-answer in the bitset \code{out}, or creating a new bitset if
-\code{out} is \code{NULL}.
-
-\code{psBitSetTest} returns a true value if the specified \code{bit}
-is set; otherwise, it returns a false value.
-
-Finally, \code{psBitSetToString} returns a string representation of
-the specified \code{bits}.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
 \subsection{Sorting}
@@ -2673,7 +3925,12 @@
 
 \begin{prototype}
-bool psMinimizeLMChi2(psMinimization *min, psImage *covar, psVector *params,
-                      const psVector *paramMask, const psArray *x, const psVector *y,
-                      const psVector *yErr, psMinimizeLMChi2Func func);
+bool psMinimizeLMChi2(psMinimization *min, 
+                      psImage *covar, 
+		      psVector *params,
+                      const psVector *paramMask, 
+		      const psArray  *x, 
+		      const psVector *y,
+                      const psVector *yErr, 
+		      psMinimizeLMChi2Func func);
 \end{prototype}
 
@@ -2713,4 +3970,22 @@
 be of type \code{psF32}.  The \code{func} function must be valid only
 for types \code{psF32}, \code{psF64}.
+
+\begin{prototype}
+bool psMinimizeGaussNewtonDelta(psVector *delta, 
+                                const psVector *params,
+                                const psVector *paramMask, 
+                                const psArray  *x, 
+                                const psVector *y,
+                                const psVector *yErr, 
+                                psMinimizeLMChi2Func func);
+\end{prototype}
+
+The function \code{psMinimizeGaussNewtonDelta} can be used to evaluate
+the goodness of a fit.  This function returns the distances of the
+current parameter set from the minimization parameters expected from
+Gauss-Newton minimization.  The arguments are identical to those of
+\code{psMinimizeLMChi2}, except only the single vector \code{delta},
+consisting of the distances, is returned.  This vector must be
+pre-allocated to the dimenstions of \code{params}.
 
 %% \subsubsubsection{Pre-defined Functions for LM}
@@ -2915,44 +4190,4 @@
 listed below, and fall into several categories.
 
-\subsubsection{Image Regions}
-
-In many places, we need to refer to a rectangular area.  We define a
-structure to represent a rectangle:
-\begin{datatype}
-typedef struct {
-  float x0;
-  float x1;
-  float y0;
-  float y1;
-} psRegion;
-\end{datatype}
-This structure is used in psLib as an abbreviation for the four
-floats, and is defined statically.  Functions which accept or return a
-\code{psRegion} shall do so by value, not by pointer.
-
-We define two functions to set and return the value of a
-\code{psRegion}.  The first defines the region by the corner
-coordinates.  The second function converts the IRAF description of a
-region in the form \code{[x0:x1,y0:y1]}, used for header entries such
-as \code{BIASSEC}, into the corresponding \code{psRegion} structure
-(any values that do not parse correctly shall be returned as
-\code{NaN}).  We also define a function that converts a
-\code{psRegion} to the corresponding IRAF description.
-
-\begin{prototype}
-psRegion psRegionSet(float x0, float x1, float y0, float y1);
-psRegion psRegionFromString(const char *region);
-char *psRegionToString(const psRegion region);
-\end{prototype}
-
-All functions which use a psRegion must interpret the definition of
-$(x0,y0)$ and $(x1,y1)$ in the same way. The coordinate $(x0,y0)$
-defines the starting pixel in the region.  The coordinate $(x1,y1)$
-defines the outer bound of the region.  The size of the region is
-$(x1-x0,y1-y1)$.  If either $x1$ or $y1$ is less than or equal to 0,
-the value is added to the image dimensions ($Nx + x1$).  Thus a region
-\code{[0:0,0:0]} refers to the full image array, while
-\code{[0:-10,0:-20]} trims the last 10 columns and the last 20 rows.
-
 \subsubsection{Image Structure Manipulation}
 
@@ -3202,5 +4437,5 @@
                           int inputMaskVal, 
                           const psPlaneTransform *outToIn,
-                          const psRegion region, 
+                          psRegion region, 
                           const psPixels *pixels, 
                           psImageInterpolateMode mode,
@@ -3418,5 +4653,5 @@
 
 \begin{prototype}
-psImage *psPixelsToMask(psImage *out, const psPixels *pixels, const psRegion region, unsigned int maskVal);
+psImage *psPixelsToMask(psImage *out, const psPixels *pixels, psRegion region, unsigned int maskVal);
 psPixels *psPixelsFromMask(psPixels *out, const psImage *mask, unsigned int maskVal);
 \end{prototype}
@@ -3727,4 +4962,20 @@
 PSF-matching.
 
+\subsubsection{Basic Image Smoothing}
+
+\begin{prototype}
+void psImageSmooth (psImage *image, double sigma, double Nsigma);
+\end{prototype}
+
+The quickest way to smooth an image is to smooth by parts, using 1D
+gaussian smoothing in X and Y independently.  \code{psImageSmooth}
+applies a single parameter Gaussian (circularly symmetric) by
+smoothing first in the X and then in the Y directions with just a
+vector.  In general, for a Gaussian of dimension N, this process is 2N
+faster than for the 2D convolution defined below.  The arguments to
+this function include the image to be smoothed, the width of the
+smoothing kernel in pixels (\code{sigma}), and the size of the
+smoothing box in sigmas.  
+
 \subsubsection{Kernel definition}
 
@@ -3881,1188 +5132,4 @@
 
 \pagebreak 
-\section{Rich Data Structures and I/O}
-
-\subsection{Metadata}
-\label{sec:metadata}
-
-\subsubsection{Conceptual Overview}
-
-Within PSLib, we provide a data structure to carry metadata and
-mechanisms to manipulate the metadata.  Metadata is a general concept
-that requires some discussion.  In any data analysis task, the
-ensemble of all possible data may be divided into two or three
-classes: there is the specific data of interest, there is data which
-is related or critical but not the primary data of interest, and there
-is all of the other data which may or may not be interesting.  For
-example, consider a simple 2D image obtained of a galaxy from a CCD
-camera on a telescope.  If you want to study the galaxy, the specific
-data of interest is the collection of pixels.  There are a variety of
-other pieces of data which are closely related and crucial to
-understanding the data in those pixels, such as the dimensions of the
-image, the coordinate system, the time of the image, the exposure
-time, and so forth.  Other data may be known which may be less
-critical to understanding the image, but which may be interesting or
-desired at a later date.  For example, the observer who took the
-image, the filter manufacturer, the humidity at the telescope, etc.
-
-Formally, all of the related data which describe the principal data of
-interest are metadata.  Note that which piece is the metadata and
-which is the data may depend on the context.  If you are examining the
-pixels in an image, the coordinate and flux of an object may be part
-of the metadata.  However, if you are analyzing a collection of
-objects extracted from an image, you may consider then pixel data
-simply part of the metadata associated with the list of objects.  
-
-There are various ways to handle metadata vs data within a programming
-environment.  In C, it is convenient to use structures to group
-associated data together.  One possibility is to define the metadata
-as part of the associated data structure.  For example, the image data
-structure would have elements for all possible associated measurement.
-This approach is both cumbersome (because of the large number metadata
-types), impractical (because the full range of necessary metadata is
-difficult to know in advance) and inflexible (because any change in
-the collection of metadata requires addition of new structure elements
-and recompilation).  
-
-An alternative is to place the metadata in a generic container and use
-lookup mechanisms to extract the appropriate metadata when needed.  An
-example of this is would be a text-based FITS header for an image read
-into a flat text buffer.  In this implementation, metadata lookup
-functions could return the current value of, for example, NAXIS1 (the
-number of columns of the image) by scanning through the header buffer.
-This method has the benefits of flexibility and simplicity of
-programming interface, but it has the disadvantage that all metadata
-is accessed though this lookup mechanism.  This may make the code less
-readable and it may slow down the access.  
-
-PSLib implements an intermediate solution to this problem.  We specify
-a flexible, generic metadata container and access methods.  Data types
-which require association with a general collection of metadata should
-include an entry of this metadata type.  However, a subset of metadata
-concepts which are basic and frequently required may be placed in the
-coded structure elements.  This approach allows the code to refer to
-the basic metadata concepts as part of the data structure (ie,
-\code{image.nx}), but also allows us to provide access to any
-arbitrary metadata which may be generated.  As a practical matter, the
-choice of which entries are only in the metadata and which are part of
-the explicit structure elements is rather subjective.  Any data
-elements which are frequently used should be put in the structure;
-those which are only infrequently needed should be left in the generic
-metadata.
-
-There are some points of caution which must be noted.  Any
-manipulation of the data should be reflected in the metadata where
-appropriate.  This is always an issue of concern.  For example,
-consider an image of dimensions \code{nx, ny}.  If a function extracts
-a subraster, it must change the values of \code{nx, ny} to match the
-new dimensions.  What should it do to the corresponding metadata?
-Clearly, it should change the corresponding value which defines
-\code{nX, nY}.  However, it is not quite so simple: there may be other
-metadata values which depend on those values.  These must also be
-changed appropriately.  What if the metadata element points to a
-copy of the metadata which may be shared by other representations of
-the image?  These must be treated differently because the change would
-invalidate those other references.  Care must be taken, therefore,
-when writing functions which operate on the data to consider all of
-the relevant metadata entries which must also be updated. 
-
-A related issue is the definition of metadata names.  Entries in a
-structure have the advantage of being hardwired: every instance of
-that structure will have the same name for the same entry.  This is
-not necessarily the case with a more flexible metadata container.  The
-image exposure time is a notorious example in astronomy.  Different
-observatories use different header keywords (ie, metadata names) for
-the same concept of the exposure time (\code{EXPTIME},
-\code{EXPOSURE}, \code{OPENTIME}, \code{INTTIME}, etc).  Any system
-which operates on these metadata needs to address the issue of
-identifying these names.  This issue seems like an argument for
-hardwiring metadata in the structure, but in fact it does not present
-such a strong case.  If the metadata are hardwired, some function will
-still have to know how to interpret the various names to populate the
-structure.  The concept can still be localized with generic metadata
-containers by including abstract metadata names within the code which
-are tied to the various implementations-specific metadata names.
-
-\subsubsection{Metadata Representation}
-
-\begin{figure}
-\psfig{file=Metadata,width=6.5in}
-\caption{Metadata Structures\label{fig:metadata}}
-\end{figure}
-
-This section addresses the question of how \PS{} metadata should be
-represented in memory, not how it should be represented on disk.
-
-We define an item of metadata with the following structure:
-\filbreak
-\begin{datatype}
-typedef struct {
-    const psS32 id;                     ///< unique ID for this item
-    char *name;                         ///< Name of item
-    psMetadataType type;                ///< type of this item
-    const union {
-        psS32 S32;                      ///< integer data
-        psF32 F32;                      ///< floating-point data
-        psF64 F64;                      ///< double-precision data
-        psList *list;                   ///< psList entry
-        psMetadata *md;                 ///< psMetadata entry
-        psPtr V;                        ///< other type
-    } data;                             ///< value of metadata
-    char *comment;                      ///< optional comment ("", not NULL)
-} psMetadataItem;
-\end{datatype}
-
-The \code{id} is a unique identifier for this item of metadata;
-experience shows that such tags are useful.  The entry \code{name}
-specifies the name of the metadata item.  The value of the metadata is
-given by the union \code{data}, and may be of type \code{psS32},
-\code{psF32}, \code{psF64}, or an arbitrary rich structure pointed at
-by the \code{void} pointer \code{V}.  A character string comment
-associated with this metadata item may be stored in the element
-\code{comment}. The \code{type} entry specifies how to interpret the
-type of the data being represented, given by the enumerated type
-\code{psMetadataType}:
-%
-\filbreak
-\begin{datatype}
-typedef enum {                         ///< type of item.data is:
-    PS_META_S32  = PS_TYPE_S32,        ///< psS32 primitive data.
-    PS_META_F32  = PS_TYPE_F32,        ///< psF32 primitive data.
-    PS_META_F64  = PS_TYPE_F64,        ///< psF64 primitive data.
-    PS_META_BOOL = PS_TYPE_BOOL,       ///< psBool primitive data.
-    PS_META_LIST = 0x10000,            ///< List data (Stored as item.data.list).
-    PS_META_STR,                       ///< String data (Stored as item.data.V).
-    PS_META_META,                      ///< Metadata (Stored as item.data.md).
-    PS_META_VEC,                       ///< Vector data (Stored as item.data.V).
-    PS_META_IMG,                       ///< Image data (Stored as item.data.V).
-    PS_META_HASH,                      ///< Hash data (Stored as item.data.V).
-    PS_META_LOOKUPTABLE,               ///< Lookup table data (Stored as item.data.V).
-    PS_META_JPEG,                      ///< JPEG data (Stored as item.data.V).
-    PS_META_PNG,                       ///< PNG data (Stored as item.data.V).
-    PS_META_ASTROM,                    ///< Astrometric coefficients (Stored as item.data.V).
-    PS_META_TIME,                      ///< psTime object (Stored as item.data.V).
-    PS_META_UNKNOWN,                   ///< Other data (Stored as item.data.V).
-    PS_META_MULTI                      ///< Used internally, do not create a metadata item of this type.
-} psMetadataType;
-\end{datatype}
-The macro \code{PS_META_IS_PRIMITIVE(psMetadataType.type)} returns
-true if the type is one of the primitive data types (S32, F64, etc).
-In such a case, the data value is directly available.  Otherwise, a
-pointer to the data is available.
-
-A collection of metadata is represented by the \code{psMetadata} structure:
-\begin{datatype}
-typedef struct {
-    psList *list;                       ///< list of psMetadataItem
-    psHash *hash;                       ///< hash table of the same metadata
-} psMetadata;
-\end{datatype}
-The type \code{psMetadata} is a container class for metadata. Note
-that there are in fact \emph{two} representations of the metadata
-(each \code{psMetadataItem} appears on both).  The first
-representation employs a doubly-linked list that allows the order of
-the metadata to be preserved (e.g., if FITS headers are read in a
-particular order, they should be written in the same order).  The
-second representation employs a hash table which allows fast look-up
-given a specific metadata keyword.
-
-Certain metadata names (such as the FITS keywords \code{COMMENT} and
-\code{HISTORY} in a FITS header) may be repeated with different
-values.  In such a case, the \code{psMetadata.list} structure contains
-the entries in their original sequence with duplicate keys.  The
-\code{psMetadata.hash} entries, which are required to have unique
-keys, would have a single entry with the keyword of the repeated key,
-with the value of \code{psMetadataType} set to \code{PS_META_MULTI},
-and the \code{psMetadataItem.data} element pointing to a \code{psList}
-containing the actual entries.  If \code{psMetadataItemAlloc} is
-called with the type set to \code{PS_META_MULTI}, such a repeated key
-is created.  In this case, the data value passed to
-\code{psMetadataItemAlloc} (the quantity in ellipsis) must be
-\code{NULL}.  An empty \code{psMetadataItem} with the given keyword is
-created to hold future entries of that keyword.
-
-As a convenience to the user, the following type-specific functions are
-also defined:
-\begin{prototype}
-psMetadataItem* psMetadataItemAllocStr(const char* name, const char* comment, const char* value);
-psMetadataItem* psMetadataItemAllocF32(const char* name, const char* comment, psF32 value);
-psMetadataItem* psMetadataItemAllocF64(const char* name, const char* comment, psF64 value);
-psMetadataItem* psMetadataItemAllocS32(const char* name, const char* comment, psS32 value);
-psMetadataItem* psMetadataItemAllocBool(const char* name, const char* comment, bool value);
-psMetadataItem* psMetadataItemAllocPtr(const char* name, psMetadataType type, const char* comment, psPtr value);
-\end{prototype}
-
-\subsubsection{Metadata APIs}
-
-\begin{prototype}
-psMetadata *psMetadataAlloc(void);
-\end{prototype}
-
-The constructor for the collection of metadata, \code{psMetadata},
-simply returns an empty metadata container (employing the constructors
-for the doubly-linked list and hash table).  The destructor needs to
-free each of the \code{psMetadataItem}s.
-
-\begin{prototype}
-psMetadataItem *psMetadataItemAlloc(const char *name, psMetadataType type, const char *comment, ...);
-psMetadataItem *psMetadataItemAllocV(const char *name, psMetadataType type, const char *comment, va_list list);
-\end{prototype}
-
-The allocator for \code{psMetadataItem} returns a full
-\code{psMetadataItem} ready for insertion into the \code{psMetadata}.
-The \code{name} entry specifies the name to use for this metadata
-item, and may include \code{sprintf}-type formating codes.  The
-\code{comment} entry is a fixed string which is used for the comment
-associated with this metadata item.  The metadata data and the
-arguments to the \code{name} formatting codes are passed, in that
-order (metadata pointer first), to \code{psMetadataItemAlloc} as
-arguments following the comment string.  The data must be a pointer
-for any data types which are stored in the element \code{data.void},
-while other data types are passed as numeric values.  The argument
-list must be interpreted appropriately by the \code{va_list} operators
-in the function.
-
-\begin{prototype}
-bool psMetadataAddItem(psMetadata *md, const psMetadataItem *item, psS32 location, psS32 flags);
-bool psMetadataAdd(psMetadata *md, int location, const char *name, int format, const char *comment, ...);
-bool psMetadataAddV(psMetadata *md, int location, const char *name, int format, const char *comment,
-                    va_list list);
-\end{prototype}
-
-Items may be added to the metadata in one of two ways --- firstly, an
-item may be added by appending a \code{psMetadataItem} which has
-already been created; and secondly by directly providing the data to
-be appended.  In both cases, the return value defines the success
-(\code{true}) or failure of the operation.  The second function,
-\code{psMetadataAdd} takes a pointer or value which is interpreted by
-the function using variadic argument interpretation.  The third
-version is the \code{va_list} version of the second function.  All
-three functions take a parameter, \code{location}, which specifies
-where in the list to place the element, following the conventions for
-the \code{psList}.  The entry \code{mode} for \code{psMetadataAddItem}
-is a bit mask constructed by OR-ing the allowed option flags (eg,
-\code{PS_META_REPLACE}) which specify minor variations on the
-behavior.  The \code{format} entry, which specifies both the metadata
-type and the optional flags, is constructed by bit-wise OR-ing the
-appropriate \code{psMetadataType} and allowed option flags.  Care
-should be taken not to leak memory when appending an item for which
-the key already exists in the metadata (and is not
-\code{PS_META_MULTI}).
-%
-
-\begin{datatype}
-typedef enum {                          ///< option flags for psMetadata functions
-    PS_META_DEFAULT         = 0,        ///< default behavior (0x0000) for use in mode above
-    PS_META_REPLACE         = 0x1000000 ///< allow entry to be replaced
-    PS_META_DUPLICATE_OK    = 0x2000000 ///< allow duplicate entries
-    PS_META_NULL            = 0x4000000 ///< psMetadataItem.data is a NULL value
-} psMetadataFlags;
-\end{datatype}
-
-The functions above take option flags which modify the behavior when
-metadata items are added to the metadata list.  These flags must be
-bit-exclusive of those used above for the \code{psMetadataTypes}.  The
-flags have the following meanings: 
-
-\code{PS_META_DEFAULT}: This is the zero bit mask, to allow the
-default behavior for \code{psMetadataAddItem} above.  If this is OR-ed
-with a \code{psMetadataType}, the result is as if no OR-ing took
-place.
-
-\code{PS_META_REPLACE}: Replace an existing, unique entry. If the
-given metadata item exists in the metadata collection, and is not of
-type \code{PS_META_MULTI}, then the item replaces the existing entry.
-
-\code{PS_META_DUPLICATE_OK}: Allow the new metadata item key to be a
-duplicate (ie, \code{PS_META_MULTI}).  If an existing item with the
-same key is already \code{PS_META_MULTI}, the new item is added to the
-\code{PS_META_MULTI} list.  If the existing item is not
-\code{PS_META_MULTI}, a \code{PS_META_MULTI} list is created to
-contain both the existing item and the new item.  The original entry's
-location on the psMetadata.list must be maintained.
-
-\code{PS_META_NULL}:  Indicates that \code{psMetadataItem.data} should be
-ignored and that the the current value is ``NULL'' or undefined.  The
-\code{psMetadataItem} must have a proper \code{type} set and it's \code{data}
-field shall have a valid value.  e.g. A \code{type} of \code{PS_META_STR} would
-require that 's \code{data} is set to \code{NULL}.
-
-There are several of cases to handle for duplication of an existing
-key by a new key, some identified above.  The following situations
-must also be handled:
-
-If the new key already exists, but is not \code{PS_META_MULTI}, and
-the new item is not flagged as either \code{PS_META_DUPLICATE_OK} or
-\code{PS_META_REPLACE}, an error is raised.  
-
-If the new key already exists, and the existing item is
-\code{PS_META_MULTI}, the new item is added to the MULTI list.  Note
-that if the new item is also of type \code{PS_META_MULTI}, no action
-is taken, but a successful exit status is returned (the action of
-adding a \code{PS_META_MULTI} item to the metadata is equivalent to
-setting that key to be tagged as \code{PS_META_MULTI}.  If it is
-{\em already} \code{PS_META_MULTI}, this effect has already been
-achieved).  
-
-An example of code to use these metadata APIs to generate the
-structure seen in Figure~\ref{fig:metadata} is given below.
-
-\begin{verbatim}
-md = psMetadataAlloc();
-
-psMetadataAdd(md, PS_LIST_TAIL, "SIMPLE",   PS_META_BOOL, "basic fits",            TRUE);
-psMetadataAdd(md, PS_LIST_TAIL, "BLANK",    PS_META_S32,  "invalid pixel data",    -32768);
-psMetadataAdd(md, PS_LIST_TAIL, "DATE-OBS", PS_META_STR,  "observing date UT", "   2004-6-16");
-psMetadataAdd(md, PS_LIST_TAIL, "COMMENT",  PS_META_LIST, "head of comment block", NULL);
-psMetadataAdd(md, PS_LIST_TAIL, "COMMENT",  PS_META_STR,  "",                      "DATA");
-psMetadataAdd(md, PS_LIST_TAIL, "COMMENT",  PS_META_STR,  "",                      "PARAMS"); 
-psMetadataAdd(md, PS_LIST_TAIL, "EXPTIME",  PS_META_F32,  "exposure time (sec)",   1.05);
-psMetadataAdd(md, PS_LIST_TAIL, "COMMENT",  PS_META_STR,  "",                      "FOO");
-
-cell = psMetadataAlloc();
-psMetadataAdd(cell, PS_LIST_TAIL, "EXTNAME",  PS_META_STR,  "",                    "CCD00");
-psMetadataAdd(cell, PS_LIST_TAIL, "BIASNAME", PS_META_STR,  "",                    "BSEC-00");
-psMetadataAdd(cell, PS_LIST_TAIL, "CHIP",     PS_META_STR,  "",                    "CHIP.00");
-psMetadataAdd(md,   PS_LIST_TAIL, "CELL.00",  PS_META_META, "",                    cell);
-
-cell = psMetadataAlloc();
-psMetadataAdd(cell, PS_LIST_TAIL, "EXTNAME",  PS_META_STR,  "",                    "CCD01");
-psMetadataAdd(cell, PS_LIST_TAIL, "BIASNAME", PS_META_STR,  "",                    "BSEC-01");
-psMetadataAdd(cell, PS_LIST_TAIL, "CHIP",     PS_META_STR,  "",                    "CHIP.01");
-psMetadataAdd(md,   PS_LIST_TAIL, "CELL.01",  PS_META_META, "",                    cell);
-\end{verbatim}
-
-The following code shows how to use the APIs to replace one of these values:
-\begin{verbatim}
-psMetadataAdd(md, PS_LIST_TAIL, "EXPTIME",  PS_META_F32 | PS_REPLACE,  "new exposure time (sec)",   2.05);
-\end{verbatim}
-
-As a convenience to the user, the following type-specific functions
-are specified:
-\begin{prototype}
-bool psMetadataAddStr(psMetadata* md, psS32 location, const char* name, const char* comment,
-                        const char* value);
-bool psMetadataAddS32(psMetadata* md, psS32 location, const char* name, const char* comment, psS32 value);
-bool psMetadataAddF32(psMetadata* md, psS32 location, const char* name, const char* comment, psF32 value);
-bool psMetadataAddF64(psMetadata* md, psS32 location, const char* name, const char* comment, psF64 value);
-bool psMetadataAddBool(psMetadata* md, psS32 location, const char* name, const char* comment, bool value);
-bool psMetadataAddPtr(psMetadata* md, psS32 location, const char* name, psMetadataType type,
-                        const char* comment, psPtr value);
-\end{prototype}
-
-
-Items may be removed from the metadata by specifying a key or a
-location in the list.  If the value of \code{name} is \code{NULL}, the
-value of \code{location} is used.  If the value of \code{name} is not
-\code{NULL}, then \code{location} must be set to
-\code{PS_LIST_UNKNOWN}.  If the key matches a metadata item, the item
-is removed from the metadata and \code{true} is returned; otherwise,
-\code{false} is returned.  If the key is not unique, then \emph{all}
-items corresponding to the key are removed, and \code{true} is
-returned.
-%
-\begin{prototype}
-bool psMetadataRemove(psMetadata *md, int location, const char *key);
-\end{prototype}
-
-Items may be found within the metadata by providing a key.  In the
-event that the key is non-unique, the first item is returned.
-\begin{prototype}
-psMetadataItem *psMetadataLookup(const psMetadata *md, const char *key);
-\end{prototype}
-
-Several utility functions are provided for simple cases.  These
-functions perform the effort of casting the data to the appropriate
-type.  The numerical functions shall return 0.0 if their key is not
-found.  If the pointer value of \code{status} is not \code{NULL}, it
-is set to reflect the success or failure of the lookup.
-\begin{prototype}
-psPtr psMetadataLookupStr(bool *status, const psMetadata *md, const char *key);
-psS32 psMetadataLookupS32(bool *status, const psMetadata *md, const char *key);
-psF32 psMetadataLookupF32(bool *status, const psMetadata *md, const char *key);
-psF64 psMetadataLookupF64(bool *status, const psMetadata *md, const char *key);
-bool psMetadataLookupBool(bool *status, const psMetadata *md, const char *key);
-psPtr psMetadataLookupPtr(bool *status, const psMetadata *md, const char *key);
-\end{prototype}
-
-Items may be retrieved from the metadata by their entry position.  The
-value of which specifies the desired entry in the fashion of
-\code{psList}.
-\begin{prototype}
-psMetadataItem *psMetadataGet(const psMetadata *md, int location);
-\end{prototype}
-
-The metadata list component may be iterated over by using a
-\code{psMetadataIterator} in a fashion equivalent to the
-\code{psListIterator}:
-\begin{datatype}
-typedef struct {
-    psListIterator* iter;              ///< iterator for the psMetadata's psList
-    regex_t* regex;                     ///< the subsetting regular expression
-} psMetadataIterator;
-\end{datatype}
-
-The iterator may be set to a location in the \code{psMetadata} list,
-and the user may get the previous or next item in the list relative to
-that location.  \code{psMetadataGetNext} has the ability to match the
-key using a POSIX \code{regex}, e.g., if the user only wants to
-iterate through \code{IPP.machines.sky} and doesn't want to bother
-with \code{IPP.machines.detector}.  The iterator should iterate over
-every item in the metadata list, even those that are contained in a
-\code{PS_META_LIST}.  The value \code{iterator} specifies the iterator
-to be used.  In setting the iterator, the position of the iterator is
-defined by \code{location}, which follows the conventions of the
-\code{psList} iterators.
-\begin{prototype}
-psMetadataIterator *psMetadataIteratorAlloc(psMetadata *md, int location, const char *regex);
-bool psMetadataIteratorSet(psMetadataIterator *iterator, int location);
-psMetadataItem *psMetadataGetAndIncrement(psMetadataIterator *iterator);
-psMetadataItem *psMetadataGetAndDecrement(psMetadataIterator *iterator);
-\end{prototype}
-
-Metadata items may be printed to an open file descriptor based on a
-provided format.  The format string is an sprintf format statement
-with exactly one \% formatting command.  If the metadata item type is
-a numeric type, this formatting command must also be numeric, and type
-conversion performed to the value to match the format type.  If the
-metadata item type is a string, the formatting command must also be
-for a string (\%s type of command).  If the metadata type is any other
-data type, printing is not allowed.
-\begin{prototype}
-bool psMetadataItemPrint(FILE *fd, const char *format, const psMetadataItem *item);
-\end{prototype}
-
-\subsubsection{Configuration files}
-\label{sec:configspec}
-
-It will be necessary for the \PS{} system, in order to load
-pre-defined settings, to parse a configuration file into a
-\code{psMetadata} structure.  This shall be performed by the
-function \code{psMetadataConfigParse}, as described below.
-
-\begin{prototype}
-psMetadata *psMetadataConfigParse(psMetadata *md, int *nFail, const char *filename, bool overwrite);
-\end{prototype}
-
-Given a metadata container, \code{md}, and the name of a configuration
-file, \code{filename}, \code{psMetadataConfigParse} shall parse the
-configuration file, placing the contained key/type/value/comment quads
-into the metadata, and returning a pointer to the metadata structure.
-The number of lines that failed to parse is returned in \code{nFail}.
-Multiple specifications of a key that haven't been declared (see
-below) are overwritten if and only if \code{overwrite} is \code{true}.
-If the metadata container is \code{NULL}, it shall be allocated.  
-
-On error, the function shall return \code{NULL}.
-
-It is also useful to be able to convert a \code{psMetadata} structure into the
-Configuration File format for debugging purposes and to enable persistent
-configuration.
-
-\begin{prototype}
-char *psMetadataConfigFormat(psMetadata *md);
-bool psMetadataConfigWrite(psMetadata *md, const char *filename);
-\end{prototype}
-
-The \code{psMetadataConfigFormat} function converts a \code{psMetadata}
-structure (including any nested \code{psMetadata}) into a Configuration File
-formatted string.  A \code{NULL} shall be returned on error.  The
-\code{psMetadataConfigWrite} behaves the same as \code{psMetadataConfigFormat}
-except that the string is written out to \code{filename}.  \code{false} is
-returned on failure.
-
-\paragraph{Comments}
-
-The configuration file shall consist of plain text with
-key/type/value/comment quads on separate lines.  Blank lines,
-including those consisting solely of whitespace (both spaces and
-tabs), shall be ignored, as shall lines that commence with the comment
-character (a hash mark, \code{#}), either immediately at the start of
-the line, or preceded by whitespace.  The key/type/value/comment quads
-shall all lie on a single line, separated by whitespace.
-
-The key shall be first, possibly preceded on the line by whitespace
-which should not form part of the key.
-
-\paragraph{NULL values}
-
-The ``value'' of a quad may be declare to be undefined with the \code{NULL}
-keyword.  \code{NULL} is allowed to co-exist with a ``comment'' and may be
-surrounded by whitespace.  Any non-whitespace character will cause of the
-``value'' to be interpreted as a string.
-
-\begin{verbatim}
-foo     STR     NULL    # string with a NULL value
-bar     STR     NULL a  # string with a value of "NULL a"
-\end{verbatim}
-
-\paragraph{Types}
-\subparagraph{Scalar \& Vector}
-
-Next, to assist the casting of the value, shall be a string identifying the
-type of the value, which shall correspond to one of the simple types supported
-in \code{psMetadata}: \code{STRING,BOOL,S32,F32,F64}; \code{STR} may be used to
-abbreviate \code{STRING}; valid time types are \code{UTC,UT1,TAI,TT}.
-
-\tbd{May, in the future, require more types, including U8,S16,C64,
-which will also necessitate updating the definition of psMetadata.}
-
-The value shall follow the type: strings may consist of multiple words, and
-shall have all leading and trailing whitespace removed; booleans shall simply
-be either \code{T} or \code{F}.  Time type values will be in the ISO8601
-compatible format of "YYYY-MM-DDTHH:MM:SS,sZ".  When parsed, time types shall
-be represented as a \code{psTime} object.
-
-Following the value may be an optional comment, preceded by a comment
-character (a hash mark, \code{#}), which in the case of a string
-value, serves to mark the end of the value, and for other types serves
-to identify the comment to the reader.  Only one comment character may
-be present on any single line (i.e., neither strings nor comments are
-permitted to contain the comment character).  The comment may consist
-of multiple words, and shall have leading and trailing whitespace
-removed.
-
-One wrinkle is the specification of vectors.  Keys for which the value
-is to be parsed as a vector shall be preceded immediately by a
-``vector symbol'', which we choose to be the ``at'' sign, \code{@}.
-In this case, the type shall be interpreted as the type for the
-vector, which may be any of the signed or unsigned integer or floating
-point types (\code{U8,U16,U32,U64,S8,S16,S32,S32,S64,F32,F64}) but not
-the complex floating point types; and the value shall consist of
-multiple numbers, separated either by a comma or whitespace.  These
-values shall populate a \code{psVector} of the appropriate type in the
-order in which they appear in the configuration file.
-
-\tbd{May add complex types, likely to be specified with values such as
-  1.23+4.56i in the future.}
-
-\tbd{May add null, Not-a-Number (NaN), de-normalized, underflow, overflow,
-and/or +/-infinity values for selected types.}
-
-\subparagraph{MULTI}
-
-An additional hurdle is the specification of keys that may be non-unique (such
-as the \code{COMMENT} keyword in a FITS header).  These keys shall be specified
-in the configuration file as non-unique with a \code{MULTI} declaration.  In
-the form \code{[keyword] MULTI}.  No other data may be provided on this line,
-though a comment, preceded by the comment marker, is valid.  A warning shall
-be produced when a key which has not been specified to be non-unique is
-repeated; in this case, the former value shall be overwritten if
-\code{overwrite} is \code{true}, otherwise the line shall be ignored and
-counted as one that could not be parsed.  It should be noted that non-unique
-keys may be of mixed type (even the \code{TYPE} and \code{METADATA} complex
-types). For example:
-\begin{verbatim}
-comment     MULTI   # a comment
-comment     STR     some string
-comment     F32     1.23456
-comment     BOOL    T
-\end{verbatim}
-
-If a line does not conform to the rules laid out here, a warning shall
-be generated, it shall be ignored and counted as a line that could not
-be parsed.  The total number of lines that were not able to be parsed
-(including those that were ignored because \code{overwrite} is
-\code{false}, and any other parsing problems, but not including blank
-lines and comment lines) shall be returned by the function in the
-argument \code{nFail}.
-
-Here are some examples of lines of a valid configuration file:
-\filbreak
-\begin{verbatim}
-Double     F64     1.23456789      # This is a comment
-Float    F32 0.98765 # This is a comment too
-String  STR This is the string that forms the value #comment
-
- # This is a comment line and is to be ignored
-boolean     BOOL    T # The value of `boolean' is `true'
-
-@primes U8  2,3 5 7,11,13 17 #   These are prime numbers
-
-comment MULTI # The rest of this line is ignored, but `comment' is set to be non-unique
-comment STR This
-comment STR     is
-comment STR       a
-comment STR        non-unique
-comment STR                  key
-Float F64 1.23456 # This generates a warning, and, if `overwrite' is `false', is ignored
-\end{verbatim}
-
-Of course, a real configuration file should look much nicer to humans
-than the above example, but PSLib must be able to parse such ugly
-files.
-
-\paragraph{Complex Types}
-\subparagraph{TYPE}
-
-We support a modest tree structure by defining a reserved keyword \code{TYPE}.
-Any line in the config file which starts with the word \code{TYPE} shall be
-interpreted as defining a new valid type.  The defined type name follows the
-word \code{TYPE}, and is in turn followed by an arbitrary number of words.
-These words are to be interpreted as the names of an embedded \code{psMetadata}
-entry, where the values are given on any line which (following the \code{TYPE}
-definition) employs the new type name.  For example, a new type may be defined
-as:
-\begin{verbatim}
-TYPE      CELL   EXTNAME   BIASSEC  CHIP
-CELL.00   CELL   CCD00     BSEC-00  CHIP.00
-CELL.01   CELL   CCD01     BSEC-01  CHIP.00
-\end{verbatim}
-
-When \code{psMetadataConfigParse} encounters the \code{TYPE} line, it
-should construct a \code{psMetadata} container and fill it with
-\code{psMetadataItems} having the names \code{EXTNAME, BIASSEC, CHIP},
-with type \code{PS_META_STR}, but data allocated.  When it next
-encounters an entry of type \code{CELL}, it should then use the given
-name (e.g., \code{CELL.00}) for the \code{psMetadataItem}, and copy
-the \code{psMetadata} data onto the \code{psMetadataItem.data.md}
-entry, filling in the values from the rest of the line (\code{CCD00,
-BSEC-00, CHIP.00}).  This hierarchical structure is illustrated in
-Figure~\ref{fig:metadata}.
-
-\subparagraph{METADATA}
-
-Another way to form a tree-like structure is to directly define a
-\code{psMetadata} entry using a sequence of successive lines to define the
-values of the \code{psMetadataItem} entries.  The initial line defines the new
-\code{psMetadata} entry and its name.  The following lines have the same format
-as the other metadata config file entries.  The sequence is terminated with a
-line with a single word \code{END}.  For example, a metadata entry may be
-defined as:
-\begin{verbatim}
-CELL      METADATA
- EXTNAME   STR   CCD00
- BIASSEC   STR   BSEC-00
- CHIP      STR   CHIP.00
- NCELL     S32   24
-END
-\end{verbatim}
-
-\paragraph{Scoping Rules}
-
-A simple set of ``Scoping Rules'' are required to properly parse a
-configuration file.  ``Scope'' refers to the current ``level'' of
-\code{METADATA} that a statement appears in.  Statements that are not contained
-in a nested \code{METADATA} are said to be in the ``Top level scope''.  Each
-level of nested \code{METADATA} statements create a new ``lower level scope''.
-
-\begin{itemize}
-\item 
-Variable names are unique only to the current level of scope.
-
-\item
-non-unique keywords (\code{MULTI}) apply only to the current scope.  i.e. They
-are invalid in ``higher'' or ``lower'' level scopes.
-
-\item
-\code{TYPE} declarations apply only to the current scope.
-
-\item
-\code{METADATA} declarations must begin and end in the same scope.  i.e.  They
-may not be declared and end in two different nested METADATA and the same
-depth.
-\end{itemize}
-
-A series of test inputs is contained in
-\S\ref{sec:configtest}.
-
-\subsection{XML Functions}
-
-Within Pan-STARRS, we will use XML documents as a transport mechanism
-to carry data between programs and between IPP and other subsystems.
-Configuration information may be stored as well as XML documents, in
-addition to the text format discussed in the discussion on Metadata.
-XML is an extremely variable document format, and it is not currently
-the intention of PSLib to provide a complete PSLib version of XML
-operations.  Rather, a limited number of operations are defined to
-convert specific data structures to an appropriate XML document.  To
-maximize the simplicity of the XML APIs, we will use the convention
-that a single XML document to be parsed by PSLib shall contain only a
-single data structure.  Each of the XML APIs therefore take as input a
-reference to a complete XML document and return a PSLib data
-structure, or take a PSLib data structure and return a complete XML
-document.
-
-We start by defining a PSLib wrapper type which is a pointer to an XML
-document in memory.  We wrap the \code{libxml2} version of an XML
-document pointer for now:
-\begin{datatype}
-typedef xmlDocPtr psXMLDoc;
-\end{datatype}
-
-\begin{prototype}
-psXMLDoc *psXMLDocAlloc(void);
-\end{prototype}
-
-The next pair of functions convert a \code{psMetadata} data structure
-to a complete \code{psXMLDoc} (in memory) and vice versa:
-\begin{prototype}
-psXMLDoc *psMetadataToXMLDoc(const psMetadata *md);
-psMetadata *psXMLDocToMetadata(const psXMLDoc *doc);
-\end{prototype}
-
-The next pair of functions loads the data in a named file into a
-complete \code{psXMLDoc} (in memory) and write out the \code{psXMLDoc}
-to a named file:
-\begin{prototype}
-psXMLDoc *psXMLParseFile(const char *filename);
-int psXMLDocToFile(const psXMLDoc *doc, const char *filename);
-\end{prototype}
-
-The next pair of functions accepts a block of memory and parses it
-into a complete \code{psXMLDoc} (also in memory), and vice versa:
-\begin{prototype}
-psXMLDoc *psXMLParseMem(const char *buffer, int size);
-int psXMLDocToMem(const psXMLDoc *doc, char *buffer);
-\end{prototype}
-
-The next pair of functions read from and write to a file descriptor.
-The first converts the incoming data to a complete \code{psXMLDoc}
-(also in memory), the second writes the \code{psXMLDoc} to the file
-descriptor:
-\begin{prototype}
-psXMLDoc *psXMLParseFD(int fd);
-int psXMLDocToFD(const psXMLDoc *doc, int fd);
-\end{prototype}
-
-\subsection{Database Functions}
-
-Many of the applications that PSLib will be used for will require
-access to a simple relational database.  PSLib includes generic
-database-independent interface mechanisms as part of its API set.  The
-most important aspect of PSLib's database support is to abstract as
-much database specific complexity as is feasible.  As almost all RDBMS
-provide at least a simple transactional model, commit and rollback
-support should be provided.
-
-Currently, only support for MySQL 4.1.x is required but other backends
-may be added as options in the future.  As a particular example which
-has implications for the database interaction model, support for
-SQLite may be required in the future.  Currently, the choice of
-backend database interface may be made as a compile option.  Details
-of the specified APIs in the discussion below refer to the relevant
-MySQL functions.
-
-Database errors must be trapped and placed onto the psError stack.
-The complete error message should be retrieved with the database's
-error function.
-
-\subsubsection{Managing the Database Connection}
-
-We specify a database handle which carries the information about the
-database connection:
-
-\begin{datatype}
-    typedef struct {
-        MYSQL *mysql;
-    } psDB;
-\end{datatype}
-
-The following collection of functions provides basic database functionality:
-
-\begin{prototype}
-    // wraps mysql_init() & mysql_real_connect()
-    psDB *psDBInit(const char *host, const char *user, const char *passwd, const char *dbname);
-
-    // wraps mysql_close()
-    void psDBCleanup(psDB *dbh);
-
-    // wraps mysql_create_db()
-    bool psDBCreate(psDB *dbh, const char *dbname);
-
-    // wraps mysql_select_db()
-    bool psDBChange(psDB *dbh, const char *dbname);
-
-    // wraps mysql_drop_db()
-    bool psDBDrop(psDB *dbh, const char *dbname);
-\end{prototype}
-
-For MySQL support, \code{psDBInit()} wraps \code{mysql_init()} and
-\code{mysql_real_connect()} in order to initialize a psDB structure and
-establish a database connection.  A null pointer should be returned on
-failure.
-
-When implementing support for SQLite, or other DB which is purely
-file-based, the \code{host}, \code{user}, and \code{passwd} arguments
-would be ignored while \code{dbname} would specify the path to the
-SQLite db file.
-
-\subsubsection{Interacting with Database Tables}
-
-The functions in this section perform high level interactions with the
-database tables.  All of them should behave ``atomically'' with
-respect to the state of the database.  Specifically, all interactions
-with the database should be done as a part of a transaction that is
-rolled-back on failure and committed only after all queries used by
-the API have been run.  In general, this API set attempts to treat a
-database table as a 2D matrix where columns can be represented by a
-\code{psVector} and rows as a \code{psMetadata} type.  A
-\code{psMetadata} collection is also used to define the columns of a
-table and as part of the query restrictions.
-
-\begin{prototype}
-    bool psDBCreateTable(psDB *dbh, const char *tableName, const psMetadata *md);
-\end{prototype}
-
-This function generates and executes the SQL needed to create a table
-named \code{tableName}, with the column names and datatypes as
-described in \code{md}.  Each data item in the \code{psMetadata}
-collection represents a single table field.  The name of the field is
-given by the name of the \code{psMetadataItem} and the data type is
-given by the \code{psMetadataItem.type} entry.  A lookup table should
-be used to convert from PSLib types into MySQL compatible SQL data
-types.  For example, a \code{PS_META_STR} would map to an SQL99
-varchar.  If the value of \code{type} is \code{PS_META_STR} then the
-\code{psMetadataItem.data} element is set to a string with the length
-for the field written as a text string.  The value of the
-\code{psMetadataItem.data} element is unused for the
-\code{PS_META_PRIMITIVE} types.  Other metadata types beyond
-\code{PS_META_STR} and \code{PS_META_PRIMITIVE} are not allowed in a
-table definition metadata collection.
-
-Database indexes can be specified by setting the \code{comment} field to
-``\code{Primary Key}'' or ``\code{Key}''.  ``Auto-incrementing'' columns may be
-specified by setting the \code{comment} field to ``\code{AUTO_INCREMENT}''.
-Indexes and auto-increments maybe be combined in the same \code{comment}.  They
-must be separated by optional whitespace, a comma, and then more optional
-whitespace.  The \code{comment} field is otherwise ignored.
-
-\begin{prototype}
-    bool psDBDropTable(psDB *dbh, const char *tableName);
-\end{prototype}
-
-This function deletes the specified table.
-
-\begin{prototype}
-    bool p_psDBRunQuery(psDB *dbh, const char *query);
-\end{prototype}
-
-This function will execute a string as a raw SQL query.  No additional
-processing of the string or abstraction of the underlying database's SQL
-dialect is provided.
-
-\begin{prototype}
-    psArray *psDBSelectColumn(psDB *dbh, const char *tableName, const char *col, unsigned long limit);
-    psVector *psDBSelectColumnNum(psDB *dbh, const char *tableName, const char *col, psElemType type, unsigned long limit);
-\end{prototype}
-
-These functions generates and executes the SQL needed to select an entire
-column from a table or up to \code{limit} rows from it.  If \code{limit} is 0,
-the entire range is returned.  The database response is processed and a
-\code{psArray} of strings is returned.  The Num version of the function returns
-the data in a \code{psVector}, data cast to \code{type}.  It returns an error
-(NULL) if the requested field is not a numerical type.
-
-\begin{prototype}
-    psArray *psDBSelectRows(psDB *dbh, const char *tableName, psMetadata *where, unsigned long limit);
-\end{prototype}
-
-This function returns rows from the specified table which match
-the restrictions given by \code{where}.  The restrictions are
-specified as field / value pairs.  The \code{psMetadata} collection
-where must consist of valid database fields, though the database query
-checking functions may be used to validate the fields as part of the
-query.  If \code{where} is \code{NULL}, then there are no restrictions
-on the rows selected.  The selected rows are returned as a
-\code{psArray} of \code{psMetadata} values, one per row. 
-
-\begin{prototype}
-    bool psDBInsertOneRow(psDB *dbh, const char *tableName, const psMetadata *row);
-\end{prototype}
-
-Insert the data from \code{row} into \code{tableName}.  It should be noted in
-the API reference that if fields are specified in \code{row} that do not exist
-in \code{tablename}, the insert will fail.
-
-\begin{prototype}
-    bool psDBInsertRows(psDB *dbh, const char *tableName, const psArray *rowSet);
-\end{prototype}
-
-Similar to \code{psDBInsertOneRow()}, this function inserts many rows at once
-and is atomic for the complete set of rows.
-
-\begin{prototype}
-    psArray *psDBDumpRows(psDB *dbh, const char *tableName);
-\end{prototype}
-
-Fetch all rows as an psArray of psMetadata.
-
-\begin{prototype}
-    psMetadata *psDBDumpCols(psDB *dbh, const char *tableName);
-\end{prototype}
-
-Fetch all columns, as either a psVector or a psArray depending on whether or not
-the column is numeric, and return them in a psMetadata structure where
-psMetadataItem.name contains the column's name.
-
-\begin{prototype}
-psS64 psDBUpdateRows(psDB *dbh, const char *tableName, const psMetadata *where, const psMetadata *values);
-\end{prototype}
-
-Update the columns contained in \code{values} in the row(s) that have a field
-with the value indicated by \code{where} (note that this is only allows very
-limited use of SQL99's ``where'' semantics).  The number of rows modified is
-returned.  A negative value is return to indicate an error. If there are
-multiple psMetadataItems in \code{where} then each item should be considered as
-an additional constraint.  e.g.  ``where foo = x and where bar = y''
-
-\begin{prototype}
-    psS64 psDBDeleteRows(psDB *dbh, const char *tableName, const psMetadata *where);
-\end{prototype}
-
-Delete the rows that are matched by \code{where} using the same semantics for
-\code{where} as in psDBUpdateRow().  A negative value is returned to indicate an
-error.
-
-\subsection{FITS I/O Functions}
-
-We need a variety of I/O functions between the disk and certain of our
-PSLib data structures.  We need the ability to access FITS headers,
-images and tables (both ASCII and Binary).  We define here the FITS
-I/O functions, all of which are currently specified as wrappers to
-functions within CFITSIO.  CFITSIO provides a wide range of utilities
-which we do not feel are particularly appropriate as part of a generic
-I/O library, such as assumptions about names which change the data
-interpretation, etc.  We are defining our calls to avoid the hidden
-'features'.  The CFITSIO functions which are wrapped should in general
-be the most basic versions.
-
-\begin{datatype}
-typedef struct {
-    fitsfile fd;
-} psFits;
-\end{datatype}
-We begin by defining a datatype to wrap the CFITSIO \code{fitsfile}
-structure.  This is necessary to allow repeated access to the data in
-a file without multiple open commands (which are expensive).
-
-\subsubsection{FITS File Manipulations}
-
-\begin{prototype}
-psFits *psFitsOpen(const char *filename);
-\end{prototype}
-
-Opens a FITS file and positions the pointer to the PHU.
-
-\begin{prototype}
-bool psFitsClose(psFits *fits);
-\end{prototype}
-
-Closes a FITS file.
-
-\begin{prototype}
-bool psFitsMoveExtName(const psFits *fits, const char *extname);
-\end{prototype}
-
-Positions the pointer to the beginning of the specified
-\code{extname}.  If the \code{extname} does not exist, the function
-shall fail.  
-
-\begin{prototype}
-bool psFitsMoveExtNum(const psFits* fits, int extnum, bool relative);
-\end{prototype}
-
-Moves the pointer to the beginning of the specified HDU number.  If
-\code{relative} is TRUE, \code{extnum} represents the number of HDUs
-relative to the current HDU.  The PHU is entry number 0, while the
-extended data segments start at number 1.
-
-\begin{prototype}
-int psFitsGetExtNum(const psFits* fits);
-\end{prototype}
-
-Returns the current HDU number (i.e., file position).  
-
-\begin{prototype}
-int psFitsGetSize(const psFits* fits);
-\end{prototype}
-
-Returns the number of HDUs in the file.
-
-\begin{datatype}
-typedef enum {
-    PS_FITS_TYPE_NONE,
-    PS_FITS_TYPE_IMAGE,
-    PS_FITS_TYPE_BINARY_TABLE,
-    PS_FITS_TYPE_ASCII_TABLE,
-    PS_FITS_TYPE_ANY
-} psFitsType;
-\end{datatype}
-
-\begin{prototype}
-psFitsType psFitsGetExtType(const psFits* fits);
-\end{prototype}
-
-Gets the current HDU's type (table or image).
-
-\begin{prototype}
-char *psFitsGetExtName(const psFits* fits);
-bool psFitsSetExtName(psFits* fits, const char* name);
-\end{prototype}
-
-\code{psFitsGetExtName} shall return the name of the current extension
-for the given \code{fits} file (as specified by the \code{EXTNAME}
-header).  \code{psFitsSetExtName} shall change the name of the current
-extension for the given \code{fits} file to \code{name}, returning
-\code{true} upon success and \code{false} otherwise.
-
-\subsubsection{FITS Header I/O Functions}
-
-\begin{prototype}
-psMetadata *psFitsReadHeader(psMetadata *out, const psFits *fits);
-\end{prototype}
-Read header data into a \code{psMetadata} structure.  The data is read
-from the current HDU pointed at by the \code{psFits *fits} entry.  If
-\code{out} is \code{NULL}, a new psMetadata is created.
-
-\begin{prototype}
-psMetadata *psFitsReadHeaderSet(const psFits *fits);
-\end{prototype}
-Load a complete set of headers from the \code{psFits} file pointer.
-This function loads the headers from all extensions into a
-\code{psMetadata} collection, each entry of which is a pointer to a
-\code{psMetadata} structure containing the header data.  The metadata
-entry names are the \code{EXTNAME} values for each header (with the
-value of \code{PHU} for the primary header unit).  At the start of the
-operation, the file pointer is rewound to the beginning of the file.
-At the end, it is positioned where it started when the function was
-called.
-
-\begin{prototype}
-bool psFitsWriteHeader(const psMetadata *output, psFits *fits);
-\end{prototype}
-Write metadata into the header of a FITS image file.  The header is
-written at the current HDU.
-
-\subsubsection{FITS Image I/O Functions}
-
-\begin{prototype}
-psImage *psFitsReadImage(psImage *out, const psFits *fits, const psRegion region, int z);
-\end{prototype}
-Read an image or subimage from the \code{psFits} file pointer.  This
-function is a wrapper to the CFITSIO library function.  The input
-parameters allow a full image or a subimage to be read.  The region to
-be read is specified by \code{region}.  A negative value for either of
-\code{region.x1} or \code{region.y1} specifies the size of the region
-to be read counting down from the end of the array.  
-
-If the native image is a cube, the value of z specifies the requested
-slice of the image.  This function must call \code{psError} and return
-\code{NULL} if any of the specified parameters are out of range for
-the data in the image file, or if the image on disk is zero- or
-one-dimensional.  This function need only read images of the native
-FITS image types (\code{psU8}, \code{psS16}, \code{psS32},
-\code{psF32}, \code{psF64}).  The user is expected to convert the data
-type as needed with \code{psImageCopy}.
- 
-\begin{prototype}
-bool psFitsUpdateImage(psFits *fits, const psImage *input, psRegion region, int z);
-\end{prototype}
-Write an image section to the open \code{psFits} file pointer.  This
-operation may write a portion of an image over the existing bytes of
-an existing image.  Care must be taken to interpret \code{region},
-which specified the output pixels to be written / over-written.  If
-the combination of \code{region} and the size of \code{psImage *input}
-implies writing pixels outside the existing data area of the image,
-the function shall return an error (ie, if \code{region.x0 + image.nx
->= NAXIS1}, \code{region.y0 + image.ny >= NAXIS2}, or \code{z >=
-NAXIS3}).  This function will only write images of the native FITS
-image types (\code{psU8}, \code{psS16}, \code{psS32}, \code{psF32},
-\code{psF64}).  The user is expected to convert the data type as
-needed with \code{psImageCopy}.  The return value must be 0 for a
-successful operation and 1 for an error.
-
-\begin{prototype}
-bool psFitsWriteImage(psFits *fits, const psMetadata *header, const psImage *input, int depth);
-\end{prototype}
-Create a new image based on the dimensions specified for the image and
-the requested depth.  The header and image data segments are written
-in the file at the current position of the \code{psFits} pointer.
-This function will only write images of the native FITS image types
-(\code{psU8}, \code{psS16}, \code{psS32}, \code{psF32}, \code{psF64}).
-The user is expected to convert the data type as needed with
-\code{psImageCopy}.  The return value must be 0 for a successful
-operation and 1 for an error.
-
-\subsubsection{FITS Table I/O Functions}
-
-\begin{prototype}
-psMetadata *psFitsReadTableRow(const psFits *fits, int row);
-\end{prototype}
-This function reads a single row of the table in the extension pointed
-at by the \code{psFits} file pointer.  The row number to be read is
-given by \code{row}.  The result is returned as a \code{psMetadata}
-collection with elements of the appropriate types and keys
-corresponding to the table column names.  The function must apply the
-needed byte-swapping on the data in the row based on the description
-of the table data in the table header.  \tbr{we may need to be more
-flexible here: if we call this function repeatedly, it would be more
-efficient to pass the corresponding header or keep it somewhere (and
-the file pointer location, for that matter).}
-
-\begin{prototype}
-void *psFitsReadTableRowRaw(size_t *size, const psFits *fits, int row);
-\end{prototype}
-This function reads a single row of the table in the extension pointed
-at by the \code{psFits} file pointer.  The row number to be read is
-given by \code{row}.  The result is returned as collection of
-\code{size} bytes allocated by the function.  The function must
-apply the needed byte-swapping on the data in the row based on the
-description of the table data in the table header.  \tbr{we may need
-to be more flexible here: if we call this function repeatedly, it
-would be more efficient to pass the corresponding header or keep it
-somewhere (and the file pointer location, for that matter).}
-
-\begin{prototype}
-psArray *psFitsReadTableColumn(const psFits *fits, const char *colname);
-\end{prototype}
-This function reads a single column of the table in the extension
-pointed at by the \code{psFits} file pointer.  The column is specified
-by the FITS table column key given by \code{row}.  The result is
-returned as a \code{psArray}, with the data from one row of the table
-column per array element.
-
-\begin{prototype}
-psVector *psFitsReadTableColumnNum(const psFits *fits, const char *colname);
-\end{prototype}
-This function reads a single column of the table in the extension
-pointed at by the \code{psFits} file pointer.  The column is specified
-by the FITS table column key given by \code{row} and must be of a
-numeric data type.  The result is returned as a \code{psVector} of the
-appropriate data type, with the data from one row of the table column
-per array element.
-
-\begin{prototype}
-psArray *psFitsReadTableRaw(size_t *size, const psFits *fits);
-\end{prototype}
-This function reads the entire data block from a table into the a
-\code{psArray}, with one element of the array per row.  The number of
-bytes per row is returned in \code{size}.  The function must apply
-the needed byte-swapping on the data in each row based on the
-description of the table data in the table header.
-
-\begin{prototype}
-psArray *psFitsReadTable (psFits *fits);
-\end{prototype}
-This function reads the entire data block from a table into the a
-\code{psArray}, with one element of the array per row.  Each row is
-stored as a \code{psMetadata} collection as described above for
-\code{psFitsReadTableRow}. 
-
-\begin{prototype}
-bool psFitsWriteTable(psFits* fits, const psMetadata *header, const psArray* table); 
-\end{prototype}
-Accepts a \code{psArray} of \code{psMetadata} and writes it to the
-current HDU.  If the current HDU is not a table type, this will fail
-and return FALSE.
-
-\begin{prototype}
-bool psFitsUpdateTable(psFits* fits, const psMetadata* data, int row); 
-\end{prototype}
-Writes the \code{psMetadata} data to a FITS table at the specified row
-in the current HDU.  If the current HDU is not a table type, this will
-fail and return FALSE.  
-
-\pagebreak
 \section{Astronomy-Specific Functions}
 
