tmuck2.4/
tmuck2.4/admin/scripts/
tmuck2.4/docs/
tmuck2.4/minimal-db/
tmuck2.4/minimal-db/data/
tmuck2.4/minimal-db/logs/
tmuck2.4/minimal-db/muf/
tmuck2.4/old/
tmuck2.4/src/
tmuck2.4/src/compile/
tmuck2.4/src/editor/
tmuck2.4/src/game/
tmuck2.4/src/interface/
tmuck2.4/src/scripts/
tmuck2.4/src/utilprogs/
/* Copyright (c) 1992 by David Moore.  All rights reserved. */
/* muck_malloc.c,v 2.8 1996/01/25 20:37:44 dmoore Exp */
#include "config.h"

#include <stdlib.h>
#include <string.h>

#include "db.h"
#include "externs.h"

#define MAX_HUNK_SIZE 64 /* Must be a multiple of hunk_node size. */

#ifdef DEBUG_MALLOCS
#include "debug_malloc.h"
#define malloc(x)	debug_malloc(x, file, line)
#define free(x)		debug_free(x, file, line)
#define realloc(x, y)	debug_realloc(x, y, file, line)
#endif


/* For strings, we'll allocate them in larger hunks of memory and then
   cut those up and hand them out.  This saves on malloc overhead. */
/* We make the assumption here that &(node.data) == &(node.next). */
/* Luckily ansi seems to say this. :) */
union hunk_node {
    union hunk_node *next;
    char align_force[ALIGN_BYTES];
    char data[1];
};

static int initialized = 0;
static union hunk_node *free_list[MAX_HUNK_SIZE + 1];


void *muck_realloc(void *cp, size_t size, const char *file, const int line)
{
    void *result;

    result = realloc(cp, size);

    if (!result) panic("Out of memory.");

    return result;
}


void *muck_malloc(size_t size, const char *file, const int line)
{
    void *result;

    result = malloc(size);

    if (!result) panic("Out of memory.");

    return result;
}
    

void muck_free(void *cp, const char *file, const int line)
{
    free(cp);
}


/* Make lenth a multiple of the needed alignment. */
#define AlignLen(l) \
   (((l) % sizeof(union hunk_node)) ? \
	(l) + sizeof(union hunk_node) - ((l) % sizeof(union hunk_node)) : \
	(l))


static void init_alloc_strings(void)
{
    int i;

    for (i = 0; i < MAX_HUNK_SIZE+1; i++)
	free_list[i] = NULL;

    initialized = 1;
}


static void generate_strings(const int len, const char *file, const int line)
{
    union hunk_node *hunk;
    int num_4k;
    int i;

    /* Try allocating them in 4K sets.  The -4 is for some mallocs
       which want to stick some overhead in the space.  This keeps
       things on a single page (hopefully). */
    num_4k = (4096 - ALIGN_BYTES) / len;

    hunk = malloc(4906 - ALIGN_BYTES);
    for (i = 0; i < num_4k; i++) {
	hunk->next = free_list[len];
	free_list[len] = hunk;
	hunk = (union hunk_node *) (len + (char *) hunk);
    }

    /* If len wasn't of a size to fit perfectly, stick extra space
       onto a smaller list. */
    i = (4096 - ALIGN_BYTES) - (num_4k * len);
    if (AlignLen(i) != i)
	i = AlignLen(i) - sizeof(union hunk_node);
    if (i > 0) {
	hunk->next = free_list[i];
	free_list[i] = hunk;
    }
}


static char *alloc_string(unsigned int len, const char *file, const int line)
{
    union hunk_node *head;

#ifdef FIX_FIX_FIX_DEBUG_MALLOCS
    return (char *) debug_malloc(len + 1, file, line);
#else
    len = len + 1;			/* for null byte */
    /* Decide to allocate a hunk or just malloc directly based on size. */
    if (len <= MAX_HUNK_SIZE) {
	if (!initialized) init_alloc_strings();

	len = AlignLen(len);

	if (!free_list[len]) generate_strings(len, file, line);

	head = free_list[len];
	free_list[len] = head->next;

	return (char *) head;
    } else {
	return (char *) malloc(len);
    }
#endif /* DEBUG_MALLOCS */
}


void muck_free_cnt_string(const char *s, unsigned int len, const char *file, const int line)
{
    union hunk_node *head;

#ifdef FIX_FIX_FIX_DEBUG_MALLOCS
    debug_free((char *) s, file, line);
#else
    len = len + 1;			/* null byte */
    if (len <= MAX_HUNK_SIZE) {
	len = AlignLen(len);

	head = (union hunk_node *) ((char *) s);
	head->next = free_list[len];
	free_list[len] = head;
    } else {
	free((char *) s);
    }
#endif /* DEBUG_MALLOCS */
}


void muck_free_string(const char *s, const char *file, const int line)
{
    muck_free_cnt_string(s, strlen(s), file, line);
}


const char *muck_alloc_cnt_string(const char *s, const unsigned int len, const char *file, const int line)
{
    char *result;

    if (s == NULL || *s == '\0' || len == 0) return NULL;

    result = (char *) alloc_string(len, file, line);
    strncpy(result, s, len + 1);

    return (const char *) result;
}


const char *muck_alloc_cnt2_string(const char *s1, const unsigned int len1, const char *s2, const unsigned int len2, const char *file, const int line)
{
    char *result;

    if ((s1 == NULL || s1 == '\0') && (s2 == NULL || s2 == '\0'))
	return NULL;

    if ((len1 + len2) == 0) return NULL;

    result = (char *) alloc_string(len1 + len2, file, line);
    strncpy(result, s1, len1 + 1);
    strncpy(result+len1, s2, len2 + 1);

    return (const char *) result;
}


const char *muck_alloc_string(const char *s, const char *file, const int line)
{
    if (s == NULL || *s == '\0') return NULL;

    return muck_alloc_cnt_string(s, strlen(s), file, line);
}