Index: /trunk/doc/draft/errors.tex
===================================================================
--- /trunk/doc/draft/errors.tex	(revision 513)
+++ /trunk/doc/draft/errors.tex	(revision 513)
@@ -0,0 +1,212 @@
+\documentclass[panstarrs]{panstarrs}
+
+\begin{document}
+  
+\section{Error Handling}
+\hlabel{errorStack}
+
+\begin{table}
+\begin{verbatim}
+typedef struct {
+    char *name;                         // category of code that caused the error
+    psErrorCode code;                   // class of error (equivalent to errno)
+    char *msg;                          // the message associated with the error
+} psErr;
+
+typedef enum {
+    PS_OLD_ERROR = 0,                   ///< This is an old error, and should append to the error stack
+    PS_NEW_ERROR = 1,                   ///< This is a new error and should clear the error stack
+} psErrorStatus;
+
+/// Prints an error message and doesn't abort; returns code
+int psError(const char *name,           ///< Category of code that caused the error
+            psErrorCode code,           ///< class of error (equivalent to errno)
+            psErrorStatus status,       ///< is this a new error?
+            const char *fmt,            ///< Format
+            ...                         ///< Extra arguments to use format
+    );
+
+const psErr *psGetError(int which);     // return specified error (or an "error" with code PS_ERR_NONE)
+const psErr *psLastError(void);         // return last error (or an "error" with code PS_ERR_NONE)
+
+void psErrorClear(void);                ///< Clear the error stack
+
+void psErrorStackPrint(FILE *fd, const char *fmt, ...); ///< print the errorstack to this file descriptor
+void psVErrorStackPrint(FILE *fd, const char *fmt, va_list va); ///< print the errorstack to this file descriptor
+const char *psErrorCodeString(psErrorCode code);        ///< return the string associated with an error code.
+
+\end{verbatim}
+\end{table}
+
+\PS{} errors shall be raised using the function \code{psError}. The \code{name} is of the
+form \code{aaa.bbb.ccc} and identifies the component raising the error.  The \code{psErrorCode} is
+an enumerated type which lists the possible textit{classes} of errors (e.g. \code{PS_ERR_IO})
+that \PS/ code can generate (see section \ref{psErrorCodes}). \code{status} specifies whether this is a
+new error, or whether this call to \code{psError} is in response to an error that has
+already resulted in a call to \code{psError}.
+The final required argument, \code{fmt}, is a \code{printf}-style
+format that is passed to \code{psLogMsg} with code \code{PS_LOG_ERROR}.
+
+The result of a call to \code{psError} shall be to push a \code{psErr} struct onto
+a stack; this stack is cleared if \code{psErrorStatus} is true, or by a call
+to \code{psErrorClear}.
+
+The last error reported is available from \code{psLastError}; if no errors are
+current, a non-\code{NULL} \code{psErr} shall be returned with code \code{PS_ERR_NONE}.
+Previous errors on the stack shall be returned by \code{psGetError} (a value of \code{0}
+passed to \code{psGetError} is equivalent to a call to \code{psLastError}).
+
+The routine \code{psErrorCodeString} returns the string associated with an error code.
+
+The entire error stack may be printed to an open file descriptor by calling \code{psErrorStackPrint}
+(or \code{psVErrorStackPrint});
+if and only if there are current errors, the printf-style string \code{fmt} is first printed
+to the file descriptor \code{fd}. In this printout, error codes shall be replaced by their
+string equivalents as defined in the next section.  Note that these are also available in
+the \code{psErr} structure. The successive lines of the traceback should be indented by
+an additional space (see example). \code{psVErrorStackPrint} shall not invoke \code{va_end}.
+
+Any \code{errorCode}s less then or equal to \code{PS_ERR_BASE} (see next section) shall be taken
+to be valid values of \code{errno}, and \code{psErrorStackPrint} shall print the value returned
+by \code{strerror} if such error codes are encountered.
+
+\subsection{Error Codes}
+\hlabel{psErrorCodes}
+
+The type \code{psErrorCode} is defined by an auxiliary file, conventionally named
+\file{psErrorCodes.dat}. This file shall consist of a number of lines, each
+of the form:
+\begin{verbatim}
+NAME [ = value ] , STRING
+\end{verbatim}
+where \code{[ = value]} is optional, and no spaces are significant except in the
+STRING.  Comments extend from \code{#} to the end of the line (except that a
+\code{\#} shall be replaced by \code{#} and not taken to start a comment). For example,
+\begin{verbatim}
+#
+# This file is used to generate psErrorClasses.h
+#
+NONE = 0,               not an error; must be 0
+BASE = 256,             first value we use; should avoid errno conflicts
+UNKNOWN,                unknown error
+IO,                     I/O error
+BADFREE,                bad argument to psFree()
+MEMORY_CORRUPTION,      memory corruption detected
+\end{verbatim}
+The values \code{NONE = 0} and {UNKNOWN} must be present.
+
+The \PS{} Makefiles shall
+generate two files, \file{psErrorCodes.h} and
+\file{psErrorCodes.c} from the input file \file{psErrorCodes.dat}.
+\file{psErrorCodes.h} shall define an enumerated type
+\code{psErrorCode} with elements \code{PS_ERR_NAME} and values as specified
+in \file{psErrorCodes.dat}, e.g.
+\begin{verbatim}
+#if !defined(PS_ERROR_CODES_H)
+#define PS_ERROR_CODES_H
+
+typedef enum {
+    PS_ERR_NONE = 0,
+    PS_ERR_BASE = 256,
+    PS_ERR_UNKNOWN,
+    PS_ERR_IO,
+    PS_ERR_BADFREE,
+    PS_ERR_MEMORY_CORRUPTION,
+    PS_ERR_N_ERR_CLASSES,
+} psErrorCode;
+
+#endif
+\end{verbatim}
+Any \code{errorCode}s less then or equal to \code{PS_ERR_BASE} shall be taken
+to be valid values of \code{errno}.
+
+The implementation may add extra fields (e.g. \code{PS_ERR_N_ERR_CLASSES}).
+
+The latter shall be of the form
+\begin{verbatim}
+static struct {
+    psErrorCode code;
+    char *descrip;
+} errorStrings[] = {
+    { PS_ERR_NONE, "not an error; must be 0"},
+    { PS_ERR_BASE, "first value we use; should avoid errno conflicts"},
+    { PS_ERR_UNKNOWN, "unknown error"},
+    { PS_ERR_IO, "I/O error"},
+    { PS_ERR_BADFREE, "bad argument to psFree()"},
+    { PS_ERR_MEMORY_CORRUPTION, "memory corruption detected"},
+    { PS_ERR_N_ERR_CLASSES, NULL},
+};
+\end{verbatim}
+
+\subsection{Example}
+
+The following output:
+\begin{verbatim}
+Traceback:
+tst.error.primary              I/O error                      Primary error
+ tst.error.middle              unknown error                  Secondary error
+  tst.error                    unknown error                  Toplevel error
+Last error is of unknown type
+Third oldest error is of type IO
+No errors. Hurrah
+\end{verbatim}
+
+produced by running this code:
+
+\begin{verbatim}
+#include "psLib.h"
+
+static int primary(int i)
+{
+    if (i != 0) {                       // let's pretend it's an I/O error
+        return psError("tst.error.primary", PS_ERR_IO, 1, "Primary error");
+    }
+
+    return 0;
+}
+
+static int middle(void)
+{
+    if (primary(1) != 0) {
+        return psError("tst.error.middle", PS_ERR_UNKNOWN, 0, "Secondary error");
+    }
+
+    return 0;
+}
+
+static int toplevel(void)
+{
+    if (middle() != 0) {
+        return psError("tst.error", PS_ERR_UNKNOWN, 0, "Toplevel error");
+    }
+
+    return 0;
+}
+
+int main(void)
+{
+    if (toplevel() != 0) {
+        psErrorStackPrint(stdout, "Traceback:\n");
+
+        if (psLastError()->code == PS_ERR_UNKNOWN) {
+            fprintf(stderr, "Last error is of unknown type\n");
+        }
+        if (psGetError(2)->code == PS_ERR_IO) {
+            fprintf(stderr, "Third oldest error is of type IO\n");
+        }
+    }
+
+    psErrorClear();
+    psErrorStackPrint(stdout, "Traceback:\n");
+
+    if (psLastError()->code == PS_ERR_NONE) {
+        fprintf(stderr, "No errors. Hurrah\n");
+    }
+
+    return 0;
+}
+\end{verbatim}
+
+%------------------------------------------------------------------------------
+
+\end{document}
