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