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()
186 =synopsis i_clear_error();
187 =category Error handling
189 Clears the error stack.
191 Called by any Imager function before doing any other processing.
195 void i_clear_error() {
196 #ifdef IMAGER_DEBUG_MALLOC
199 for (i = 0; i < ERRSTK; ++i) {
200 if (error_space[i]) {
201 myfree(error_stack[i].msg);
202 error_stack[i].msg = NULL;
211 =item i_push_error(int code, char const *msg)
212 =synopsis i_push_error(0, "Yep, it's broken");
213 =synopsis i_push_error(errno, "Error writing");
214 =category Error handling
216 Called by an Imager function to push an error message onto the stack.
218 No message is pushed if the stack is full (since this means someone
219 forgot to call i_clear_error(), or that a function that doesn't do
220 error handling is calling function that does.).
224 void i_push_error(int code, char const *msg) {
225 size_t size = strlen(msg)+1;
228 /* bad, bad programmer */
232 if (error_space[error_sp] < size) {
233 if (error_stack[error_sp].msg)
234 myfree(error_stack[error_sp].msg);
235 /* memory allocated on the following line is only ever released when
236 we need a bigger string */
237 /* size is size (len+1) of an existing string, overflow would mean
238 the system is broken anyway */
239 error_stack[error_sp].msg = mymalloc(size); /* checked 17jul05 tonyc */
240 error_space[error_sp] = size;
242 strcpy(error_stack[error_sp].msg, msg);
243 error_stack[error_sp].code = code;
250 =item i_push_errorvf(int C<code>, char const *C<fmt>, va_list C<ap>)
252 =category Error handling
254 Intended for use by higher level functions, takes a varargs pointer
255 and a format to produce the finally pushed error message.
257 Does not support perl specific format codes.
261 void i_push_errorvf(int code, char const *fmt, va_list ap) {
263 #if defined(IMAGER_VSNPRINTF)
264 vsnprintf(buf, sizeof(buf), fmt, ap);
265 #elif defined(_MSC_VER)
266 _vsnprintf(buf, sizeof(buf), fmt, ap);
268 /* is there a way to detect vsnprintf()?
269 for this and other functions we need some mechanism to handle
270 detection (like perl's Configure, or autoconf)
272 vsprintf(buf, fmt, ap);
274 i_push_error(code, buf);
278 =item i_push_errorf(int code, char const *fmt, ...)
279 =synopsis i_push_errorf(errno, "Cannot open file %s: %d", filename, errno);
280 =category Error handling
282 A version of i_push_error() that does printf() like formatting.
284 Does not support perl specific format codes.
288 void i_push_errorf(int code, char const *fmt, ...) {
291 i_push_errorvf(code, fmt, ap);
295 #ifdef IMAGER_I_FAILED
296 #error "This isn't used and is untested"
299 =item i_failed(char const *msg)
301 Called by Imager code to indicate that a top-level has failed.
303 msg can be NULL, in which case no error is pushed.
305 Calls the current failed callback, if any.
307 Aborts the program with an error, if failures have been set to be fatal.
309 Returns zero if it does not abort.
313 int i_failed(int code, char const *msg) {
315 i_push_error(code, msg);
317 failed_cb(error_stack + error_sp);
318 if (failures_fatal) {
320 size_t total; /* total length of error messages */
321 char *full; /* full message for logging */
323 fprintf(stderr, "%s: ", argv0);
324 fputs("error:\n", stderr);
326 while (error_stack[sp].msg) {
327 fprintf(stderr, " %s\n", error_stack[sp].msg);
330 /* we want to log the error too, build an error message to hand to
332 total = 1; /* remember the NUL */
333 for (sp = error_sp; error_stack[sp].msg; ++sp) {
334 size_t new_total += strlen(error_stack[sp].msg) + 2;
335 if (new_total < total) {
336 /* overflow, somehow */
340 full = mymalloc(total);
342 /* just quit, at least it's on stderr */
346 for (sp = error_sp; error_stack[sp].msg; ++sp) {
347 strcat(full, error_stack[sp].msg);
350 /* lose the extra ": " */
351 full[strlen(full)-2] = '\0';
352 i_fatal(EXIT_FAILURE, "%s", full);
361 =item im_assert_fail(file, line, message)
363 Called when an im_assert() assertion fails.
369 im_assert_fail(char const *file, int line, char const *message) {
370 fprintf(stderr, "Assertion failed line %d file %s: %s\n",
371 line, file, message);
380 This interface isn't thread safe.
384 Tony Cook <tony@develop-help.com>
386 Stack concept by Arnar Mar Hrafnkelsson <addi@umich.edu>