From ba066c34dde204aa192d03a23a81356374d93731 Mon Sep 17 00:00:00 2001 From: chatty Date: Wed, 7 Apr 1993 11:50:31 +0000 Subject: Initial revision --- comm/error.cc | 261 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 261 insertions(+) create mode 100644 comm/error.cc (limited to 'comm/error.cc') diff --git a/comm/error.cc b/comm/error.cc new file mode 100644 index 0000000..fc02eb9 --- /dev/null +++ b/comm/error.cc @@ -0,0 +1,261 @@ +/* + * The Unix Channel + * + * by Michel Beaudouin-Lafon + * + * Copyright 1990-1993 + * Laboratoire de Recherche en Informatique (LRI) + * + * Error management + * + * $Id$ + * $CurLog$ + */ + +#include "error.h" + +#include +#include +#include +#include + +/*?class UchERROR +The set of global functions described here are designed to handle errors. +An error has a type, an origin, and a message. +The type defines how the error is handled. +The origin and the message are used to generate the error message. +The origin is usually the function name where the error occurred. +A log file may be defined for storing all error messages, in addition to the normal +notification mechanism. + +Handling the error is a three steps process: +first the error string is generated, then the error is emitted by a user-defined error handler, +and finally the way the program continues is determined from the error type. +These types are described by the following values (enumerated type \typ{^{errtype}}): +\index{errtype :: ErrNone}\index{errtype :: ErrLog}\index{errtype :: ErrWarn} +\index{errtype :: ErrAbort}\index{errtype :: ErrExit}\index{errtype :: ErrFatal} +\index{errtype :: ErrUsage} +\begin{itemize} +\item \var{ErrNone} is not an error: the handler is not called and the program continues; +\item \var{ErrLog} is an error that is only logged to the log file: the handler is not called and the program continues; +\item \var{ErrWarn} is a warning: the handler is called and the program then continues; +\item \var{ErrAbort} handles the error and calls \fun{abort}; +\item \var{ErrExit} handles the error and calls \fun{exit(0)}; +\item \var{ErrFatal} handles the error and calls \fun{exit(1)}; +\item \var{ErrUsage} handles the error and calls \fun{exit(1)}; +\var{ErrUsage} is different from \var{ErrFatal} in that the generated error message +is not the same (see \fun{MakeErrorString}). +\end{itemize} + +The type of an error handler is the following: +\index{ErrorHandler} +\begin{ccode} +typedef errtype (*ErrorHandler) (errtype, const char* who, const char* what, const char* msg); +\end{ccode} +?*/ + +// static data for error handling: message table and default handler +// +char* ErrorTable [] = { + "Subclass should implement virtual member", // ErrShouldImplement +}; + +static char ProgName [128], LogFile [128]; +static bool LogOn =FALSE; + +static errtype +DefaultHandler (errtype how, const char* /*who*/, const char* /*what*/, const char* msg) +{ + write (2, msg, strlen (msg)); + return how; +} + +static ErrorHandler Handler = DefaultHandler; + +// main function for handling errors +// +static bool +HandleError (errtype how, const char* who, const char* what) +{ + if (how == ErrNone) + return TRUE; + + char *msg = MakeErrorString (how, who, what); + + if (how >= ErrLog && LogOn) { + LogMessage (msg); + if (how == ErrLog) + return TRUE; + } + + how = (*Handler) (how, who, what, msg); + + switch (how) { + case ErrNone: + return TRUE; + case ErrLog: + case ErrWarn: + break; + case ErrAbort: + write (2, "aborting\n", 9); + abort (); + break; + case ErrExit: + exit (0); + break; + case ErrUsage: + case ErrFatal: + exit (1); + break; + } + return FALSE; +} + +// public functions: +// register program name, cleanup function, log file +// change error handler +// error functions +// + +/*? +Set the program name, that is used to label each output message. +This usually called from \fun{main} with \com{argv[0]} as argument. +?*/ +void +ProgramName (const char* name) +{ + if (name) + strncpy (ProgName, name, sizeof (ProgName) -1); + else + ProgName [0] = 0; +} + +/*? +Set the log file name. +All messages are appended to the logfile. +If \var{reset} is TRUE, the file is cleared. +NOTE : logging is not currently implemented. +?*/ +void +LogfileName (const char* file, bool reset) +{ + if (file) { + strncpy (LogFile, file, sizeof (LogFile) -1); + LogOn = TRUE; + if (reset) { + // to do: clear logfile + } + } else + LogOn = FALSE; +} + +/*?nodoc?*/ +void +CleanUp (CleanUpProc) +{ + // to do: register function +} + +/*? +Append a message to the logfile, if one has been specified. +NOTE : logging is not currently implemented. +?*/ +void +LogMessage (const char*) +{ + // to be done +} + +/*? +Build an error message from the type of error, the place where the error occurred, +and the error message itself, with the following format:\\ +``\com{ [program\_name :] [fatal error in]}\var{who}\com{: }\var{what}''\\ +When \var{how} is \var{ErrUsage}, the format is\\ +``\com{ usage: program\_name}\var{what}''.\\ +The string returned is the address of a static buffer that is overwritten +each time this function is called. +?*/ +char* +MakeErrorString (errtype how, const char* who, const char* what) +{ + static char errmsg [1024]; + + if (how == ErrUsage) + sprintf (errmsg, "usage: %s %s\n", ProgName, what); + else + sprintf (errmsg, "%s%s%s%s: %s\n", + ProgName, + ProgName [0] ? ": " : "", + how >= ErrAbort ? "fatal error in " : "", + who, + what); + return errmsg; +} + +/*? +Change the error handler. +The error handler is called each time an error is emitted. +It is called with four arguments: +the error type, the error source, the error message, +and the error string as returned by \fun{MakeErrorString}. +It should return an error type (usually the first argument) that determines +what happens next: nothing, logging to a file, aborting, or exiting. +The default error handler can be reset by passing the argument 0. +The default error handler writes the error string to the standard error, +and returns its first argument. +?*/ +ErrorHandler +SetErrorHandler (ErrorHandler h) +{ + ErrorHandler old = Handler; + if (! h) + h = DefaultHandler; + Handler = h; + return old; +} + +/*? +Emit an error of type \var{how}, from function \var{who}, with message \var{what}. +?*/ +void +Error (errtype how, const char* who, const char* what) +{ + HandleError (how, who, what); +} + +/*? +Emit a system error of type \var{how}, from function \var{who}. +The message is retrieved from the value of the global variable \var{errno}. +Thus, this function should be used after system calls that set \var{errno}. +\var{exc1} and \var{exc2}, if non negative, are error codes (values of \var{errno}) to be ignored: +if the current error code is one of these, the function returns FALSE. +This is useful for instance to ignore interrupted system calls: +\begin{ccode} + #include + n = read (...); + if (n < 0) + SysError (ErrWarn, "read", EINTR); +\end{ccode} +?*/ +bool +SysError (errtype how, const char* who, int exc1, int exc2) +{ + extern int errno; + extern int sys_nerr; + extern char* sys_errlist []; + char* msg; + char defmsg [80]; + + if (! errno || errno == exc1 || errno == exc2) + return FALSE; + + if (errno >= sys_nerr) + sprintf (msg = defmsg, "system error code %d", errno); + else + if (errno == 0) + msg = "internal error"; + else + msg = sys_errlist [errno]; + return HandleError (how, who, msg); +} + -- cgit v1.1