fill out documentation
[imager.git] / error.c
1 /*
2 =head1 NAME
3
4 error.c - error reporting code for Imager
5
6 =head1 SYNOPSIS
7
8   // user code:
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 *);
13   i_error_cb old_ecb;
14   old_ecb = i_set_error_cb(error_cb);
15   i_failed_cb old_fcb;
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();
20   }
21
22   // imager code:
23   undef_int i_something(...) {
24     i_clear_error();
25     if (!some_lower_func(...)) {
26       return i_failed("could not something");
27     }
28     return 1;
29   }
30   undef_int some_lower_func(...) {
31     if (somethingelse_failed()) {
32       i_push_error("could not somethingelse");
33       return 0;
34     }
35     return 1;
36   }
37
38 =head1 DESCRIPTION
39
40 This module provides the C level error handling functionality for
41 Imager.
42
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
47 or the pointers.
48
49 The interface as currently defined isn't thread safe, unfortunately.
50
51 This code uses Imager's mymalloc() for memory allocation, so out of
52 memory errors are I<always> fatal.
53
54 =head1 INTERFACE
55
56 These functions form the interface that a user of Imager sees (from
57 C).  The Perl level won't use all of this.
58
59 =over
60
61 =cut
62 */
63
64 #include "imageri.h"
65 #include <stdio.h>
66 #include <stdlib.h>
67
68 #if 0
69 static i_error_cb error_cb;
70 static i_failed_cb failed_cb;
71 static int failures_fatal;
72 static char *argv0;
73 /*
74 =item i_set_argv0(char const *program)
75
76 Sets the name of the program to be displayed in fatal error messages.
77
78 The simplest way to use this is just:
79
80   i_set_argv0(argv[0]);
81
82 when your program starts.
83 */
84 void i_set_argv0(char const *name) {
85   char *dupl;
86   if (!name)
87     return;
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 */
91   strcpy(dupl, name);
92   if (argv0)
93     myfree(argv0);
94   argv0 = dupl;
95 }
96
97 /*
98 =item i_set_failure_fatal(int failure_fatal)
99
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.
102
103 Returns the previous setting.
104
105 =cut
106 */
107 int i_set_failures_fatal(int fatal) {
108   int old = failures_fatal;
109   failures_fatal = fatal;
110
111   return old;
112 }
113
114 /*
115 =item i_set_error_cb(i_error_cb)
116
117 Sets a callback function that is called each time an error is pushed
118 onto the error stack.
119
120 Returns the previous callback.
121
122 i_set_failed_cb() is probably more useful.
123
124 =cut
125 */
126 i_error_cb i_set_error_cb(i_error_cb cb) {
127   i_error_cb old = error_cb;
128   error_cb = cb;
129
130   return old;
131 }
132
133 /*
134 =item i_set_failed_cb(i_failed_cb cb)
135
136 Sets a callback function that is called each time an Imager function
137 fails.
138
139 Returns the previous callback.
140
141 =cut
142 */
143 i_failed_cb i_set_failed_cb(i_failed_cb cb) {
144   i_failed_cb old = failed_cb;
145   failed_cb = cb;
146
147   return old;
148 }
149
150 #endif
151
152 /*
153 =item im_errors(ctx)
154 =synopsis i_errmsg *errors = im_errors(aIMCTX);
155 =synopsis i_errmsg *errors = i_errors();
156
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.
159
160 Also callable as C<i_errors()>.
161
162 =cut
163 */
164 i_errmsg *im_errors(im_context_t ctx) {
165   return ctx->error_stack + ctx->error_sp;
166 }
167
168 /*
169 =back
170
171 =head1 INTERNAL FUNCTIONS
172
173 These functions are called by Imager to report errors through the
174 above interface.
175
176 It may be desirable to have functions to mark the stack and reset to
177 the mark.
178
179 =over
180
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
186
187 Clears the error stack.
188
189 Called by any Imager function before doing any other processing.
190
191 Also callable as C<i_clear_error()>.
192
193 =cut
194 */
195
196 void
197 im_clear_error(im_context_t ctx) {
198 #ifdef IMAGER_DEBUG_MALLOC
199   int i;
200
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;
206     }
207   }
208 #endif
209   ctx->error_sp = IM_ERROR_COUNT-1;
210 }
211
212 /*
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
219
220 Called by an Imager function to push an error message onto the stack.
221
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.).
225
226 =cut
227 */
228 void
229 im_push_error(im_context_t ctx, int code, char const *msg) {
230   size_t size = strlen(msg)+1;
231
232   if (ctx->error_sp <= 0)
233     /* bad, bad programmer */
234     return;
235
236   --ctx->error_sp;
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;
246   }
247   strcpy(ctx->error_stack[ctx->error_sp].msg, msg);
248   ctx->error_stack[ctx->error_sp].code = code;
249 }
250
251 #if 0
252
253 void
254 i_push_error(int code, char const *msg) {
255   im_push_error(im_get_context(), code, msg);
256 }
257
258 #endif
259
260 /*
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
267
268 Intended for use by higher level functions, takes a varargs pointer
269 and a format to produce the finally pushed error message.
270
271 Does not support perl specific format codes.
272
273 Also callable as C<i_push_errorvf(code, format, args)>
274
275 =cut
276 */
277 void 
278 im_push_errorvf(im_context_t ctx, int code, char const *fmt, va_list ap) {
279   char buf[1024];
280 #if defined(IMAGER_VSNPRINTF)
281   vsnprintf(buf, sizeof(buf), fmt, ap);
282 #elif defined(_MSC_VER)
283   _vsnprintf(buf, sizeof(buf), fmt, ap);
284 #else
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)
288    */
289   vsprintf(buf, fmt, ap);
290 #endif
291   im_push_error(ctx, code, buf);
292 }
293
294 /*
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
298
299 A version of i_push_error() that does printf() like formatting.
300
301 Does not support perl specific format codes.
302
303 =cut
304 */
305 void
306 i_push_errorf(int code, char const *fmt, ...) {
307   va_list ap;
308   va_start(ap, fmt);
309   i_push_errorvf(code, fmt, ap);
310   va_end(ap);
311 }
312
313 /*
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
317
318 A version of im_push_error() that does printf() like formatting.
319
320 Does not support perl specific format codes.
321
322 =cut
323 */
324 void
325 im_push_errorf(im_context_t ctx, int code, char const *fmt, ...) {
326   va_list ap;
327   va_start(ap, fmt);
328   im_push_errorvf(ctx, code, fmt, ap);
329   va_end(ap);
330 }
331
332 #ifdef IMAGER_I_FAILED
333 #error "This isn't used and is untested"
334
335 /*
336 =item i_failed(char const *msg)
337
338 Called by Imager code to indicate that a top-level has failed.
339
340 msg can be NULL, in which case no error is pushed.
341
342 Calls the current failed callback, if any.
343
344 Aborts the program with an error, if failures have been set to be fatal.
345
346 Returns zero if it does not abort.
347
348 =cut
349 */
350 int i_failed(int code, char const *msg) {
351   if (msg)
352     i_push_error(code, msg);
353   if (failed_cb)
354     failed_cb(error_stack + error_sp);
355   if (failures_fatal) {
356     int sp;
357     size_t total; /* total length of error messages */
358     char *full; /* full message for logging */
359     if (argv0)
360       fprintf(stderr, "%s: ", argv0);
361     fputs("error:\n", stderr);
362     sp = error_sp;
363     while (error_stack[sp].msg) {
364       fprintf(stderr, " %s\n", error_stack[sp].msg);
365       ++sp;
366     }
367     /* we want to log the error too, build an error message to hand to
368        i_fatal() */
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 */
374         break;
375       }
376     }
377     full = mymalloc(total);
378     if (!full) {
379       /* just quit, at least it's on stderr */
380       exit(EXIT_FAILURE);
381     }
382     *full = 0;
383     for (sp = error_sp; error_stack[sp].msg; ++sp) {
384       strcat(full, error_stack[sp].msg);
385       strcat(full, ": ");
386     }
387     /* lose the extra ": " */
388     full[strlen(full)-2] = '\0';
389     i_fatal(EXIT_FAILURE, "%s", full);
390   }
391
392   return 0;
393 }
394
395 #endif
396
397 /*
398 =item im_assert_fail(file, line, message)
399
400 Called when an im_assert() assertion fails.
401
402 =cut
403 */
404
405 void
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);
409   abort();
410 }
411
412 /*
413 =back
414
415 =head1 BUGS
416
417 This interface isn't thread safe.
418
419 =head1 AUTHOR
420
421 Tony Cook <tony@develop-help.com>
422
423 Stack concept by Arnar Mar Hrafnkelsson <addi@umich.edu>
424
425 =cut
426 */