blob: aa82c4ec90f22e20529d12d4fb6337e0e75fe405 [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
2 * memory.c: libxml memory allocator wrapper.
3 *
Daniel Veillardc5d64342001-06-24 12:13:24 +00004 * daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +00005 */
6
Bjorn Reese70a9da52001-04-21 16:57:29 +00007#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +00008
Owen Taylor3473f882001-02-23 17:55:21 +00009#include <string.h>
10
11#ifdef HAVE_SYS_TYPES_H
12#include <sys/types.h>
13#endif
14#ifdef HAVE_TIME_H
15#include <time.h>
16#endif
17#ifdef HAVE_MALLOC_H
18#include <malloc.h>
19#endif
20#ifdef HAVE_STDLIB_H
21#include <stdlib.h>
22#endif
23#ifdef HAVE_CTYPE_H
24#include <ctype.h>
25#endif
26
27
28#include <libxml/xmlmemory.h>
Daniel Veillardd0463562001-10-13 09:15:48 +000029#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000030#include <libxml/xmlerror.h>
31
Daniel Veillard56a4cb82001-03-24 17:00:36 +000032void xmlMallocBreakpoint(void);
Daniel Veillard8599e702001-07-17 21:38:51 +000033void * xmlMemMalloc(size_t size);
34void * xmlMallocLoc(size_t size, const char * file, int line);
35void * xmlMemRealloc(void *ptr,size_t size);
Daniel Veillard56a4cb82001-03-24 17:00:36 +000036void xmlMemFree(void *ptr);
37char * xmlMemoryStrdup(const char *str);
38
39/************************************************************************
40 * *
41 * Macros, variables and associated types *
42 * *
43 ************************************************************************/
44
45
Owen Taylor3473f882001-02-23 17:55:21 +000046#ifdef xmlMalloc
47#undef xmlMalloc
48#endif
49#ifdef xmlRealloc
50#undef xmlRealloc
51#endif
52#ifdef xmlMemStrdup
53#undef xmlMemStrdup
54#endif
55
56
57/*
58 * Each of the blocks allocated begin with a header containing informations
59 */
60
61#define MEMTAG 0x5aa5
62
63#define MALLOC_TYPE 1
64#define REALLOC_TYPE 2
65#define STRDUP_TYPE 3
66
67typedef struct memnod {
68 unsigned int mh_tag;
69 unsigned int mh_type;
70 unsigned long mh_number;
71 size_t mh_size;
72#ifdef MEM_LIST
73 struct memnod *mh_next;
74 struct memnod *mh_prev;
75#endif
76 const char *mh_file;
77 unsigned int mh_line;
78} MEMHDR;
79
80
81#ifdef SUN4
82#define ALIGN_SIZE 16
83#else
84#define ALIGN_SIZE sizeof(double)
85#endif
86#define HDR_SIZE sizeof(MEMHDR)
87#define RESERVE_SIZE (((HDR_SIZE + (ALIGN_SIZE-1)) \
88 / ALIGN_SIZE ) * ALIGN_SIZE)
89
90
91#define CLIENT_2_HDR(a) ((MEMHDR *) (((char *) (a)) - RESERVE_SIZE))
92#define HDR_2_CLIENT(a) ((void *) (((char *) (a)) + RESERVE_SIZE))
93
94
95static unsigned long debugMemSize = 0;
96static unsigned long debugMaxMemSize = 0;
97static int block=0;
Daniel Veillardb44025c2001-10-11 22:55:55 +000098static int xmlMemStopAtBlock = 0;
99static void *xmlMemTraceBlockAt = NULL;
100static int xmlMemInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000101#ifdef MEM_LIST
102static MEMHDR *memlist = NULL;
103#endif
104
105void debugmem_tag_error(void *addr);
106#ifdef MEM_LIST
107void debugmem_list_add(MEMHDR *);
108void debugmem_list_delete(MEMHDR *);
109#endif
110#define Mem_Tag_Err(a) debugmem_tag_error(a);
111
112#ifndef TEST_POINT
113#define TEST_POINT
114#endif
115
116/**
117 * xmlMallocBreakpoint:
118 *
119 * Breakpoint to use in conjunction with xmlMemStopAtBlock. When the block
120 * number reaches the specified value this function is called. One need to add a breakpoint
121 * to it to get the context in which the given block is allocated.
122 */
123
124void
125xmlMallocBreakpoint(void) {
126 xmlGenericError(xmlGenericErrorContext,
127 "xmlMallocBreakpoint reached on block %d\n", xmlMemStopAtBlock);
128}
129
130/**
131 * xmlMallocLoc:
132 * @size: an int specifying the size in byte to allocate.
133 * @file: the file name or NULL
134 * @line: the line number
135 *
136 * a malloc() equivalent, with logging of the allocation info.
137 *
138 * Returns a pointer to the allocated area or NULL in case of lack of memory.
139 */
140
141void *
Daniel Veillard8599e702001-07-17 21:38:51 +0000142xmlMallocLoc(size_t size, const char * file, int line)
Owen Taylor3473f882001-02-23 17:55:21 +0000143{
144 MEMHDR *p;
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000145 void *ret;
Owen Taylor3473f882001-02-23 17:55:21 +0000146
147 if (!xmlMemInitialized) xmlInitMemory();
148#ifdef DEBUG_MEMORY
149 xmlGenericError(xmlGenericErrorContext,
150 "Malloc(%d)\n",size);
151#endif
152
153 TEST_POINT
154
155 p = (MEMHDR *) malloc(RESERVE_SIZE+size);
156
157 if (!p) {
158 xmlGenericError(xmlGenericErrorContext,
159 "xmlMalloc : Out of free space\n");
160 xmlMemoryDump();
161 return(NULL);
162 }
163 p->mh_tag = MEMTAG;
164 p->mh_number = ++block;
165 p->mh_size = size;
166 p->mh_type = MALLOC_TYPE;
167 p->mh_file = file;
168 p->mh_line = line;
169 debugMemSize += size;
170 if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
171#ifdef MEM_LIST
172 debugmem_list_add(p);
173#endif
174
175#ifdef DEBUG_MEMORY
176 xmlGenericError(xmlGenericErrorContext,
177 "Malloc(%d) Ok\n",size);
178#endif
179
180 if (xmlMemStopAtBlock == block) xmlMallocBreakpoint();
181
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000182 ret = HDR_2_CLIENT(p);
183
184 if (xmlMemTraceBlockAt == ret) {
185 xmlGenericError(xmlGenericErrorContext,
186 "%p : Malloc(%d) Ok\n", xmlMemTraceBlockAt, size);
187 xmlMallocBreakpoint();
188 }
189
Owen Taylor3473f882001-02-23 17:55:21 +0000190 TEST_POINT
191
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000192 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000193}
194
195/**
196 * xmlMemMalloc:
197 * @size: an int specifying the size in byte to allocate.
198 *
199 * a malloc() equivalent, with logging of the allocation info.
200 *
201 * Returns a pointer to the allocated area or NULL in case of lack of memory.
202 */
203
204void *
Daniel Veillard8599e702001-07-17 21:38:51 +0000205xmlMemMalloc(size_t size)
Owen Taylor3473f882001-02-23 17:55:21 +0000206{
207 return(xmlMallocLoc(size, "none", 0));
208}
209
210/**
211 * xmlReallocLoc:
212 * @ptr: the initial memory block pointer
213 * @size: an int specifying the size in byte to allocate.
214 * @file: the file name or NULL
215 * @line: the line number
216 *
217 * a realloc() equivalent, with logging of the allocation info.
218 *
219 * Returns a pointer to the allocated area or NULL in case of lack of memory.
220 */
221
222void *
Daniel Veillard8599e702001-07-17 21:38:51 +0000223xmlReallocLoc(void *ptr,size_t size, const char * file, int line)
Owen Taylor3473f882001-02-23 17:55:21 +0000224{
225 MEMHDR *p;
226 unsigned long number;
227
228 if (!xmlMemInitialized) xmlInitMemory();
229 TEST_POINT
230
231 p = CLIENT_2_HDR(ptr);
232 number = p->mh_number;
233 if (p->mh_tag != MEMTAG) {
234 Mem_Tag_Err(p);
235 goto error;
236 }
237 p->mh_tag = ~MEMTAG;
238 debugMemSize -= p->mh_size;
239#ifdef MEM_LIST
240 debugmem_list_delete(p);
241#endif
242
243 p = (MEMHDR *) realloc(p,RESERVE_SIZE+size);
244 if (!p) {
245 goto error;
246 }
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000247 if (xmlMemTraceBlockAt == ptr) {
248 xmlGenericError(xmlGenericErrorContext,
249 "%p : Realloced(%d -> %d) Ok\n",
250 xmlMemTraceBlockAt, p->mh_size, size);
251 xmlMallocBreakpoint();
252 }
Owen Taylor3473f882001-02-23 17:55:21 +0000253 p->mh_tag = MEMTAG;
254 p->mh_number = number;
255 p->mh_type = REALLOC_TYPE;
256 p->mh_size = size;
257 p->mh_file = file;
258 p->mh_line = line;
259 debugMemSize += size;
260 if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
261#ifdef MEM_LIST
262 debugmem_list_add(p);
263#endif
264
265 TEST_POINT
266
267 return(HDR_2_CLIENT(p));
268
269error:
270 return(NULL);
271}
272
273/**
274 * xmlMemRealloc:
275 * @ptr: the initial memory block pointer
276 * @size: an int specifying the size in byte to allocate.
277 *
278 * a realloc() equivalent, with logging of the allocation info.
279 *
280 * Returns a pointer to the allocated area or NULL in case of lack of memory.
281 */
282
283void *
Daniel Veillard8599e702001-07-17 21:38:51 +0000284xmlMemRealloc(void *ptr,size_t size) {
Owen Taylor3473f882001-02-23 17:55:21 +0000285 return(xmlReallocLoc(ptr, size, "none", 0));
286}
287
288/**
289 * xmlMemFree:
290 * @ptr: the memory block pointer
291 *
292 * a free() equivalent, with error checking.
293 */
294void
295xmlMemFree(void *ptr)
296{
297 MEMHDR *p;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000298 char *target;
Owen Taylor3473f882001-02-23 17:55:21 +0000299
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000300 if (ptr == (void *) -1) {
301 xmlGenericError(xmlGenericErrorContext,
302 "trying to free pointer from freed area\n");
303 goto error;
304 }
305
306 if (xmlMemTraceBlockAt == ptr) {
307 xmlGenericError(xmlGenericErrorContext,
308 "%p : Freed()\n", xmlMemTraceBlockAt);
309 xmlMallocBreakpoint();
310 }
311
Owen Taylor3473f882001-02-23 17:55:21 +0000312 TEST_POINT
313
Daniel Veillard92ad2102001-03-27 12:47:33 +0000314 target = (char *) ptr;
315
Owen Taylor3473f882001-02-23 17:55:21 +0000316 p = CLIENT_2_HDR(ptr);
317 if (p->mh_tag != MEMTAG) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000318 Mem_Tag_Err(p);
319 goto error;
Owen Taylor3473f882001-02-23 17:55:21 +0000320 }
321 p->mh_tag = ~MEMTAG;
322 debugMemSize -= p->mh_size;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000323 memset(target, -1, p->mh_size);
Owen Taylor3473f882001-02-23 17:55:21 +0000324
325#ifdef MEM_LIST
326 debugmem_list_delete(p);
327#endif
328 free(p);
329
330 TEST_POINT
331
332 return;
333
334error:
335 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard8599e702001-07-17 21:38:51 +0000336 "xmlFree(%lX) error\n", (unsigned long) ptr);
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000337 xmlMallocBreakpoint();
Owen Taylor3473f882001-02-23 17:55:21 +0000338 return;
339}
340
341/**
342 * xmlMemStrdupLoc:
343 * @ptr: the initial string pointer
344 * @file: the file name or NULL
345 * @line: the line number
346 *
347 * a strdup() equivalent, with logging of the allocation info.
348 *
349 * Returns a pointer to the new string or NULL if allocation error occured.
350 */
351
352char *
353xmlMemStrdupLoc(const char *str, const char *file, int line)
354{
355 char *s;
356 size_t size = strlen(str) + 1;
357 MEMHDR *p;
358
359 if (!xmlMemInitialized) xmlInitMemory();
360 TEST_POINT
361
362 p = (MEMHDR *) malloc(RESERVE_SIZE+size);
363 if (!p) {
364 goto error;
365 }
366 p->mh_tag = MEMTAG;
367 p->mh_number = ++block;
368 p->mh_size = size;
369 p->mh_type = STRDUP_TYPE;
370 p->mh_file = file;
371 p->mh_line = line;
372 debugMemSize += size;
373 if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
374#ifdef MEM_LIST
375 debugmem_list_add(p);
376#endif
377 s = (char *) HDR_2_CLIENT(p);
378
379 if (xmlMemStopAtBlock == block) xmlMallocBreakpoint();
380
381 if (s != NULL)
382 strcpy(s,str);
383 else
384 goto error;
385
386 TEST_POINT
387
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000388 if (xmlMemTraceBlockAt == s) {
389 xmlGenericError(xmlGenericErrorContext,
390 "%p : Strdup() Ok\n", xmlMemTraceBlockAt);
391 xmlMallocBreakpoint();
392 }
393
Owen Taylor3473f882001-02-23 17:55:21 +0000394 return(s);
395
396error:
397 return(NULL);
398}
399
400/**
401 * xmlMemoryStrdup:
402 * @ptr: the initial string pointer
403 *
404 * a strdup() equivalent, with logging of the allocation info.
405 *
406 * Returns a pointer to the new string or NULL if allocation error occured.
407 */
408
409char *
410xmlMemoryStrdup(const char *str) {
411 return(xmlMemStrdupLoc(str, "none", 0));
412}
413
414/**
415 * xmlMemUsed:
416 *
417 * returns the amount of memory currenly allocated
418 *
419 * Returns an int representing the amount of memory allocated.
420 */
421
422int
423xmlMemUsed(void) {
424 return(debugMemSize);
425}
426
427#ifdef MEM_LIST
428/**
429 * xmlMemContentShow:
430 * @fp: a FILE descriptor used as the output file
431 * @p: a memory block header
432 *
433 * tries to show some content from the memory block
434 */
435
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000436static void
Owen Taylor3473f882001-02-23 17:55:21 +0000437xmlMemContentShow(FILE *fp, MEMHDR *p)
438{
439 int i,j,len = p->mh_size;
440 const char *buf = (const char *) HDR_2_CLIENT(p);
441
442 if (p == NULL) {
443 fprintf(fp, " NULL");
444 return;
445 }
446
447 for (i = 0;i < len;i++) {
448 if (buf[i] == 0) break;
449 if (!isprint(buf[i])) break;
450 }
451 if ((i < 4) && ((buf[i] != 0) || (i == 0))) {
452 if (len >= 4) {
453 MEMHDR *q;
454 void *cur;
455
456 for (j = 0;j < len -3;j += 4) {
457 cur = *((void **) &buf[j]);
458 q = CLIENT_2_HDR(cur);
459 p = memlist;
460 while (p != NULL) {
461 if (p == q) break;
462 p = p->mh_next;
463 }
464 if ((p != NULL) && (p == q)) {
465 fprintf(fp, " pointer to #%lu at index %d",
466 p->mh_number, j);
467 return;
468 }
469 }
470 }
471 } else if ((i == 0) && (buf[i] == 0)) {
472 fprintf(fp," null");
473 } else {
474 if (buf[i] == 0) fprintf(fp," \"%.25s\"", buf);
475 else {
476 fprintf(fp," [");
477 for (j = 0;j < i;j++)
478 fprintf(fp,"%c", buf[j]);
479 fprintf(fp,"]");
480 }
481 }
482}
483#endif
484
485/**
486 * xmlMemShow:
487 * @fp: a FILE descriptor used as the output file
488 * @nr: number of entries to dump
489 *
490 * show a show display of the memory allocated, and dump
491 * the @nr last allocated areas which were not freed
492 */
493
494void
495xmlMemShow(FILE *fp, int nr)
496{
497#ifdef MEM_LIST
498 MEMHDR *p;
499#endif
500
501 if (fp != NULL)
502 fprintf(fp," MEMORY ALLOCATED : %lu, MAX was %lu\n",
503 debugMemSize, debugMaxMemSize);
504#ifdef MEM_LIST
505 if (nr > 0) {
506 fprintf(fp,"NUMBER SIZE TYPE WHERE\n");
507 p = memlist;
508 while ((p) && nr > 0) {
509 fprintf(fp,"%6lu %6u ",p->mh_number,p->mh_size);
510 switch (p->mh_type) {
511 case STRDUP_TYPE:fprintf(fp,"strdup() in ");break;
512 case MALLOC_TYPE:fprintf(fp,"malloc() in ");break;
513 case REALLOC_TYPE:fprintf(fp,"realloc() in ");break;
514 default:fprintf(fp," ??? in ");break;
515 }
516 if (p->mh_file != NULL)
517 fprintf(fp,"%s(%d)", p->mh_file, p->mh_line);
518 if (p->mh_tag != MEMTAG)
519 fprintf(fp," INVALID");
520 xmlMemContentShow(fp, p);
521 fprintf(fp,"\n");
522 nr--;
523 p = p->mh_next;
524 }
525 }
526#endif /* MEM_LIST */
527}
528
529/**
530 * xmlMemDisplay:
531 * @fp: a FILE descriptor used as the output file, if NULL, the result is
532 * written to the file .memorylist
533 *
534 * show in-extenso the memory blocks allocated
535 */
536
537void
538xmlMemDisplay(FILE *fp)
539{
540#ifdef MEM_LIST
541 MEMHDR *p;
542 int idx;
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000543 int nb = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000544#if defined(HAVE_LOCALTIME) && defined(HAVE_STRFTIME)
545 time_t currentTime;
546 char buf[500];
547 struct tm * tstruct;
548
549 currentTime = time(NULL);
550 tstruct = localtime(&currentTime);
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000551 strftime(buf, sizeof(buf) - 1, "%I:%M:%S %p", tstruct);
Owen Taylor3473f882001-02-23 17:55:21 +0000552 fprintf(fp," %s\n\n", buf);
553#endif
554
555
556 fprintf(fp," MEMORY ALLOCATED : %lu, MAX was %lu\n",
557 debugMemSize, debugMaxMemSize);
558 fprintf(fp,"BLOCK NUMBER SIZE TYPE\n");
559 idx = 0;
560 p = memlist;
561 while (p) {
562 fprintf(fp,"%-5u %6lu %6u ",idx++,p->mh_number,p->mh_size);
563 switch (p->mh_type) {
564 case STRDUP_TYPE:fprintf(fp,"strdup() in ");break;
565 case MALLOC_TYPE:fprintf(fp,"malloc() in ");break;
566 case REALLOC_TYPE:fprintf(fp,"realloc() in ");break;
567 default:fprintf(fp," ??? in ");break;
568 }
569 if (p->mh_file != NULL) fprintf(fp,"%s(%d)", p->mh_file, p->mh_line);
570 if (p->mh_tag != MEMTAG)
571 fprintf(fp," INVALID");
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000572 nb++;
573 if (nb < 100)
574 xmlMemContentShow(fp, p);
575 else
576 fprintf(fp," skip");
577
Owen Taylor3473f882001-02-23 17:55:21 +0000578 fprintf(fp,"\n");
579 p = p->mh_next;
580 }
581#else
582 fprintf(fp,"Memory list not compiled (MEM_LIST not defined !)\n");
583#endif
584}
585
586#ifdef MEM_LIST
587
588void debugmem_list_add(MEMHDR *p)
589{
590 p->mh_next = memlist;
591 p->mh_prev = NULL;
592 if (memlist) memlist->mh_prev = p;
593 memlist = p;
594#ifdef MEM_LIST_DEBUG
595 if (stderr)
596 Mem_Display(stderr);
597#endif
598}
599
600void debugmem_list_delete(MEMHDR *p)
601{
602 if (p->mh_next)
603 p->mh_next->mh_prev = p->mh_prev;
604 if (p->mh_prev)
605 p->mh_prev->mh_next = p->mh_next;
606 else memlist = p->mh_next;
607#ifdef MEM_LIST_DEBUG
608 if (stderr)
609 Mem_Display(stderr);
610#endif
611}
612
613#endif
614
615/*
616 * debugmem_tag_error : internal error function.
617 */
618
619void debugmem_tag_error(void *p)
620{
621 xmlGenericError(xmlGenericErrorContext,
622 "Memory tag error occurs :%p \n\t bye\n", p);
623#ifdef MEM_LIST
624 if (stderr)
625 xmlMemDisplay(stderr);
626#endif
627}
628
Daniel Veillardb44025c2001-10-11 22:55:55 +0000629static FILE *xmlMemoryDumpFile = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +0000630
631
632/**
633 * xmlMemoryDump:
634 *
635 * Dump in-extenso the memory blocks allocated to the file .memorylist
636 */
637
638void
639xmlMemoryDump(void)
640{
641#if defined(DEBUG_MEMORY_LOCATION) | defined(DEBUG_MEMORY)
642 FILE *dump;
643
644 dump = fopen(".memdump", "w");
645 if (dump == NULL) xmlMemoryDumpFile = stdout;
646 else xmlMemoryDumpFile = dump;
647
648 xmlMemDisplay(xmlMemoryDumpFile);
649
650 if (dump != NULL) fclose(dump);
651#endif
652}
653
654
655/****************************************************************
656 * *
657 * Initialization Routines *
658 * *
659 ****************************************************************/
660
Owen Taylor3473f882001-02-23 17:55:21 +0000661/**
662 * xmlInitMemory:
663 *
664 * Initialize the memory layer.
665 *
666 * Returns 0 on success
667 */
668
669static int xmlInitMemoryDone = 0;
670
671int
672xmlInitMemory(void)
673{
674 int ret;
675
676#ifdef HAVE_STDLIB_H
677 char *breakpoint;
678#endif
679
680 if (xmlInitMemoryDone) return(-1);
681
682#ifdef HAVE_STDLIB_H
683 breakpoint = getenv("XML_MEM_BREAKPOINT");
684 if (breakpoint != NULL) {
685 sscanf(breakpoint, "%d", &xmlMemStopAtBlock);
686 }
687#endif
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000688#ifdef HAVE_STDLIB_H
689 breakpoint = getenv("XML_MEM_TRACE");
690 if (breakpoint != NULL) {
691 sscanf(breakpoint, "%p", &xmlMemTraceBlockAt);
692 }
693#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000694
695#ifdef DEBUG_MEMORY
696 xmlGenericError(xmlGenericErrorContext,
697 "xmlInitMemory() Ok\n");
698#endif
699 ret = 0;
700 return(ret);
701}
702
703/**
704 * xmlMemSetup:
705 * @freeFunc: the free() function to use
706 * @mallocFunc: the malloc() function to use
707 * @reallocFunc: the realloc() function to use
708 * @strdupFunc: the strdup() function to use
709 *
710 * Override the default memory access functions with a new set
711 * This has to be called before any other libxml routines !
712 *
713 * Should this be blocked if there was already some allocations
714 * done ?
715 *
716 * Returns 0 on success
717 */
718int
719xmlMemSetup(xmlFreeFunc freeFunc, xmlMallocFunc mallocFunc,
720 xmlReallocFunc reallocFunc, xmlStrdupFunc strdupFunc) {
721 if (freeFunc == NULL)
722 return(-1);
723 if (mallocFunc == NULL)
724 return(-1);
725 if (reallocFunc == NULL)
726 return(-1);
727 if (strdupFunc == NULL)
728 return(-1);
729 xmlFree = freeFunc;
730 xmlMalloc = mallocFunc;
731 xmlRealloc = reallocFunc;
732 xmlMemStrdup = strdupFunc;
733 return(0);
734}
735
736/**
737 * xmlMemGet:
738 * @freeFunc: the free() function in use
739 * @mallocFunc: the malloc() function in use
740 * @reallocFunc: the realloc() function in use
741 * @strdupFunc: the strdup() function in use
742 *
743 * Return the memory access functions set currently in use
744 *
745 * Returns 0 on success
746 */
747int
748xmlMemGet(xmlFreeFunc *freeFunc, xmlMallocFunc *mallocFunc,
749 xmlReallocFunc *reallocFunc, xmlStrdupFunc *strdupFunc) {
750 if (freeFunc != NULL) *freeFunc = xmlFree;
751 if (mallocFunc != NULL) *mallocFunc = xmlMalloc;
752 if (reallocFunc != NULL) *reallocFunc = xmlRealloc;
753 if (strdupFunc != NULL) *strdupFunc = xmlMemStrdup;
754 return(0);
755}
756