1 | /***************************************
2 | $Header: /home/amb/cxref/RCS/memory.c 1.12 1999/01/16 11:09:59 amb Exp $
3 |
4 | C Cross Referencing & Documentation tool. Version 1.5.
5 |
6 | Memory management functions
7 | ******************/ /******************
8 | Written by Andrew M. Bishop
9 |
10 | This file Copyright 1995,96,97 Andrew M. Bishop
11 | It may be distributed under the GNU Public License, version 2, or
12 | any higher version. See section COPYING of the GNU Public license
13 | for conditions under which this file may be redistributed.
14 | ***************************************/
15 |
16 | /*+ The amount of debugging, non-zero for totals, 2 for logging, 4 for printing each call. +*/
17 | #define DEBUG 0
18 |
19 | /* The configure output */
20 |
21 | #include "autoconfig.h"
22 |
23 | #include <stdio.h>
24 | #include <stdlib.h>
25 | #include <string.h>
26 |
27 | #ifdef USE_STD_ARG
28 | #include <stdarg.h>
29 | #else
30 | #include <varargs.h>
31 | #endif
32 |
33 | #include <memory.h>
34 | #include "memory.h"
35 |
36 | /*+ A private memory heap is used to reduce the number of malloc calls that are made, the Heap type is a pointer to this. +*/
37 | typedef struct _Heap *Heap;
38 |
39 | /*+ A structure containing all of the information about the private heap in a linked list. +*/
40 | struct _Heap
41 | {
42 | char* mem; /*+ The memory that is private to the heap. +*/
43 | Heap next; /*+ The next Heap structure. +*/
44 | };
45 |
46 | /*+ Local variable to control the usage of the private heap; +*/
47 | static Heap first=NULL; /*+ the first segment of memory on the private heap. +*/
48 | static int heap_left=0; /*+ the amount of space left in the current heap segment. +*/
49 |
50 | static char* get_space(unsigned int l);
51 | static Heap add_to_heap(unsigned int l);
52 |
53 | #if DEBUG&2
54 | /*+ Variable used for debugging, not a good thing to do. what if more than 16384 mallocs? +*/
55 | static void* addresses[16384];
56 | static char* files[16384];
57 | static int lines[16384];
58 | #endif
59 | #if DEBUG
60 | /*+ Variable used for debugging. +*/
61 | static int malloc_count=0;
62 | static int realloc_count=0;
63 | static int free_count=0;
64 | #endif
65 |
66 |
67 | /*++++++++++++++++++++++++++++++++++++++
68 | A replacement malloc() function.
69 |
70 | void* SafeMalloc Returns the address.
71 |
72 | unsigned int size The size of the memory to allocate.
73 |
74 | char* file The file that the function is called from.
75 |
76 | int line The line number that the function is called from.
77 | ++++++++++++++++++++++++++++++++++++++*/
78 |
79 | void* SafeMalloc(unsigned int size,char* file,int line)
80 | {
81 | void* rptr=malloc(size);
82 |
83 | #if DEBUG&4
84 | printf("$$Malloc #%5d of %4d bytes at %08lx (%s:%3d)\n",malloc_count+1,size,(long)rptr,file,line);
85 | #endif
86 | #if DEBUG&2
87 | if(malloc_count==(sizeof(addresses)/sizeof(addresses[0])))
88 | {fprintf(stderr,"$$Too many Mallocs to log, edit memory.c\n");exit(3);}
89 | addresses[malloc_count]=(void*)rptr;
90 | files[malloc_count]=file;
91 | lines[malloc_count]=line;
92 | #endif
93 | #if DEBUG
94 | malloc_count++;
95 | if(!rptr) printf("$$Warning Malloc() returning NULL (%s:%3d)\n",file,line);
96 | #endif
97 | #if !DEBUG
98 | if(!rptr) printf("Warning Malloc() returning NULL (%s:%3d)\n",file,line);
99 | #endif
100 |
101 | return(rptr);
102 | }
103 |
104 |
105 | /*++++++++++++++++++++++++++++++++++++++
106 | A replacement calloc() function.
107 |
108 | void* SafeCalloc Returns the address.
109 |
110 | unsigned int n The number of items to allocate.
111 |
112 | unsigned int size The size of the memory to allocate.
113 |
114 | char* file The file that the function is called from.
115 |
116 | int line The line number that the function is called from.
117 | ++++++++++++++++++++++++++++++++++++++*/
118 |
119 | void* SafeCalloc(unsigned int n,unsigned int size,char* file,int line)
120 | {
121 | void* rptr=calloc(n,size);
122 |
123 | #if DEBUG&4
124 | printf("$$Calloc #%5d of %4d bytes at %08lx (%s:%3d)\n",malloc_count+1,size,(long)rptr,file,line);
125 | #endif
126 | #if DEBUG&2
127 | if(malloc_count==(sizeof(addresses)/sizeof(addresses[0])))
128 | {fprintf(stderr,"$$Too many Mallocs to log, edit memory.c\n");exit(3);}
129 | addresses[malloc_count]=(void*)rptr;
130 | files[malloc_count]=file;
131 | lines[malloc_count]=line;
132 | #endif
133 | #if DEBUG
134 | malloc_count++;
135 | if(!rptr) printf("$$Warning Calloc() returning NULL (%s:%3d)\n",file,line);
136 | #endif
137 | #if !DEBUG
138 | if(!rptr) printf("Warning Calloc() returning NULL (%s:%3d)\n",file,line);
139 | #endif
140 |
141 | return(rptr);
142 | }
143 |
144 |
145 | /*++++++++++++++++++++++++++++++++++++++
146 | A replacement realloc() function.
147 |
148 | void* SafeRealloc Returns the address.
149 |
150 | void* ptr The old pointer.
151 |
152 | unsigned int size The size of the new memory to allocate.
153 |
154 | char* file The file that the function is called from.
155 |
156 | int line The line number that the function is called from.
157 | ++++++++++++++++++++++++++++++++++++++*/
158 |
159 | void* SafeRealloc(void* ptr,unsigned int size,char* file,int line)
160 | {
161 | void* rptr=realloc(ptr,size);
162 |
163 | #if DEBUG&4
164 | printf("$$Realloc #%4d of %4d bytes at %08lx (old %08lx) (%s:%3d)\n",realloc_count+1,size,(long)rptr,(long)ptr,file,line);
165 | #endif
166 | #if DEBUG&2
167 | {
168 | int i;
169 | for(i=0;i<malloc_count;i++)
170 | if(addresses[i]==(void*)ptr)
171 | {addresses[i]=rptr;break;}
172 | if(i==malloc_count)
173 | printf("$$Realloc() called for a non Malloced pointer %08lx (%s:%3d)\n",(long)ptr,file,line);
174 | }
175 | #endif
176 | #if DEBUG
177 | realloc_count++;
178 | if(!rptr) printf("$$Warning Realloc() returning NULL (%s:%3d)\n",file,line);
179 | #endif
180 | #if !DEBUG
181 | if(!rptr) printf("Warning Realloc() returning NULL (%s:%3d)\n",file,line);
182 | #endif
183 |
184 | return(rptr);
185 | }
186 |
187 |
188 | /*++++++++++++++++++++++++++++++++++++++
189 | A replacement free() function.
190 |
191 | void* ptr The pointer that is to be freed up.
192 |
193 | char* file The file that the function is called from.
194 |
195 | int line The line number that the function is called from.
196 | ++++++++++++++++++++++++++++++++++++++*/
197 |
198 | void SafeFree(void* ptr,char* file,int line)
199 | {
200 | #if DEBUG&4
201 | printf("$$Free #%5d at %08lx (%s:%3d)\n",free_count+1,(long)ptr,file,line);
202 | #endif
203 | #if DEBUG&2
204 | {
205 | int i;
206 | for(i=0;i<malloc_count;i++)
207 | if(addresses[i]==(void*)ptr)
208 | {addresses[i]=(void*)1;break;}
209 | if(i==malloc_count)
210 | printf("$$Free() called for a non Malloced pointer %08lx (%s:%3d)\n",(long)ptr,file,line);
211 | }
212 | #endif
213 | #if DEBUG
214 | free_count++;
215 | if(!ptr) printf("$$Calling Free() on NULL (%s:%3d)\n",file,line);
216 | else
217 | #endif
218 | #if !DEBUG
219 | if(!ptr) printf("Calling Free() on NULL (%s:%3d)\n",file,line);
220 | else
221 | #endif
222 |
223 | free(ptr);
224 | }
225 |
226 |
227 | /*++++++++++++++++++++++++++++++++++++++
228 | A function to copy a string on the public global heap.
229 |
230 | char* SafeMallocString Returns the copy of the string.
231 |
232 | char* x The string to be copied.
233 |
234 | char* file The file that the function is called from.
235 |
236 | int line The line number that the function is called from.
237 | ++++++++++++++++++++++++++++++++++++++*/
238 |
239 | char* SafeMallocString(char* x,char* file,int line)
240 | {
241 | char* t=NULL;
242 |
243 | if(x)
244 | {
245 | t=(char*)SafeMalloc(strlen(x)+1,file,line);
246 | strcpy(t,x);
247 | }
248 |
249 | return(t);
250 | }
251 |
252 |
253 | /*++++++++++++++++++++++++++++++++++++++
254 | A function to copy a string on the local private memory heap.
255 |
256 | char* CopyString Returns the copy of the string.
257 |
258 | char* x The string to be copied.
259 | ++++++++++++++++++++++++++++++++++++++*/
260 |
261 | char* CopyString(char* x)
262 | {
263 | char* t=NULL;
264 |
265 | if(x)
266 | {
267 | t=get_space(strlen(x)+1);
268 | strcpy(t,x);
269 | }
270 |
271 | return(t);
272 | }
273 |
274 |
275 | /*++++++++++++++++++++++++++++++++++++++
276 | A function to concatenate a number of strings.
277 |
278 | char* ConcatStrings Returns the a pointer to the new string.
279 |
280 | int n The number of strings
281 |
282 | char* s The first string.
283 |
284 | ... The other strings, 'n' including 's'.
285 |
286 | Any of the strings that are inputs can be NULL, in this case they are quietly ignored.
287 | ++++++++++++++++++++++++++++++++++++++*/
288 |
289 | char* ConcatStrings(int n,char* s, ...)
290 | {
291 | char* t=NULL,*str;
292 | unsigned int l=0;
293 | int i;
294 | va_list ap;
295 |
296 | #ifdef USE_STD_ARG
297 | va_start(ap,s);
298 | #else
299 | va_start(ap);
300 | #endif
301 |
302 | for(i=0;i<n;i++)
303 | {
304 | if(i)
305 | str=va_arg(ap, char *);
306 | else
307 | str=s;
308 |
309 | if(str)
310 | l+=strlen(str);
311 | }
312 |
313 | va_end(ap);
314 |
315 | if(l)
316 | {
317 | t=get_space(l+1); t[0]=0;
318 |
319 | #ifdef USE_STD_ARG
320 | va_start(ap,s);
321 | #else
322 | va_start(ap);
323 | #endif
324 |
325 | for(i=0;i<n;i++)
326 | {
327 | if(i)
328 | str=va_arg(ap, char *);
329 | else
330 | str=s;
331 |
332 | if(str)
333 | strcat(t,str);
334 | }
335 |
336 | va_end(ap);
337 | }
338 |
339 | return(t);
340 | }
341 |
342 |
343 | /*++++++++++++++++++++++++++++++++++++++
344 | Prints out the number of mallocs / reallocs and frees.
345 | ++++++++++++++++++++++++++++++++++++++*/
346 |
347 | void PrintMemoryStatistics(void)
348 | {
349 | #if DEBUG
350 | printf("\n"
351 | "$$Memory usage : %5d Malloc()/Calloc() calls\n"
352 | "$$ %5d Realloc() calls\n"
353 | "$$ %5d Free() calls\n"
354 | "$$ %5d Net calls (Malloc-Free)\n",
355 | malloc_count,realloc_count,free_count,malloc_count-free_count);
356 | #endif
357 |
358 | #if DEBUG&2
359 | {
360 | int i;
361 | for(i=0;i<malloc_count;i++)
362 | if(addresses[i]!=(void*)1)
363 | printf("$$Malloc #%5d at address %08lx is not freed (%s:%3d) = '%s'\n",i+1,(long)addresses[i],files[i],lines[i],(char*)addresses[i]);
364 | }
365 | #endif
366 | }
367 |
368 |
369 | /*++++++++++++++++++++++++++++++++++++++
370 | Tidies up the local heap of memory.
371 | ++++++++++++++++++++++++++++++++++++++*/
372 |
373 | void TidyMemory(void)
374 | {
375 | if(first)
376 | {
377 | Heap h=first,n;
378 | do
379 | {
380 | n=h->next;
381 | Free(h->mem);
382 | Free(h);
383 | h=n;
384 | }
385 | while(h);
386 | }
387 |
388 | first=NULL;
389 | heap_left=0;
390 | }
391 |
392 | /*+ The size of each of the heap allocations +*/
393 | #define HEAP_INC 8192
394 |
395 | /*+ The size of a string that is large enough to have it's own mallocation. +*/
396 | #define SMALL_STRING 256
397 |
398 | /*++++++++++++++++++++++++++++++++++++++
399 | A function to get some memory for a string, allocate a new heap structure if needed.
400 |
401 | char* get_space Returns a pointer to enough space.
402 |
403 | unsigned int l The amount of space that is needed.
404 | ++++++++++++++++++++++++++++++++++++++*/
405 |
406 | static char* get_space(unsigned int l)
407 | {
408 | static Heap current=NULL;
409 | char* r=NULL;
410 |
411 | if(l <= SMALL_STRING)
412 | {
413 | if(heap_left < l)
414 | {
415 | current=add_to_heap(HEAP_INC);
416 | heap_left=HEAP_INC;
417 | }
418 |
419 | heap_left-=l;
420 |
421 | r=¤t->mem[heap_left]; /* Work downwards */
422 | }
423 | else
424 | {
425 | Heap h=add_to_heap(l);
426 | r=h->mem;
427 | }
428 |
429 | return(r);
430 | }
431 |
432 |
433 | /*++++++++++++++++++++++++++++++++++++++
434 | Add some bytes to the privately maintained memory heap.
435 |
436 | Heap add_to_heap Returns a pointer to the required memory.
437 |
438 | unsigned int l The size of the memory that is required.
439 | ++++++++++++++++++++++++++++++++++++++*/
440 |
441 | static Heap add_to_heap(unsigned int l)
442 | {
443 | Heap* h=&first;
444 |
445 | while(*h)
446 | h=&(*h)->next;
447 |
448 | *h=(Heap)Malloc(sizeof(struct _Heap));
449 | (*h)->next=NULL;
450 | (*h)->mem=(char*)Malloc(l);
451 |
452 | return(*h);
453 | }