    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=&current->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  | }