1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398
|
/**
*
* File: $RCSfile: gan_err.c,v $
* Module: Exception module
* Part of: Gandalf Library
*
* Revision: $Revision: 1.9 $
* Last edited: $Date: 2003/01/31 18:56:41 $
* Author: $Author: pm $
* Copyright: (c) 2000 Industrial Research Limited
*/
/* This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <stdio.h>
#include <gandalf/common/gan_err_trace.h>
#include <gandalf/common/gan_err.h>
/**
* \addtogroup Common
* \{
*/
/**
* \defgroup CommonError Error Handling
* \{
*/
/*
* \brief Default error reporter.
* \return No value.
*
* Typically the application should provide its own error reporter.
*/
static void
gan_err_default_reporter(void)
{
int i, n; /* Loop counter */
const char * func_name;
int err_code;
const char * file_name;
int line_number;
const char * message;
n = gan_err_get_error_count();
for ( i = 1; i<=n; i++ )
{
if ((gan_err_get_error(i, &func_name, &err_code, &file_name,
&line_number, &message ) != GAN_EC_OK))
fprintf(stderr, "**** gan_err_get_error unsuccessful\n");
fprintf(stderr, "\nError number %d\n", i );
fprintf(stderr, "func_name = %s\n", func_name );
fprintf(stderr, "err_code = %d\n", err_code );
fprintf(stderr, "file_name = %s\n", file_name );
fprintf(stderr, "line_number = %d\n", line_number );
fprintf(stderr, "message = %s\n", message );
}
fprintf(stderr, "gan_err_default_reporter()\n");
}
/* Pointer to current error reporting function. This is setup using
* gan_err_set_reporter(), and typically invoked using gan_err_report().
*
* Default reporter is gan_err_default_reporter().
*/
static Gan_ErrorReporterFunc
gan_err_current_reporter = gan_err_default_reporter;
/* Flag indicating Trace Mode - see GAN_ERR_TRACE_X in gan_exception.h for
* details. Default action is to set trace off. Permitted values are:
* GAN_ERR_TRACE_OFF or GAN_ERR_TRACE_ON.
*/
static Gan_TraceMode gan_err_trace_mode = GAN_ERR_TRACE_OFF;
/* The error trace */
/* Statically allocate last and 2nd to last records for error trace */
static Gan_ErrorTrace record_last = { NULL, GAN_ET_YES, GAN_ET_NO,
GAN_ET_YES, NULL,
GAN_EC_DFT_SPARE, NULL, 0, NULL };
static Gan_ErrorTrace record_2nd_last = { &record_last, GAN_ET_YES, GAN_ET_NO,
GAN_ET_YES, NULL,
GAN_EC_DFT_SPARE, NULL, 0, NULL };
/* Address of error trace (i.e. top of LIFO stack) */
static Gan_ErrorTrace * gan_err_trace_top = &record_2nd_last;
/**
* \brief Installs an error reporter
* \param app_error_reporter Pointer to an application defined function
* \return Pointer to previously installed error reporter, if successful.
* \c NULL otherwise.
*
* This exception module allows an application defined function to be called
* when an error is reported using gan_err_report().
* gan_err_set_reporter() installs this error reporter.
* \a app_error_reporter should be a pointer to an application defined function
* to access error details, or the macros:
* - GAN_ERR_DFL To set default error reporter
* - GAN_ERR_IGN To ignore error reporting
*
* If GAN_ERR_DFL is provided, then the default error reporter (see below) is
* installed.
* \warning The default error reporter simply writes a message to \c stderr.
* The exception module is initialised to use the default error
* reporter.
* \sa gan_err_get_reporter().
* \note Other functions that invoke the current error handler must check first
* if it is set to #GAN_ERR_IGN. If so, ignore the invocation.
* gan_err_current_reporter() is module scope variable.
*/
Gan_ErrorReporterFunc gan_err_set_reporter(
Gan_ErrorReporterFunc app_error_reporter )
{
/* Buffer old handler, so that it can be returned */
Gan_ErrorReporterFunc gan_err_temp_reporter = gan_err_current_reporter;
/* Set reporter, noting default (GAN_ERR_DFL) or ignore
(GAN_ERR_IGN) modes */
if ( app_error_reporter == GAN_ERR_DFL )
gan_err_current_reporter = gan_err_default_reporter;
else if ( app_error_reporter == GAN_ERR_IGN )
gan_err_current_reporter = GAN_ERR_IGN;
else
gan_err_current_reporter = app_error_reporter; /* Set reporter */
return gan_err_temp_reporter;
}
/**
* \brief Returns current error reporter.
* \return Pointer to current error reporter, or #GAN_ERR_DFL or #GAN_ERR_IGN.
*
* Returns current error reporter.
*
* \sa gan_err_set_reporter().
*/
Gan_ErrorReporterFunc
gan_err_get_reporter(void)
{
return gan_err_current_reporter;
}
/**
* \brief Registers occurence of an error.
* \param func_name Name of function in which error occurs
* \param err_code Numeric code of error
* \param file_name Name of file in which error occurs
* \param line_number Line in file at which error occurs
* \param message Message string describing error
*
* \return The error number of error registered. #GAN_EC_DFT_DEEP_ERROR if a
* deep error occurs, \a err_code otherwise.
*
* Registers occurence of an error. Intended to be called at the lowest
* function level immediately after the occurence of an error, and called at
* every level of the function call stack during unwinding, until the error is
* handled, or it unwinds into a function level where a different error
* handling mechanism is used.
*
* If the trace mode is #GAN_ERR_TRACE_OFF, this function causes the current
* error reporter to called immediately. If the trace mode is
* #GAN_ERR_TRACE_ON, this function causes the details of the error to be
* placed onto an error trace. The error details are reported in "batch" at a
* later time upon invokation of gan_err_report().
*
* \warning #GAN_EC_DFT_DEEP_ERROR is registered in the top record of the error
* trace if a deep error occurs. The error requested to be registered
* is placed in the second top record of the error trace. This error
* may be missing the message string, because it may have been the
* process of allocating memory for this string that caused the deep
* error to occur.
*
* This function is typically called using the macro gan_err_register().
*
* \sa gan_err_register() (macro), gan_err_set_trace().
* \note If trace mode is off then call error reporter immediately, otherwise
* push error details onto error trace.
*/
int
gan_err_register_fileline ( const char *func_name,
int err_code,
const char *file_name,
int line_number,
const char *message )
{
Gan_ErrorTrace *atrace = NULL;
int the_err_code = GAN_EC_FAIL; /* Registered error code */
/* When trace mode is off, still use the trace, but flush it before and
* after use.
*/
if ( gan_err_trace_mode == GAN_ERR_TRACE_OFF )
gan_err_trace_top = gan_et_flush_trace(gan_err_trace_top);
gan_err_trace_top = gan_et_push ( gan_err_trace_top, func_name, err_code,
file_name, line_number, message );
/* Note the registered error code. Could be a deep error */
if ( (atrace = gan_et_get_record_first(gan_err_trace_top)) != NULL )
the_err_code = atrace->err_code;
/* Report immediately. Use trace as interim storage. Flush afterwards */
if ( gan_err_trace_mode == GAN_ERR_TRACE_OFF )
{
gan_err_report();
gan_err_trace_top = gan_et_flush_trace(gan_err_trace_top);
/* This flush is belts and braces. The primary flush is at the head
* of this function.
*/
}
return the_err_code;
}
/**
* \brief Invokes current error reporter.
* \return No value.
*
* Invokes current error reporter. That's all. It is the responsibility of the
* error reporter to traverse the error trace, read the details of each error,
* and to report those details in whatever application specific manner it
* chooses.
*
* This function is automatically called from gan_err_register_fileline() when
* trace mode is OFF.
*
* \warning The error reporter will not be called if
* gan_err_set_reporter(#GAN_ERR_IGN) has been called.
* The default error reporter is called when
* gan_err_set_reporter(#GAN_ERR_DFL);
* \sa gan_err_set_trace(), gan_err_set_reporter().
*/
void
gan_err_report(void)
{
if (gan_err_current_reporter == GAN_ERR_DFL )
gan_err_default_reporter();
else if ( gan_err_current_reporter != GAN_ERR_IGN )
gan_err_current_reporter();
return;
} /* gan_err_report() */
/**
* \brief Enable or disable use of trace to store error details.
* \param trace_mode Whether to switch trace mode on or off
* \return No value.
*
* A trace is a data structure that stacks error details for subsequent
* reporting (activated by gan_err_report()). If trace is disabled by
* passing \a trace_mode as #GAN_ERR_TRACE_OFF, then errors are reported
* immediately upon being registered i.e. when gan_err_register() is called.
* Otherwise trace mode is switched on by passing #GAN_ERR_TRACE_ON.
*
* \warning Trace mode is initialised to #GAN_ERR_TRACE_OFF.
* Any non-zero trace_mode is assumed equivalent to
* #GAN_ERR_TRACE_OFF.
* When trace is turned off, the trace is flushed immediately.
* \sa gan_err_report(), gan_err_register().
*/
void
gan_err_set_trace( Gan_TraceMode trace_mode )
{
if ( trace_mode == GAN_ERR_TRACE_OFF )
gan_err_trace_top = gan_et_flush_trace(gan_err_trace_top);
gan_err_trace_mode = trace_mode;
return;
}
/**
* \brief Flush all errors in trace.
* \return No value.
*
* Flush all errors in error trace
* \note Traverse error trace from start to finish deleting all error records
* (except two reserved ones which are transparent to this module).
*/
void
gan_err_flush_trace( void )
{
gan_err_trace_top = gan_et_flush_trace(gan_err_trace_top);
return;
} /* gan_err_flush_trace() */
/**
* \brief Gets the number of errors in error trace.
* \return Number of errors in error trace.
*
* Gets the number of errors in error trace.
*
* \sa gan_err_get_error().
*/
int
gan_err_get_error_count( void )
{
return gan_et_get_record_count(gan_err_trace_top);
} /* gan_err_get_error_count() */
/**
* \brief Gets details of n-th error stored in the error trace.
* \param n Index of requested error [1..N]
* \param func_name Name of function in which error occurs
* \param err_code Numeric code of error
* \param file_name Name of file in which error occurs
* \param line_number Line in file at which error occurs
* \param message Message string describing error
* \return Status of n-th error.
*
* If any of above pointers are \c NULL, then those details are not returned.
*
* Gets details of \a n-th error. \a n=1 refers to the most recent error
* registered in error trace. Usually gan_err_get_error_count() is called to
* obtain the number of error records in the trace. Return values:
* - #GAN_EC_DFT_BAD_N Index '\a n' out of bounds,
* - #GAN_EC_DFT_EMPTY Error trace is empty (regardless of requested n)
* - #GAN_EC_OK Otherwise.
*
* \warning The returned strings (\a func_name, \a file_name, \a message) are
* not guaranteed to exist at a later time, nor should they be
* modified in place. Therefore the calling function must either
* use the returned strings immediately or make copies.
*
* Because the stack is numbered from the top (1=most
* recent) an arbitrary index i may refer to different
* error records at different times. However, index 1
* always refers to the most recent error.
*
* \sa gan_err_get_error_count().
*/
int
gan_err_get_error ( int n,
const char **func_name,
int *err_code,
const char **file_name,
int *line_number,
const char **message )
{
int count;
int i; /* Loop counter */
Gan_ErrorTrace *a_record = NULL;
if ( (count = gan_et_get_record_count(gan_err_trace_top)) < 1 )
return GAN_EC_DFT_EMPTY; /* Error trace is empty */
/* Boundary check on n */
if ( (n < 1) || (n > count) )
return GAN_EC_DFT_BAD_N; /* Out of bounds, bye */
for ( a_record = gan_et_get_record_first(gan_err_trace_top), i = 1;
i < n; i++ )
a_record = gan_et_get_record_next(a_record); /* Step to N-th error */
if ( func_name != NULL )
*func_name = a_record->func_name;
if ( err_code != NULL )
*err_code = a_record->err_code;
if ( file_name != NULL )
*file_name = a_record->file_name;
if ( line_number != NULL )
*line_number = a_record->line_number;
if ( message != NULL )
*message = a_record->message;
return GAN_EC_OK;
} /* gan_err_get_error() */
/**
* \}
*/
/**
* \}
*/
|