polylib: errors.c Source File

- Main Page
- Classes
- Files

- File List
- File Members

# errors.c

Go to the documentation of this file.

    00001 /*
    00002     This file is part of PolyLib.
    00003
    00004     PolyLib is free software: you can redistribute it and/or modify
    00005     it under the terms of the GNU General Public License as published by
    00006     the Free Software Foundation, either version 3 of the License, or
    00007     (at your option) any later version.
    00008
    00009     PolyLib is distributed in the hope that it will be useful,
    00010     but WITHOUT ANY WARRANTY; without even the implied warranty of
    00011     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    00012     GNU General Public License for more details.
    00013
    00014     You should have received a copy of the GNU General Public License
    00015     along with PolyLib.  If not, see <http://www.gnu.org/licenses/>.
    00016 */
    00017
    00018 /*
    00019   $Id: errors.c,v 1.6 2006/03/15 19:59:37 verdoolaege Exp $
    00020
    00021   Exception management.
    00022   See "arithmetic_errors.h".
    00023
    00024   $Log: errors.c,v $
    00025   Revision 1.6  2006/03/15 19:59:37  verdoolaege
    00026   arith: add some missing consts
    00027
    00028   Revision 1.5  2004/08/31 18:01:56  verdoolaege
    00029   remove warning
    00030
    00031   Revision 1.4  2004/02/11 10:19:54  verdoolaege
    00032   add const qualifier
    00033
    00034   Revision 1.3  2004/02/08 21:53:27  kienhuis
    00035   Update from Fabien Coelho, via Bart Kienhuis
    00036
    00037   I've updated here in the C3/Linear library the arithmetic_error
    00038   package that I developped (with others) to handle exceptions in C.
    00039   It adds a simple callback feature which is needed for pips here.
    00040   If you do not use it, it should not harm;-)
    00041
    00042   Revision 1.27  2003/09/04 09:40:37  coelho
    00043   init added.
    00044   verbosity mask added.
    00045
    00046   Revision 1.26  2003/09/03 14:05:20  coelho
    00047   push/pop callbacks called.
    00048
    00049   Revision 1.20  2003/08/18 09:55:09  coelho
    00050   get_exception_name added...
    00051
    00052   Revision 1.19  2003/06/13 13:59:07  coelho
    00053   const out.
    00054
    00055   Revision 1.18  2003/06/13 13:54:47  coelho
    00056   hop.
    00057
    00058   Revision 1.17  2002/04/02 08:44:54  coelho
    00059   timeout_error ajoute.
    00060
    00061   Revision 1.16  2000/10/27 13:26:03  ancourt
    00062   exception_thrown -> linear_number_of_exception_thrown
    00063
    00064   Revision 1.15  2000/07/27 15:21:55  coelho
    00065   message++
    00066
    00067   Revision 1.14  2000/07/27 14:59:59  coelho
    00068   trace added.
    00069
    00070   Revision 1.13  2000/07/26 08:41:23  coelho
    00071   the_last_just_thrown_exception management added.
    00072
    00073   Revision 1.12  1998/10/26 18:48:34  coelho
    00074   message++.
    00075
    00076   Revision 1.11  1998/10/26 14:38:06  coelho
    00077   constants back in.
    00078
    00079   Revision 1.10  1998/10/26 14:35:47  coelho
    00080   constants in .h.
    00081
    00082   Revision 1.9  1998/10/24 15:36:22  coelho
    00083   better exception error messages...
    00084
    00085   Revision 1.8  1998/10/24 15:19:17  coelho
    00086   more verbose throw...
    00087
    00088   Revision 1.7  1998/10/24 14:31:13  coelho
    00089   new stack implementation.
    00090   checks for matching catch/uncatch.
    00091   debug mode.
    00092
    00093   Revision 1.6  1998/10/24 09:31:06  coelho
    00094   RCS headers.
    00095   'const' tried.
    00096
    00097 */
    00098
    00099 #include <stdio.h>
    00100 #include <stdlib.h>
    00101 #include <string.h>
    00102
    00103 #include "arithmetique.h"
    00104
    00105 /* global constants to designate exceptions.
    00106    to be put in the type field bellow.
    00107    cproto 4.6 does not line 'const'...
    00108 */
    00109 unsigned int overflow_error = 1;
    00110 unsigned int simplex_arithmetic_error = 2;
    00111 unsigned int user_exception_error = 4;
    00112 unsigned int parser_exception_error = 8;
    00113 unsigned int timeout_error = 16;
    00114
    00115 /* catch all */
    00116 unsigned int any_exception_error = ~0;
    00117
    00118
    00119 /*
    00120  * On a few systems, type boolean and/or its values FALSE, TRUE may appear
    00121  * in standard header files.  Or you may have conflicts with application-
    00122  * specific header files that you want to include together with these files.
    00123  * Defining HAVE_BOOLEAN before including jpeglib.h should make it work.
    00124  */
    00125
    00126 #ifndef HAVE_BOOLEAN
    00127 typedef int boolean;
    00128 #endif
    00129 #ifndef FALSE                   /* in case these macros already exist */
    00130 #define FALSE   0               /* values of boolean */
    00131 #endif
    00132 #ifndef TRUE
    00133 #define TRUE    1
    00134 #endif
    00135
    00136 const char *get_exception_name(unsigned int exception)
    00137 {
    00138   if (exception==overflow_error)
    00139     return "overflow_error exception";
    00140   if (exception==simplex_arithmetic_error)
    00141     return "simplex_arithmetic_error exception";
    00142   if (exception==user_exception_error)
    00143     return "user_exception_error exception";
    00144   if (exception==parser_exception_error)
    00145     return "parser_exception_error exception";
    00146   if (exception==timeout_error)
    00147     return "timeout_error exception";
    00148   if (exception==any_exception_error)
    00149     return "all exceptions mask";
    00150
    00151   return "unknown or mixed exception";
    00152 }
    00153
    00154 /* keep track of last thrown exception for RETHROW()
    00155  */
    00156 unsigned int the_last_just_thrown_exception = 0;
    00157
    00158 /* whether to run in debug mode (that is to trace catch/uncatch/throw)
    00159  */
    00160 static int linear_exception_debug_mode = FALSE;
    00161 static unsigned int linear_exception_verbose = 1 | 2 | 16 ;
    00162
    00163 /* A structure for the exception stack.
    00164  */
    00165 typedef struct
    00166 {
    00167   /* exception type.
    00168    */
    00169   int what;
    00170
    00171   /* where to jump to.
    00172    */
    00173   jmp_buf where;
    00174
    00175   /* location of the CATCH to be matched against the UNCATCH.
    00176    */
    00177   const char * function;
    00178   const char * file;
    00179   int    line;
    00180 }
    00181   linear_exception_holder;
    00182
    00183 /* exception stack.
    00184    maximum extension.
    00185    current index (next available bucket)
    00186  */
    00187 #define MAX_STACKED_CONTEXTS 64
    00188 static linear_exception_holder exception_stack[MAX_STACKED_CONTEXTS];
    00189 static int exception_index = 0;
    00190
    00191 /* callbacks...
    00192  */
    00193 static exception_callback_t push_callback = NULL;
    00194 static exception_callback_t pop_callback = NULL;
    00195
    00196 void set_exception_callbacks(exception_callback_t push,
    00197                              exception_callback_t pop)
    00198 {
    00199   if (push_callback!=NULL || pop_callback!=NULL)
    00200   {
    00201     fprintf(stderr, "exception callbacks already defined! (%p, %p)\n",
    00202             push_callback, pop_callback);
    00203     abort();
    00204   }
    00205
    00206   push_callback = push;
    00207   pop_callback = pop;
    00208 }
    00209
    00210 /* total number of exceptions thrown, for statistics.
    00211  */
    00212 int linear_number_of_exception_thrown = 0;
    00213
    00214 /* dump stack
    00215  */
    00216 void dump_exception_stack_to_file(FILE * f)
    00217 {
    00218   int i;
    00219   fprintf(f, "[dump_exception_stack_to_file] size=%d\n", exception_index);
    00220   for (i=0; i<exception_index; i++)
    00221   {
    00222     fprintf(f,
    00223             "%d: [%s:%d in %s (%d)]\n",
    00224             i,
    00225             exception_stack[i].file,
    00226             exception_stack[i].line,
    00227             exception_stack[i].function,
    00228             exception_stack[i].what);
    00229   }
    00230   fprintf(f, "\n");
    00231 }
    00232
    00233 void dump_exception_stack()
    00234 {
    00235   dump_exception_stack_to_file(stderr);
    00236 }
    00237
    00238 #define exception_debug_message(type)                             \
    00239     fprintf(stderr, "%s[%s:%d %s (%d)/%d]\n",                     \
    00240             type, file, line, function, what, exception_index)
    00241
    00242 #define exception_debug_trace(type) \
    00243     if (linear_exception_debug_mode) { exception_debug_message(type); }
    00244
    00245
    00246 /* push a what exception on stack.
    00247  */
    00248 jmp_buf *
    00249 push_exception_on_stack(
    00250     int what,
    00251     const char * function,
    00252     const char * file,
    00253     int line)
    00254 {
    00255   exception_debug_trace("PUSH ");
    00256
    00257   if (exception_index==MAX_STACKED_CONTEXTS)
    00258   {
    00259     exception_debug_message("push");
    00260     fprintf(stderr, "exception stack overflow\n");
    00261     dump_exception_stack();
    00262     abort();
    00263   }
    00264
    00265   if (push_callback) push_callback(file, function, line);
    00266
    00267   the_last_just_thrown_exception = 0;
    00268
    00269   exception_stack[exception_index].what = what;
    00270   exception_stack[exception_index].function = function;
    00271   exception_stack[exception_index].file = file;
    00272   exception_stack[exception_index].line = line;
    00273
    00274   return & exception_stack[exception_index++].where;
    00275 }
    00276
    00277 #if !defined(same_string_p)
    00278 #define same_string_p(s1, s2) (strcmp((s1),(s2))==0)
    00279 #endif
    00280
    00281 /* pop a what exception.
    00282    check for any mismatch!
    00283  */
    00284 void
    00285 pop_exception_from_stack(
    00286     int what,
    00287     const char * function,
    00288     const char * file,
    00289     int line)
    00290 {
    00291   exception_debug_trace("POP  ");
    00292
    00293   if (exception_index==0)
    00294   {
    00295     exception_debug_message("pop");
    00296     fprintf(stderr, "exception stack underflow\n");
    00297     dump_exception_stack();
    00298     abort();
    00299   }
    00300
    00301   if (pop_callback) pop_callback(file, function, line);
    00302
    00303   exception_index--;
    00304   the_last_just_thrown_exception = 0;
    00305
    00306   if ((exception_stack[exception_index].what != what) ||
    00307       !same_string_p(exception_stack[exception_index].file, file) ||
    00308       !same_string_p(exception_stack[exception_index].function, function))
    00309   {
    00310     exception_debug_message("pop");
    00311     fprintf(stderr,
    00312             "exception stack mismatch at depth=%d:\n"
    00313             "   CATCH: %s:%d in %s (%d)\n"
    00314             " UNCATCH: %s:%d in %s (%d)\n",
    00315             exception_index,
    00316             exception_stack[exception_index].file,
    00317             exception_stack[exception_index].line,
    00318             exception_stack[exception_index].function,
    00319             exception_stack[exception_index].what,
    00320             file, line, function, what);
    00321     dump_exception_stack();
    00322     abort();
    00323   }
    00324 }
    00325
    00326 /* throws an exception of a given type by searching for
    00327    the specified 'what' in the current exception stack.
    00328 */
    00329 void throw_exception(
    00330     int what,
    00331     const char * function,
    00332     const char * file,
    00333     int line)
    00334 {
    00335   int i;
    00336
    00337   exception_debug_trace("THROW");
    00338
    00339   the_last_just_thrown_exception = what; /* for rethrow */
    00340
    00341   for (i=exception_index-1; i>=0; i--)
    00342   {
    00343     if (pop_callback)
    00344       /* pop with push parameters! */
    00345       pop_callback(exception_stack[i].file,
    00346                    exception_stack[i].function,
    00347                    exception_stack[i].line);
    00348
    00349     if (exception_stack[i].what & what)
    00350     {
    00351       exception_index = i;
    00352       linear_number_of_exception_thrown++;
    00353
    00354       if (linear_exception_debug_mode)
    00355         fprintf(stderr, "---->[%s:%d %s (%d)/%d]\n",
    00356                 exception_stack[i].file,
    00357                 exception_stack[i].line,
    00358                 exception_stack[i].function,
    00359                 exception_stack[i].what,
    00360                 i);
    00361
    00362       /* trace some exceptions... */
    00363       if (linear_exception_verbose & what)
    00364         fprintf(stderr, "exception %d/%d: %s(%s:%d) -> %s(%s:%d)\n",
    00365                 what, exception_stack[i].what,
    00366                 function, file, line,
    00367                 exception_stack[i].function,
    00368                 exception_stack[i].file,
    00369                 exception_stack[i].line);
    00370
    00371       longjmp(exception_stack[i].where, 0);
    00372     }
    00373   }
    00374
    00375   /* error. */
    00376   exception_debug_message("throw");
    00377   fprintf(stderr,
    00378           "exception not found in stack:\n"
    00379           "an exception was THROWN without a proper matching CATCH\n");
    00380   dump_exception_stack();
    00381   abort();
    00382 }
    00383
    00384 void linear_initialize_exception_stack(
    00385   unsigned int verbose_exceptions,
    00386   exception_callback_t push,
    00387   exception_callback_t pop)
    00388 {
    00389   linear_exception_verbose = verbose_exceptions;
    00390   set_exception_callbacks(push, pop);
    00391 }