view src/vmsgmalloc.c @ 21998:ccda0e3ab1b6

(reporter-bug-hook): Use rfc822-goto-eoh.
author Richard M. Stallman <rms@gnu.org>
date Fri, 08 May 1998 22:05:42 +0000
parents ee40177f6c68
children b7aa6ac26872
line wrap: on
line source

/* DO NOT EDIT THIS FILE -- it is automagically generated.  -*- C -*- */

#define _MALLOC_INTERNAL

/* The malloc headers and source files from the C library follow here.  */

/* Declarations for `malloc' and friends.
   Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
		  Written May 1989 by Mike Haertel.

This file is part of GNU Emacs.

GNU Emacs is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.

GNU Emacs is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with GNU Emacs; see the file COPYING.  If not, write to
the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.

   The author may be reached (Email) at the address mike@ai.mit.edu,
   or (US mail) as Mike Haertel c/o Free Software Foundation.  */

#ifndef _MALLOC_H

#define _MALLOC_H	1

#ifdef	__cplusplus
extern "C"
{
#endif

#if defined (__cplusplus) || (defined (__STDC__) && __STDC__)
#undef	__P
#define	__P(args)	args
#undef  __const
#define __const		const
#undef	__ptr_t
#define	__ptr_t		void *
#else /* Not C++ or ANSI C.  */
#undef	__P
#define	__P(args)	()
#undef	__const
#define	__const
#undef	__ptr_t
#define	__ptr_t		char *
#endif /* C++ or ANSI C.  */

#ifndef	NULL
#define	NULL	0
#endif

#ifdef	__STDC__
#include <stddef.h>
#else
#ifdef VMS /* The following are defined in stdio.h, but we need it NOW!
	      But do NOT do it with defines here, for then, VAX C is going
	      to barf when it gets to stdio.h and the typedefs in there! */
typedef unsigned int size_t;
typedef int ptrdiff_t;
#else /* not VMS */
#undef	size_t
#define	size_t		unsigned int
#undef	ptrdiff_t
#define	ptrdiff_t	int
#endif /* VMS */
#endif


/* Allocate SIZE bytes of memory.  */
extern __ptr_t malloc __P ((size_t __size));
/* Re-allocate the previously allocated block
   in __ptr_t, making the new block SIZE bytes long.  */
extern __ptr_t realloc __P ((__ptr_t __ptr, size_t __size));
/* Allocate NMEMB elements of SIZE bytes each, all initialized to 0.  */
extern __ptr_t calloc __P ((size_t __nmemb, size_t __size));
/* Free a block allocated by `malloc', `realloc' or `calloc'.  */
extern void free __P ((__ptr_t __ptr));

/* Allocate SIZE bytes allocated to ALIGNMENT bytes.  */
extern __ptr_t memalign __P ((size_t __alignment, size_t __size));

/* Allocate SIZE bytes on a page boundary.  */
extern __ptr_t valloc __P ((size_t __size));

#ifdef VMS
/* VMS hooks to deal with two heaps */
/* Allocate SIZE bytes of memory.  */
extern __ptr_t __vms_malloc __P ((size_t __size));
/* Re-allocate the previously allocated block
   in __ptr_t, making the new block SIZE bytes long.  */
extern __ptr_t __vms_realloc __P ((__ptr_t __ptr, size_t __size));
/* Free a block allocated by `malloc', `realloc' or `calloc'.  */
extern void __vms_free __P ((__ptr_t __ptr));
#endif

#ifdef _MALLOC_INTERNAL

#include <stdio.h>		/* Harmless, gets __GNU_LIBRARY__ defined.  */

#if defined(HAVE_CONFIG_H) || defined(emacs)
#include <config.h>
#endif

#if	defined(__GNU_LIBRARY__) || defined(STDC_HEADERS) || defined(USG)
#include <string.h>
#else
#ifndef memset
#define	memset(s, zero, n)	bzero ((s), (n))
#endif
#ifndef memcpy
#define	memcpy(d, s, n)		bcopy ((s), (d), (n))
#endif
#ifndef memmove
#define	memmove(d, s, n)	bcopy ((s), (d), (n))
#endif
#endif


#if	defined(__GNU_LIBRARY__) || defined(__STDC__)
#include <limits.h>
#else
#define	CHAR_BIT	8
#endif

/* The allocator divides the heap into blocks of fixed size; large
   requests receive one or more whole blocks, and small requests
   receive a fragment of a block.  Fragment sizes are powers of two,
   and all fragments of a block are the same size.  When all the
   fragments in a block have been freed, the block itself is freed.  */
#define INT_BIT		(CHAR_BIT * sizeof(int))
#ifdef VMS
#define BLOCKLOG	9
#else
#define BLOCKLOG	(INT_BIT > 16 ? 12 : 9)
#endif
#define BLOCKSIZE	(1 << BLOCKLOG)
#define BLOCKIFY(SIZE)	(((SIZE) + BLOCKSIZE - 1) / BLOCKSIZE)

/* Determine the amount of memory spanned by the initial heap table
   (not an absolute limit).  */
#define HEAP		(INT_BIT > 16 ? 4194304 : 65536)

/* Number of contiguous free blocks allowed to build up at the end of
   memory before they will be returned to the system.  */
#define FINAL_FREE_BLOCKS	8

/* Data structure giving per-block information.  */
typedef union
  {
    /* Heap information for a busy block.  */
    struct
      {
	/* Zero for a large block, or positive giving the
	   logarithm to the base two of the fragment size.  */
	int type;
	union
	  {
	    struct
	      {
		size_t nfree;	/* Free fragments in a fragmented block.  */
		size_t first;	/* First free fragment of the block.  */
	      } frag;
	    /* Size (in blocks) of a large cluster.  */
	    size_t size;
	  } info;
      } busy;
    /* Heap information for a free block
       (that may be the first of a free cluster).  */
    struct
      {
	size_t size;		/* Size (in blocks) of a free cluster.  */
	size_t next;		/* Index of next free cluster.  */
	size_t prev;		/* Index of previous free cluster.  */
      } free;
  } malloc_info;

/* Pointer to first block of the heap.  */
extern char *_heapbase;

/* Table indexed by block number giving per-block information.  */
extern malloc_info *_heapinfo;

/* Address to block number and vice versa.  */
#define BLOCK(A)	(((char *) (A) - _heapbase) / BLOCKSIZE + 1)
#define ADDRESS(B)	((__ptr_t) (((B) - 1) * BLOCKSIZE + _heapbase))

/* Current search index for the heap table.  */
extern size_t _heapindex;

/* Limit of valid info table indices.  */
extern size_t _heaplimit;

/* Doubly linked lists of free fragments.  */
struct list
  {
    struct list *next;
    struct list *prev;
  };

/* Free list headers for each fragment size.  */
extern struct list _fraghead[];

/* List of blocks allocated with `memalign' (or `valloc').  */
struct alignlist
  {
    struct alignlist *next;
    __ptr_t aligned;		/* The address that memaligned returned.  */
    __ptr_t exact;		/* The address that malloc returned.  */
  };
extern struct alignlist *_aligned_blocks;

/* Instrumentation.  */
extern size_t _chunks_used;
extern size_t _bytes_used;
extern size_t _chunks_free;
extern size_t _bytes_free;

/* Internal version of `free' used in `morecore' (malloc.c). */
extern void _free_internal __P ((__ptr_t __ptr));

#endif /* _MALLOC_INTERNAL.  */

/* Underlying allocation function; successive calls should
   return contiguous pieces of memory.  */
/* It does NOT always return contiguous pieces of memory on VMS. */
extern __ptr_t (*__morecore) __P ((ptrdiff_t __size));

/* Underlying deallocation function. It accepts both a pointer and
   a size to back up. It is implementation dependent what is really
   used. */
extern __ptr_t (*__lesscore) __P ((__ptr_t __ptr, ptrdiff_t __size));

/* Default value of `__morecore'.  */
extern __ptr_t __default_morecore __P ((ptrdiff_t __size));

/* Default value of `__lesscore'.  */
extern __ptr_t __default_lesscore __P ((__ptr_t __ptr, ptrdiff_t __size));

#ifdef VMS
/* Default value of `__morecore'.  */
extern __ptr_t __vms_morecore __P ((ptrdiff_t __size));

/* Default value of `__lesscore'.  */
extern __ptr_t __vms_lesscore __P ((__ptr_t __ptr, ptrdiff_t __size));
#endif

/* If not NULL, this function is called after each time
   `__morecore' is called to increase the data size.  */
extern void (*__after_morecore_hook) __P ((void));

/* If not NULL, this function is called after each time
   `__lesscore' is called to increase the data size.  */
extern void (*__after_lesscore_hook) __P ((void));

/* Nonzero if `malloc' has been called and done its initialization.  */
extern int __malloc_initialized;

/* Hooks for debugging versions.  */
extern void (*__free_hook) __P ((__ptr_t __ptr));
extern __ptr_t (*__malloc_hook) __P ((size_t __size));
extern __ptr_t (*__realloc_hook) __P ((__ptr_t __ptr, size_t __size));

/* Activate a standard collection of debugging hooks.  */
extern int mcheck __P ((void (*__func) __P ((void))));

/* Activate a standard collection of tracing hooks.  */
extern void mtrace __P ((void));

/* Statistics available to the user.  */
struct mstats
  {
    size_t bytes_total;		/* Total size of the heap. */
    size_t chunks_used;		/* Chunks allocated by the user. */
    size_t bytes_used;		/* Byte total of user-allocated chunks. */
    size_t chunks_free;		/* Chunks in the free list. */
    size_t bytes_free;		/* Byte total of chunks in the free list. */
  };

/* Pick up the current statistics. */
extern struct mstats mstats __P ((void));

/* Call WARNFUN with a warning message when memory usage is high.  */
extern void memory_warnings __P ((__ptr_t __start,
				  void (*__warnfun) __P ((__const char *))));


/* Relocating allocator.  */

/* Allocate SIZE bytes, and store the address in *HANDLEPTR.  */
extern __ptr_t r_alloc __P ((__ptr_t *__handleptr, size_t __size));

/* Free the storage allocated in HANDLEPTR.  */
extern void r_alloc_free __P ((__ptr_t *__handleptr));

/* Adjust the block at HANDLEPTR to be SIZE bytes long.  */
extern __ptr_t r_re_alloc __P ((__ptr_t *__handleptr, size_t __size));


#ifdef	__cplusplus
}
#endif

#endif /* malloc.h  */
/* Memory allocator `malloc'.
   Copyright 1990, 1991, 1992, 1993 Free Software Foundation
		  Written May 1989 by Mike Haertel.

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Library General Public License for more details.

You should have received a copy of the GNU Library General Public
License along with this library; see the file COPYING.LIB.  If
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
Cambridge, MA 02139, USA.

   The author may be reached (Email) at the address mike@ai.mit.edu,
   or (US mail) as Mike Haertel c/o Free Software Foundation.  */

#ifndef	_MALLOC_INTERNAL
#define _MALLOC_INTERNAL
#include <malloc.h>
#endif

#ifdef VMS
/* How to really get more memory.  */
__ptr_t (*__morecore) __P ((ptrdiff_t __size)) = __vms_morecore;
#else
/* How to really get more memory.  */
__ptr_t (*__morecore) __P ((ptrdiff_t __size)) = __default_morecore;
#endif

/* Debugging hook for `malloc'.  */
#ifdef VMS
__ptr_t (*__malloc_hook) __P ((size_t __size)) = __vms_malloc;
#else
__ptr_t (*__malloc_hook) __P ((size_t __size));
#endif

/* Pointer to the base of the first block.  */
char *_heapbase;

/* Block information table.  Allocated with align/__free (not malloc/free).  */
malloc_info *_heapinfo;

/* Number of info entries.  */
static size_t heapsize;

/* Search index in the info table.  */
size_t _heapindex;

/* Limit of valid info table indices.  */
size_t _heaplimit;

/* Free lists for each fragment size.  */
struct list _fraghead[BLOCKLOG];

/* Instrumentation.  */
size_t _chunks_used;
size_t _bytes_used;
size_t _chunks_free;
size_t _bytes_free;

/* Are you experienced?  */
int __malloc_initialized;

void (*__after_morecore_hook) __P ((void));

/* Aligned allocation.  */
static __ptr_t align __P ((size_t));
static __ptr_t
align (size)
     size_t size;
{
  __ptr_t result;
  unsigned long int adj;

  result = (*__morecore) (size);
  adj = (unsigned long int) ((unsigned long int) ((char *) result -
						(char *) NULL)) % BLOCKSIZE;
  if (adj != 0)
    {
      adj = BLOCKSIZE - adj;
      (void) (*__morecore) (adj);
      result = (char *) result + adj;
    }

  if (__after_morecore_hook)
    (*__after_morecore_hook) ();

  return result;
}

/* Set everything up and remember that we have.  */
static int initialize __P ((void));
static int
initialize ()
{
#ifdef RL_DEBUG
  extern VMS_present_buffer();
  printf("__malloc_initialized = %d\n", __malloc_initialized);
  VMS_present_buffer();
#endif
  heapsize = HEAP / BLOCKSIZE;
  _heapinfo = (malloc_info *) align (heapsize * sizeof (malloc_info));
  if (_heapinfo == NULL)
    return 0;
  memset (_heapinfo, 0, heapsize * sizeof (malloc_info));
  _heapinfo[0].free.size = 0;
  _heapinfo[0].free.next = _heapinfo[0].free.prev = 0;
  _heapindex = 0;
  _heapbase = (char *) _heapinfo;
#ifdef RL_DEBUG
/* debug */
  printf("_heapbase = 0%o/0x%x/%d\n", _heapbase, _heapbase, _heapbase);
/* end debug */
#endif
  __malloc_initialized = 1;
  return 1;
}

/* Get neatly aligned memory, initializing or
   growing the heap info table as necessary. */
static __ptr_t morecore __P ((size_t));
static __ptr_t
morecore (size)
     size_t size;
{
  __ptr_t result;
  malloc_info *newinfo, *oldinfo;
  size_t newsize;

  result = align (size);
  if (result == NULL)
    return NULL;

  /* Check if we need to grow the info table.  */
  if ((size_t) BLOCK ((char *) result + size) > heapsize)
    {
      newsize = heapsize;
      while ((size_t) BLOCK ((char *) result + size) > newsize)
	newsize *= 2;
      newinfo = (malloc_info *) align (newsize * sizeof (malloc_info));
      if (newinfo == NULL)
	{
	  (*__lesscore) (result, size);
	  return NULL;
	}
      memset (newinfo, 0, newsize * sizeof (malloc_info));
      memcpy (newinfo, _heapinfo, heapsize * sizeof (malloc_info));
      oldinfo = _heapinfo;
      newinfo[BLOCK (oldinfo)].busy.type = 0;
      newinfo[BLOCK (oldinfo)].busy.info.size
	= BLOCKIFY (heapsize * sizeof (malloc_info));
      _heapinfo = newinfo;
      _free_internal (oldinfo);
      heapsize = newsize;
    }

  _heaplimit = BLOCK ((char *) result + size);
  return result;
}

/* Allocate memory from the heap.  */
__ptr_t
malloc (size)
     size_t size;
{
  __ptr_t result;
  size_t block, blocks, lastblocks, start;
  register size_t i;
  struct list *next;

  if (size == 0)
    return NULL;

  if (__malloc_hook != NULL)
    return (*__malloc_hook) (size);

  if (!__malloc_initialized)
    if (!initialize ())
      return NULL;

  if (size < sizeof (struct list))
      size = sizeof (struct list);

  /* Determine the allocation policy based on the request size.  */
  if (size <= BLOCKSIZE / 2)
    {
      /* Small allocation to receive a fragment of a block.
	 Determine the logarithm to base two of the fragment size. */
      register size_t log = 1;
      --size;
      while ((size /= 2) != 0)
	++log;

      /* Look in the fragment lists for a
	 free fragment of the desired size. */
      next = _fraghead[log].next;
      if (next != NULL)
	{
	  /* There are free fragments of this size.
	     Pop a fragment out of the fragment list and return it.
	     Update the block's nfree and first counters. */
	  result = (__ptr_t) next;
	  next->prev->next = next->next;
	  if (next->next != NULL)
	    next->next->prev = next->prev;
	  block = BLOCK (result);
	  if (--_heapinfo[block].busy.info.frag.nfree != 0)
	    _heapinfo[block].busy.info.frag.first = (unsigned long int)
	      ((unsigned long int) ((char *) next->next - (char *) NULL)
	       % BLOCKSIZE) >> log;

	  /* Update the statistics.  */
	  ++_chunks_used;
	  _bytes_used += 1 << log;
	  --_chunks_free;
	  _bytes_free -= 1 << log;
	}
      else
	{
	  /* No free fragments of the desired size, so get a new block
	     and break it into fragments, returning the first.  */
	  result = malloc (BLOCKSIZE);
	  if (result == NULL)
	    return NULL;

	  /* Link all fragments but the first into the free list.  */
	  for (i = 1; i < (size_t) (BLOCKSIZE >> log); ++i)
	    {
	      next = (struct list *) ((char *) result + (i << log));
#ifdef RL_DEBUG
	      printf("DEBUG:  malloc (%d): next = %p\n", size, next);
#endif
	      next->next = _fraghead[log].next;
	      next->prev = &_fraghead[log];
	      next->prev->next = next;
	      if (next->next != NULL)
		next->next->prev = next;
	    }

	  /* Initialize the nfree and first counters for this block.  */
	  block = BLOCK (result);
	  _heapinfo[block].busy.type = log;
	  _heapinfo[block].busy.info.frag.nfree = i - 1;
	  _heapinfo[block].busy.info.frag.first = i - 1;

	  _chunks_free += (BLOCKSIZE >> log) - 1;
	  _bytes_free += BLOCKSIZE - (1 << log);
	  _bytes_used -= BLOCKSIZE - (1 << log);
	}
    }
  else
    {
      /* Large allocation to receive one or more blocks.
	 Search the free list in a circle starting at the last place visited.
	 If we loop completely around without finding a large enough
	 space we will have to get more memory from the system.  */
      blocks = BLOCKIFY (size);
      start = block = _heapindex;
      while (_heapinfo[block].free.size < blocks)
	{
	  block = _heapinfo[block].free.next;
	  if (block == start)
	    {
	      /* Need to get more from the system.  Check to see if
		 the new core will be contiguous with the final free
		 block; if so we don't need to get as much.  */
	      block = _heapinfo[0].free.prev;
	      lastblocks = _heapinfo[block].free.size;
	      if (_heaplimit != 0 && block + lastblocks == _heaplimit &&
		  (*__morecore) (0) == ADDRESS (block + lastblocks) &&
		  (morecore ((blocks - lastblocks) * BLOCKSIZE)) != NULL)
		{
		  _heapinfo[block].free.size = blocks;
		  _bytes_free += (blocks - lastblocks) * BLOCKSIZE;
		  continue;
		}
	      result = morecore (blocks * BLOCKSIZE);
	      if (result == NULL)
		return NULL;
	      block = BLOCK (result);
	      _heapinfo[block].busy.type = 0;
	      _heapinfo[block].busy.info.size = blocks;
	      ++_chunks_used;
	      _bytes_used += blocks * BLOCKSIZE;
	      return result;
	    }
	}

      /* At this point we have found a suitable free list entry.
	 Figure out how to remove what we need from the list. */
      result = ADDRESS (block);
      if (_heapinfo[block].free.size > blocks)
	{
	  /* The block we found has a bit left over,
	     so relink the tail end back into the free list. */
	  _heapinfo[block + blocks].free.size
	    = _heapinfo[block].free.size - blocks;
	  _heapinfo[block + blocks].free.next
	    = _heapinfo[block].free.next;
	  _heapinfo[block + blocks].free.prev
	    = _heapinfo[block].free.prev;
	  _heapinfo[_heapinfo[block].free.prev].free.next
	    = _heapinfo[_heapinfo[block].free.next].free.prev
	    = _heapindex = block + blocks;
	}
      else
	{
	  /* The block exactly matches our requirements,
	     so just remove it from the list. */
	  _heapinfo[_heapinfo[block].free.next].free.prev
	    = _heapinfo[block].free.prev;
	  _heapinfo[_heapinfo[block].free.prev].free.next
	    = _heapindex = _heapinfo[block].free.next;
	  --_chunks_free;
	}

      _heapinfo[block].busy.type = 0;
      _heapinfo[block].busy.info.size = blocks;
      ++_chunks_used;
      _bytes_used += blocks * BLOCKSIZE;
      _bytes_free -= blocks * BLOCKSIZE;
    }

  return result;
}
/* Free a block of memory allocated by `malloc'.
   Copyright 1990, 1991, 1992 Free Software Foundation
		  Written May 1989 by Mike Haertel.

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Library General Public License for more details.

You should have received a copy of the GNU Library General Public
License along with this library; see the file COPYING.LIB.  If
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
Cambridge, MA 02139, USA.

   The author may be reached (Email) at the address mike@ai.mit.edu,
   or (US mail) as Mike Haertel c/o Free Software Foundation.  */

#ifndef	_MALLOC_INTERNAL
#define _MALLOC_INTERNAL
#include <malloc.h>
#endif

#ifdef VMS
/* How to really get more memory.  */
__ptr_t (*__lesscore) __P ((__ptr_t __ptr,ptrdiff_t __size)) = __vms_lesscore;
#else
/* How to really get more memory.  */
__ptr_t (*__lesscore) __P ((__ptr_t __ptr,ptrdiff_t __size)) = __default_lesscore;
#endif

/* Debugging hook for free.  */
#ifdef VMS
void (*__free_hook) __P ((__ptr_t __ptr)) = __vms_free;
#else
void (*__free_hook) __P ((__ptr_t __ptr));
#endif

/* List of blocks allocated by memalign.  */
struct alignlist *_aligned_blocks = NULL;

/* Return memory to the heap.
   Like `free' but don't call a __free_hook if there is one.  */
void
_free_internal (ptr)
     __ptr_t ptr;
{
  int type;
  size_t block, blocks;
  register size_t i;
  struct list *prev, *next;

  block = BLOCK (ptr);

  type = _heapinfo[block].busy.type;
  switch (type)
    {
    case 0:
      /* Get as many statistics as early as we can.  */
      --_chunks_used;
      _bytes_used -= _heapinfo[block].busy.info.size * BLOCKSIZE;
      _bytes_free += _heapinfo[block].busy.info.size * BLOCKSIZE;

      /* Find the free cluster previous to this one in the free list.
	 Start searching at the last block referenced; this may benefit
	 programs with locality of allocation.  */
      i = _heapindex;
      if (i > block)
	while (i > block)
	  i = _heapinfo[i].free.prev;
      else
	{
	  do
	    i = _heapinfo[i].free.next;
	  while (i > 0 && i < block);
	  i = _heapinfo[i].free.prev;
	}

      /* Determine how to link this block into the free list.  */
      if (block == i + _heapinfo[i].free.size)
	{
	  /* Coalesce this block with its predecessor.  */
	  _heapinfo[i].free.size += _heapinfo[block].busy.info.size;
	  block = i;
	}
      else
	{
	  /* Really link this block back into the free list.  */
	  _heapinfo[block].free.size = _heapinfo[block].busy.info.size;
	  _heapinfo[block].free.next = _heapinfo[i].free.next;
	  _heapinfo[block].free.prev = i;
	  _heapinfo[i].free.next = block;
	  _heapinfo[_heapinfo[block].free.next].free.prev = block;
	  ++_chunks_free;
	}

      /* Now that the block is linked in, see if we can coalesce it
	 with its successor (by deleting its successor from the list
	 and adding in its size).  */
      if (block + _heapinfo[block].free.size == _heapinfo[block].free.next)
	{
	  _heapinfo[block].free.size
	    += _heapinfo[_heapinfo[block].free.next].free.size;
	  _heapinfo[block].free.next
	    = _heapinfo[_heapinfo[block].free.next].free.next;
	  _heapinfo[_heapinfo[block].free.next].free.prev = block;
	  --_chunks_free;
	}

      /* Now see if we can return stuff to the system.  */
      blocks = _heapinfo[block].free.size;
      if (blocks >= FINAL_FREE_BLOCKS && block + blocks == _heaplimit
	  && (*__morecore) (0) == ADDRESS (block + blocks))
	{
	  register size_t bytes = blocks * BLOCKSIZE;
	  _heaplimit -= blocks;
	  (*__lesscore) (ADDRESS(block), bytes);
	  _heapinfo[_heapinfo[block].free.prev].free.next
	    = _heapinfo[block].free.next;
	  _heapinfo[_heapinfo[block].free.next].free.prev
	    = _heapinfo[block].free.prev;
	  block = _heapinfo[block].free.prev;
	  --_chunks_free;
	  _bytes_free -= bytes;
	}

      /* Set the next search to begin at this block.  */
      _heapindex = block;
      break;

    default:
      /* Do some of the statistics.  */
      --_chunks_used;
      _bytes_used -= 1 << type;
      ++_chunks_free;
      _bytes_free += 1 << type;

      /* Get the address of the first free fragment in this block.  */
      prev = (struct list *) ((char *) ADDRESS (block) +
			   (_heapinfo[block].busy.info.frag.first << type));
#ifdef RL_DEBUG
      printf("_free_internal(0%o/0x%x/%d) :\n", ptr, ptr, ptr);
      printf("  block = %d, type = %d, prev = 0%o/0x%x/%d\n",
	     block, type, prev, prev, prev);
      printf("  _heapinfo[block=%d].busy.info.frag.nfree = %d\n",
	     block,
	     _heapinfo[block].busy.info.frag.nfree);
#endif

      if (_heapinfo[block].busy.info.frag.nfree == (BLOCKSIZE >> type) - 1)
	{
	  /* If all fragments of this block are free, remove them
	     from the fragment list and free the whole block.  */
	  next = prev;
	  for (i = 1; i < (size_t) (BLOCKSIZE >> type); ++i)
	    next = next->next;
	  prev->prev->next = next;
	  if (next != NULL)
	    next->prev = prev->prev;
	  _heapinfo[block].busy.type = 0;
	  _heapinfo[block].busy.info.size = 1;

	  /* Keep the statistics accurate.  */
	  ++_chunks_used;
	  _bytes_used += BLOCKSIZE;
	  _chunks_free -= BLOCKSIZE >> type;
	  _bytes_free -= BLOCKSIZE;

	  free (ADDRESS (block));
	}
      else if (_heapinfo[block].busy.info.frag.nfree != 0)
	{
	  /* If some fragments of this block are free, link this
	     fragment into the fragment list after the first free
	     fragment of this block. */
#ifdef RL_DEBUG
	  printf("There's a bug hiding here (%s:%d), so I will print some values\n", __FILE__, __LINE__);
#endif
	  next = (struct list *) ptr;
#ifdef RL_DEBUG
	  printf("    (struct list *)next (0%o / 0x%x / %d) ->\n", next, next, next);
	  printf("          next = 0%o / 0x%x / %d\n", next->next,next->next,next->next);
	  printf("          prev = 0%o / 0x%x / %d\n", next->prev,next->prev,next->prev);
	  printf("    (struct list *)prev (0%o / 0x%x / %d)->\n", prev, prev, prev);
	  printf("          next = 0%o / 0x%x / %d\n", prev->next,prev->next,prev->next);
	  printf("          prev = 0%o / 0x%x / %d\n", prev->prev,prev->prev,prev->prev);
#endif
	  next->next = prev->next;
	  next->prev = prev;
	  prev->next = next;
	  if (next->next != NULL)
	    next->next->prev = next;
	  ++_heapinfo[block].busy.info.frag.nfree;
	}
      else
	{
	  /* No fragments of this block are free, so link this
	     fragment into the fragment list and announce that
	     it is the first free fragment of this block. */
	  prev = (struct list *) ptr;
	  _heapinfo[block].busy.info.frag.nfree = 1;
	  _heapinfo[block].busy.info.frag.first = (unsigned long int)
	    ((unsigned long int) ((char *) ptr - (char *) NULL)
	     % BLOCKSIZE >> type);
	  prev->next = _fraghead[type].next;
	  prev->prev = &_fraghead[type];
	  prev->prev->next = prev;
	  if (prev->next != NULL)
	    prev->next->prev = prev;
	}
      break;
    }
}

/* Return memory to the heap.  */
void
free (ptr)
     __ptr_t ptr;
{
  register struct alignlist *l;

  if (ptr == NULL)
    return;

  for (l = _aligned_blocks; l != NULL; l = l->next)
    if (l->aligned == ptr)
      {
	l->aligned = NULL;	/* Mark the slot in the list as free.  */
	ptr = l->exact;
	break;
      }

  if (__free_hook != NULL)
    (*__free_hook) (ptr);
  else
    _free_internal (ptr);
}
/* Change the size of a block allocated by `malloc'.
   Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
		     Written May 1989 by Mike Haertel.

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Library General Public License for more details.

You should have received a copy of the GNU Library General Public
License along with this library; see the file COPYING.LIB.  If
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
Cambridge, MA 02139, USA.

   The author may be reached (Email) at the address mike@ai.mit.edu,
   or (US mail) as Mike Haertel c/o Free Software Foundation.  */

#ifndef	_MALLOC_INTERNAL
#define _MALLOC_INTERNAL
#include <malloc.h>
#endif

#define min(A, B) ((A) < (B) ? (A) : (B))

/* Debugging hook for realloc.  */
#ifdef VMS
__ptr_t (*__realloc_hook) __P ((__ptr_t __ptr, size_t __size)) = __vms_realloc;
#else
__ptr_t (*__realloc_hook) __P ((__ptr_t __ptr, size_t __size));
#endif

/* Resize the given region to the new size, returning a pointer
   to the (possibly moved) region.  This is optimized for speed;
   some benchmarks seem to indicate that greater compactness is
   achieved by unconditionally allocating and copying to a
   new region.  This module has incestuous knowledge of the
   internals of both free and malloc. */
__ptr_t
realloc (ptr, size)
     __ptr_t ptr;
     size_t size;
{
  __ptr_t result;
  int type;
  size_t block, blocks, oldlimit;

  if (size == 0)
    {
      free (ptr);
      return malloc (0);
    }
  else if (ptr == NULL)
    return malloc (size);

  if (__realloc_hook != NULL)
    return (*__realloc_hook) (ptr, size);

  block = BLOCK (ptr);

  type = _heapinfo[block].busy.type;
  switch (type)
    {
    case 0:
      /* Maybe reallocate a large block to a small fragment.  */
      if (size <= BLOCKSIZE / 2)
	{
	  result = malloc (size);
	  if (result != NULL)
	    {
	      memcpy (result, ptr, size);
	      free (ptr);
	      return result;
	    }
	}

      /* The new size is a large allocation as well;
	 see if we can hold it in place. */
      blocks = BLOCKIFY (size);
      if (blocks < _heapinfo[block].busy.info.size)
	{
	  /* The new size is smaller; return
	     excess memory to the free list. */
	  _heapinfo[block + blocks].busy.type = 0;
	  _heapinfo[block + blocks].busy.info.size
	    = _heapinfo[block].busy.info.size - blocks;
	  _heapinfo[block].busy.info.size = blocks;
	  free (ADDRESS (block + blocks));
	  result = ptr;
	}
      else if (blocks == _heapinfo[block].busy.info.size)
	/* No size change necessary.  */
	result = ptr;
      else
	{
	  /* Won't fit, so allocate a new region that will.
	     Free the old region first in case there is sufficient
	     adjacent free space to grow without moving. */
	  blocks = _heapinfo[block].busy.info.size;
	  /* Prevent free from actually returning memory to the system.  */
	  oldlimit = _heaplimit;
	  _heaplimit = 0;
	  free (ptr);
	  _heaplimit = oldlimit;
	  result = malloc (size);
	  if (result == NULL)
	    {
	      /* Now we're really in trouble.  We have to unfree
		 the thing we just freed.  Unfortunately it might
		 have been coalesced with its neighbors.  */
	      if (_heapindex == block)
	        (void) malloc (blocks * BLOCKSIZE);
	      else
		{
		  __ptr_t previous = malloc ((block - _heapindex) * BLOCKSIZE);
		  (void) malloc (blocks * BLOCKSIZE);
		  free (previous);
		}
	      return NULL;
	    }
	  if (ptr != result)
	    memmove (result, ptr, blocks * BLOCKSIZE);
	}
      break;

    default:
      /* Old size is a fragment; type is logarithm
	 to base two of the fragment size.  */
      if (size > (size_t) (1 << (type - 1)) && size <= (size_t) (1 << type))
	/* The new size is the same kind of fragment.  */
	result = ptr;
      else
	{
	  /* The new size is different; allocate a new space,
	     and copy the lesser of the new size and the old. */
	  result = malloc (size);
	  if (result == NULL)
	    return NULL;
	  memcpy (result, ptr, min (size, (size_t) 1 << type));
	  free (ptr);
	}
      break;
    }

  return result;
}
/* Copyright (C) 1991, 1992 Free Software Foundation, Inc.

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Library General Public License for more details.

You should have received a copy of the GNU Library General Public
License along with this library; see the file COPYING.LIB.  If
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
Cambridge, MA 02139, USA.

   The author may be reached (Email) at the address mike@ai.mit.edu,
   or (US mail) as Mike Haertel c/o Free Software Foundation.  */

#ifndef	_MALLOC_INTERNAL
#define	_MALLOC_INTERNAL
#include <malloc.h>
#endif

/* Allocate an array of NMEMB elements each SIZE bytes long.
   The entire array is initialized to zeros.  */
__ptr_t
calloc (nmemb, size)
     register size_t nmemb;
     register size_t size;
{
  register __ptr_t result = malloc (nmemb * size);

  if (result != NULL)
    (void) memset (result, 0, nmemb * size);

  return result;
}
/* Copyright (C) 1991, 1992 Free Software Foundation, Inc.
This file is part of the GNU C Library.

The GNU C Library is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.

The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with the GNU C Library; see the file COPYING.  If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */

#ifndef	_MALLOC_INTERNAL
#define	_MALLOC_INTERNAL
#include <malloc.h>
#endif

#ifndef	__GNU_LIBRARY__
#define	__sbrk	sbrk
#ifdef VMS
#define __brk brk
#endif
#endif

extern __ptr_t __sbrk __P ((int increment));

#ifndef NULL
#define NULL 0
#endif

#if defined(emacs) && defined(VMS)
/* Dumping of Emacs on VMS does not include the heap!
   So let's make a huge array from which initial data will be
   allocated.

   VMS_ALLOCATION_SIZE is the amount of memory we preallocate.
   We don't want it to be too large, because it only gives a larger
   dump file. The way to check how much is really used is to
   make VMS_ALLOCATION_SIZE very large, to link Emacs with the
   debugger, run Emacs, check how much was allocated. Then set
   VMS_ALLOCATION_SIZE to something suitable, recompile gmalloc,
   relink Emacs, and you should be off.

   N.B. This is experimental, but it worked quite fine on Emacs 18.
*/
#ifndef VMS_ALLOCATION_SIZE
#define VMS_ALLOCATION_SIZE (512*(512+128))
#endif

int vms_out_initial = 0;
char vms_initial_buffer[VMS_ALLOCATION_SIZE];
char *vms_current_brk = vms_initial_buffer;
char *vms_end_brk = &vms_initial_buffer[VMS_ALLOCATION_SIZE-1];

__ptr_t
__vms_initial_morecore (increment)
     ptrdiff_t increment;
{
  __ptr_t result = NULL;
  __ptr_t temp;

  /* It's far easier to make the alignment here than to make a
     kludge in align () */
#ifdef RL_DEBUG
  printf(">>>foo... %p...", vms_current_brk);
#endif
  vms_current_brk += (BLOCKSIZE - ((unsigned long) vms_current_brk
				       & (BLOCKSIZE - 1))) & (BLOCKSIZE - 1);
#ifdef RL_DEBUG
  printf("bar... %p. (%d)\n", vms_current_brk, increment);
#endif
  temp = vms_current_brk + (int) increment;
  if (temp <= vms_end_brk)
    {
      if (increment >= 0)
	result = vms_current_brk;
      else
	result = temp;
      vms_current_brk = temp;
    }
  return result;
}

__ptr_t
__vms_initial_lesscore (ptr, size)
     __ptr_t ptr;
     ptrdiff_t size;
{
  if (ptr >= vms_initial_buffer
      && ptr < vms_initial_buffer+VMS_ALLOCATION_SIZE)
    {
      vms_current_brk = ptr;
      return vms_current_brk;
    }
  return vms_current_brk;
}

VMS_present_buffer()
{
  printf("Vms initial buffer starts at 0%o/0x%x/%d and ends at 0%o/0x%x/%d\n",
	 vms_initial_buffer, vms_initial_buffer, vms_initial_buffer, 
	 vms_end_brk, vms_end_brk, vms_end_brk);
}
#endif /* defined(emacs) && defined(VMS) */

#ifdef VMS
/* Unfortunately, the VAX C sbrk() is buggy. For example, it returns
   memory in 512 byte chunks (not a bug, but there's more), AND it
   adds an extra 512 byte chunk if you ask for a multiple of 512
   bytes (you ask for 512 bytes, you get 1024 bytes...). And also,
   the VAX C sbrk does not handle negative increments...
   There's a similar problem with brk(). Even if you set the break
   to an even page boundary, it gives you one extra page... */

static char vms_brk_info_fetched = -1; /* -1 if this is the first time, otherwise
					  bit 0 set if 'increment' needs adjustment
					  bit 1 set if the value to brk() needs adjustment */
static char *vms_brk_start = 0;
static char *vms_brk_end = 0;
static char *vms_brk_current = 0;
#endif

/* Allocate INCREMENT more bytes of data space,
   and return the start of data space, or NULL on errors.
   If INCREMENT is negative, shrink data space.  */
__ptr_t
__default_morecore (increment)
     ptrdiff_t increment;
{
  __ptr_t result;
#ifdef VMS
  __ptr_t temp;

#ifdef RL_DEBUG
  printf("DEBUG:  morecore: increment = %x\n", increment);
  printf("        @ start:  vms_brk_info_fetched = %x\n", vms_brk_info_fetched);
  printf("                  vms_brk_start   = %p\n", vms_brk_start);
  printf("                  vms_brk_current = %p\n", vms_brk_current);
  printf("                  vms_brk_end     = %p\n", vms_brk_end);
  printf("        @ end:    ");
#endif

  if (vms_brk_info_fetched < 0)
    {
      vms_brk_current = vms_brk_start = __sbrk (512);
      vms_brk_end = __sbrk (0);
      if (vms_brk_end - vms_brk_current == 1024)
	vms_brk_info_fetched = 1;
      else
	vms_brk_info_fetched = 0;
      vms_brk_end = brk(vms_brk_start);
      if (vms_brk_end != vms_brk_start)
	vms_brk_info_fetched |= 2;
#ifdef RL_DEBUG
      printf("vms_brk_info_fetched = %x\n", vms_brk_info_fetched);
      printf("                  vms_brk_start   = %p\n", vms_brk_start);
      printf("                  vms_brk_current = %p\n", vms_brk_current);
      printf("                  vms_brk_end     = %p\n", vms_brk_end);
      printf("                  ");
#endif
    }

  if (increment < 0)
    {
      printf("BZZZZZT! ERROR: __default_morecore does NOT take negative args\n");
      return NULL;
    }

  if (increment > 0)
    {
      result = vms_brk_current;
      temp = vms_brk_current + increment;

      if (temp > vms_brk_end)
	{
	  __ptr_t foo;

	  foo = __sbrk (0);
	  if (foo == vms_brk_end)
	    {
	      increment = temp - vms_brk_end;
	      if (increment > (vms_brk_info_fetched & 1))
		increment -=  (vms_brk_info_fetched & 1);
	      foo = __sbrk(increment);
#ifdef RL_DEBUG
	      printf("__sbrk(%d) --> %p\n", increment, foo);
#endif
	      if (foo == (__ptr_t) -1)
		return NULL;
#ifdef RL_DEBUG
	      printf("                  ");
#endif
	    }
	  else
	    {
	      result = __sbrk (increment);

	      if (result == (__ptr_t) -1)
		return NULL;

	      temp = result + increment;
	    }

	  vms_brk_end = __sbrk(0);
	}
      vms_brk_current = temp;
#ifdef RL_DEBUG
      printf("vms_brk_current = %p\n", vms_brk_current);
      printf("                  vms_brk_end     = %p\n", vms_brk_end);
#endif
      return result;
    }
#ifdef RL_DEBUG
  printf(" nothing more...\n");
#endif

  /* OK, so the user wanted to check where the heap limit is. Let's
     see if the system thinks it is where we think it is. */
  temp = __sbrk (0);
  if (temp != vms_brk_end)
    {
      /* the value has changed.
	 Let's trust the system and modify our value */
      vms_brk_current = vms_brk_end = temp;
    }
  return vms_brk_current;

#else /* not VMS */
  result = __sbrk ((int) increment);
  if (result == (__ptr_t) -1)
    return NULL;
  return result;
#endif /* VMS */
}

__ptr_t
__default_lesscore (ptr, size)
     __ptr_t ptr;
     ptrdiff_t size;
{
#ifdef VMS
  if (vms_brk_end != 0)
    {
      vms_brk_current = ptr;
      if (vms_brk_current < vms_brk_start)
	vms_brk_current = vms_brk_start;
      vms_brk_end = (char *) vms_brk_current -
	((vms_brk_info_fetched >> 1) & 1);
#ifdef RL_DEBUG
      printf("<<<bar... %p (%p (%p, %d))...",
	     vms_brk_end, vms_brk_current, ptr, size);
#endif
      vms_brk_end = __brk (vms_brk_end);
#ifdef RL_DEBUG
      printf("foo... %p.\n", vms_brk_end);
#endif
    }

  return vms_brk_current;
#else /* not VMS */
  __default_morecore (-size);
#endif
}

/* Allocate memory on a page boundary.
   Copyright (C) 1991, 1992 Free Software Foundation, Inc.

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Library General Public License for more details.

You should have received a copy of the GNU Library General Public
License along with this library; see the file COPYING.LIB.  If
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
Cambridge, MA 02139, USA.

   The author may be reached (Email) at the address mike@ai.mit.edu,
   or (US mail) as Mike Haertel c/o Free Software Foundation.  */

#ifndef	_MALLOC_INTERNAL
#define	_MALLOC_INTERNAL
#include <malloc.h>
#endif

#if defined (emacs) || defined (HAVE_CONFIG_H)
#include "config.h"
#endif

#ifdef	__GNU_LIBRARY__
extern size_t __getpagesize __P ((void));
#else
#if !defined(USG) && !defined(VMS)
extern size_t getpagesize __P ((void));
#define	__getpagesize()	getpagesize()
#else
#include <sys/param.h>
#ifdef	EXEC_PAGESIZE
#define	__getpagesize()	EXEC_PAGESIZE
#else /* No EXEC_PAGESIZE.  */
#ifdef	NBPG
#ifndef	CLSIZE
#define	CLSIZE	1
#endif /* No CLSIZE.  */
#define	__getpagesize()	(NBPG * CLSIZE)
#else /* No NBPG.  */
#define	__getpagesize()	NBPC
#endif /* NBPG.  */
#endif /* EXEC_PAGESIZE.  */
#endif /* USG.  */
#endif

static size_t pagesize;

__ptr_t
valloc (size)
     size_t size;
{
  if (pagesize == 0)
    pagesize = __getpagesize ();

  return memalign (pagesize, size);
}
/* Copyright (C) 1991, 1992 Free Software Foundation, Inc.

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Library General Public License for more details.

You should have received a copy of the GNU Library General Public
License along with this library; see the file COPYING.LIB.  If
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
Cambridge, MA 02139, USA.  */

#ifndef	_MALLOC_INTERNAL
#define _MALLOC_INTERNAL
#include <malloc.h>
#endif

__ptr_t
memalign (alignment, size)
     size_t alignment;
     size_t size;
{
  __ptr_t result;
  unsigned long int adj;

  size = ((size + alignment - 1) / alignment) * alignment;

  result = malloc (size);
  if (result == NULL)
    return NULL;
  adj = (unsigned long int) ((unsigned long int) ((char *) result -
						(char *) NULL)) % alignment;
  if (adj != 0)
    {
      struct alignlist *l;
      for (l = _aligned_blocks; l != NULL; l = l->next)
	if (l->aligned == NULL)
	  /* This slot is free.  Use it.  */
	  break;
      if (l == NULL)
	{
	  l = (struct alignlist *) malloc (sizeof (struct alignlist));
	  if (l == NULL)
	    {
	      free (result);
	      return NULL;
	    }
	}
      l->exact = result;
      result = l->aligned = (char *) result + alignment - adj;
      l->next = _aligned_blocks;
      _aligned_blocks = l;
    }

  return result;
}

#ifdef VMS
struct vms_malloc_data
{
  int __malloc_initialized;
  char *_heapbase;
  malloc_info *_heapinfo;
  size_t heapsize;
  size_t _heapindex;
  size_t _heaplimit;
  size_t _chunks_used;
  size_t _bytes_used;
  size_t _chunks_free;
  size_t _bytes_free;
} ____vms_malloc_data[] =
{
  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
};

struct vms_core_routines
{
  __ptr_t (*__morecore) __P ((ptrdiff_t increment));
  __ptr_t (*__lesscore) __P ((__ptr_t address, ptrdiff_t increment));
} ____vms_core_routines[] =
{
  { __vms_initial_morecore, __vms_initial_lesscore },
  { __default_morecore, __default_lesscore },
  { 0, 0 }
};

static int current_vms_data = -1;
static int current_vms_core_routines = 0;

static void use_vms_core_routines (int i)
{
  current_vms_core_routines = i;
  current_vms_data = i;
}

static void use_vms_data (int i)
{
  use_vms_core_routines (i);
  __malloc_initialized = ____vms_malloc_data[i].__malloc_initialized;
  _heapbase = ____vms_malloc_data[i]._heapbase;
  _heapinfo = ____vms_malloc_data[i]._heapinfo;
  heapsize = ____vms_malloc_data[i].heapsize;
  _heapindex = ____vms_malloc_data[i]._heapindex;
  _heaplimit = ____vms_malloc_data[i]._heaplimit;
  _chunks_used = ____vms_malloc_data[i]._chunks_used;
  _bytes_used = ____vms_malloc_data[i]._bytes_used;
  _chunks_free = ____vms_malloc_data[i]._chunks_free;
  _bytes_free = ____vms_malloc_data[i]._bytes_free;
}
  
static void store_vms_data (int i)
{
  ____vms_malloc_data[i].__malloc_initialized = __malloc_initialized;
  ____vms_malloc_data[i]._heapbase = _heapbase;
  ____vms_malloc_data[i]._heapinfo = _heapinfo;
  ____vms_malloc_data[i].heapsize = heapsize;
  ____vms_malloc_data[i]._heapindex = _heapindex;
  ____vms_malloc_data[i]._heaplimit = _heaplimit;
  ____vms_malloc_data[i]._chunks_used = _chunks_used;
  ____vms_malloc_data[i]._bytes_used = _bytes_used;
  ____vms_malloc_data[i]._chunks_free = _chunks_free;
  ____vms_malloc_data[i]._bytes_free = _bytes_free;
}

static void store_current_vms_data ()
{
  switch (current_vms_data)
    {
    case 0:
    case 1:
      store_vms_data (current_vms_data);
      break;
    }
}

__ptr_t __vms_morecore (increment)
     ptrdiff_t increment;
{
  return
    (*____vms_core_routines[current_vms_core_routines].__morecore) (increment);
}

__ptr_t __vms_lesscore (ptr, increment)
     __ptr_t ptr;
     ptrdiff_t increment;
{
  return
    (*____vms_core_routines[current_vms_core_routines].__lesscore) (ptr,increment);
}

__ptr_t __vms_malloc (size)
     size_t size;
{
  __ptr_t result;
  int old_current_vms_data = current_vms_data;

  __malloc_hook = 0;

  store_current_vms_data ();

  if (____vms_malloc_data[0]._heapbase != 0)
    use_vms_data (0);
  else
    use_vms_core_routines (0);
  result = malloc (size);
  store_vms_data (0);
  if (result == NULL)
    {
      use_vms_data (1);
      result = malloc (size);
      store_vms_data (1);
      vms_out_initial = 1;
    }
  __malloc_hook = __vms_malloc;
  if (old_current_vms_data != -1)
    use_vms_data (current_vms_data);
  return result;
}

void __vms_free (ptr)
     __ptr_t ptr;
{
  int old_current_vms_data = current_vms_data;

  __free_hook = 0;

  store_current_vms_data ();

  if (ptr >= vms_initial_buffer && ptr <= vms_end_brk)
    {
      use_vms_data (0);
      free (ptr);
      store_vms_data (0);
    }
  else
    {
      use_vms_data (1);
      free (ptr);
      store_vms_data (1);
      if (_chunks_free == 0 && _chunks_used == 0)
	vms_out_initial = 0;
    }
  __free_hook = __vms_free;
  if (old_current_vms_data != -1)
    use_vms_data (current_vms_data);
}

__ptr_t __vms_realloc (ptr, size)
     __ptr_t ptr;
     size_t size;
{
  __ptr_t result;
  int old_current_vms_data = current_vms_data;

  __realloc_hook = 0;

  store_current_vms_data ();

  if (ptr >= vms_initial_buffer && ptr <= vms_end_brk)
    {
      use_vms_data (0);
      result = realloc (ptr, size);
      store_vms_data (0);
    }
  else
    {
      use_vms_data (1);
      result = realloc (ptr, size);
      store_vms_data (1);
    }
  __realloc_hook = __vms_realloc;
  if (old_current_vms_data != -1)
    use_vms_data (current_vms_data);
  return result;
}  
#endif /* VMS */
/* Standard debugging hooks for `malloc'.
   Copyright 1990, 1991, 1992 Free Software Foundation
   Written May 1989 by Mike Haertel.

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Library General Public License for more details.

You should have received a copy of the GNU Library General Public
License along with this library; see the file COPYING.LIB.  If
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
Cambridge, MA 02139, USA.

   The author may be reached (Email) at the address mike@ai.mit.edu,
   or (US mail) as Mike Haertel c/o Free Software Foundation.  */

#ifndef	_MALLOC_INTERNAL
#define	_MALLOC_INTERNAL
#include <malloc.h>
#endif

/* Old hook values.  */
static void (*old_free_hook) __P ((__ptr_t ptr));
static __ptr_t (*old_malloc_hook) __P ((size_t size));
static __ptr_t (*old_realloc_hook) __P ((__ptr_t ptr, size_t size));

/* Function to call when something awful happens.  */
static void (*abortfunc) __P ((void));

/* Arbitrary magical numbers.  */
#define MAGICWORD	0xfedabeeb
#define MAGICBYTE	((char) 0xd7)

struct hdr
  {
    size_t size;		/* Exact size requested by user.  */
    unsigned long int magic;	/* Magic number to check header integrity.  */
  };

static void checkhdr __P ((__const struct hdr *));
static void
checkhdr (hdr)
     __const struct hdr *hdr;
{
  if (hdr->magic != MAGICWORD || ((char *) &hdr[1])[hdr->size] != MAGICBYTE)
    (*abortfunc) ();
}

static void freehook __P ((__ptr_t));
static void
freehook (ptr)
     __ptr_t ptr;
{
  struct hdr *hdr = ((struct hdr *) ptr) - 1;
  checkhdr (hdr);
  hdr->magic = 0;
  __free_hook = old_free_hook;
  free (hdr);
  __free_hook = freehook;
}

static __ptr_t mallochook __P ((size_t));
static __ptr_t
mallochook (size)
     size_t size;
{
  struct hdr *hdr;

  __malloc_hook = old_malloc_hook;
  hdr = (struct hdr *) malloc (sizeof (struct hdr) + size + 1);
  __malloc_hook = mallochook;
  if (hdr == NULL)
    return NULL;

  hdr->size = size;
  hdr->magic = MAGICWORD;
  ((char *) &hdr[1])[size] = MAGICBYTE;
  return (__ptr_t) (hdr + 1);
}

static __ptr_t reallochook __P ((__ptr_t, size_t));
static __ptr_t
reallochook (ptr, size)
     __ptr_t ptr;
     size_t size;
{
  struct hdr *hdr = ((struct hdr *) ptr) - 1;

  checkhdr (hdr);
  __free_hook = old_free_hook;
  __malloc_hook = old_malloc_hook;
  __realloc_hook = old_realloc_hook;
  hdr = (struct hdr *) realloc ((__ptr_t) hdr, sizeof (struct hdr) + size + 1);
  __free_hook = freehook;
  __malloc_hook = mallochook;
  __realloc_hook = reallochook;
  if (hdr == NULL)
    return NULL;

  hdr->size = size;
  ((char *) &hdr[1])[size] = MAGICBYTE;
  return (__ptr_t) (hdr + 1);
}

int
mcheck (func)
     void (*func) __P ((void));
{
  extern void abort __P ((void));
  static int mcheck_used = 0;

  abortfunc = (func != NULL) ? func : abort;

  /* These hooks may not be safely inserted if malloc is already in use.  */
  if (!__malloc_initialized && !mcheck_used)
    {
      old_free_hook = __free_hook;
      __free_hook = freehook;
      old_malloc_hook = __malloc_hook;
      __malloc_hook = mallochook;
      old_realloc_hook = __realloc_hook;
      __realloc_hook = reallochook;
      mcheck_used = 1;
    }

  return mcheck_used ? 0 : -1;
}
/* More debugging hooks for `malloc'.
   Copyright (C) 1991, 1992 Free Software Foundation, Inc.
		 Written April 2, 1991 by John Gilmore of Cygnus Support.
		 Based on mcheck.c by Mike Haertel.

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Library General Public License for more details.

You should have received a copy of the GNU Library General Public
License along with this library; see the file COPYING.LIB.  If
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
Cambridge, MA 02139, USA.

   The author may be reached (Email) at the address mike@ai.mit.edu,
   or (US mail) as Mike Haertel c/o Free Software Foundation.  */

#ifndef	_MALLOC_INTERNAL
#define	_MALLOC_INTERNAL
#include <malloc.h>
#endif

#include <stdio.h>

#ifndef	__GNU_LIBRARY__
extern char *getenv ();
#else
#include <stdlib.h>
#endif

static FILE *mallstream;
static char mallenv[]= "MALLOC_TRACE";
static char mallbuf[BUFSIZ];	/* Buffer for the output.  */

/* Address to breakpoint on accesses to... */
__ptr_t mallwatch;

/* Old hook values.  */
static __ptr_t (*tr_old_morecore) __P ((ptrdiff_t increment));
static __ptr_t (*tr_old_lesscore) __P ((__ptr_t ptr, ptrdiff_t increment));
static void (*tr_old_free_hook) __P ((__ptr_t ptr));
static __ptr_t (*tr_old_malloc_hook) __P ((size_t size));
static __ptr_t (*tr_old_realloc_hook) __P ((__ptr_t ptr, size_t size));

/* This function is called when the block being alloc'd, realloc'd, or
   freed has an address matching the variable "mallwatch".  In a debugger,
   set "mallwatch" to the address of interest, then put a breakpoint on
   tr_break.  */

void tr_break __P ((void));
void
tr_break ()
{
}

static void tr_freehook __P ((__ptr_t));
static void
tr_freehook (ptr)
     __ptr_t ptr;
{
  fprintf (mallstream, "- %p\n", ptr);	/* Be sure to print it first.  */
  if (ptr == mallwatch)
    tr_break ();
  __free_hook = tr_old_free_hook;
  free (ptr);
  __free_hook = tr_freehook;
}

static __ptr_t tr_morecore __P ((ptrdiff_t));
static __ptr_t
tr_morecore (increment)
     ptrdiff_t increment;
{
  __ptr_t p;

  __morecore = tr_old_morecore;
  p = (__ptr_t) (*__morecore) (increment);
  __morecore = tr_morecore;

  fprintf (mallstream, "$ %p %d\n", p, increment);

  return p;
}

static __ptr_t tr_lesscore __P ((__ptr_t, ptrdiff_t));
static __ptr_t
tr_lesscore (ptr, increment)
     __ptr_t ptr;
     ptrdiff_t increment;
{
  __ptr_t p;

  __lesscore = tr_old_lesscore;
  p = (__ptr_t) (*__lesscore) (ptr, increment);
  __lesscore = tr_lesscore;

  fprintf (mallstream, "* %p (%p, %d)\n", p, ptr, increment);

  return p;
}

static __ptr_t tr_mallochook __P ((size_t));
static __ptr_t
tr_mallochook (size)
     size_t size;
{
  __ptr_t hdr;

  __malloc_hook = tr_old_malloc_hook;
  hdr = (__ptr_t) malloc (size);
  __malloc_hook = tr_mallochook;

  /* We could be printing a NULL here; that's OK.  */
  fprintf (mallstream, "+ %p %x\n", hdr, size);

  if (hdr == mallwatch)
    tr_break ();

  return hdr;
}

static __ptr_t tr_reallochook __P ((__ptr_t, size_t));
static __ptr_t
tr_reallochook (ptr, size)
     __ptr_t ptr;
     size_t size;
{
  __ptr_t hdr;

  if (ptr == mallwatch)
    tr_break ();

  __free_hook = tr_old_free_hook;
  __malloc_hook = tr_old_malloc_hook;
  __realloc_hook = tr_old_realloc_hook;
  hdr = (__ptr_t) realloc (ptr, size);
  __free_hook = tr_freehook;
  __malloc_hook = tr_mallochook;
  __realloc_hook = tr_reallochook;
  if (hdr == NULL)
    /* Failed realloc.  */
    fprintf (mallstream, "! %p %x\n", ptr, size);
  else
    fprintf (mallstream, "< %p\n> %p %x\n", ptr, hdr, size);

  if (hdr == mallwatch)
    tr_break ();

  return hdr;
}

/* We enable tracing if either the environment variable MALLOC_TRACE
   is set, or if the variable mallwatch has been patched to an address
   that the debugging user wants us to stop on.  When patching mallwatch,
   don't forget to set a breakpoint on tr_break!  */

void
mtrace ()
{
  char *mallfile;

  mallfile = getenv (mallenv);
  if (mallfile != NULL || mallwatch != NULL)
    {
      mallstream = fopen (mallfile != NULL ? mallfile : "/dev/null", "w");
      if (mallstream != NULL)
	{
	  /* Be sure it doesn't malloc its buffer!  */
	  setbuf (mallstream, mallbuf);
	  fprintf (mallstream, "= Start\n");
#if defined(emacs) && defined(VMS)
	  fprintf (mallstream, "= Initial buffer spans %p -- %p\n",
		   vms_initial_buffer, vms_end_brk + 1);
#endif
	  tr_old_morecore = __morecore;
	  __morecore = tr_morecore;
	  tr_old_lesscore = __lesscore;
	  __lesscore = tr_lesscore;
	  tr_old_free_hook = __free_hook;
	  __free_hook = tr_freehook;
	  tr_old_malloc_hook = __malloc_hook;
	  __malloc_hook = tr_mallochook;
	  tr_old_realloc_hook = __realloc_hook;
	  __realloc_hook = tr_reallochook;
	}
    }
}
/* Access the statistics maintained by `malloc'.
   Copyright 1990, 1991, 1992 Free Software Foundation
		  Written May 1989 by Mike Haertel.

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Library General Public License for more details.

You should have received a copy of the GNU Library General Public
License along with this library; see the file COPYING.LIB.  If
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
Cambridge, MA 02139, USA.

   The author may be reached (Email) at the address mike@ai.mit.edu,
   or (US mail) as Mike Haertel c/o Free Software Foundation.  */

#ifndef	_MALLOC_INTERNAL
#define _MALLOC_INTERNAL
#include <malloc.h>
#endif

struct mstats
mstats ()
{
  struct mstats result;

  result.bytes_total = (char *) (*__morecore) (0) - _heapbase;
  result.chunks_used = _chunks_used;
  result.bytes_used = _bytes_used;
  result.chunks_free = _chunks_free;
  result.bytes_free = _bytes_free;
  return result;
}