File Coverage

context.c
Criterion Covered Total %
statement 62 167 37.1
branch 25 82 30.4
condition n/a
subroutine n/a
pod n/a
total 87 249 34.9


line stmt bran cond sub pod time code
1             #include "imageri.h"
2             #include
3              
4             static volatile im_slot_t slot_count = 1;
5             static im_slot_destroy_t *volatile slot_destructors;
6             static volatile i_mutex_t slot_mutex;
7              
8             /*
9             =item im_context_new()
10              
11             Create a new Imager context object.
12              
13             =cut
14             */
15              
16             im_context_t
17 79           im_context_new(void) {
18 79           im_context_t ctx = malloc(sizeof(im_context_struct));
19             int i;
20              
21 79 50         if (!slot_mutex)
22 79           slot_mutex = i_mutex_new();
23              
24 79 50         if (!ctx)
25 0           return NULL;
26            
27 79           ctx->error_sp = IM_ERROR_COUNT-1;
28 1659 100         for (i = 0; i < IM_ERROR_COUNT; ++i) {
29 1580           ctx->error_alloc[i] = 0;
30 1580           ctx->error_stack[i].msg = NULL;
31 1580           ctx->error_stack[i].code = 0;
32             }
33             #ifdef IMAGER_LOG
34 79           ctx->log_level = 0;
35 79           ctx->lg_file = NULL;
36             #endif
37 79           ctx->max_width = 0;
38 79           ctx->max_height = 0;
39 79           ctx->max_bytes = DEF_BYTES_LIMIT;
40              
41 79           ctx->slot_alloc = slot_count;
42 79           ctx->slots = calloc(sizeof(void *), ctx->slot_alloc);
43 79 50         if (!ctx->slots) {
44 0           free(ctx);
45 0           return NULL;
46             }
47              
48 79           ctx->file_magic = NULL;
49              
50 79           ctx->refcount = 1;
51              
52             #ifdef IMAGER_TRACE_CONTEXT
53             fprintf(stderr, "im_context: created %p\n", ctx);
54             #endif
55              
56              
57 79           return ctx;
58             }
59              
60             /*
61             =item im_context_refinc(ctx, where)
62             X
63             =section Context objects
64             =synopsis im_context_refinc(aIMCTX, "a description");
65              
66             Add a new reference to the context.
67              
68             =cut
69             */
70              
71             void
72 2222           im_context_refinc(im_context_t ctx, const char *where) {
73 2222           ++ctx->refcount;
74              
75             #ifdef IMAGER_TRACE_CONTEXT
76             fprintf(stderr, "im_context:%s: refinc %p (count now %lu)\n", where,
77             ctx, (unsigned long)ctx->refcount);
78             #endif
79 2222           }
80              
81             /*
82             =item im_context_refdec(ctx, where)
83             X
84             =section Context objects
85             =synopsis im_context_refdec(aIMCTX, "a description");
86              
87             Remove a reference to the context, releasing it if all references have
88             been removed.
89              
90             =cut
91             */
92              
93             void
94 2299           im_context_refdec(im_context_t ctx, const char *where) {
95             int i;
96             im_slot_t slot;
97              
98 2299 50         im_assert(ctx->refcount > 0);
99              
100 2299           --ctx->refcount;
101              
102             #ifdef IMAGER_TRACE_CONTEXT
103             fprintf(stderr, "im_context:%s: delete %p (count now %lu)\n", where,
104             ctx, (unsigned long)ctx->refcount);
105             #endif
106              
107 2299 100         if (ctx->refcount != 0)
108 2221           return;
109              
110             /* lock here to avoid slot_destructors from being moved under us */
111 78           i_mutex_lock(slot_mutex);
112 156 100         for (slot = 0; slot < ctx->slot_alloc; ++slot) {
113 78 50         if (ctx->slots[slot] && slot_destructors[slot])
    0          
114 0           slot_destructors[slot](ctx->slots[slot]);
115             }
116 78           i_mutex_unlock(slot_mutex);
117              
118 78           free(ctx->slots);
119              
120 1638 100         for (i = 0; i < IM_ERROR_COUNT; ++i) {
121 1560 100         if (ctx->error_stack[i].msg)
122 56           myfree(ctx->error_stack[i].msg);
123             }
124              
125             {
126 78           im_file_magic *p = ctx->file_magic;
127 79 100         while (p != NULL) {
128 1           im_file_magic *n = p->next;
129 1           free(p->m.name);
130 1           free(p->m.magic);
131 1           free(p->m.mask);
132 1           free(p);
133 1           p = n;
134             }
135             }
136             #ifdef IMAGER_LOG
137 78 100         if (ctx->lg_file && ctx->own_log)
    50          
138 17           fclose(ctx->lg_file);
139             #endif
140              
141 78           free(ctx);
142             }
143              
144             /*
145             =item im_context_clone(ctx)
146              
147             Clone an Imager context object, returning the result.
148              
149             The error stack is not copied from the original context.
150              
151             =cut
152             */
153              
154             im_context_t
155 0           im_context_clone(im_context_t ctx, const char *where) {
156 0           im_context_t nctx = malloc(sizeof(im_context_struct));
157             int i;
158              
159 0 0         if (!nctx)
160 0           return NULL;
161              
162 0           nctx->slot_alloc = slot_count;
163 0           nctx->slots = calloc(sizeof(void *), nctx->slot_alloc);
164 0 0         if (!nctx->slots) {
165 0           free(nctx);
166 0           return NULL;
167             }
168              
169 0           nctx->error_sp = IM_ERROR_COUNT-1;
170 0 0         for (i = 0; i < IM_ERROR_COUNT; ++i) {
171 0           nctx->error_alloc[i] = 0;
172 0           nctx->error_stack[i].msg = NULL;
173             }
174             #ifdef IMAGER_LOG
175 0           nctx->log_level = ctx->log_level;
176 0 0         if (ctx->lg_file) {
177 0 0         if (ctx->own_log) {
178 0           int newfd = dup(fileno(ctx->lg_file));
179 0 0         if (newfd >= 0) {
180 0           nctx->own_log = 1;
181 0           nctx->lg_file = fdopen(newfd, "w");
182 0 0         if (nctx->lg_file)
183 0           setvbuf(nctx->lg_file, NULL, _IONBF, BUFSIZ);
184             }
185             else {
186             #ifdef IMAGER_TRACE_CONTEXT
187             perror("im_context:failed to clone log");
188             #endif
189 0           free(nctx->slots);
190 0           free(nctx);
191 0           return NULL;
192             }
193             }
194             else {
195             /* stderr */
196 0           nctx->lg_file = ctx->lg_file;
197 0           nctx->own_log = 0;
198             }
199             }
200             else {
201 0           nctx->lg_file = NULL;
202             }
203             #endif
204 0           nctx->max_width = ctx->max_width;
205 0           nctx->max_height = ctx->max_height;
206 0           nctx->max_bytes = ctx->max_bytes;
207              
208 0           nctx->refcount = 1;
209              
210             {
211 0           im_file_magic *inp = ctx->file_magic;
212 0           im_file_magic **outpp = &nctx->file_magic;
213 0           *outpp = NULL;
214 0 0         while (inp) {
215 0           im_file_magic *m = malloc(sizeof(im_file_magic));
216 0 0         if (!m) {
217             /* should free any parts of the list already allocated */
218 0           im_context_refdec(nctx, "failed cloning");
219 0           return NULL;
220             }
221 0           m->next = NULL;
222 0           m->m.name = strdup(inp->m.name);
223 0           m->m.magic_size = inp->m.magic_size;
224 0           m->m.magic = malloc(inp->m.magic_size);
225 0           m->m.mask = malloc(inp->m.magic_size);
226 0 0         if (m->m.name == NULL || m->m.magic == NULL || m->m.mask == NULL) {
    0          
    0          
227 0           free(m->m.name);
228 0           free(m->m.magic);
229 0           free(m->m.mask);
230 0           free(m);
231 0           im_context_refdec(nctx, "failed cloning");
232 0           return NULL;
233             }
234 0           memcpy(m->m.magic, inp->m.magic, m->m.magic_size);
235 0           memcpy(m->m.mask, inp->m.mask, m->m.magic_size);
236 0           *outpp = m;
237 0           outpp = &m->next;
238 0           inp = inp->next;
239             }
240             }
241              
242             #ifdef IMAGER_TRACE_CONTEXT
243             fprintf(stderr, "im_context:%s: cloned %p to %p\n", where, ctx, nctx);
244             #endif
245              
246 0           return nctx;
247             }
248              
249             /*
250             =item im_context_slot_new(destructor)
251              
252             Allocate a new context-local-storage slot.
253              
254             C will be called when the context is destroyed if the
255             corresponding slot is non-NULL.
256              
257             =cut
258             */
259              
260             im_slot_t
261 0           im_context_slot_new(im_slot_destroy_t destructor) {
262             im_slot_t new_slot;
263             im_slot_destroy_t *new_destructors;
264 0 0         if (!slot_mutex)
265 0           slot_mutex = i_mutex_new();
266              
267 0           i_mutex_lock(slot_mutex);
268              
269 0           new_slot = slot_count++;
270 0           new_destructors = realloc(slot_destructors, sizeof(void *) * slot_count);
271 0 0         if (!new_destructors)
272 0           i_fatal(1, "Cannot allocate memory for slot destructors");
273 0           slot_destructors = new_destructors;
274              
275 0           slot_destructors[new_slot] = destructor;
276              
277 0           i_mutex_unlock(slot_mutex);
278              
279 0           return new_slot;
280             }
281              
282             /*
283             =item im_context_slot_set(slot, value)
284              
285             Set the value of a slot.
286              
287             Returns true on success.
288              
289             Aborts if the slot supplied is invalid.
290              
291             If reallocation of slot storage fails, returns false.
292              
293             =cut
294             */
295              
296             int
297 0           im_context_slot_set(im_context_t ctx, im_slot_t slot, void *value) {
298 0 0         if (slot < 0 || slot >= slot_count) {
    0          
299 0           fprintf(stderr, "Invalid slot %d (valid 0 - %d)\n",
300 0           (int)slot, (int)slot_count-1);
301 0           abort();
302             }
303              
304 0 0         if (slot >= ctx->slot_alloc) {
305             ssize_t i;
306 0           size_t new_alloc = slot_count;
307 0           void **new_slots = realloc(ctx->slots, sizeof(void *) * new_alloc);
308              
309 0 0         if (!new_slots)
310 0           return 0;
311              
312 0 0         for (i = ctx->slot_alloc; i < new_alloc; ++i)
313 0           new_slots[i] = NULL;
314              
315 0           ctx->slots = new_slots;
316 0           ctx->slot_alloc = new_alloc;
317             }
318              
319 0           ctx->slots[slot] = value;
320              
321 0           return 1;
322             }
323              
324             /*
325             =item im_context_slot_get(ctx, slot)
326              
327             Retrieve the value previously stored in the given slot of the context
328             object.
329              
330             =cut
331             */
332              
333             void *
334 0           im_context_slot_get(im_context_t ctx, im_slot_t slot) {
335 0 0         if (slot < 0 || slot >= slot_count) {
    0          
336 0           fprintf(stderr, "Invalid slot %d (valid 0 - %d)\n",
337 0           (int)slot, (int)slot_count-1);
338 0           abort();
339             }
340              
341 0 0         if (slot >= ctx->slot_alloc)
342 0           return NULL;
343              
344 0           return ctx->slots[slot];
345             }
346              
347             /*
348             =item im_add_file_magic(ctx, name, bits, mask, length)
349              
350             Add file type magic to the given context.
351              
352             =cut
353             */
354              
355             int
356 1           im_add_file_magic(im_context_t ctx, const char *name,
357             const unsigned char *bits, const unsigned char *mask,
358             size_t length) {
359 1           im_file_magic *m = malloc(sizeof(im_file_magic));
360              
361 1 50         if (m == NULL)
362 0           return 0;
363              
364 1 50         if (length > 512)
365 0           length = 512;
366              
367 1           m->m.name = strdup(name);
368 1           m->m.magic = malloc(length);
369 1           m->m.mask = malloc(length);
370 1           m->m.magic_size = length;
371              
372 1 50         if (name == NULL || bits == NULL || mask == NULL) {
    50          
    50          
373 0           free(m->m.name);
374 0           free(m->m.magic);
375 0           free(m->m.mask);
376 0           free(m);
377 0           return 0;
378             }
379 1           memcpy(m->m.magic, bits, length);
380 1           memcpy(m->m.mask, mask, length);
381 1           m->next = ctx->file_magic;
382 1           ctx->file_magic = m;
383              
384 1           return 1;
385             }