1 /*
2  * Copyright 2001-2004 Brandon Long
3  * All Rights Reserved.
4  *
5  * ClearSilver Templating System
6  *
7  * This code is made available under the terms of the ClearSilver License.
8  * http://www.clearsilver.net/license.hdf
9  *
10  */
11 
12 #ifndef __NEO_ERR_H_
13 #define __NEO_ERR_H_ 1
14 
15 #include "util/neo_misc.h"
16 
17 /* For compilers (well, cpp actually) which don't define __PRETTY_FUNCTION__ */
18 #ifndef __GNUC__
19 #define __PRETTY_FUNCTION__ "unknown_function"
20 #endif
21 
22 __BEGIN_DECLS
23 
24 /* For 64 bit systems which don't like mixing ints and pointers, we have the
25  * _INT version for doing that comparison */
26 #define STATUS_OK ((NEOERR *)0)
27 #define STATUS_OK_INT 0
28 #define INTERNAL_ERR ((NEOERR *)1)
29 #define INTERNAL_ERR_INT 1
30 
31 /* NEOERR flags */
32 #define NE_IN_USE (1<<0)
33 
34 typedef int NERR_TYPE;
35 
36 /* Predefined Error Types - These are all registered in nerr_init */
37 extern NERR_TYPE NERR_PASS;
38 extern NERR_TYPE NERR_ASSERT;
39 extern NERR_TYPE NERR_NOT_FOUND;
40 extern NERR_TYPE NERR_DUPLICATE;
41 extern NERR_TYPE NERR_NOMEM;
42 extern NERR_TYPE NERR_PARSE;
43 extern NERR_TYPE NERR_OUTOFRANGE;
44 extern NERR_TYPE NERR_SYSTEM;
45 extern NERR_TYPE NERR_IO;
46 extern NERR_TYPE NERR_LOCK;
47 extern NERR_TYPE NERR_DB;
48 extern NERR_TYPE NERR_EXISTS;
49 
50 typedef struct _neo_err
51 {
52   int error;
53   int err_stack;
54   int flags;
55   char desc[256];
56   const char *file;
57   const char *func;
58   int lineno;
59   /* internal use only */
60   struct _neo_err *next;
61 } NEOERR;
62 
63 /* Technically, we could do this in configure and detect what their compiler
64  * can handle, but for now... */
65 #if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
66 #define USE_C99_VARARG_MACROS 1
67 #elif __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 4) || defined (S_SPLINT_S)
68 #define USE_GNUC_VARARG_MACROS 1
69 #else
70 #error The compiler is missing support for variable-argument macros.
71 #endif
72 
73 
74 /*
75  * function: nerr_raise
76  * description: Use this method to create an error "exception" for
77  *              return up the call chain
78  * arguments: using the macro, the function name, file, and lineno are
79  *            automagically recorded for you.  You just provide the
80  *            error (from those listed above) and the printf-style
81  *            reason.  THIS IS A PRINTF STYLE FUNCTION, DO NOT PASS
82  *            UNKNOWN STRING DATA AS THE FORMAT STRING.
83  * returns: a pointer to a NEOERR, or INTERNAL_ERR if allocation of
84  *          NEOERR fails
85  */
86 #if defined(USE_C99_VARARG_MACROS)
87 #define nerr_raise(e,f,...) \
88    nerr_raisef(__PRETTY_FUNCTION__,__FILE__,__LINE__,e,f,__VA_ARGS__)
89 #elif defined(USE_GNUC_VARARG_MACROS)
90 #define nerr_raise(e,f,a...) \
91    nerr_raisef(__PRETTY_FUNCTION__,__FILE__,__LINE__,e,f,##a)
92 #endif
93 
94 NEOERR *nerr_raisef (const char *func, const char *file, int lineno,
95                      NERR_TYPE error, const char *fmt, ...)
96                      ATTRIBUTE_PRINTF(5,6);
97 
98 
99 
100 #if defined(USE_C99_VARARG_MACROS)
101 #define nerr_raise_errno(e,f,...) \
102    nerr_raise_errnof(__PRETTY_FUNCTION__,__FILE__,__LINE__,e,f,__VA_ARGS__)
103 #elif defined(USE_GNUC_VARARG_MACROS)
104 #define nerr_raise_errno(e,f,a...) \
105    nerr_raise_errnof(__PRETTY_FUNCTION__,__FILE__,__LINE__,e,f,##a)
106 #endif
107 
108 NEOERR *nerr_raise_errnof (const char *func, const char *file, int lineno,
109                            int error, const char *fmt, ...)
110                            ATTRIBUTE_PRINTF(5,6);
111 
112 /* function: nerr_pass
113  * description: this function is used to pass an error up a level in the
114  *              call chain (ie, if the error isn't handled at the
115  *              current level).  This allows us to track the traceback
116  *              of the error.
117  * arguments: with the macro, the function name, file and lineno are
118  *            automagically recorded.  Just pass the error.
119  * returns: a pointer to an error
120  */
121 #define nerr_pass(e) \
122    nerr_passf(__PRETTY_FUNCTION__,__FILE__,__LINE__,e)
123 
124 NEOERR *nerr_passf (const char *func, const char *file, int lineno,
125                     NEOERR *err);
126 
127 /* function: nerr_pass_ctx
128  * description: this function is used to pass an error up a level in the
129  *              call chain (ie, if the error isn't handled at the
130  *              current level).  This allows us to track the traceback
131  *              of the error.
132  *              This version includes context information about lower
133  *              errors
134  * arguments: with the macro, the function name, file and lineno are
135  *            automagically recorded.  Just pass the error and
136  *            a printf format string giving more information about where
137  *            the error is occuring.
138  * returns: a pointer to an error
139  */
140 #if defined(USE_C99_VARARG_MACROS)
141 #define nerr_pass_ctx(e,f,...) \
142    nerr_pass_ctxf(__PRETTY_FUNCTION__,__FILE__,__LINE__,e,f,__VA_ARGS__)
143 #elif defined(USE_GNUC_VARARG_MACROS)
144 #define nerr_pass_ctx(e,f,a...) \
145    nerr_pass_ctxf(__PRETTY_FUNCTION__,__FILE__,__LINE__,e,f,##a)
146 #endif
147 
148 NEOERR *nerr_pass_ctxf (const char *func, const char *file, int lineno,
149                         NEOERR *err, const char *fmt, ...)
150                         ATTRIBUTE_PRINTF(5,6);
151 
152 /* function: nerr_log_error
153  * description: currently, this prints out the error to stderr, and
154  *             free's the error chain
155  */
156 void nerr_log_error (NEOERR *err);
157 
158 #include "util/neo_str.h"
159 /* function: nerr_error_string
160  * description: returns the string associated with an error (the bottom
161  *              level of the error chain)
162  * arguments: err - error
163  *            str - string to which the data is appended
164  * returns: None - errors appending to the string are ignored
165  */
166 void nerr_error_string (NEOERR *err, STRING *str);
167 
168 /* function: nerr_error_traceback
169  * description: returns the full traceback of the error chain
170  * arguments: err - error
171  *            str - string to which the data is appended
172  * returns: None - errors appending to the string are ignored
173  */
174 void nerr_error_traceback (NEOERR *err, STRING *str);
175 
176 /* function: nerr_ignore
177  * description: you should only call this if you actually handle the
178  *              error (should I rename it?).  Free's the error chain.
179  */
180 void nerr_ignore (NEOERR **err);
181 
182 /* function: nerr_register
183  * description: register an error type.  This will assign a numeric value
184  *              to the type, and keep track of the "pretty name" for it.
185  * arguments: err - pointer to a NERR_TYPE
186  *            name - pretty name for the error type
187  * returns: NERR_NOMEM on no memory
188  */
189 NEOERR *nerr_register (NERR_TYPE *err, const char *name);
190 
191 /* function: nerr_init
192  * description: initialize the NEOERR system.  Can be called more than once.
193  *              Is not thread safe.  This registers all of the built in
194  *              error types as defined at the top of this file.  If you don't
195  *              call this, all exceptions will be returned as UnknownError.
196  * arguments: None
197  * returns: possibly NERR_NOMEM, but somewhat unlikely.  Possibly an
198  *          UnknownError if NERR_NOMEM hasn't been registered yet.
199  */
200 NEOERR *nerr_init (void);
201 
202 /* function: nerr_match
203  * description: nerr_match is used to walk the NEOERR chain and match
204  *              the error against a specific error type.  In exception
205  *              parlance, this would be the equivalent of "catch".
206  *              Typically, you can just compare a NEOERR against STATUS_OK
207  *              or just test for true if you are checking for any error.
208  * arguments: err - the NEOERR that has an error.
209  *            type - the NEOERR type, as registered with nerr_register
210  * returns: true on match
211  */
212 int nerr_match (NEOERR *err, NERR_TYPE type);
213 
214 /* function: nerr_handle
215  * description: nerr_handle is a convenience function.  It is the equivalent
216  *              of nerr_match, but it will also deallocate the error chain
217  *              on a match.
218  * arguments: err - pointer to a pointer NEOERR
219  *            type - the NEOERR type, as registered with nerr_register
220  * returns: true on match
221  */
222 int nerr_handle (NEOERR **err, NERR_TYPE type);
223 
224 __END_DECLS
225 
226 #endif /* __NEO_ERR_H_ */
227