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;
11 Create a new Imager context object.
17 im_context_new(void) {
18 im_context_t ctx = malloc(sizeof(im_context_struct));
22 slot_mutex = i_mutex_new();
27 ctx->error_sp = IM_ERROR_COUNT-1;
28 for (i = 0; i < IM_ERROR_COUNT; ++i) {
29 ctx->error_alloc[i] = 0;
30 ctx->error_stack[i].msg = NULL;
31 ctx->error_stack[i].code = 0;
39 ctx->max_bytes = DEF_BYTES_LIMIT;
41 ctx->slot_alloc = slot_count;
42 ctx->slots = calloc(sizeof(void *), ctx->slot_alloc);
48 ctx->file_magic = NULL;
52 #ifdef IMAGER_TRACE_CONTEXT
53 fprintf(stderr, "im_context: created %p\n", ctx);
61 =item im_context_refinc(ctx, where)
62 X<im_context_refinc API>
63 =section Context objects
64 =synopsis im_context_refinc(aIMCTX, "a description");
66 Add a new reference to the context.
72 im_context_refinc(im_context_t ctx, const char *where) {
75 #ifdef IMAGER_TRACE_CONTEXT
76 fprintf(stderr, "im_context:%s: refinc %p (count now %lu)\n", where,
77 ctx, (unsigned long)ctx->refcount);
82 =item im_context_refdec(ctx, where)
83 X<im_context_refdec API>
84 =section Context objects
85 =synopsis im_context_refdec(aIMCTX, "a description");
87 Remove a reference to the context, releasing it if all references have
94 im_context_refdec(im_context_t ctx, const char *where) {
98 im_assert(ctx->refcount > 0);
102 #ifdef IMAGER_TRACE_CONTEXT
103 fprintf(stderr, "im_context:%s: delete %p (count now %lu)\n", where,
104 ctx, (unsigned long)ctx->refcount);
107 if (ctx->refcount != 0)
110 /* lock here to avoid slot_destructors from being moved under us */
111 i_mutex_lock(slot_mutex);
112 for (slot = 0; slot < ctx->slot_alloc; ++slot) {
113 if (ctx->slots[slot] && slot_destructors[slot])
114 slot_destructors[slot](ctx->slots[slot]);
116 i_mutex_unlock(slot_mutex);
120 for (i = 0; i < IM_ERROR_COUNT; ++i) {
121 if (ctx->error_stack[i].msg)
122 myfree(ctx->error_stack[i].msg);
126 im_file_magic *p = ctx->file_magic;
128 im_file_magic *n = p->next;
137 if (ctx->lg_file && ctx->own_log)
138 fclose(ctx->lg_file);
145 =item im_context_clone(ctx)
147 Clone an Imager context object, returning the result.
149 The error stack is not copied from the original context.
155 im_context_clone(im_context_t ctx, const char *where) {
156 im_context_t nctx = malloc(sizeof(im_context_struct));
162 nctx->slot_alloc = slot_count;
163 nctx->slots = calloc(sizeof(void *), nctx->slot_alloc);
169 nctx->error_sp = IM_ERROR_COUNT-1;
170 for (i = 0; i < IM_ERROR_COUNT; ++i) {
171 nctx->error_alloc[i] = 0;
172 nctx->error_stack[i].msg = NULL;
175 nctx->log_level = ctx->log_level;
178 int newfd = dup(fileno(ctx->lg_file));
181 nctx->lg_file = fdopen(newfd, "w");
183 setvbuf(nctx->lg_file, NULL, _IONBF, BUFSIZ);
186 #ifdef IMAGER_TRACE_CONTEXT
187 perror("im_context:failed to clone log");
196 nctx->lg_file = ctx->lg_file;
201 nctx->lg_file = NULL;
204 nctx->max_width = ctx->max_width;
205 nctx->max_height = ctx->max_height;
206 nctx->max_bytes = ctx->max_bytes;
211 im_file_magic *inp = ctx->file_magic;
212 im_file_magic **outpp = &nctx->file_magic;
215 im_file_magic *m = malloc(sizeof(im_file_magic));
217 /* should free any parts of the list already allocated */
218 im_context_refdec(nctx, "failed cloning");
222 m->m.name = strdup(inp->m.name);
223 m->m.magic_size = inp->m.magic_size;
224 m->m.magic = malloc(inp->m.magic_size);
225 m->m.mask = malloc(inp->m.magic_size);
226 if (m->m.name == NULL || m->m.magic == NULL || m->m.mask == NULL) {
231 im_context_refdec(nctx, "failed cloning");
234 memcpy(m->m.magic, inp->m.magic, m->m.magic_size);
235 memcpy(m->m.mask, inp->m.mask, m->m.magic_size);
242 #ifdef IMAGER_TRACE_CONTEXT
243 fprintf(stderr, "im_context:%s: cloned %p to %p\n", where, ctx, nctx);
250 =item im_context_slot_new(destructor)
252 Allocate a new context-local-storage slot.
254 C<desctructor> will be called when the context is destroyed if the
255 corresponding slot is non-NULL.
261 im_context_slot_new(im_slot_destroy_t destructor) {
263 im_slot_destroy_t *new_destructors;
265 slot_mutex = i_mutex_new();
267 i_mutex_lock(slot_mutex);
269 new_slot = slot_count++;
270 new_destructors = realloc(slot_destructors, sizeof(void *) * slot_count);
271 if (!new_destructors)
272 i_fatal(1, "Cannot allocate memory for slot destructors");
273 slot_destructors = new_destructors;
275 slot_destructors[new_slot] = destructor;
277 i_mutex_unlock(slot_mutex);
283 =item im_context_slot_set(slot, value)
285 Set the value of a slot.
287 Returns true on success.
289 Aborts if the slot supplied is invalid.
291 If reallocation of slot storage fails, returns false.
297 im_context_slot_set(im_context_t ctx, im_slot_t slot, void *value) {
298 if (slot < 0 || slot >= slot_count) {
299 fprintf(stderr, "Invalid slot %d (valid 0 - %d)\n",
300 (int)slot, (int)slot_count-1);
304 if (slot >= ctx->slot_alloc) {
306 size_t new_alloc = slot_count;
307 void **new_slots = realloc(ctx->slots, sizeof(void *) * new_alloc);
312 for (i = ctx->slot_alloc; i < new_alloc; ++i)
315 ctx->slots = new_slots;
316 ctx->slot_alloc = new_alloc;
319 ctx->slots[slot] = value;
325 =item im_context_slot_get(ctx, slot)
327 Retrieve the value previously stored in the given slot of the context
334 im_context_slot_get(im_context_t ctx, im_slot_t slot) {
335 if (slot < 0 || slot >= slot_count) {
336 fprintf(stderr, "Invalid slot %d (valid 0 - %d)\n",
337 (int)slot, (int)slot_count-1);
341 if (slot >= ctx->slot_alloc)
344 return ctx->slots[slot];
348 =item im_add_file_magic(ctx, name, bits, mask, length)
350 Add file type magic to the given context.
356 im_add_file_magic(im_context_t ctx, const char *name,
357 const unsigned char *bits, const unsigned char *mask,
359 im_file_magic *m = malloc(sizeof(im_file_magic));
367 m->m.name = strdup(name);
368 m->m.magic = malloc(length);
369 m->m.mask = malloc(length);
370 m->m.magic_size = length;
372 if (name == NULL || bits == NULL || mask == NULL) {
379 memcpy(m->m.magic, bits, length);
380 memcpy(m->m.mask, mask, length);
381 m->next = ctx->file_magic;