File Coverage

error.c
Criterion Covered Total %
statement 30 34 88.2
branch 5 6 83.3
condition n/a
subroutine n/a
pod n/a
total 35 40 87.5


line stmt bran cond sub pod time code
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 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
66             #include
67              
68             /*
69             =item im_errors(ctx)
70             =synopsis i_errmsg *errors = im_errors(aIMCTX);
71             =synopsis i_errmsg *errors = i_errors();
72              
73             Returns a pointer to the first element of an array of error messages,
74             terminated by a NULL pointer. The highest level message is first.
75              
76             Also callable as C.
77              
78             =cut
79             */
80 348           i_errmsg *im_errors(im_context_t ctx) {
81 348           return ctx->error_stack + ctx->error_sp;
82             }
83              
84             /*
85             =back
86              
87             =head1 INTERNAL FUNCTIONS
88              
89             These functions are called by Imager to report errors through the
90             above interface.
91              
92             It may be desirable to have functions to mark the stack and reset to
93             the mark.
94              
95             =over
96              
97             =item im_clear_error(ctx)
98             XX
99             =synopsis im_clear_error(aIMCTX);
100             =synopsis i_clear_error();
101             =category Error handling
102              
103             Clears the error stack.
104              
105             Called by any Imager function before doing any other processing.
106              
107             Also callable as C.
108              
109             =cut
110             */
111              
112             void
113 2434           im_clear_error(im_context_t ctx) {
114             #ifdef IMAGER_DEBUG_MALLOC
115             int i;
116              
117             for (i = 0; i < IM_ERROR_COUNT; ++i) {
118             if (ctx->error_space[i]) {
119             myfree(ctx->error_stack[i].msg);
120             ctx->error_stack[i].msg = NULL;
121             ctx->error_space[i] = 0;
122             }
123             }
124             #endif
125 2434           ctx->error_sp = IM_ERROR_COUNT-1;
126 2434           }
127              
128             /*
129             =item im_push_error(ctx, code, message)
130             XX
131             =synopsis i_push_error(0, "Yep, it's broken");
132             =synopsis i_push_error(errno, "Error writing");
133             =synopsis im_push_error(aIMCTX, 0, "Something is wrong");
134             =category Error handling
135              
136             Called by an Imager function to push an error message onto the stack.
137              
138             No message is pushed if the stack is full (since this means someone
139             forgot to call i_clear_error(), or that a function that doesn't do
140             error handling is calling function that does.).
141              
142             =cut
143             */
144             void
145 417           im_push_error(im_context_t ctx, int code, char const *msg) {
146 417           size_t size = strlen(msg)+1;
147              
148 417 50         if (ctx->error_sp <= 0)
149             /* bad, bad programmer */
150 0           return;
151              
152 417           --ctx->error_sp;
153 417 100         if (ctx->error_alloc[ctx->error_sp] < size) {
154 90 100         if (ctx->error_stack[ctx->error_sp].msg)
155 33           myfree(ctx->error_stack[ctx->error_sp].msg);
156             /* memory allocated on the following line is only ever released when
157             we need a bigger string */
158             /* size is size (len+1) of an existing string, overflow would mean
159             the system is broken anyway */
160 90           ctx->error_stack[ctx->error_sp].msg = mymalloc(size); /* checked 17jul05 tonyc */
161 90           ctx->error_alloc[ctx->error_sp] = size;
162             }
163 417           strcpy(ctx->error_stack[ctx->error_sp].msg, msg);
164 417           ctx->error_stack[ctx->error_sp].code = code;
165             }
166              
167             /*
168             =item im_push_errorvf(ctx, code, format, args)
169             XX
170             =synopsis va_args args;
171             =synopsis va_start(args, lastarg);
172             =synopsis im_push_errorvf(ctx, code, format, args);
173             =category Error handling
174              
175             Intended for use by higher level functions, takes a varargs pointer
176             and a format to produce the finally pushed error message.
177              
178             Does not support perl specific format codes.
179              
180             Also callable as C
181              
182             =cut
183             */
184             void
185 92           im_push_errorvf(im_context_t ctx, int code, char const *fmt, va_list ap) {
186             char buf[1024];
187             #if defined(IMAGER_VSNPRINTF)
188 92           vsnprintf(buf, sizeof(buf), fmt, ap);
189             #elif defined(_MSC_VER)
190             _vsnprintf(buf, sizeof(buf), fmt, ap);
191             #else
192             /* is there a way to detect vsnprintf()?
193             for this and other functions we need some mechanism to handle
194             detection (like perl's Configure, or autoconf)
195             */
196             vsprintf(buf, fmt, ap);
197             #endif
198 92           im_push_error(ctx, code, buf);
199 92           }
200              
201             /*
202             =item i_push_errorf(int code, char const *fmt, ...)
203             =synopsis i_push_errorf(errno, "Cannot open file %s: %d", filename, errno);
204             =category Error handling
205              
206             A version of i_push_error() that does printf() like formatting.
207              
208             Does not support perl specific format codes.
209              
210             =cut
211             */
212             void
213 17           i_push_errorf(int code, char const *fmt, ...) {
214             va_list ap;
215 17           va_start(ap, fmt);
216 17           i_push_errorvf(code, fmt, ap);
217 17           va_end(ap);
218 17           }
219              
220             /*
221             =item im_push_errorf(ctx, code, char const *fmt, ...)
222             =synopsis im_push_errorf(aIMCTX, errno, "Cannot open file %s: %d", filename, errno);
223             =category Error handling
224              
225             A version of im_push_error() that does printf() like formatting.
226              
227             Does not support perl specific format codes.
228              
229             =cut
230             */
231             void
232 75           im_push_errorf(im_context_t ctx, int code, char const *fmt, ...) {
233             va_list ap;
234 75           va_start(ap, fmt);
235 75           im_push_errorvf(ctx, code, fmt, ap);
236 75           va_end(ap);
237 75           }
238              
239             #ifdef IMAGER_I_FAILED
240             #error "This isn't used and is untested"
241              
242             /*
243             =item i_failed(char const *msg)
244              
245             Called by Imager code to indicate that a top-level has failed.
246              
247             msg can be NULL, in which case no error is pushed.
248              
249             Calls the current failed callback, if any.
250              
251             Aborts the program with an error, if failures have been set to be fatal.
252              
253             Returns zero if it does not abort.
254              
255             =cut
256             */
257             int i_failed(int code, char const *msg) {
258             if (msg)
259             i_push_error(code, msg);
260             if (failed_cb)
261             failed_cb(error_stack + error_sp);
262             if (failures_fatal) {
263             int sp;
264             size_t total; /* total length of error messages */
265             char *full; /* full message for logging */
266             if (argv0)
267             fprintf(stderr, "%s: ", argv0);
268             fputs("error:\n", stderr);
269             sp = error_sp;
270             while (error_stack[sp].msg) {
271             fprintf(stderr, " %s\n", error_stack[sp].msg);
272             ++sp;
273             }
274             /* we want to log the error too, build an error message to hand to
275             i_fatal() */
276             total = 1; /* remember the NUL */
277             for (sp = error_sp; error_stack[sp].msg; ++sp) {
278             size_t new_total += strlen(error_stack[sp].msg) + 2;
279             if (new_total < total) {
280             /* overflow, somehow */
281             break;
282             }
283             }
284             full = mymalloc(total);
285             if (!full) {
286             /* just quit, at least it's on stderr */
287             exit(EXIT_FAILURE);
288             }
289             *full = 0;
290             for (sp = error_sp; error_stack[sp].msg; ++sp) {
291             strcat(full, error_stack[sp].msg);
292             strcat(full, ": ");
293             }
294             /* lose the extra ": " */
295             full[strlen(full)-2] = '\0';
296             i_fatal(EXIT_FAILURE, "%s", full);
297             }
298              
299             return 0;
300             }
301              
302             #endif
303              
304             #ifdef IM_ASSERT
305              
306             /*
307             =item im_assert_fail(file, line, message)
308              
309             Called when an im_assert() assertion fails.
310              
311             Only available when Imager is built with assertions.
312              
313             =cut
314             */
315              
316             void
317 0           im_assert_fail(char const *file, int line, char const *message) {
318 0           fprintf(stderr, "Assertion failed line %d file %s: %s\n",
319             line, file, message);
320 0           abort();
321             }
322              
323             #endif
324              
325             /*
326             =back
327              
328             =head1 BUGS
329              
330             This interface isn't thread safe.
331              
332             =head1 AUTHOR
333              
334             Tony Cook
335              
336             Stack concept by Arnar Mar Hrafnkelsson
337              
338             =cut
339             */