fix date on 1.009 release in Changes
[imager.git] / context.c
CommitLineData
74315ca9 1#include "imageri.h"
31a13473 2#include <stdio.h>
74315ca9 3
d7506bda
TC
4static volatile im_slot_t slot_count = 1;
5static im_slot_destroy_t *volatile slot_destructors;
6static volatile i_mutex_t slot_mutex;
fc02e376 7
74315ca9
TC
8/*
9=item im_context_new()
10
11Create a new Imager context object.
12
13=cut
14*/
15
16im_context_t
17im_context_new(void) {
cf8c77ae 18 im_context_t ctx = malloc(sizeof(im_context_struct));
74315ca9
TC
19 int i;
20
fc02e376
TC
21 if (!slot_mutex)
22 slot_mutex = i_mutex_new();
23
cf8c77ae
TC
24 if (!ctx)
25 return NULL;
26
74315ca9
TC
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;
32 }
33#ifdef IMAGER_LOG
34 ctx->log_level = 0;
35 ctx->lg_file = NULL;
36#endif
44d86483
TC
37 ctx->max_width = 0;
38 ctx->max_height = 0;
cf8c77ae 39 ctx->max_bytes = DEF_BYTES_LIMIT;
74315ca9 40
f4ced639
TC
41 ctx->slot_alloc = slot_count;
42 ctx->slots = calloc(sizeof(void *), ctx->slot_alloc);
fc02e376
TC
43 if (!ctx->slots) {
44 free(ctx);
45 return NULL;
46 }
47
31a13473
TC
48 ctx->refcount = 1;
49
50#ifdef IMAGER_TRACE_CONTEXT
51 fprintf(stderr, "im_context: created %p\n", ctx);
52#endif
53
fc02e376 54
74315ca9
TC
55 return ctx;
56}
57
58/*
31a13473 59=item im_context_refinc(ctx, where)
abffffed
TC
60X<im_context_refinc API>
61=section Context objects
62=synopsis im_context_refinc(aIMCTX, "a description");
31a13473
TC
63
64Add a new reference to the context.
65
66=cut
67*/
68
69void
70im_context_refinc(im_context_t ctx, const char *where) {
71 ++ctx->refcount;
72
73#ifdef IMAGER_TRACE_CONTEXT
74 fprintf(stderr, "im_context:%s: refinc %p (count now %lu)\n", where,
75 ctx, (unsigned long)ctx->refcount);
76#endif
77}
78
79/*
abffffed
TC
80=item im_context_refdec(ctx, where)
81X<im_context_refdec API>
82=section Context objects
83=synopsis im_context_refdec(aIMCTX, "a description");
74315ca9 84
abffffed
TC
85Remove a reference to the context, releasing it if all references have
86been removed.
74315ca9
TC
87
88=cut
89*/
90
91void
31a13473 92im_context_refdec(im_context_t ctx, const char *where) {
74315ca9 93 int i;
fc02e376 94 im_slot_t slot;
74315ca9 95
31a13473
TC
96 im_assert(ctx->refcount > 0);
97
98 --ctx->refcount;
99
100#ifdef IMAGER_TRACE_CONTEXT
101 fprintf(stderr, "im_context:%s: delete %p (count now %lu)\n", where,
102 ctx, (unsigned long)ctx->refcount);
103#endif
104
105 if (ctx->refcount != 0)
106 return;
107
d7506bda
TC
108 /* lock here to avoid slot_destructors from being moved under us */
109 i_mutex_lock(slot_mutex);
fc02e376
TC
110 for (slot = 0; slot < ctx->slot_alloc; ++slot) {
111 if (ctx->slots[slot] && slot_destructors[slot])
112 slot_destructors[slot](ctx->slots[slot]);
113 }
d7506bda 114 i_mutex_unlock(slot_mutex);
fc02e376
TC
115
116 free(ctx->slots);
117
74315ca9
TC
118 for (i = 0; i < IM_ERROR_COUNT; ++i) {
119 if (ctx->error_stack[i].msg)
120 myfree(ctx->error_stack[i].msg);
121 }
122#ifdef IMAGER_LOG
6ee0c41f 123 if (ctx->lg_file && ctx->own_log)
74315ca9
TC
124 fclose(ctx->lg_file);
125#endif
cf8c77ae
TC
126
127 free(ctx);
74315ca9
TC
128}
129
130/*
131=item im_context_clone(ctx)
132
133Clone an Imager context object, returning the result.
134
a6c8996f
TC
135The error stack is not copied from the original context.
136
74315ca9
TC
137=cut
138*/
139
140im_context_t
31a13473 141im_context_clone(im_context_t ctx, const char *where) {
cf8c77ae 142 im_context_t nctx = malloc(sizeof(im_context_struct));
74315ca9
TC
143 int i;
144
cf8c77ae
TC
145 if (!nctx)
146 return NULL;
147
d7506bda
TC
148 nctx->slot_alloc = slot_count;
149 nctx->slots = calloc(sizeof(void *), nctx->slot_alloc);
fc02e376
TC
150 if (!nctx->slots) {
151 free(nctx);
152 return NULL;
153 }
fc02e376 154
a6c8996f 155 nctx->error_sp = IM_ERROR_COUNT-1;
74315ca9 156 for (i = 0; i < IM_ERROR_COUNT; ++i) {
a6c8996f
TC
157 nctx->error_alloc[i] = 0;
158 nctx->error_stack[i].msg = NULL;
74315ca9
TC
159 }
160#ifdef IMAGER_LOG
161 nctx->log_level = ctx->log_level;
162 if (ctx->lg_file) {
6ee0c41f
TC
163 if (ctx->own_log) {
164 int newfd = dup(fileno(ctx->lg_file));
9ca939d0
TC
165 if (newfd >= 0) {
166 nctx->own_log = 1;
167 nctx->lg_file = fdopen(newfd, "w");
168 if (nctx->lg_file)
169 setvbuf(nctx->lg_file, NULL, _IONBF, BUFSIZ);
170 }
171 else {
172#ifdef IMAGER_TRACE_CONTEXT
173 perror("im_context:failed to clone log");
174#endif
175 free(nctx->slots);
176 free(nctx);
177 return NULL;
178 }
6ee0c41f
TC
179 }
180 else {
181 /* stderr */
182 nctx->lg_file = ctx->lg_file;
183 nctx->own_log = 0;
184 }
74315ca9
TC
185 }
186 else {
44d86483 187 nctx->lg_file = NULL;
74315ca9
TC
188 }
189#endif
44d86483
TC
190 nctx->max_width = ctx->max_width;
191 nctx->max_height = ctx->max_height;
192 nctx->max_bytes = ctx->max_bytes;
fc02e376 193
31a13473 194 nctx->refcount = 1;
74315ca9 195
31a13473
TC
196#ifdef IMAGER_TRACE_CONTEXT
197 fprintf(stderr, "im_context:%s: cloned %p to %p\n", where, ctx, nctx);
198#endif
199
200 return nctx;
74315ca9 201}
fc02e376
TC
202
203/*
204=item im_context_slot_new(destructor)
205
206Allocate a new context-local-storage slot.
207
c135e76b
TC
208C<desctructor> will be called when the context is destroyed if the
209corresponding slot is non-NULL.
210
fc02e376
TC
211=cut
212*/
213
214im_slot_t
215im_context_slot_new(im_slot_destroy_t destructor) {
216 im_slot_t new_slot;
217 im_slot_destroy_t *new_destructors;
218 if (!slot_mutex)
219 slot_mutex = i_mutex_new();
220
221 i_mutex_lock(slot_mutex);
222
223 new_slot = slot_count++;
224 new_destructors = realloc(slot_destructors, sizeof(void *) * slot_count);
225 if (!new_destructors)
226 i_fatal(1, "Cannot allocate memory for slot destructors");
227 slot_destructors = new_destructors;
228
229 slot_destructors[new_slot] = destructor;
230
231 i_mutex_unlock(slot_mutex);
232
233 return new_slot;
234}
235
236/*
237=item im_context_slot_set(slot, value)
238
239Set the value of a slot.
240
241Returns true on success.
242
243Aborts if the slot supplied is invalid.
244
245If reallocation of slot storage fails, returns false.
246
247=cut
248*/
249
250int
251im_context_slot_set(im_context_t ctx, im_slot_t slot, void *value) {
252 if (slot < 0 || slot >= slot_count) {
253 fprintf(stderr, "Invalid slot %d (valid 0 - %d)\n",
254 (int)slot, (int)slot_count-1);
255 abort();
256 }
257
258 if (slot >= ctx->slot_alloc) {
259 ssize_t i;
260 size_t new_alloc = slot_count;
261 void **new_slots = realloc(ctx->slots, sizeof(void *) * new_alloc);
262
263 if (!new_slots)
264 return 0;
265
266 for (i = ctx->slot_alloc; i < new_alloc; ++i)
267 new_slots[i] = NULL;
268
269 ctx->slots = new_slots;
270 ctx->slot_alloc = new_alloc;
271 }
272
273 ctx->slots[slot] = value;
274
275 return 1;
276}
277
278/*
279=item im_context_slot_get(ctx, slot)
280
281Retrieve the value previously stored in the given slot of the context
282object.
283
284=cut
285*/
286
287void *
288im_context_slot_get(im_context_t ctx, im_slot_t slot) {
289 if (slot < 0 || slot >= slot_count) {
290 fprintf(stderr, "Invalid slot %d (valid 0 - %d)\n",
291 (int)slot, (int)slot_count-1);
292 abort();
293 }
294
295 if (slot >= ctx->slot_alloc)
296 return NULL;
297
298 return ctx->slots[slot];
299}