]> git.imager.perl.org - imager.git/blob - io.c
don't supply a default for a missing channel list
[imager.git] / io.c
1 #include "imager.h"
2 #include "imageri.h"
3 #include <stdlib.h>
4 #ifndef _MSC_VER
5 #include <unistd.h>
6 #endif
7
8
9 /* FIXME: make allocation dynamic */
10
11
12 #ifdef IMAGER_DEBUG_MALLOC
13
14 #define MAXMAL 102400
15 #define MAXDESC 65
16
17 #define UNDRRNVAL 10
18 #define OVERRNVAL 10
19
20 #define PADBYTE 0xaa
21
22
23 static int malloc_need_init = 1;
24
25 typedef struct {
26   void* ptr;
27   size_t size;
28   char comm[MAXDESC];
29 } malloc_entry;
30
31 malloc_entry malloc_pointers[MAXMAL];
32
33
34
35
36 /* Utility functions */
37
38
39 static
40 void
41 malloc_init(void) {
42   int i;
43   for(i=0; i<MAXMAL; i++) malloc_pointers[i].ptr = NULL;
44   malloc_need_init = 0;
45   atexit(malloc_state);
46 }
47
48
49 static
50 int 
51 find_ptr(void *p) {
52   int i;
53   for(i=0;i<MAXMAL;i++)
54     if (malloc_pointers[i].ptr == p)
55       return i;
56   return -1;
57 }
58
59
60 /* Takes a pointer to real start of array,
61  * sets the entries in the table, returns
62  * the offset corrected pointer */
63
64 static
65 void *
66 set_entry(int i, char *buf, size_t size, char *file, int line) {
67   memset( buf, PADBYTE, UNDRRNVAL );
68   memset( &buf[UNDRRNVAL+size], PADBYTE, OVERRNVAL );
69   buf += UNDRRNVAL;
70   malloc_pointers[i].ptr  = buf;
71   malloc_pointers[i].size = size;
72 #ifdef IMAGER_SNPRINTF
73   snprintf(malloc_pointers[i].comm, sizeof(malloc_pointers[i].comm), 
74            "%s (%d)", file, line);
75 #else
76   sprintf(malloc_pointers[i].comm,"%s (%d)", file, line);
77 #endif
78   return buf;
79 }
80
81 void
82 malloc_state(void) {
83   int i;
84   size_t total = 0;
85
86   i_clear_error();
87   mm_log((0,"malloc_state()\n"));
88   bndcheck_all();
89   for(i=0; i<MAXMAL; i++) if (malloc_pointers[i].ptr != NULL) {
90       mm_log((0,"%d: %lu (%p) : %s\n", i, (unsigned long)malloc_pointers[i].size, malloc_pointers[i].ptr, malloc_pointers[i].comm));
91     total += malloc_pointers[i].size;
92   }
93   if (total == 0) mm_log((0,"No memory currently used!\n"))
94     else mm_log((0,"total: %lu\n", (unsigned long)total));
95 }
96
97
98
99 void*
100 mymalloc_file_line(size_t size, char* file, int line) {
101   char *buf;
102   int i;
103   if (malloc_need_init) malloc_init();
104   
105   /* bndcheck_all(); Uncomment for LOTS OF THRASHING */
106   
107   if ( (i = find_ptr(NULL)) < 0 ) {
108     mm_log((0,"more than %d segments allocated at %s (%d)\n", MAXMAL, file, line));
109     exit(3);
110   }
111
112   if ( (buf = malloc(size+UNDRRNVAL+OVERRNVAL)) == NULL ) {
113     mm_log((1,"Unable to allocate %ld for %s (%i)\n", (long)size, file, line));
114     exit(3);
115   }
116   
117   buf = set_entry(i, buf, size, file, line);
118   mm_log((1,"mymalloc_file_line: slot <%d> %ld bytes allocated at %p for %s (%d)\n", i, (long)size, buf, file, line));
119   return buf;
120 }
121
122 void *
123 (mymalloc)(size_t size) {
124   return mymalloc_file_line(size, "unknown", 0);
125 }
126
127 void*
128 myrealloc_file_line(void *ptr, size_t newsize, char* file, int line) {
129   char *buf;
130   int i;
131
132   if (malloc_need_init) malloc_init();
133   /* bndcheck_all(); ACTIVATE FOR LOTS OF THRASHING */
134   
135   if (!ptr) {
136     mm_log((1, "realloc called with ptr = NULL, sending request to malloc\n"));
137     return mymalloc_file_line(newsize, file, line);
138   }
139   
140   if (!newsize) {
141     mm_log((1, "newsize = 0, sending request to free\n"));
142     myfree_file_line(ptr, file, line);
143     return NULL;
144   }
145
146   if ( (i = find_ptr(ptr)) == -1) {
147     mm_log((0, "Unable to find %p in realloc for %s (%i)\n", ptr, file, line));
148     exit(3);
149   }
150   
151   if ( (buf = realloc(((char *)ptr)-UNDRRNVAL, UNDRRNVAL+OVERRNVAL+newsize)) == NULL ) {
152     mm_log((1,"Unable to reallocate %ld bytes at %p for %s (%i)\n", (long)
153             newsize, ptr, file, line));
154     exit(3); 
155   }
156   
157   buf = set_entry(i, buf, newsize, file, line);
158   mm_log((1,"realloc_file_line: slot <%d> %ld bytes allocated at %p for %s (%d)\n", i, (long)newsize, buf, file, line));
159   return buf;
160 }
161
162 void *
163 (myrealloc)(void *ptr, size_t newsize) {
164   return myrealloc_file_line(ptr, newsize, "unknown", 0);
165 }
166
167 static
168 void
169 bndcheck(int idx) {
170   int i;
171   size_t s = malloc_pointers[idx].size;
172   unsigned char *pp = malloc_pointers[idx].ptr;
173   if (!pp) {
174     mm_log((1, "bndcheck: No pointer in slot %d\n", idx));
175     return;
176   }
177   
178   for(i=0;i<UNDRRNVAL;i++) {
179     if (pp[-(1+i)] != PADBYTE)
180       mm_log((1,"bndcheck: UNDERRUN OF %d bytes detected: slot = %d, point = %p, size = %ld\n", i+1, idx, pp, (long)s ));
181   }
182   
183   for(i=0;i<OVERRNVAL;i++) {
184     if (pp[s+i] != PADBYTE)
185       mm_log((1,"bndcheck: OVERRUN OF %d bytes detected: slot = %d, point = %p, size = %ld\n", i+1, idx, pp, (long)s ));
186   }
187 }
188
189 void
190 bndcheck_all() {
191   int idx;
192   mm_log((1, "bndcheck_all()\n"));
193   for(idx=0; idx<MAXMAL; idx++)
194     if (malloc_pointers[idx].ptr)
195       bndcheck(idx);
196 }
197
198 void
199 myfree_file_line(void *p, char *file, int line) {
200   char  *pp = p;
201   int match = 0;
202   int i;
203
204   if (p == NULL)
205     return;
206   
207   for(i=0; i<MAXMAL; i++) if (malloc_pointers[i].ptr == p) {
208     mm_log((1,"myfree_file_line: pointer %i (%s) freed at %s (%i)\n", i, malloc_pointers[i].comm, file, line));
209     bndcheck(i);
210     malloc_pointers[i].ptr = NULL;
211     match++;
212   }
213
214   mm_log((1, "myfree_file_line: freeing address %p (real %p)\n", pp, pp-UNDRRNVAL));
215   
216   if (match != 1) {
217     mm_log((1, "myfree_file_line: INCONSISTENT REFCOUNT %d at %s (%i)\n", match, file, line));
218     fprintf(stderr, "myfree_file_line: INCONSISTENT REFCOUNT %d at %s (%i)\n", match, file, line);
219                 exit(255);
220   }
221   
222   
223   free(pp-UNDRRNVAL);
224 }
225
226 void
227 (myfree)(void *block) {
228   myfree_file_line(block, "unknown", 0);
229 }
230
231 #else 
232
233 void
234 malloc_state() {
235 }
236
237 void*
238 mymalloc(size_t size) {
239   void *buf;
240
241   if (size < 0) {
242     fprintf(stderr, "Attempt to allocate size %ld\n", (long)size);
243     exit(3);
244   }
245
246   if ( (buf = malloc(size)) == NULL ) {
247     mm_log((1, "mymalloc: unable to malloc %ld\n", (long)size));
248     fprintf(stderr,"Unable to malloc %ld.\n", (long)size); exit(3);
249   }
250   mm_log((1, "mymalloc(size %ld) -> %p\n", (long)size, buf));
251   return buf;
252 }
253
254 void *
255 mymalloc_file_line(size_t size, char *file, int line) {
256   return mymalloc(size);
257 }
258
259 void
260 myfree(void *p) {
261   mm_log((1, "myfree(p %p)\n", p));
262   free(p);
263 }
264
265 void
266 myfree_file_line(void *p, char *file, int line) {
267   myfree(p);
268 }
269
270 void *
271 myrealloc(void *block, size_t size) {
272   void *result;
273
274   mm_log((1, "myrealloc(block %p, size %ld)\n", block, (long)size));
275   if ((result = realloc(block, size)) == NULL) {
276     mm_log((1, "myrealloc: out of memory\n"));
277     fprintf(stderr, "Out of memory.\n");
278     exit(3);
279   }
280   return result;
281 }
282
283 void *
284 myrealloc_file_line(void *block, size_t newsize, char *file, int size) {
285   return myrealloc(block, newsize);
286 }
287
288 #endif /* IMAGER_MALLOC_DEBUG */
289
290
291
292
293 /* memory pool implementation */
294
295 void
296 i_mempool_init(i_mempool *mp) {
297   mp->alloc = 10;
298   mp->used  = 0;
299   mp->p = mymalloc(sizeof(void*)*mp->alloc);
300 }
301
302 void
303 i_mempool_extend(i_mempool *mp) {
304   mp->p = myrealloc(mp->p, mp->alloc * 2);
305   mp->alloc *=2;
306 }
307
308 void *
309 i_mempool_alloc(i_mempool *mp, size_t size) {
310   if (mp->used == mp->alloc) i_mempool_extend(mp);
311   mp->p[mp->used] = mymalloc(size);
312   mp->used++;
313   return mp->p[mp->used-1];
314 }
315
316
317 void
318 i_mempool_destroy(i_mempool *mp) {
319   unsigned int i;
320   for(i=0; i<mp->used; i++) myfree(mp->p[i]);
321   myfree(mp->p);
322 }
323
324
325
326 /* Should these really be here? */
327
328 #undef min
329 #undef max
330
331 i_img_dim
332 i_minx(i_img_dim a, i_img_dim b) {
333   if (a<b) return a; else return b;
334 }
335
336 i_img_dim
337 i_maxx(i_img_dim a, i_img_dim b) {
338   if (a>b) return a; else return b;
339 }
340
341
342 struct utf8_size {
343   int mask, expect;
344   int size;
345 };
346
347 struct utf8_size utf8_sizes[] =
348 {
349   { 0x80, 0x00, 1 },
350   { 0xE0, 0xC0, 2 },
351   { 0xF0, 0xE0, 3 },
352   { 0xF8, 0xF0, 4 },
353 };
354
355 /*
356 =item i_utf8_advance(char **p, size_t *len)
357
358 Retrieve a C<UTF-8> character from the stream.
359
360 Modifies *p and *len to indicate the consumed characters.
361
362 This doesn't support the extended C<UTF-8> encoding used by later
363 versions of Perl.  Since this is typically used to implement text
364 output by font drivers, the strings supplied shouldn't have such out
365 of range characters.
366
367 This doesn't check that the C<UTF-8> character is using the shortest
368 possible representation.
369
370 Returns ~0UL on failure.
371
372 =cut
373 */
374
375 unsigned long 
376 i_utf8_advance(char const **p, size_t *len) {
377   unsigned char c;
378   int i, ci, clen = 0;
379   unsigned char codes[3];
380   if (*len == 0)
381     return ~0UL;
382   c = *(*p)++; --*len;
383
384   for (i = 0; i < sizeof(utf8_sizes)/sizeof(*utf8_sizes); ++i) {
385     if ((c & utf8_sizes[i].mask) == utf8_sizes[i].expect) {
386       clen = utf8_sizes[i].size;
387       break;
388     }
389   }
390   if (clen == 0 || *len < clen-1) {
391     --*p; ++*len;
392     return ~0UL;
393   }
394
395   /* check that each character is well formed */
396   i = 1;
397   ci = 0;
398   while (i < clen) {
399     if (((*p)[ci] & 0xC0) != 0x80) {
400       --*p; ++*len;
401       return ~0UL;
402     }
403     codes[ci] = (*p)[ci];
404     ++ci; ++i;
405   }
406   *p += clen-1; *len -= clen-1;
407   if (c & 0x80) {
408     if ((c & 0xE0) == 0xC0) {
409       return ((c & 0x1F) << 6) + (codes[0] & 0x3F);
410     }
411     else if ((c & 0xF0) == 0xE0) {
412       return ((c & 0x0F) << 12) | ((codes[0] & 0x3F) << 6) | (codes[1] & 0x3f);
413     }
414     else if ((c & 0xF8) == 0xF0) {
415       return ((c & 0x07) << 18) | ((codes[0] & 0x3F) << 12) 
416               | ((codes[1] & 0x3F) << 6) | (codes[2] & 0x3F);
417     }
418     else {
419       *p -= clen; *len += clen;
420       return ~0UL;
421     }
422   }
423   else {
424     return c;
425   }
426 }
427