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