]> git.imager.perl.org - imager.git/blame - error.c
[rt #75878] pass --verbose through to Imager::Probe in sub-modules
[imager.git] / error.c
CommitLineData
606237f9
TC
1/*
2=head1 NAME
3
4error.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
40This module provides the C level error handling functionality for
41Imager.
42
c5cf7614
TC
43A few functions return or pass in an i_errmsg *, this is list of error
44structures, terminated by an entry with a NULL msg value, each of
45which contains a msg and an error code. Even though these aren't
46passed as i_errmsg const * pointers, don't modify the strings
47or the pointers.
606237f9
TC
48
49The interface as currently defined isn't thread safe, unfortunately.
50
51This code uses Imager's mymalloc() for memory allocation, so out of
52memory errors are I<always> fatal.
53
54=head1 INTERFACE
55
56These functions form the interface that a user of Imager sees (from
57C). The Perl level won't use all of this.
58
59=over
60
61=cut
62*/
63
d03fd5a4 64#include "imager.h"
606237f9
TC
65#include <stdio.h>
66#include <stdlib.h>
67
d03fd5a4
TC
68/* we never actually use the last item - it's the NULL terminator */
69#define ERRSTK 20
70static i_errmsg error_stack[ERRSTK];
71static 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. */
76static int error_space[ERRSTK];
77
78static i_error_cb error_cb;
79static i_failed_cb failed_cb;
80static int failures_fatal;
81static char *argv0;
82
83/*
84=item i_set_argv0(char const *program)
85
86Sets the name of the program to be displayed in fatal error messages.
87
88The simplest way to use this is just:
89
90 i_set_argv0(argv[0]);
91
92when your program starts.
93*/
94void i_set_argv0(char const *name) {
95 char *dupl;
96 if (!name)
97 return;
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 */
101 strcpy(dupl, name);
102 if (argv0)
103 myfree(argv0);
104 argv0 = dupl;
105}
106
606237f9 107/*
d03fd5a4
TC
108=item i_set_failure_fatal(int failure_fatal)
109
110If failure_fatal is non-zero then any future failures will result in
111Imager exiting your program with a message describing the failure.
112
113Returns the previous setting.
114
115=cut
116*/
117int i_set_failures_fatal(int fatal) {
118 int old = failures_fatal;
119 failures_fatal = fatal;
120
121 return old;
122}
123
124/*
125=item i_set_error_cb(i_error_cb)
126
127Sets a callback function that is called each time an error is pushed
128onto the error stack.
129
130Returns the previous callback.
131
132i_set_failed_cb() is probably more useful.
133
134=cut
135*/
136i_error_cb i_set_error_cb(i_error_cb cb) {
137 i_error_cb old = error_cb;
138 error_cb = cb;
139
140 return old;
141}
142
143/*
144=item i_set_failed_cb(i_failed_cb cb)
145
146Sets a callback function that is called each time an Imager function
147fails.
148
149Returns the previous callback.
150
151=cut
152*/
153i_failed_cb i_set_failed_cb(i_failed_cb cb) {
154 i_failed_cb old = failed_cb;
155 failed_cb = cb;
156
157 return old;
158}
159
160/*
161=item i_errors()
606237f9
TC
162
163Returns a pointer to the first element of an array of error messages,
164terminated by a NULL pointer. The highest level message is first.
165
166=cut
167*/
d03fd5a4
TC
168i_errmsg *i_errors() {
169 return error_stack + error_sp;
9c852bc4
TC
170}
171
606237f9
TC
172/*
173=back
174
175=head1 INTERNAL FUNCTIONS
176
177These functions are called by Imager to report errors through the
178above interface.
179
180It may be desirable to have functions to mark the stack and reset to
181the mark.
182
183=over
184
d03fd5a4 185=item i_clear_error()
6cfee9d1 186=synopsis i_clear_error();
92bda632
TC
187=category Error handling
188
189Clears the error stack.
190
5715f7c3 191Called by any Imager function before doing any other processing.
606237f9 192
92bda632
TC
193=cut
194*/
d03fd5a4 195void i_clear_error() {
cd4b0b20
TC
196#ifdef IMAGER_DEBUG_MALLOC
197 int i;
198
d03fd5a4
TC
199 for (i = 0; i < ERRSTK; ++i) {
200 if (error_space[i]) {
201 myfree(error_stack[i].msg);
202 error_stack[i].msg = NULL;
203 error_space[i] = 0;
cd4b0b20
TC
204 }
205 }
206#endif
d03fd5a4 207 error_sp = ERRSTK-1;
9c852bc4
TC
208}
209
606237f9 210/*
d03fd5a4 211=item i_push_error(int code, char const *msg)
6cfee9d1
TC
212=synopsis i_push_error(0, "Yep, it's broken");
213=synopsis i_push_error(errno, "Error writing");
92bda632
TC
214=category Error handling
215
6cfee9d1 216Called by an Imager function to push an error message onto the stack.
606237f9
TC
217
218No message is pushed if the stack is full (since this means someone
219forgot to call i_clear_error(), or that a function that doesn't do
220error handling is calling function that does.).
221
222=cut
223*/
d03fd5a4 224void i_push_error(int code, char const *msg) {
8d14daab 225 size_t size = strlen(msg)+1;
606237f9 226
d03fd5a4 227 if (error_sp <= 0)
606237f9
TC
228 /* bad, bad programmer */
229 return;
230
d03fd5a4
TC
231 --error_sp;
232 if (error_space[error_sp] < size) {
233 if (error_stack[error_sp].msg)
234 myfree(error_stack[error_sp].msg);
f0960b14 235 /* memory allocated on the following line is only ever released when
606237f9 236 we need a bigger string */
f0960b14
TC
237 /* size is size (len+1) of an existing string, overflow would mean
238 the system is broken anyway */
d03fd5a4
TC
239 error_stack[error_sp].msg = mymalloc(size); /* checked 17jul05 tonyc */
240 error_space[error_sp] = size;
606237f9 241 }
d03fd5a4
TC
242 strcpy(error_stack[error_sp].msg, msg);
243 error_stack[error_sp].code = code;
244
245 if (error_cb)
246 error_cb(code, msg);
9c852bc4 247}
606237f9 248
c5cf7614 249/*
d03fd5a4
TC
250=item i_push_errorvf(int C<code>, char const *C<fmt>, va_list C<ap>)
251
92bda632
TC
252=category Error handling
253
c5cf7614
TC
254Intended for use by higher level functions, takes a varargs pointer
255and a format to produce the finally pushed error message.
256
6cfee9d1
TC
257Does not support perl specific format codes.
258
c5cf7614
TC
259=cut
260*/
d03fd5a4 261void i_push_errorvf(int code, char const *fmt, va_list ap) {
c5cf7614 262 char buf[1024];
86c8d19a
TC
263#if defined(IMAGER_VSNPRINTF)
264 vsnprintf(buf, sizeof(buf), fmt, ap);
265#elif defined(_MSC_VER)
c5cf7614
TC
266 _vsnprintf(buf, sizeof(buf), fmt, ap);
267#else
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)
271 */
272 vsprintf(buf, fmt, ap);
273#endif
d03fd5a4 274 i_push_error(code, buf);
9c852bc4
TC
275}
276
c5cf7614
TC
277/*
278=item i_push_errorf(int code, char const *fmt, ...)
6cfee9d1 279=synopsis i_push_errorf(errno, "Cannot open file %s: %d", filename, errno);
92bda632
TC
280=category Error handling
281
5715f7c3 282A version of i_push_error() that does printf() like formatting.
c5cf7614 283
6cfee9d1
TC
284Does not support perl specific format codes.
285
c5cf7614
TC
286=cut
287*/
d03fd5a4 288void i_push_errorf(int code, char const *fmt, ...) {
c5cf7614
TC
289 va_list ap;
290 va_start(ap, fmt);
291 i_push_errorvf(code, fmt, ap);
292 va_end(ap);
606237f9
TC
293}
294
f0960b14
TC
295#ifdef IMAGER_I_FAILED
296#error "This isn't used and is untested"
297
606237f9
TC
298/*
299=item i_failed(char const *msg)
300
301Called by Imager code to indicate that a top-level has failed.
302
c5cf7614 303msg can be NULL, in which case no error is pushed.
606237f9
TC
304
305Calls the current failed callback, if any.
306
307Aborts the program with an error, if failures have been set to be fatal.
308
309Returns zero if it does not abort.
310
311=cut
312*/
c5cf7614 313int i_failed(int code, char const *msg) {
606237f9 314 if (msg)
c5cf7614 315 i_push_error(code, msg);
606237f9
TC
316 if (failed_cb)
317 failed_cb(error_stack + error_sp);
318 if (failures_fatal) {
c5cf7614 319 int sp;
8d14daab 320 size_t total; /* total length of error messages */
c5cf7614 321 char *full; /* full message for logging */
606237f9
TC
322 if (argv0)
323 fprintf(stderr, "%s: ", argv0);
324 fputs("error:\n", stderr);
c5cf7614
TC
325 sp = error_sp;
326 while (error_stack[sp].msg) {
a743c0a6 327 fprintf(stderr, " %s\n", error_stack[sp].msg);
c5cf7614
TC
328 ++sp;
329 }
330 /* we want to log the error too, build an error message to hand to
b1e96952 331 i_fatal() */
c5cf7614
TC
332 total = 1; /* remember the NUL */
333 for (sp = error_sp; error_stack[sp].msg; ++sp) {
8d14daab
TC
334 size_t new_total += strlen(error_stack[sp].msg) + 2;
335 if (new_total < total) {
336 /* overflow, somehow */
337 break;
338 }
c5cf7614 339 }
a6c47345 340 full = mymalloc(total);
c5cf7614
TC
341 if (!full) {
342 /* just quit, at least it's on stderr */
343 exit(EXIT_FAILURE);
344 }
345 *full = 0;
346 for (sp = error_sp; error_stack[sp].msg; ++sp) {
347 strcat(full, error_stack[sp].msg);
348 strcat(full, ": ");
606237f9 349 }
c5cf7614
TC
350 /* lose the extra ": " */
351 full[strlen(full)-2] = '\0';
b1e96952 352 i_fatal(EXIT_FAILURE, "%s", full);
606237f9
TC
353 }
354
355 return 0;
356}
357
f0960b14
TC
358#endif
359
b3afeed5
TC
360/*
361=item im_assert_fail(file, line, message)
362
363Called when an im_assert() assertion fails.
364
365=cut
366*/
367
368void
369im_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);
d03fd5a4 372 exit(EXIT_FAILURE);
b3afeed5
TC
373}
374
606237f9
TC
375/*
376=back
377
378=head1 BUGS
379
380This interface isn't thread safe.
381
382=head1 AUTHOR
383
384Tony Cook <tony@develop-help.com>
385
386Stack concept by Arnar Mar Hrafnkelsson <addi@umich.edu>
387
388=cut
389*/