4 error.c - error reporting code for Imager
9 int new_fatal; // non-zero if errors are fatal
10 int old_fatal = i_set_failure_fatal(new_fatal);
11 i_set_argv0("name of your program");
12 extern void error_cb(char const *);
14 old_ecb = i_set_error_cb(error_cb);
16 extern void failed_cb(char **errors);
17 old_fcb = i_set_failed_cb(failed_cb);
18 if (!i_something(...)) {
19 char **errors = i_errors();
23 undef_int i_something(...) {
25 if (!some_lower_func(...)) {
26 return i_failed("could not something");
30 undef_int some_lower_func(...) {
31 if (somethingelse_failed()) {
32 i_push_error("could not somethingelse");
40 This module provides the C level error handling functionality for
43 A few functions return or pass in an i_errmsg *, this is list of error
44 structures, terminated by an entry with a NULL msg value, each of
45 which contains a msg and an error code. Even though these aren't
46 passed as i_errmsg const * pointers, don't modify the strings
49 The interface as currently defined isn't thread safe, unfortunately.
51 This code uses Imager's mymalloc() for memory allocation, so out of
52 memory errors are I<always> fatal.
56 These functions form the interface that a user of Imager sees (from
57 C). The Perl level won't use all of this.
68 /* we never actually use the last item - it's the NULL terminator */
70 static i_errmsg error_stack[ERRSTK];
71 static int error_sp = ERRSTK - 1;
72 /* we track the amount of space used each string, so we don't reallocate
73 space unless we need to.
74 This also means that a memory tracking library may see the memory
75 allocated for this as a leak. */
76 static int error_space[ERRSTK];
78 static i_error_cb error_cb;
79 static i_failed_cb failed_cb;
80 static int failures_fatal;
84 =item i_set_argv0(char const *program)
86 Sets the name of the program to be displayed in fatal error messages.
88 The simplest way to use this is just:
92 when your program starts.
94 void i_set_argv0(char const *name) {
98 /* if the user has an existing string of MAXINT length then
99 the system is broken anyway */
100 dupl = mymalloc(strlen(name)+1); /* check 17jul05 tonyc */
108 =item i_set_failure_fatal(int failure_fatal)
110 If failure_fatal is non-zero then any future failures will result in
111 Imager exiting your program with a message describing the failure.
113 Returns the previous setting.
117 int i_set_failures_fatal(int fatal) {
118 int old = failures_fatal;
119 failures_fatal = fatal;
125 =item i_set_error_cb(i_error_cb)
127 Sets a callback function that is called each time an error is pushed
128 onto the error stack.
130 Returns the previous callback.
132 i_set_failed_cb() is probably more useful.
136 i_error_cb i_set_error_cb(i_error_cb cb) {
137 i_error_cb old = error_cb;
144 =item i_set_failed_cb(i_failed_cb cb)
146 Sets a callback function that is called each time an Imager function
149 Returns the previous callback.
153 i_failed_cb i_set_failed_cb(i_failed_cb cb) {
154 i_failed_cb old = failed_cb;
163 Returns a pointer to the first element of an array of error messages,
164 terminated by a NULL pointer. The highest level message is first.
168 i_errmsg *i_errors() {
169 return error_stack + error_sp;
175 =head1 INTERNAL FUNCTIONS
177 These functions are called by Imager to report errors through the
180 It may be desirable to have functions to mark the stack and reset to
185 =item i_clear_error()
187 Called by any imager function before doing any other processing.
190 void i_clear_error() {
191 #ifdef IMAGER_DEBUG_MALLOC
194 for (i = 0; i < ERRSTK; ++i) {
195 if (error_space[i]) {
196 myfree(error_stack[i].msg);
197 error_stack[i].msg = NULL;
206 =item i_push_error(int code, char const *msg)
208 Called by an imager function to push an error message onto the stack.
210 No message is pushed if the stack is full (since this means someone
211 forgot to call i_clear_error(), or that a function that doesn't do
212 error handling is calling function that does.).
216 void i_push_error(int code, char const *msg) {
217 int size = strlen(msg)+1;
220 /* bad, bad programmer */
224 if (error_space[error_sp] < size) {
225 if (error_stack[error_sp].msg)
226 myfree(error_stack[error_sp].msg);
227 /* memory allocated on the following line is only ever released when
228 we need a bigger string */
229 /* size is size (len+1) of an existing string, overflow would mean
230 the system is broken anyway */
231 error_stack[error_sp].msg = mymalloc(size); /* checked 17jul05 tonyc */
232 error_space[error_sp] = size;
234 strcpy(error_stack[error_sp].msg, msg);
235 error_stack[error_sp].code = code;
242 =item i_push_errorvf(int code, char const *fmt, va_list ap)
244 Intended for use by higher level functions, takes a varargs pointer
245 and a format to produce the finally pushed error message.
249 void i_push_errorvf(int code, char const *fmt, va_list ap) {
251 #if defined(_MSC_VER)
252 _vsnprintf(buf, sizeof(buf), fmt, ap);
254 /* is there a way to detect vsnprintf()?
255 for this and other functions we need some mechanism to handle
256 detection (like perl's Configure, or autoconf)
258 vsprintf(buf, fmt, ap);
260 i_push_error(code, buf);
264 =item i_push_errorf(int code, char const *fmt, ...)
266 A version of i_push_error() that does printf() like formating.
270 void i_push_errorf(int code, char const *fmt, ...) {
273 i_push_errorvf(code, fmt, ap);
277 #ifdef IMAGER_I_FAILED
278 #error "This isn't used and is untested"
281 =item i_failed(char const *msg)
283 Called by Imager code to indicate that a top-level has failed.
285 msg can be NULL, in which case no error is pushed.
287 Calls the current failed callback, if any.
289 Aborts the program with an error, if failures have been set to be fatal.
291 Returns zero if it does not abort.
295 int i_failed(int code, char const *msg) {
297 i_push_error(code, msg);
299 failed_cb(error_stack + error_sp);
300 if (failures_fatal) {
302 int total; /* total length of error messages */
303 char *full; /* full message for logging */
305 fprintf(stderr, "%s: ", argv0);
306 fputs("error:\n", stderr);
308 while (error_stack[sp].msg) {
309 fprintf(stderr, " %s\n", error_stack[sp].msg);
312 /* we want to log the error too, build an error message to hand to
314 total = 1; /* remember the NUL */
315 for (sp = error_sp; error_stack[sp].msg; ++sp) {
316 total += strlen(error_stack[sp].msg) + 2;
318 full = mymalloc(total);
320 /* just quit, at least it's on stderr */
324 for (sp = error_sp; error_stack[sp].msg; ++sp) {
325 strcat(full, error_stack[sp].msg);
328 /* lose the extra ": " */
329 full[strlen(full)-2] = '\0';
330 m_fatal(EXIT_FAILURE, "%s", full);
343 This interface isn't thread safe.
347 Tony Cook <tony@develop-help.com>
349 Stack concept by Arnar Mar Hrafnkelsson <addi@umich.edu>