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