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