IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Ignore:
Timestamp:
Apr 26, 2004, 12:19:55 PM (22 years ago)
Author:
Paul Price
Message:

Added RHL's discussion on psError. This needs to be revised so that
additional errors may be added by other projects (e.g. MOPS).
Also put in a warning about the metadata: care needs to be taken when
trying to add a key that's already there.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/doc/pslib/psLibSDRS.tex

    r411 r516  
    1 %%% $Id: psLibSDRS.tex,v 1.36 2004-04-09 05:16:54 price Exp $
     1%%% $Id: psLibSDRS.tex,v 1.37 2004-04-26 22:19:55 price Exp $
    22\documentclass[panstarrs]{panstarrs}
    33
     
    2727\RevisionsStart
    2828% version  Date            Description
    29 DR-1       & 2003 Mar 11 & Draft \\
    30 \hline
    31 DR-2       & 2003 Mar 29 & Reorganized, spell-checked \\
     29DR & 2004 Mar 29 & Draft \\ \hline
     3000 & 2004 Apr 1  & First version, sent to MHPCC \\ \hline
     3101 & 2004 Apr 23 & Added section on error handling \\ \hline
    3232\RevisionsEnd
    3333
     
    3535
    3636\DocumentsInternal
    37 PSCD-430-xxx  &   PS-1 Design Reference Mission \\ \hline
     37PSCD-130-001  &   PS-1 Design Reference Mission \\ \hline
    3838PSCD-430-004  &   Pan-STARRS IPP C Code Conventions \\ \hline
    3939PSCD-430-005  &   Pan-STARRS IPP SRS \\ \hline
     
    801801%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    802802
    803 \subsection{Miscellaneous Utilities}
    804 
    805 We require several very low-level functions.  Two functions provide
    806 conveniences tied to the logging facilities:
    807 %
     803\subsection{Error Handling}
     804\hlabel{errorStack}
     805
     806\PS{} errors shall be raised using a function, \code{psError}, with
     807the caller supplying a component name and error message.  It is
     808desireable to be able to trace an error through the program so that
     809the events that led to the error may be quickly and clearly
     810identified.
     811
     812\begin{verbatim}
     813/// Prints an error message and doesn't abort; returns code
     814int psError(const char *name,           ///< Category of code that caused the error
     815            psErrorCode code,           ///< class of error (equivalent to errno)
     816            psErrorStatus status,       ///< is this a new error?
     817            const char *fmt,            ///< Format
     818            ...                         ///< Extra arguments to use format
     819    );
     820
     821typedef enum {
     822    PS_OLD_ERROR = 0,                   ///< This is an old error, and should append to the error stack
     823    PS_NEW_ERROR = 1,                   ///< This is a new error and should clear the error stack
     824} psErrorStatus;
     825\end{verbatim}
     826
     827The \code{name} is of the form \code{aaa.bbb.ccc} and identifies the
     828component raising the error.  The \code{psErrorCode} is an enumerated
     829type which lists the possible \textit{classes} of errors
     830(e.g. \code{PS_ERR_IO}) that \PS{} code can generate (see section
     831\ref{psErrorCodes}). \code{status} specifies whether this is a new
     832error, or whether this call to \code{psError} is in response to an
     833error that has already resulted in a call to \code{psError}.  The
     834final required argument, \code{fmt}, is a \code{printf}-style format
     835that is passed to \code{psLogMsg} with code \code{PS_LOG_ERROR}.
     836
     837The result of a call to \code{psError} shall be to push an error onto
     838a stack; this stack is cleared if \code{psErrorStatus} is true, or by a call
     839to \code{psErrorClear}.  The errors are defined as the following:
     840
     841\begin{verbatim}
     842typedef struct {
     843    char *name;                         ///< category of code that caused the error
     844    psErrorCode code;                   ///< class of error (equivalent to errno)
     845    char *msg;                          ///< the message associated with the error
     846} psErr;
     847\end{verbatim}
     848
     849
     850The last error reported is available from \code{psLastError}; if no
     851errors are current, a non-\code{NULL} \code{psErr} shall be returned
     852with code \code{PS_ERR_NONE}.  Previous errors on the stack shall be
     853returned by \code{psGetError} (a value of \code{0} passed to
     854\code{psGetError} is equivalent to a call to \code{psLastError}).
     855
     856\begin{verbatim}
     857const psErr *psGetError(int which);     ///< return specified error (or an "error" with code PS_ERR_NONE)
     858const psErr *psLastError(void);         ///< return last error (or an "error" with code PS_ERR_NONE)
     859\end{verbatim}
     860
     861The error stack may be completely cleared:
     862
     863\begin{verbatim}
     864void psErrorClear(void);                ///< Clear the error stack
     865\end{verbatim}
     866
     867The entire error stack may be printed to an open file descriptor by
     868calling \code{psErrorStackPrint} (or \code{psVErrorStackPrint}); if
     869and only if there are current errors, the printf-style string
     870\code{fmt} is first printed to the file descriptor \code{fd}. In this
     871printout, error codes shall be replaced by their string equivalents as
     872defined in the next section.  Note that these are also available in
     873the \code{psErr} structure. The successive lines of the traceback
     874should be indented by an additional space (see
     875example). \code{psVErrorStackPrint} shall not invoke \code{va_end}.
     876
     877\begin{verbatim}
     878void psErrorStackPrint(FILE *fd, const char *fmt, ...); ///< print the errorstack to this file descriptor
     879void psVErrorStackPrint(FILE *fd, const char *fmt, va_list va); ///< print the errorstack to this file
     880                                                                ///< descriptor
     881\end{verbatim}
     882
     883Any \code{errorCode}s less then or equal to \code{PS_ERR_BASE} (see
     884next section) shall be taken to be valid values of \code{errno}, and
     885\code{psErrorStackPrint} shall print the value returned by
     886\code{strerror} if such error codes are encountered.
     887
     888The routine \code{psErrorCodeString} returns the string associated
     889with an error code:
     890
     891\begin{verbatim}
     892const char *psErrorCodeString(psErrorCode code);        ///< return the string associated with an error code.
     893\end{verbatim}
     894
     895
     896\subsubsection{Error Codes}
     897\hlabel{psErrorCodes}
     898
     899The type \code{psErrorCode} is defined by an auxiliary file, conventionally named
     900\file{psErrorCodes.dat}. This file shall consist of a number of lines, each
     901of the form:
     902\begin{verbatim}
     903NAME [ = value ] , STRING
     904\end{verbatim}
     905where \code{[ = value]} is optional, and no spaces are significant except in the
     906STRING.  Comments extend from \code{#} to the end of the line (except that a
     907\code{\#} shall be replaced by \code{#} and not taken to start a comment). For example,
     908\begin{verbatim}
     909#
     910# This file is used to generate psErrorClasses.h
     911#
     912NONE = 0,               not an error; must be 0
     913BASE = 256,             first value we use; should avoid errno conflicts
     914UNKNOWN,                unknown error
     915IO,                     I/O error
     916BADFREE,                bad argument to psFree()
     917MEMORY_CORRUPTION,      memory corruption detected
     918\end{verbatim}
     919The values \code{NONE = 0} and {UNKNOWN} must be present.
     920
     921The \PS{} Makefiles shall
     922generate two files, \file{psErrorCodes.h} and
     923\file{psErrorCodes.c} from the input file \file{psErrorCodes.dat}.
     924\file{psErrorCodes.h} shall define an enumerated type
     925\code{psErrorCode} with elements \code{PS_ERR_NAME} and values as specified
     926in \file{psErrorCodes.dat}, e.g.
     927\begin{verbatim}
     928#if !defined(PS_ERROR_CODES_H)
     929#define PS_ERROR_CODES_H
     930
     931typedef enum {
     932    PS_ERR_NONE = 0,
     933    PS_ERR_BASE = 256,
     934    PS_ERR_UNKNOWN,
     935    PS_ERR_IO,
     936    PS_ERR_BADFREE,
     937    PS_ERR_MEMORY_CORRUPTION,
     938    PS_ERR_N_ERR_CLASSES,
     939} psErrorCode;
     940
     941#endif
     942\end{verbatim}
     943Any \code{errorCode}s less then or equal to \code{PS_ERR_BASE} shall be taken
     944to be valid values of \code{errno}.
     945
     946The implementation may add extra fields (e.g. \code{PS_ERR_N_ERR_CLASSES}).
     947
     948The latter shall be of the form
     949\begin{verbatim}
     950static struct {
     951    psErrorCode code;
     952    char *descrip;
     953} errorStrings[] = {
     954    { PS_ERR_NONE, "not an error; must be 0"},
     955    { PS_ERR_BASE, "first value we use; should avoid errno conflicts"},
     956    { PS_ERR_UNKNOWN, "unknown error"},
     957    { PS_ERR_IO, "I/O error"},
     958    { PS_ERR_BADFREE, "bad argument to psFree()"},
     959    { PS_ERR_MEMORY_CORRUPTION, "memory corruption detected"},
     960    { PS_ERR_N_ERR_CLASSES, NULL},
     961};
     962\end{verbatim}
     963
     964\subsubsection{Example}
     965
     966The following example code:
     967
     968\begin{verbatim}
     969#include "psLib.h"
     970
     971static int primary(int i)
     972{
     973    if (i != 0) {                       // let's pretend it's an I/O error
     974        return psError("tst.error.primary", PS_ERR_IO, 1, "Primary error");
     975    }
     976
     977    return 0;
     978}
     979
     980static int middle(void)
     981{
     982    if (primary(1) != 0) {
     983        return psError("tst.error.middle", PS_ERR_UNKNOWN, 0, "Secondary error");
     984    }
     985
     986    return 0;
     987}
     988
     989static int toplevel(void)
     990{
     991    if (middle() != 0) {
     992        return psError("tst.error", PS_ERR_UNKNOWN, 0, "Toplevel error");
     993    }
     994
     995    return 0;
     996}
     997
     998int main(void)
     999{
     1000    if (toplevel() != 0) {
     1001        psErrorStackPrint(stdout, "Traceback:\n");
     1002
     1003        if (psLastError()->code == PS_ERR_UNKNOWN) {
     1004            fprintf(stderr, "Last error is of unknown type\n");
     1005        }
     1006        if (psGetError(2)->code == PS_ERR_IO) {
     1007            fprintf(stderr, "Third oldest error is of type IO\n");
     1008        }
     1009    }
     1010
     1011    psErrorClear();
     1012    psErrorStackPrint(stdout, "Traceback:\n");
     1013
     1014    if (psLastError()->code == PS_ERR_NONE) {
     1015        fprintf(stderr, "No errors. Hurrah\n");
     1016    }
     1017
     1018    return 0;
     1019}
     1020\end{verbatim}
     1021
     1022
     1023Produces the following output:
     1024
     1025\begin{verbatim}
     1026Traceback:
     1027tst.error.primary              I/O error                      Primary error
     1028 tst.error.middle              unknown error                  Secondary error
     1029  tst.error                    unknown error                  Toplevel error
     1030Last error is of unknown type
     1031Third oldest error is of type IO
     1032No errors. Hurrah
     1033\end{verbatim}
     1034
     1035%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     1036
     1037\subsection{Abort}
     1038
     1039\code{psAbort}, shall call \code{psMsgLog} with a
     1040level of \code{PS_LOG_ABORT}, and then call \code{abort}.
     1041
    8081042\begin{verbatim}
    8091043void psAbort(char *name, char *fmt,...);
    810 void psError(char *name, char *fmt,...);
    811 \end{verbatim}
    812 %
    813 The first function, \code{psAbort}, shall call \code{psMsgLog} with a
    814 level of \code{PS_LOG_ABORT}, and then call \code{abort}.  The second
    815 function, \code{psError}, shall call \code{psMsgLog} with a level of
    816 \code{PS_LOG_ERROR}, and then return.  In cases of doubt, a good
    817 choice for \code{name} is \code{__func__}. 
    818 
    819 A few useful string functions are also necessary:
    820 %
    821 \begin{verbatim}
    822 PS_STRING(S);
    823 char *psStringCopy(char *string);
    824 char *psStringNCopy(char *string, int nChar);
    825 \end{verbatim}
    826 %
    827 The first function simply converts the argument to a string
    828 \tbd{explanation of usage and rationale?}.  The second function,
    829 \code{psStringCopy}, shall allocate a sufficient memory block and
    830 return a copy of the input string.  Similarly, \code{psStringNCopy}
    831 shall allocate exactly \code{nChar} bytes and copy as much of the
    832 input string as possible into the resulting block without overrunning
    833 the available space.  The last byte of the output string is required
    834 to be \code{NULL}, as well as any additional bytes if \code{string} is
    835 not long enough to fill the output string.
     1044\end{verbatim}
    8361045
    8371046%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     
    25802789second representation employs a hash table which allows fast look-up
    25812790given a specific metadata keyword.
    2582 
    2583 When we refer to ``metadata'' (especially in the case of images), we
    2584 generally mean a \code{psMetadata}:
    2585 \begin{verbatim}
    2586 typedef psMetadata psMetadata;
    2587 \end{verbatim}
    25882791
    25892792An example of the usage of the metadata APIs is as follows:
     
    27392942and the \tbd{first} item is returned.
    27402943
     2944Care should be taken not to leak memory when appending an item for
     2945which the key already exists in the metadata (and is not
     2946\code{PS_META_NON_UNIQUE}).
     2947
    27412948\begin{verbatim}
    27422949/// delete entry from the metadata
Note: See TracChangeset for help on using the changeset viewer.