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.
69 static i_error_cb error_cb;
70 static i_failed_cb failed_cb;
71 static int failures_fatal;
74 =item i_set_argv0(char const *program)
76 Sets the name of the program to be displayed in fatal error messages.
78 The simplest way to use this is just:
82 when your program starts.
84 void i_set_argv0(char const *name) {
88 /* if the user has an existing string of MAXINT length then
89 the system is broken anyway */
90 dupl = mymalloc(strlen(name)+1); /* check 17jul05 tonyc */
98 =item i_set_failure_fatal(int failure_fatal)
100 If failure_fatal is non-zero then any future failures will result in
101 Imager exiting your program with a message describing the failure.
103 Returns the previous setting.
107 int i_set_failures_fatal(int fatal) {
108 int old = failures_fatal;
109 failures_fatal = fatal;
115 =item i_set_error_cb(i_error_cb)
117 Sets a callback function that is called each time an error is pushed
118 onto the error stack.
120 Returns the previous callback.
122 i_set_failed_cb() is probably more useful.
126 i_error_cb i_set_error_cb(i_error_cb cb) {
127 i_error_cb old = error_cb;
134 =item i_set_failed_cb(i_failed_cb cb)
136 Sets a callback function that is called each time an Imager function
139 Returns the previous callback.
143 i_failed_cb i_set_failed_cb(i_failed_cb cb) {
144 i_failed_cb old = failed_cb;
154 =synopsis i_errmsg *errors = im_errors(aIMCTX);
155 =synopsis i_errmsg *errors = i_errors();
157 Returns a pointer to the first element of an array of error messages,
158 terminated by a NULL pointer. The highest level message is first.
160 Also callable as C<i_errors()>.
164 i_errmsg *im_errors(im_context_t ctx) {
165 return ctx->error_stack + ctx->error_sp;
171 =head1 INTERNAL FUNCTIONS
173 These functions are called by Imager to report errors through the
176 It may be desirable to have functions to mark the stack and reset to
181 =item im_clear_error(ctx)
182 X<im_clear_error API>X<i_clear_error API>
183 =synopsis im_clear_error(aIMCTX);
184 =synopsis i_clear_error();
185 =category Error handling
187 Clears the error stack.
189 Called by any Imager function before doing any other processing.
191 Also callable as C<i_clear_error()>.
197 im_clear_error(im_context_t ctx) {
198 #ifdef IMAGER_DEBUG_MALLOC
201 for (i = 0; i < IM_ERROR_COUNT; ++i) {
202 if (ctx->error_space[i]) {
203 myfree(ctx->error_stack[i].msg);
204 ctx->error_stack[i].msg = NULL;
205 ctx->error_space[i] = 0;
209 ctx->error_sp = IM_ERROR_COUNT-1;
213 =item im_push_error(ctx, code, message)
214 X<im_push_error API>X<i_push_error API>
215 =synopsis i_push_error(0, "Yep, it's broken");
216 =synopsis i_push_error(errno, "Error writing");
217 =synopsis im_push_error(aIMCTX, 0, "Something is wrong");
218 =category Error handling
220 Called by an Imager function to push an error message onto the stack.
222 No message is pushed if the stack is full (since this means someone
223 forgot to call i_clear_error(), or that a function that doesn't do
224 error handling is calling function that does.).
229 im_push_error(im_context_t ctx, int code, char const *msg) {
230 size_t size = strlen(msg)+1;
232 if (ctx->error_sp <= 0)
233 /* bad, bad programmer */
237 if (ctx->error_alloc[ctx->error_sp] < size) {
238 if (ctx->error_stack[ctx->error_sp].msg)
239 myfree(ctx->error_stack[ctx->error_sp].msg);
240 /* memory allocated on the following line is only ever released when
241 we need a bigger string */
242 /* size is size (len+1) of an existing string, overflow would mean
243 the system is broken anyway */
244 ctx->error_stack[ctx->error_sp].msg = mymalloc(size); /* checked 17jul05 tonyc */
245 ctx->error_alloc[ctx->error_sp] = size;
247 strcpy(ctx->error_stack[ctx->error_sp].msg, msg);
248 ctx->error_stack[ctx->error_sp].code = code;
254 i_push_error(int code, char const *msg) {
255 im_push_error(im_get_context(), code, msg);
261 =item im_push_errorvf(ctx, code, format, args)
262 X<im_push_error_vf API>X<i_push_errorvf API>
263 =synopsis va_args args;
264 =synopsis va_start(args, lastarg);
265 =synopsis im_push_errorvf(ctx, code, format, args);
266 =category Error handling
268 Intended for use by higher level functions, takes a varargs pointer
269 and a format to produce the finally pushed error message.
271 Does not support perl specific format codes.
273 Also callable as C<i_push_errorvf(code, format, args)>
278 im_push_errorvf(im_context_t ctx, int code, char const *fmt, va_list ap) {
280 #if defined(IMAGER_VSNPRINTF)
281 vsnprintf(buf, sizeof(buf), fmt, ap);
282 #elif defined(_MSC_VER)
283 _vsnprintf(buf, sizeof(buf), fmt, ap);
285 /* is there a way to detect vsnprintf()?
286 for this and other functions we need some mechanism to handle
287 detection (like perl's Configure, or autoconf)
289 vsprintf(buf, fmt, ap);
291 im_push_error(ctx, code, buf);
295 =item i_push_errorf(int code, char const *fmt, ...)
296 =synopsis i_push_errorf(errno, "Cannot open file %s: %d", filename, errno);
297 =category Error handling
299 A version of i_push_error() that does printf() like formatting.
301 Does not support perl specific format codes.
306 i_push_errorf(int code, char const *fmt, ...) {
309 i_push_errorvf(code, fmt, ap);
314 =item im_push_errorf(ctx, code, char const *fmt, ...)
315 =synopsis im_push_errorf(aIMCTX, errno, "Cannot open file %s: %d", filename, errno);
316 =category Error handling
318 A version of im_push_error() that does printf() like formatting.
320 Does not support perl specific format codes.
325 im_push_errorf(im_context_t ctx, int code, char const *fmt, ...) {
328 im_push_errorvf(ctx, code, fmt, ap);
332 #ifdef IMAGER_I_FAILED
333 #error "This isn't used and is untested"
336 =item i_failed(char const *msg)
338 Called by Imager code to indicate that a top-level has failed.
340 msg can be NULL, in which case no error is pushed.
342 Calls the current failed callback, if any.
344 Aborts the program with an error, if failures have been set to be fatal.
346 Returns zero if it does not abort.
350 int i_failed(int code, char const *msg) {
352 i_push_error(code, msg);
354 failed_cb(error_stack + error_sp);
355 if (failures_fatal) {
357 size_t total; /* total length of error messages */
358 char *full; /* full message for logging */
360 fprintf(stderr, "%s: ", argv0);
361 fputs("error:\n", stderr);
363 while (error_stack[sp].msg) {
364 fprintf(stderr, " %s\n", error_stack[sp].msg);
367 /* we want to log the error too, build an error message to hand to
369 total = 1; /* remember the NUL */
370 for (sp = error_sp; error_stack[sp].msg; ++sp) {
371 size_t new_total += strlen(error_stack[sp].msg) + 2;
372 if (new_total < total) {
373 /* overflow, somehow */
377 full = mymalloc(total);
379 /* just quit, at least it's on stderr */
383 for (sp = error_sp; error_stack[sp].msg; ++sp) {
384 strcat(full, error_stack[sp].msg);
387 /* lose the extra ": " */
388 full[strlen(full)-2] = '\0';
389 i_fatal(EXIT_FAILURE, "%s", full);
398 =item im_assert_fail(file, line, message)
400 Called when an im_assert() assertion fails.
406 im_assert_fail(char const *file, int line, char const *message) {
407 fprintf(stderr, "Assertion failed line %d file %s: %s\n",
408 line, file, message);
417 This interface isn't thread safe.
421 Tony Cook <tony@develop-help.com>
423 Stack concept by Arnar Mar Hrafnkelsson <addi@umich.edu>