/*
* fhist - file history and comparison tools
* Copyright (C) 1991-1994, 1998, 2000-2002 Peter Miller;
* All rights reserved.
*
* Derived from a work
* Copyright (C) 1990 David I. Bell.
*
* This program 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 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
*
* MANIFEST: functions to isolate malloc
*
* Malloc interludes which allow for releasing of all used memory blocks.
* Just call cm_reset whenever you want to free all allocated memory.
* This is convenient when reinitializing a program which allocates memory.
*
* Note: You must make sure that old stale pointers are not referenced,
* such as static pointers which were 0 when the program started but
* won't be later. In other words, to be safe you should not assume any
* variables have been initialized, even for zero values.
*/
#include <ac/errno.h>
#include <ac/stdlib.h>
#include <ac/stddef.h>
#include <cmalloc.h>
#include <error.h>
#undef malloc
#undef realloc
#undef free
#undef calloc
#define MAGIC 54928347L
/*
* This is to protect DOS.
* On a 16-bit machine, this will be 65535,
* exactly right for small-memory-model doc programs.
*
* but on a 32-bit machine, like most unixes,
* this is essentially infinity.
*/
#define BIG ((unsigned int)-1)
typedef struct chunk CHUNK;
struct chunk
{
CHUNK *next; /* next chunk in chain */
CHUNK *prev; /* previous chunk in chain */
long magic; /* magic value */
double data[1]; /* data storage (varying size) */
};
#define CHUNKSIZE(size) (sizeof(CHUNK) + (size) - sizeof(double))
#define DPTOCP(dp) \
((CHUNK *)(void*)(((char *)(dp)) - offsetof(CHUNK, data[0])))
static CHUNK head = {&head, &head};
/*
* Actual calls to malloc, realloc, calloc, and free.
* Users must be sure not to intermix these calls with the ones above.
*/
void *
r_alloc(size_t size)
{
void *result;
if (size > BIG)
{
errno = EINVAL;
return 0;
}
errno = 0;
result = malloc((unsigned int) size);
if (!result && !errno)
errno = ENOMEM;
return result;
}
void *
r_realloc(void *dp, size_t size)
{
void *result;
if (size > BIG)
{
errno = EINVAL;
return 0;
}
errno = 0;
result = realloc(dp, (unsigned int) size);
if (!result && !errno)
errno = ENOMEM;
return result;
}
void *
r_realloc_and_check(void *a, size_t b)
{
void *result;
result = r_realloc(a, b);
if (!result)
nfatal_raw("realloc(%lu)", (unsigned long)b);
return result;
}
void
r_free(void *dp)
{
free(dp);
}
void *
r_alloc_and_check(size_t n)
{
void *result;
result = r_alloc(n);
if (!result)
nfatal_raw("malloc(%lu)", (unsigned long)n);
return result;
}
/*
* Allocate some memory.
*/
void *
cm_alloc(size_t size)
{
CHUNK *cp;
if (size > BIG)
{
errno = EINVAL;
return 0;
}
cp = (CHUNK *)r_alloc((size_t)CHUNKSIZE(size));
if (!cp)
return 0;
cp->magic = MAGIC;
cp->next = head.next;
cp->next->prev = cp;
cp->prev = &head;
head.next = cp;
return (void *)cp->data;
}
void *
cm_alloc_and_check(size_t n)
{
void *result;
result = cm_alloc(n);
if (!result)
nfatal_raw("malloc(%lu)", (unsigned long)n);
return result;
}
/*
* Reallocate memory.
*/
void *
cm_realloc(void *dp, size_t size)
{
CHUNK *cp;
if (!dp || size > BIG)
{
errno = EINVAL;
return 0;
}
cp = DPTOCP(dp);
if (cp->magic != MAGIC)
{
error_raw
(
"%s: %d: bad realloc %08lX (bug)",
__FILE__,
__LINE__,
(unsigned long)dp
);
errno = EINVAL;
return 0;
}
cp = (CHUNK *)r_realloc(cp, (size_t)CHUNKSIZE(size));
if (!cp)
return 0;
cp->next->prev = cp;
cp->prev->next = cp;
return (void *)cp->data;
}
void *
cm_realloc_and_check(void *a, size_t b)
{
void *result;
result = cm_realloc(a, b);
if (!result)
nfatal_raw("malloc(%lu)", (unsigned long)b);
return result;
}
/*
* Allocate zeroed memory.
*/
void *
cm_calloc(size_t nelem, size_t elsize)
{
size_t totalsize;
CHUNK *cp;
if (nelem > BIG || elsize > BIG)
{
errno = EINVAL;
return 0;
}
totalsize = CHUNKSIZE(nelem * elsize);
if (totalsize > BIG)
{
errno = EINVAL;
return 0;
}
cp = (CHUNK *)r_alloc(totalsize);
if (!cp)
return 0;
cp->magic = MAGIC;
cp->next = head.next;
cp->next->prev = cp;
cp->prev = &head;
head.next = cp;
return (void *)cp->data;
}
void *
cm_calloc_and_check(size_t a, size_t b)
{
void *result;
result = cm_calloc(a, b);
if (!result)
nfatal_raw("malloc(%lu)", (unsigned long)b);
return result;
}
/*
* Free memory.
*/
void
cm_free(void *dp)
{
CHUNK *cp;
if (!dp)
return;
cp = DPTOCP(dp);
if (cp->magic != MAGIC)
{
error_raw
(
"%s: %d: bad free %08lX (bug)",
__FILE__,
__LINE__,
(unsigned long)dp
);
return;
}
cp->prev->next = cp->next;
cp->next->prev = cp->prev;
cp->next = 0;
cp->prev = 0;
cp->magic = 0;
r_free(cp);
}
/*
* Reset the whole memory arena.
* This frees all memory allocated since the last cm_reset call.
*/
void
cm_reset(void)
{
CHUNK *cp;
while (head.next != &head)
{
cp = head.next;
if (cp->magic != MAGIC)
{
error_raw
(
"%s: %d: bad cm_reset %08lX (bug)",
__FILE__,
__LINE__,
(unsigned long)cp
);
break;
}
head.next = cp->next;
cp->next = 0;
cp->prev = 0;
cp->magic = 0;
r_free(cp);
}
head.next = &head;
head.prev = &head;
}
syntax highlighted by Code2HTML, v. 0.9.1