ds2.10/bin/
ds2.10/extra/
ds2.10/extra/crat/
ds2.10/extra/creremote/
ds2.10/extra/mingw/
ds2.10/extra/wolfpaw/
ds2.10/fluffos-2.16-ds05/
ds2.10/fluffos-2.16-ds05/Win32/
ds2.10/fluffos-2.16-ds05/compat/
ds2.10/fluffos-2.16-ds05/compat/simuls/
ds2.10/fluffos-2.16-ds05/include/
ds2.10/fluffos-2.16-ds05/testsuite/
ds2.10/fluffos-2.16-ds05/testsuite/clone/
ds2.10/fluffos-2.16-ds05/testsuite/command/
ds2.10/fluffos-2.16-ds05/testsuite/data/
ds2.10/fluffos-2.16-ds05/testsuite/etc/
ds2.10/fluffos-2.16-ds05/testsuite/include/
ds2.10/fluffos-2.16-ds05/testsuite/inherit/
ds2.10/fluffos-2.16-ds05/testsuite/inherit/master/
ds2.10/fluffos-2.16-ds05/testsuite/log/
ds2.10/fluffos-2.16-ds05/testsuite/single/
ds2.10/fluffos-2.16-ds05/testsuite/single/tests/compiler/
ds2.10/fluffos-2.16-ds05/testsuite/single/tests/efuns/
ds2.10/fluffos-2.16-ds05/testsuite/single/tests/operators/
ds2.10/fluffos-2.16-ds05/testsuite/u/
ds2.10/lib/cmds/admins/
ds2.10/lib/cmds/common/
ds2.10/lib/cmds/creators/include/
ds2.10/lib/daemon/services/
ds2.10/lib/daemon/tmp/
ds2.10/lib/doc/
ds2.10/lib/doc/bguide/
ds2.10/lib/doc/efun/all/
ds2.10/lib/doc/efun/arrays/
ds2.10/lib/doc/efun/buffers/
ds2.10/lib/doc/efun/compile/
ds2.10/lib/doc/efun/floats/
ds2.10/lib/doc/efun/functions/
ds2.10/lib/doc/efun/general/
ds2.10/lib/doc/efun/mixed/
ds2.10/lib/doc/efun/numbers/
ds2.10/lib/doc/efun/parsing/
ds2.10/lib/doc/help/classes/
ds2.10/lib/doc/help/races/
ds2.10/lib/doc/lfun/
ds2.10/lib/doc/lfun/all/
ds2.10/lib/doc/lfun/lib/abilities/
ds2.10/lib/doc/lfun/lib/armor/
ds2.10/lib/doc/lfun/lib/bank/
ds2.10/lib/doc/lfun/lib/bot/
ds2.10/lib/doc/lfun/lib/clay/
ds2.10/lib/doc/lfun/lib/clean/
ds2.10/lib/doc/lfun/lib/clerk/
ds2.10/lib/doc/lfun/lib/client/
ds2.10/lib/doc/lfun/lib/combat/
ds2.10/lib/doc/lfun/lib/connect/
ds2.10/lib/doc/lfun/lib/container/
ds2.10/lib/doc/lfun/lib/corpse/
ds2.10/lib/doc/lfun/lib/creator/
ds2.10/lib/doc/lfun/lib/daemon/
ds2.10/lib/doc/lfun/lib/damage/
ds2.10/lib/doc/lfun/lib/deterioration/
ds2.10/lib/doc/lfun/lib/donate/
ds2.10/lib/doc/lfun/lib/door/
ds2.10/lib/doc/lfun/lib/equip/
ds2.10/lib/doc/lfun/lib/file/
ds2.10/lib/doc/lfun/lib/fish/
ds2.10/lib/doc/lfun/lib/fishing/
ds2.10/lib/doc/lfun/lib/flashlight/
ds2.10/lib/doc/lfun/lib/follow/
ds2.10/lib/doc/lfun/lib/ftp_client/
ds2.10/lib/doc/lfun/lib/ftp_data_connection/
ds2.10/lib/doc/lfun/lib/fuel/
ds2.10/lib/doc/lfun/lib/furnace/
ds2.10/lib/doc/lfun/lib/genetics/
ds2.10/lib/doc/lfun/lib/holder/
ds2.10/lib/doc/lfun/lib/id/
ds2.10/lib/doc/lfun/lib/interactive/
ds2.10/lib/doc/lfun/lib/lamp/
ds2.10/lib/doc/lfun/lib/leader/
ds2.10/lib/doc/lfun/lib/light/
ds2.10/lib/doc/lfun/lib/limb/
ds2.10/lib/doc/lfun/lib/living/
ds2.10/lib/doc/lfun/lib/load/
ds2.10/lib/doc/lfun/lib/look/
ds2.10/lib/doc/lfun/lib/manipulate/
ds2.10/lib/doc/lfun/lib/meal/
ds2.10/lib/doc/lfun/lib/messages/
ds2.10/lib/doc/lfun/lib/player/
ds2.10/lib/doc/lfun/lib/poison/
ds2.10/lib/doc/lfun/lib/position/
ds2.10/lib/doc/lfun/lib/post_office/
ds2.10/lib/doc/lfun/lib/potion/
ds2.10/lib/doc/lfun/lib/room/
ds2.10/lib/doc/lfun/lib/server/
ds2.10/lib/doc/lfun/lib/spell/
ds2.10/lib/doc/lfun/lib/torch/
ds2.10/lib/doc/lfun/lib/vendor/
ds2.10/lib/doc/lfun/lib/virt_sky/
ds2.10/lib/doc/lfun/lib/weapon/
ds2.10/lib/doc/lfun/lib/worn_storage/
ds2.10/lib/doc/lpc/constructs/
ds2.10/lib/doc/lpc/etc/
ds2.10/lib/doc/lpc/intermediate/
ds2.10/lib/doc/lpc/types/
ds2.10/lib/doc/misc/
ds2.10/lib/doc/old/
ds2.10/lib/doc/phints/
ds2.10/lib/domains/
ds2.10/lib/domains/Praxis/adm/
ds2.10/lib/domains/Praxis/attic/
ds2.10/lib/domains/Praxis/cemetery/mon/
ds2.10/lib/domains/Praxis/data/
ds2.10/lib/domains/Praxis/death/
ds2.10/lib/domains/Praxis/mountains/
ds2.10/lib/domains/Praxis/obj/armour/
ds2.10/lib/domains/Praxis/obj/magic/
ds2.10/lib/domains/Praxis/obj/weapon/
ds2.10/lib/domains/Praxis/orc_valley/
ds2.10/lib/domains/Ylsrim/
ds2.10/lib/domains/Ylsrim/adm/
ds2.10/lib/domains/Ylsrim/armor/
ds2.10/lib/domains/Ylsrim/broken/
ds2.10/lib/domains/Ylsrim/fish/
ds2.10/lib/domains/Ylsrim/meal/
ds2.10/lib/domains/Ylsrim/npc/
ds2.10/lib/domains/Ylsrim/obj/
ds2.10/lib/domains/Ylsrim/virtual/
ds2.10/lib/domains/Ylsrim/weapon/
ds2.10/lib/domains/alpha/room/
ds2.10/lib/domains/alpha/virtual/
ds2.10/lib/domains/campus/adm/
ds2.10/lib/domains/campus/etc/
ds2.10/lib/domains/campus/meals/
ds2.10/lib/domains/campus/txt/ai/charles/
ds2.10/lib/domains/campus/txt/ai/charles/bak2/
ds2.10/lib/domains/campus/txt/ai/charles/bak2/bak1/
ds2.10/lib/domains/campus/txt/ai/charly/
ds2.10/lib/domains/campus/txt/ai/charly/bak/
ds2.10/lib/domains/campus/txt/jenny/
ds2.10/lib/domains/cave/doors/
ds2.10/lib/domains/cave/etc/
ds2.10/lib/domains/cave/meals/
ds2.10/lib/domains/cave/weap/
ds2.10/lib/domains/default/chamber/
ds2.10/lib/domains/default/creator/
ds2.10/lib/domains/default/doors/
ds2.10/lib/domains/default/etc/
ds2.10/lib/domains/default/vehicle/
ds2.10/lib/domains/default/virtual/
ds2.10/lib/domains/town/save/
ds2.10/lib/domains/town/txt/shame/
ds2.10/lib/domains/town/virtual/
ds2.10/lib/domains/town/virtual/bottom/
ds2.10/lib/domains/town/virtual/space/
ds2.10/lib/estates/
ds2.10/lib/ftp/
ds2.10/lib/lib/comp/
ds2.10/lib/lib/daemons/
ds2.10/lib/lib/daemons/include/
ds2.10/lib/lib/lvs/
ds2.10/lib/lib/user/
ds2.10/lib/lib/virtual/
ds2.10/lib/log/
ds2.10/lib/log/adm/
ds2.10/lib/log/archive/
ds2.10/lib/log/chan/
ds2.10/lib/log/errors/
ds2.10/lib/log/law/adm/
ds2.10/lib/log/law/email/
ds2.10/lib/log/law/names/
ds2.10/lib/log/law/sites-misc/
ds2.10/lib/log/law/sites-register/
ds2.10/lib/log/law/sites-tempban/
ds2.10/lib/log/law/sites-watch/
ds2.10/lib/log/open/
ds2.10/lib/log/reports/
ds2.10/lib/log/router/
ds2.10/lib/log/secure/
ds2.10/lib/log/watch/
ds2.10/lib/obj/book_source/
ds2.10/lib/obj/include/
ds2.10/lib/powers/prayers/
ds2.10/lib/powers/spells/
ds2.10/lib/realms/template/
ds2.10/lib/realms/template/adm/
ds2.10/lib/realms/template/area/
ds2.10/lib/realms/template/area/armor/
ds2.10/lib/realms/template/area/npc/
ds2.10/lib/realms/template/area/obj/
ds2.10/lib/realms/template/area/room/
ds2.10/lib/realms/template/area/weap/
ds2.10/lib/realms/template/bak/
ds2.10/lib/realms/template/cmds/
ds2.10/lib/save/kills/o/
ds2.10/lib/secure/cfg/classes/
ds2.10/lib/secure/cmds/builders/
ds2.10/lib/secure/cmds/creators/include/
ds2.10/lib/secure/cmds/players/include/
ds2.10/lib/secure/daemon/imc2server/
ds2.10/lib/secure/daemon/include/
ds2.10/lib/secure/lib/
ds2.10/lib/secure/lib/include/
ds2.10/lib/secure/lib/net/include/
ds2.10/lib/secure/lib/std/
ds2.10/lib/secure/log/adm/
ds2.10/lib/secure/log/bak/
ds2.10/lib/secure/log/intermud/
ds2.10/lib/secure/log/network/
ds2.10/lib/secure/modules/
ds2.10/lib/secure/npc/
ds2.10/lib/secure/obj/include/
ds2.10/lib/secure/room/
ds2.10/lib/secure/save/
ds2.10/lib/secure/save/backup/
ds2.10/lib/secure/save/boards/
ds2.10/lib/secure/save/players/g/
ds2.10/lib/secure/tmp/
ds2.10/lib/secure/upgrades/files/
ds2.10/lib/secure/verbs/creators/
ds2.10/lib/std/board/
ds2.10/lib/std/lib/
ds2.10/lib/verbs/admins/include/
ds2.10/lib/verbs/builders/
ds2.10/lib/verbs/common/
ds2.10/lib/verbs/common/include/
ds2.10/lib/verbs/creators/
ds2.10/lib/verbs/creators/include/
ds2.10/lib/verbs/rooms/
ds2.10/lib/verbs/rooms/include/
ds2.10/lib/www/client/
ds2.10/lib/www/errors/
ds2.10/lib/www/images/
ds2.10/win32/
/* Satoria's malloc intended to be optimized for lpmud.
 ** this memory manager distinguishes between two sizes
 ** of blocks: small and large.  It manages them separately
 ** in the hopes of avoiding fragmentation between them.
 ** It expects small blocks to mostly be temporaries.
 ** It expects an equal number of future requests as small
 ** block deallocations.
 **
 ** support for atari st/tt and FAST_FIT by amylaar @cs.tu-berlin.de
 **
 ** adapted by Blackthorn@Genocide to work with MudOS 0.9.15 - 93/01/26
 **
 ** Amiga Lattice support added by Robocoder@TMI-2
 */

#define IN_MALLOC_WRAPPER
#define NO_OPCODES
#include "std.h"
#include "file_incl.h"
#include "lpc_incl.h"
#include "simulate.h"
#include "comm.h"

#if defined(sparc)
#define MALLOC_ALIGN 8
#else
#define MALLOC_ALIGN 4
#endif

#define POINTER void *
#define FREE_RETURN_TYPE void
#define FREE_RETURN return;
#define SFREE_RETURN_TYPE FREE_RETURN_TYPE
#define SFREE_RETURN FREE_RETURN

#define FIT_STYLE_FAST_FIT

#undef LARGE_TRACE

#define fake(s)

#define SMALL_BLOCK_MAX_BYTES	32
#define SMALL_CHUNK_SIZE	0x4000
#define CHUNK_SIZE		0x40000

#define SMALL_BLOCK_MAX (SMALL_BLOCK_MAX_BYTES/SIZEOF_INT)

#define PREV_BLOCK	0x80000000
#define THIS_BLOCK	0x40000000
#define NO_REF  	0x20000000	/* check this in gcollect.c */
#define MASK		0x0FFFFFFF

#define MAGIC       0x17952932

/* SMALL BLOCK info */

typedef unsigned int u;

static u *last_small_chunk = 0;
static u *sfltable[SMALL_BLOCK_MAX] =
{0, 0, 0, 0, 0, 0, 0, 0};	/* freed list */
static u *next_unused = 0;
static u unused_size = 0;	/* until we need a new chunk */

/* LARGE BLOCK info */

#ifndef FIT_STYLE_FAST_FIT
static u *free_list = 0;
#endif				/* FIT_STYLE_FAST_FIT */
static u *start_next_block = 0;

/* STATISTICS */

static int small_count[SMALL_BLOCK_MAX] =
{0, 0, 0, 0, 0, 0, 0, 0};
static int small_total[SMALL_BLOCK_MAX] =
{0, 0, 0, 0, 0, 0, 0, 0};
static int small_max[SMALL_BLOCK_MAX] =
{0, 0, 0, 0, 0, 0, 0, 0};
static int small_free[SMALL_BLOCK_MAX] =
{0, 0, 0, 0, 0, 0, 0, 0};

typedef struct {
    unsigned counter, size;
}      t_stat;

#define count(a,b) { a.size+=(b); if ((b)<0) --a.counter; else ++a.counter; }
#define count_up(a,b)   { a.size+=(b); ++a.counter; }
#define count_back(a,b) { a.size-=(b); --a.counter; }

#if 0
int debugmalloc = 0;		/* Only used when debuging malloc() */
#endif

/********************************************************/
/*  SMALL BLOCK HANDLER					*/
/********************************************************/

static char *large_malloc (u, int);
static void large_free (char *);
static int malloc_size_mask (void);
static int malloced_size (POINTER);
static void show_block (u *);
static void remove_from_free_list (u *);
static void add_to_free_list (u *);
static void build_block (u *, u);
static void mark_block (u *);
static char *esbrk (u);
static int resort_free_list (void);
#ifdef DEBUG
static void walk_new_small_malloced (void (*func) (POINTER, int));
#endif

#define s_size_ptr(p)	(p)
#define s_next_ptr(p)	((u **) (p+1))

t_stat small_alloc_stat =
{0, 0};
t_stat small_free_stat =
{0, 0};
t_stat small_chunk_stat =
{0, 0};

POINTER CDECL smalloc_malloc (size_t size)
{
    /* int i; */
    u *temp;

    DEBUG_CHECK(size == 0, "Malloc size 0.\n");
    if (size > SMALL_BLOCK_MAX_BYTES)
        return large_malloc(size, 0);

#if SIZEOF_PTR > SIZEOF_INT
    if (size < SIZEOF_PTR)
        size = SIZEOF_PTR;
#endif

    size = (size + 7) & ~3;	/* block size in bytes */
#define SIZE_INDEX(u_array, size) 	(*(u*) ((char*)u_array-8+size))
#define SIZE_PNT_INDEX(u_array, size)	(*(u**)((char*)u_array-8+size))
    /* i = (size - 8) >> 2; */
    count_up(small_alloc_stat, size);

    SIZE_INDEX(small_count, size) += 1;	/* update statistics */
    SIZE_INDEX(small_total, size) += 1;
    if (SIZE_INDEX(small_count, size) > SIZE_INDEX(small_max, size))
        SIZE_INDEX(small_max, size) = SIZE_INDEX(small_count, size);

    if (temp = SIZE_PNT_INDEX(sfltable, size)) {	/* allocate from the
                                                         * free list */
        count_back(small_free_stat, size);
        temp++;
        SIZE_PNT_INDEX(sfltable, size) = *(u **) temp;
        fake("From free list.");
        return (char *) temp;
    }				/* else allocate from the chunk */
    if (unused_size < size) {	/* no room in chunk, get another */
        /*
         * don't waste this smaller block
         */
        if (unused_size) {
            count_up(small_free_stat, unused_size);
            *s_size_ptr(next_unused) = unused_size >> 2;
            *s_next_ptr(next_unused) = SIZE_PNT_INDEX(sfltable, unused_size);
            SIZE_PNT_INDEX(sfltable, unused_size) = next_unused;
        }

        fake("Allocating new small chunk.");
        next_unused = (u *) large_malloc(SMALL_CHUNK_SIZE + SIZEOF_PTR, 1);
        if (next_unused == 0)
            return 0;

        *next_unused = (u) last_small_chunk;
        last_small_chunk = next_unused++;
        count_up(small_chunk_stat, SMALL_CHUNK_SIZE +  SIZEOF_PTR);
        count_up(small_alloc_stat, SIZEOF_PTR);
        unused_size = SMALL_CHUNK_SIZE;
    } else
        fake("Allocated from chunk.");

    temp = (u *) s_next_ptr(next_unused);
    *s_size_ptr(next_unused) = size >> 2;
    unused_size -= size;
    if (unused_size < (SIZEOF_INT + SIZEOF_PTR)) {
        count_up(small_alloc_stat, unused_size);
        if ((size + unused_size) < (SMALL_BLOCK_MAX_BYTES + SIZEOF_INT)) {
            /*
             * try to avoid waste
             */
            size += unused_size;
            *s_size_ptr(next_unused) = size >> 2;
        }
        unused_size = 0;
    }
    next_unused += size >> 2;

    fake("allocation from chunk successful\n");
    return (char *) temp;
}

#ifdef DEBUG
char *debug_free_ptr;
#endif				/* DEBUG */

static int malloc_size_mask()
{
    return MASK;
}

static int malloced_size (POINTER ptr)
{
    return (((u *) ptr)[-1] & MASK);
}

SFREE_RETURN_TYPE CDECL smalloc_free (POINTER ptr)
{
    u *block;
    u i;

    if (!ptr)
        SFREE_RETURN;

#ifdef DEBUG
    debug_free_ptr = ptr;
#endif				/* DEBUG */
    block = (u *) ptr;
    block -= 1;
    i = (*s_size_ptr(block) & MASK);
    if ((*s_size_ptr(block) & MASK) > SMALL_BLOCK_MAX + 1) {
        fake("sfree calls large_free");
        large_free(ptr);
        SFREE_RETURN
    }
    count_back(small_alloc_stat, i << 2);
    count_up(small_free_stat, i << 2);
    i -= 2;
    *s_next_ptr(block) = sfltable[i];
    sfltable[i] = block;
    small_free[i] += 1;
    fake("Freed");
    SFREE_RETURN
}

/************************************************/
/*	LARGE BLOCK HANDLER			*/
/************************************************/

#define BEST_FIT	0
#define FIRST_FIT	1
#define HYBRID		2

#define fit_style BEST_FIT
/* if this is a constant, evaluate at compile-time.... */
#ifndef fit_style
int fit_style = BEST_FIT;
#endif

#define l_size_ptr(p)		(p)
#define l_next_ptr(p)		(*((u **) (p+1)))
#define l_prev_ptr(p)		(*((u **) ((u **)(p+1)+1)))
#define l_next_block(p)		(p + (MASK & (*(p))) )
#define l_prev_block(p) 	(p - (MASK & (*(p-1))) )
#define l_prev_free(p)		(!(*p & PREV_BLOCK))
#define l_next_free(p)		(!(*l_next_block(p) & THIS_BLOCK))

static void show_block (u * ptr)
{
    printf("[%c%d: %d]  ", (*ptr & THIS_BLOCK ? '+' : '-'),
            ptr, (*ptr & MASK));
}

#ifdef FIT_STYLE_FAST_FIT

#if defined(atarist) || defined (sun) || defined(AMIGA)
/* there is a type signed char */
typedef SIGNED char balance_t;

#define BALANCE_T_BITS 8
#else
typedef short balance_t;

#define BALANCE_T_BITS 16
#endif
#if (defined(atarist) && !defined(ATARI_TT)) || defined(sparc) || defined(AMIGA)
/* try to avoid multiple shifts, because these are costly */
#define NO_BARREL_SHIFT
#endif

typedef struct free_block_s {
    u size;
    struct free_block_s *parent, *left, *right;
    balance_t balance;
    short align_dummy;
} free_block_t;

/* prepare two nodes for the free tree that will never be removed,
   so that we can always assume that the tree is and remains non-empty. */
/* some compilers don't understand forward declarations of static vars. */
extern free_block_t dummy2;

static free_block_t dummy = {
    /* size */ 0,
    /* parent */ &dummy2,
    /* left */ 0,
    /* right */ 0,
    /* balance */ 0
};

free_block_t dummy2 =
{
    /* size */ 0,
    /* parent */ 0,
    /* left */ &dummy,
    /* right */ 0,
    /* balance */ -1
};

static free_block_t *free_tree = &dummy2;

#ifdef DEBUG_AVL
static int inconsistency = 0;

static int check_avl (free_block_t * parent, free_block_t * p)
{
    int left, right;

    if (!p)
        return 0;
    left = check_avl(p, p->left);
    right = check_avl(p, p->right);
    if (p->balance != right - left || p->balance < -1 || p->balance > 1) {
        printf("Inconsistency in avl node!\n");
        printf("node:%x\n", p);
        printf("size: %d\n", p->size);
        printf("left node:%x\n", p->left);
        printf("left  height: %d\n", left);
        printf("right node:%x\n", p->right);
        printf("right height: %d\n", right);
        printf("alleged balance: %d\n", p->balance);
        inconsistency = 1;
    }
    if (p->parent != parent) {
        printf("Inconsistency in avl node!\n");
        printf("node:%x\n", p);
        printf("size: %d\n", p->size);
        printf("parent: %x\n", parent);
        printf("parent size: %d\n", parent->size);
        printf("alleged parent: %x\n", p->parent);
        printf("alleged parent size: %d\n", p->parent->size);
        printf("left  height: %d\n", left);
        printf("right height: %d\n", right);
        printf("alleged balance: %d\n", p->balance);
        inconsistency = 1;
    }
    return left > right ? left + 1 : right + 1;
}

/* this function returns a value so that it can be used in ,-expressions. */
static int do_check_avl()
{
    check_avl(0, free_tree);
    if (inconsistency) {
        fflush(stderr);
        fflush(stdout);
        fatal("Inconsistency could crash the driver\n");
    }
    return 0;
}
#endif				/* DEBUG_AVL */

t_stat large_free_stat;
static void remove_from_free_list (u * ptr)
{
    free_block_t *p, *q, *r, *s, *t;

    fake((do_check_avl(), "remove_from_free_list called"));
    p = (free_block_t *) (ptr + 1);
    count_back(large_free_stat, p->size << 2);
#ifdef DEBUG_AVL
    printf("node:%x\n", p);
    printf("size:%d\n", p->size);
#endif
    if (p->left) {
        if (q = p->right) {
            fake("two childs");
            s = q;
            for (; r = q, q = r->left;);
            if (r == s) {
                r->left = s = p->left;
                s->parent = r;
                if (r->parent = s = p->parent) {
                    if (p == s->left) {
                        s->left = r;
                    } else {
                        s->right = r;
                    }
                } else {
                    free_tree = r;
                }
                r->balance = p->balance;
                p = r;
                goto balance_right;
            } else {
                t = r->parent;
                if (t->left = s = r->right) {
                    s->parent = t;
                }
                r->balance = p->balance;
                r->left = s = p->left;
                s->parent = r;
                r->right = s = p->right;
                s->parent = r;
                if (r->parent = s = p->parent) {
                    if (p == s->left) {
                        s->left = r;
                    } else {
                        s->right = r;
                    }
                } else {
                    free_tree = r;
                }
                p = t;
                goto balance_left;
            }
        } else {		/* no right child, but left child */
            /*
             * We set up the free list in a way so that there will remain at
             * least two nodes, and the avl property ensures that the left
             * child is a leaf ==> there is a parent
             */
            fake("no right child, but left child");
            s = p;
            p = s->parent;
            r = s->left;
            r->parent = p;
            if (s == p->left) {
                p->left = r;
                goto balance_left;
            } else {
                p->right = r;
                goto balance_right;
            }
        }
    } else {			/* no left child */
        /*
         * We set up the free list in a way so that there is a node left of
         * all used nodes, so there is a parent
         */
        fake("no left child");
        s = p;
        p = s->parent;
        if (q = r = s->right) {
            r->parent = p;
        }
        if (s == p->left) {
            p->left = r;
            goto balance_left;
        } else {
            p->right = r;
            goto balance_right;
        }
    }
balance_q:
    r = p;
    p = q;
    if (r == p->right) {
        balance_t b;

balance_right:
        b = p->balance;
        if (b > 0) {
            p->balance = 0;
            if (q = p->parent)
                goto balance_q;
            return;
        } else if (b < 0) {
            r = p->left;
            b = r->balance;
            if (b <= 0) {
                /* R-Rotation */
#ifdef DEBUG_AVL
                fake("R-Rotation.");
                printf("r->balance: %d\n", r->balance);
#endif
                if (p->left = s = r->right) {
                    s->parent = p;
                }
                r->right = p;
                s = p->parent;
                p->parent = r;
                b += 1;
                r->balance = b;
                b = -b;
#ifdef DEBUG_AVL
                printf("node r: %x\n", r);
                printf("r->balance: %d\n", r->balance);
                printf("node p: %x\n", p);
                p->balance = b;
                printf("p->balance: %d\n", p->balance);
                printf("r-height: %d\n", check_avl(r->parent, r));
#endif
                if (r->parent = s) {
                    if (p->balance = b) {
                        if (p == s->left) {
                            s->left = r;
                            return;
                        } else {
                            s->right = r;
                            return;
                        }
                    }
                    if (p == s->left) {
                        fake("left from parent");
                        goto balance_left_s;
                    } else {
                        fake("right from parent");
                        p = s;
                        p->right = r;
                        goto balance_right;
                    }
                }
                p->balance = b;
                free_tree = r;
                return;
            } else {		/* r->balance == +1 */
                /* LR-Rotation */
                balance_t b2;

                fake("LR-Rotation.");
                t = r->right;
                b = t->balance;
                if (p->left = s = t->right) {
                    s->parent = p;
                }
                if (r->right = s = t->left) {
                    s->parent = r;
                }
                t->left = r;
                t->right = p;
                r->parent = t;
                s = p->parent;
                p->parent = t;
#ifdef NO_BARREL_SHIFT
                b = -b;
                b2 = b >> 1;
                r->balance = b2;
                b -= b2;
                p->balance = b;
#else
                b2 = (unsigned char) b >> 7;
                p->balance = b2;
                b2 = -b2 - b;
                r->balance = b2;
#endif
                t->balance = 0;
#ifdef DEBUG_AVL
                printf("t-height: %d\n", check_avl(t->parent, t));
#endif
                if (t->parent = s) {
                    if (p == s->left) {
                        p = s;
                        s->left = t;
                        goto balance_left;
                    } else {
                        p = s;
                        s->right = t;
                        goto balance_right;
                    }
                }
                free_tree = t;
                return;
            }
        } else {		/* p->balance == 0 */
            p->balance = -1;
            return;
        }
    } else {			/* r == p->left */
        balance_t b;

        goto balance_left;
balance_left_s:
        p = s;
        s->left = r;
balance_left:
        b = p->balance;
        if (b < 0) {
            p->balance = 0;
            if (q = p->parent)
                goto balance_q;
            return;
        } else if (b > 0) {
            r = p->right;
            b = r->balance;
            if (b >= 0) {
                /* L-Rotation */
#ifdef DEBUG_AVL
                fake("L-Rotation.");
                printf("r->balance: %d\n", r->balance);
#endif
                if (p->right = s = r->left) {
                    s->parent = p;
                }
                fake("subtree relocated");
                r->left = p;
                s = p->parent;
                p->parent = r;
                b -= 1;
                r->balance = b;
                b = -b;
#ifdef DEBUG_AVL
                fake("balances calculated");
                printf("node r: %x\n", r);
                printf("r->balance: %d\n", r->balance);
                printf("node p: %x\n", p);
                p->balance = b;
                printf("p->balance: %d\n", p->balance);
                printf("r-height: %d\n", check_avl(r->parent, r));
#endif
                if (r->parent = s) {
                    if (p->balance = b) {
                        if (p == s->left) {
                            s->left = r;
                            return;
                        } else {
                            s->right = r;
                            return;
                        }
                    }
                    if (p == s->left) {
                        fake("left from parent");
                        goto balance_left_s;
                    } else {
                        fake("right from parent");
                        p = s;
                        p->right = r;
                        goto balance_right;
                    }
                }
                p->balance = b;
                free_tree = r;
                return;
            } else {		/* r->balance == -1 */
                /* RL-Rotation */
                balance_t b2;

                fake("RL-Rotation.");
                t = r->left;
                b = t->balance;
                if (p->right = s = t->left) {
                    s->parent = p;
                }
                if (r->left = s = t->right) {
                    s->parent = r;
                }
                t->right = r;
                t->left = p;
                r->parent = t;
                s = p->parent;
                p->parent = t;
#ifdef NO_BARREL_SHIFT
                b = -b;
                b2 = b >> 1;
                p->balance = b2;
                b -= b2;
                r->balance = b;
#else
                b2 = (unsigned char) b >> 7;
                r->balance = b2;
                b2 = -b2 - b;
                p->balance = b2;
#endif
                t->balance = 0;
                if (t->parent = s) {
                    if (p == s->left) {
                        p = s;
                        s->left = t;
                        goto balance_left;
                    } else {
                        s->right = t;
                        p = s;
                        goto balance_right;
                    }
                }
                free_tree = t;
                return;
            }
        } else {		/* p->balance == 0 */
            p->balance++;
            return;
        }
    }
}

static void add_to_free_list (u * ptr)
{
    u size;
    free_block_t *p, *q, *r;

    /*
     * When there is a distinction between data and address registers and/or
     * accesses, gcc will choose data type for q, so an assignmnt to q will
     * faciliate branching
     */

    fake((do_check_avl(), "add_to_free_list called"));
    size = *ptr & MASK;
#ifdef DEBUG_AVL
    printf("size:%d\n", size);
#endif
    q = (free_block_t *) size;	/* this assignment is a hint for
                                 * register choice */
    r = (free_block_t *) (ptr + 1);
    count_up(large_free_stat, size << 2);
    q = free_tree;
    for (;; /* p = q */ ) {
        p = (free_block_t *) q;
#ifdef DEBUG_AVL
        printf("checked node size %d\n", p->size);
#endif
        if (size < p->size) {
            if (q = p->left) {
                continue;
            }
            fake("add left");
            p->left = r;
            break;
        } else {		/* >= */
            if (q = p->right) {
                continue;
            }
            fake("add right");
            p->right = r;
            break;
        }
    }
    r->size = size;
    r->parent = p;
    r->left = 0;
    r->right = 0;
    r->balance = 0;
#ifdef DEBUG_AVL
    fake("built new leaf.");
    printf("p->balance:%d\n", p->balance);
#endif
    do {
        free_block_t *s;

        if (r == p->left) {
            balance_t b;

            if (!(b = p->balance)) {
#ifdef DEBUG_AVL
                printf("p->size: %d\n", p->size);
                printf("p->balance: %d\n", p->balance);
                printf("p->right-h: %d\n", check_avl(p, p->right));
                printf("p->left -h: %d\n", check_avl(p, p->left));
                fake("growth propagation from left side");
#endif
                p->balance = -1;
            } else if (b < 0) {
#ifdef DEBUG_AVL
                printf("p->balance:%d\n", p->balance);
#endif
                if (r->balance < 0) {
                    /* R-Rotation */
                    fake("R-Rotation");
                    if (p->left = s = r->right) {
                        s->parent = p;
                    }
                    r->right = p;
                    p->balance = 0;
                    r->balance = 0;
                    s = p->parent;
                    p->parent = r;
                    if (r->parent = s) {
                        if (s->left == p) {
                            s->left = r;
                        } else {
                            s->right = r;
                        }
                    } else {
                        free_tree = r;
                    }
                } else {	/* r->balance == +1 */
                    /* LR-Rotation */
                    balance_t b2;
                    free_block_t *t = r->right;

#ifdef DEBUG_AVL
                    fake("LR-Rotation");
                    printf("t = %x\n", t);
                    printf("r->balance:%d\n", r->balance);
#endif
                    if (p->left = s = t->right) {
                        s->parent = p;
                    }
                    fake("relocated right subtree");
                    t->right = p;
                    if (r->right = s = t->left) {
                        s->parent = r;
                    }
                    fake("relocated left subtree");
                    t->left = r;
                    b = t->balance;
#ifdef NO_BARREL_SHIFT
                    b = -b;
                    b2 = b >> 1;
                    r->balance = b2;
                    b -= b2;
                    p->balance = b;
#else
                    b2 = (unsigned char) b >> 7;
                    p->balance = b2;
                    b2 = -b2 - b;
                    r->balance = b2;
#endif
                    t->balance = 0;
                    fake("balances calculated");
                    s = p->parent;
                    p->parent = t;
                    r->parent = t;
                    if (t->parent = s) {
                        if (s->left == p) {
                            s->left = t;
                        } else {
                            s->right = t;
                        }
                    } else {
                        free_tree = t;
                    }
#ifdef DEBUG_AVL
                    printf("p->balance:%d\n", p->balance);
                    printf("r->balance:%d\n", r->balance);
                    printf("t->balance:%d\n", t->balance);
                    fake((do_check_avl(), "LR-Rotation completed."));
#endif
                }
                break;
            } else {		/* p->balance == +1 */
                p->balance = 0;
                fake("growth of left side balanced the node");
                break;
            }
        } else {		/* r == p->right */
            balance_t b;

            if (!(b = p->balance)) {
                fake("growth propagation from right side");
                p->balance++;
            } else if (b > 0) {
                if (r->balance > 0) {
                    /* L-Rotation */
                    fake("L-Rotation");
                    if (p->right = s = r->left) {
                        s->parent = p;
                    }
                    r->left = p;
                    p->balance = 0;
                    r->balance = 0;
                    s = p->parent;
                    p->parent = r;
                    if (r->parent = s) {
                        if (s->left == p) {
                            s->left = r;
                        } else {
                            s->right = r;
                        }
                    } else {
                        free_tree = r;
                    }
                } else {	/* r->balance == -1 */
                    /* RL-Rotation */
                    balance_t b2;
                    free_block_t *t = r->left;

#ifdef DEBUG_AVL
                    fake("RL-Rotation");
                    printf("t = %x\n", t);
                    printf("r->balance:%d\n", r->balance);
#endif
                    if (p->right = s = t->left) {
                        s->parent = p;
                    }
                    fake("relocated left subtree");
                    t->left = p;
                    if (r->left = s = t->right) {
                        s->parent = r;
                    }
                    fake("relocated right subtree");
                    t->right = r;
                    b = t->balance;
#ifdef NO_BARREL_SHIFT
                    b = -b;
                    b2 = b >> 1;
                    p->balance = b2;
                    b -= b2;
                    r->balance = b;
#else
                    b2 = (unsigned char) b >> 7;
                    r->balance = b2;
                    b2 = -b2 - b;
                    p->balance = b2;
#endif
                    t->balance = 0;
                    s = p->parent;
                    p->parent = t;
                    r->parent = t;
                    if (t->parent = s) {
                        if (s->left == p) {
                            s->left = t;
                        } else {
                            s->right = t;
                        }
                    } else {
                        free_tree = t;
                    }
                    fake("RL-Rotation completed.");
                }
                break;
            } else {		/* p->balance == -1 */
#ifdef DEBUG_AVL
                printf("p->balance: %d\n", p->balance);
                printf("p->right-h: %d\n", check_avl(p, p->right));
                printf("p->left -h: %d\n", check_avl(p, p->left));
#endif
                p->balance = 0;
                fake("growth of right side balanced the node");
                break;
            }
        }
        r = p;
        p = p->parent;
    } while (q = p);
    fake((do_check_avl(), "add_to_free_list successful"));
}

#else				/* FIT_STYLE_FAST_FIT */

void show_free_list()
{
    u *p;

    p = free_list;
    while (p) {
        show_block(p);
        p = l_next_ptr(p);
    }
    printf("\n");
}

t_stat large_free_stat;
void remove_from_free_list (u * ptr)
{
    count_back(large_free_stat, (*ptr & MASK) << 2);

    if (l_prev_ptr(ptr))
        l_next_ptr(l_prev_ptr(ptr)) = l_next_ptr(ptr);
    else
        free_list = l_next_ptr(ptr);

    if (l_next_ptr(ptr))
        l_prev_ptr(l_next_ptr(ptr)) = l_prev_ptr(ptr);
}

void add_to_free_list (u * ptr)
{
    extern int puts();

    count_up(large_free_stat, (*ptr & MASK) << 2);

#ifdef DEBUG
    if (free_list && l_prev_ptr(free_list))
        puts("Free list consistency error.");
#endif

    l_next_ptr(ptr) = free_list;
    if (free_list)
        l_prev_ptr(free_list) = ptr;
    l_prev_ptr(ptr) = 0;
    free_list = ptr;
}
#endif				/* FIT_STYLE_FAST_FIT */

static void build_block (	/* build a properly annotated unalloc block */
        u * ptr, u size)
{
    u tmp;

    tmp = (*ptr & PREV_BLOCK) | size;
    *(ptr + size - 1) = size;
    *(ptr) = tmp;		/* mark this block as free */
    *(ptr + size) &= ~PREV_BLOCK;	/* unmark previous block */
}

static void mark_block (	/* mark this block as allocated */
        u * ptr)
{
    *l_next_block(ptr) |= PREV_BLOCK;
    *ptr |= THIS_BLOCK;
}

/*
 * It is system dependent how sbrk() aligns data, so we simpy use brk()
 * to insure that we have enough.
 */
t_stat sbrk_stat;
static char *esbrk (u size)
{
#ifdef SBRK_OK
#ifdef NeXT

    void *addr = NULL;
    static void *current_break = NULL;
    static int anywhere = FALSE;
    kern_return_t ret;

    /*
     * try to extend current break
     */
    addr = current_break;
    ret = vm_allocate(task_self(), (vm_address_t *) & addr, size, anywhere);
    if (ret != KERN_SUCCESS && (anywhere == FALSE)) {
        /*
         * allocate anywhere
         */
        anywhere = TRUE;
        ret = vm_allocate(task_self(), (vm_address_t *) & addr, size, TRUE);
        if (ret != KERN_SUCCESS)
            return (NULL);
    }
    count_up(sbrk_stat, size);
    current_break = (void *) ((char *) addr + size);
    return (addr);

#else

#ifndef linux
    extern char *sbrkx();
#endif				/* linux */

    static char *current_break = 0;

    if (current_break == 0)
        current_break = (char *)sbrkx(0);
    if (brk(current_break + size) == -1)
        return 0;

    count_up(sbrk_stat, size);
    current_break += size;
    return current_break - size;

#endif				/* NeXT */
#else				/* not SBRK_OK */

    count_up(sbrk_stat, size);
    return (char *)malloc(size);

#endif				/* SBRK_OK */
}

t_stat large_alloc_stat;
static char *large_malloc (u size, int force_more)
{
    u real_size;
    u *ptr;

    fake("large_malloc called");
#ifdef LARGE_TRACE
    printf("request:%d.", size);
#endif
    size = (size + 7) >> 2;	/* plus overhead */
    count_up(large_alloc_stat, size << 2);

retry:
    ptr = 0;
    if (!force_more) {
#ifdef FIT_STYLE_FAST_FIT

        free_block_t *p, *q, *r;
        u minsplit;
        u tempsize;

        ptr++;
        minsplit = size + SMALL_BLOCK_MAX + 1;
        q = free_tree;
        for (;;) {
            p = q;
#ifdef DEBUG_AVL
            printf("checked node size %d\n", p->size);
#endif
            tempsize = p->size;
            if (minsplit < tempsize) {
                ptr = (u *) p;	/* remember this fit */
                if (q = p->left) {
                    continue;
                }
                /* We don't need that much, but that's the best fit we have */
                break;
            } else if (size > tempsize) {
                if (q = p->right) {
                    continue;
                }
                break;
            } else {		/* size <= tempsize <= minsplit */
                if (size == tempsize) {
                    ptr = (u *) p;
                    break;
                }
                /* size < tempsize */
                if (q = p->left) {
                    r = p;
                    /*
                     * if r is used in the following loop instead of p, gcc
                     * will handle q very inefficient throughout the function
                     * large_malloc()
                     */
                    for (;;) {
                        p = q;
                        tempsize = p->size;
                        if (size < tempsize) {
                            if (q = p->left) {
                                continue;
                            }
                            break;
                        } else if (size > tempsize) {
                            if (q = p->right) {
                                continue;
                            }
                            break;
                        } else {
                            ptr = (u *) p;
                            goto found_fit;
                        }
                    }
                    p = r;
                }
                tempsize = p->size;
                if (minsplit > tempsize) {
                    if (q = p->right) {
                        for (;;) {
                            p = q;
                            tempsize = p->size;
                            if (minsplit <= tempsize) {
                                ptr = (u *) p;	/* remember this fit */
                                if (q = p->left) {
                                    continue;
                                }
                                break;
                            } else {	/* minsplit > tempsize */
                                if (q = p->right) {
                                    continue;
                                }
                                break;
                            }
                        }	/* end inner for */
                        break;
                    }
                    break;	/* no new fit */
                }
                /* minsplit == tempsize  ==> best non-exact fit */
                ptr = (u *) p;
                break;
            }
        }			/* end outer for */
found_fit:
        ptr--;
#else				/* FIT_STYLE */
        u best_size;
        u *first, *best;

#ifdef LARGE_TRACE
        u search_length = 0;

#endif

        first = best = 0;
        best_size = MASK;
        ptr = free_list;

        while (ptr) {
            u tempsize;

#ifdef LARGE_TRACE
            search_length++;
#endif
            /* Perfect fit? */
            tempsize = *ptr & MASK;
            if (tempsize == size) {
                best = first = ptr;
                break;
                /* always accept perfect fit */
            }
            /* does it really even fit at all */
            if (tempsize >= size + SMALL_BLOCK_MAX + 1) {
                /* try first fit */
                if (!first) {
                    first = ptr;
                    if (fit_style == FIRST_FIT)
                        break;
                    /* just use this one! */
                }
                /* try best fit */
                tempsize -= size;
                if (tempsize > 0 && tempsize <= best_size) {
                    best = ptr;
                    best_size = tempsize;
                }
            }
            ptr = l_next_ptr(ptr);
        }			/* end while */

#ifdef LARGE_TRACE
        printf("search length %d\n", search_length);
#endif
        if (fit_style == BEST_FIT)
            ptr = best;
        else
            ptr = first;
        /* FIRST_FIT and HYBRID both leave it in first */

#endif				/* FIT_STYLE */
    }				/* end of  if (!force_more) */
    if (!ptr) {			/* no match, allocate more memory */
        u chunk_size, block_size;

        block_size = size * SIZEOF_INT;
        if (force_more || (block_size > CHUNK_SIZE))
            chunk_size = block_size;
        else
            chunk_size = CHUNK_SIZE;

#ifdef SBRK_OK
        if (!start_next_block) {
            count_up(large_alloc_stat, SIZEOF_INT);
            start_next_block = (u *) esbrk(SIZEOF_INT);
            if (!start_next_block)
                fatal("Couldn't malloc anything");
            *(start_next_block) = PREV_BLOCK;
            fake("Allocated little fake block");
        }
        ptr = (u *) esbrk(chunk_size);
#else				/* not SBRK_OK */
        ptr = (u *) esbrk(chunk_size + SIZEOF_INT);
#endif				/* SBRK_OK */
        if (ptr == 0) {
            extern char *reserved_area;
            extern int slow_shut_down_to_do;
            static int going_to_exit = 0;
            static char mess1[] = "Temporary out of MEMORY. Freeing reserve.\n";
            static char mess2[] = "Totally out of MEMORY.\n";

            if (going_to_exit)
                exit(3);
            if (reserved_area) {
                smalloc_free(reserved_area);
                reserved_area = 0;
                write(1, mess1, sizeof(mess1) - 1);
                slow_shut_down_to_do = 6;
                force_more = 0;
                goto retry;
            }
            if (force_more) {
                force_more = 0;
                goto retry;
            }
            going_to_exit = 1;
            write(1, mess2, sizeof(mess2) - 1);
            (void) dump_trace(0);
            exit(2);
        }
#ifdef SBRK_OK
        ptr -= 1;		/* overlap old memory block */
#else				/* not SBRK_OK */
        if (start_next_block == ptr) {
            ptr -= 1;		/* overlap old memory block */
            chunk_size += SIZEOF_INT;
        } else
            *ptr = PREV_BLOCK;
        start_next_block = (u *) ((char *) ptr + chunk_size);
#endif				/* SBRK_OK */
        block_size = chunk_size / SIZEOF_INT;

        /* configure header info on chunk */

        build_block(ptr, block_size);
        if (force_more)
            fake("Build little block");
        else
            fake("Built memory block description.");
        *l_next_block(ptr) = THIS_BLOCK;
        add_to_free_list(ptr);
    }				/* end of creating a new chunk */
    remove_from_free_list(ptr);
    real_size = *ptr & MASK;

    if (real_size - size) {
        /* split block pointed to by ptr into two blocks */
        build_block(ptr + size, real_size - size);
        fake("Built empty block");
        /*
         * When we allocate a new chunk, it might differ very slightly in
         * size from the desired size.
         */
        if (real_size - size >= SMALL_BLOCK_MAX + 1) {
            add_to_free_list(ptr + size);
        } else {
            mark_block(ptr + size);
        }
        build_block(ptr, size);
    }
    mark_block(ptr);
    fake("built allocated block");
    return (char *) (ptr + 1);
}

static void large_free (char * ptr)
{
    u size, *p;

    p = (u *) ptr;
    p -= 1;
    size = *p & MASK;
    count_back(large_alloc_stat, (size << 2));

    if (!(*(p + size) & THIS_BLOCK)) {
        remove_from_free_list(p + size);
        size += (*(p + size) & MASK);
        *p = (*p & PREV_BLOCK) | size;
    }
    if (l_prev_free(p)) {
        remove_from_free_list(l_prev_block(p));
        size += (*l_prev_block(p) & MASK);
        p = l_prev_block(p);
    }
    build_block(p, size);

    add_to_free_list(p);
}

POINTER CDECL smalloc_realloc (POINTER p, size_t size)
{
    unsigned *q, old_size;
    char *t;

    q = (unsigned *) p;

#if MALLOC_ALIGN > 4
    while (!(old_size = *--q));
    old_size = ((old_size & MASK) - 1) * SIZEOF_INT;
#else
    --q;
    old_size = ((*q & MASK) - 1) * SIZEOF_INT;
#endif
    if (old_size >= size)
        return p;

    t = smalloc_malloc(size);
    if (t == 0)
        return (char *) 0;

    memcpy(t, p, old_size);
    smalloc_free(p);
    return t;
}

static int resort_free_list()
{
    return 0;
}
#ifdef DO_MSTATS
#define dump_stat(str,stat) outbuf_addv(ob, str,stat.counter,stat.size)
void show_mstats (outbuffer_t * ob, char * s)
{
    outbuf_addv(ob, "Memory allocation statistics %s\n", s);
    outbuf_add(ob, "Type                   Count      Space (bytes)\n");
    dump_stat("sbrk requests:     %8d        %10d (a)\n", sbrk_stat);
    dump_stat("large blocks:      %8d        %10d (b)\n", large_alloc_stat);
    dump_stat("large free blocks: %8d        %10d (c)\n\n", large_free_stat);
    dump_stat("small chunks:      %8d        %10d (d)\n", small_chunk_stat);
    dump_stat("small blocks:      %8d        %10d (e)\n", small_alloc_stat);
    dump_stat("small free blocks: %8d        %10d (f)\n", small_free_stat);
    outbuf_addv(ob,
            "unused from current chunk          %10d (g)\n\n", unused_size);
    outbuf_addv(ob,
            "    Small blocks are stored in small chunks, which are allocated as\n");
    outbuf_addv(ob,
            "large blocks.  Therefore, the total large blocks allocated (b) plus\n");
    outbuf_addv(ob,
            "the large free blocks (c) should equal total storage from sbrk (a).\n");
    outbuf_addv(ob,
            "Similarly, (e) + (f) + (g) equals (d).  The total amount of storage\n");
    outbuf_addv(ob,
            "wasted is (c) + (f) + (g); the amount allocated is (b) - (f) - (g).\n");
}
#endif

/*
 * calloc() is provided because some stdio packages uses it.
 */
POINTER CDECL smalloc_calloc (size_t nelem, size_t sizel)
{
    char *p;

    if (nelem == 0 || sizel == 0)
        return 0;
    p = smalloc_malloc(nelem * sizel);
    if (p == 0)
        return 0;
    (void) memset(p, '\0', nelem * sizel);
    return p;
}

#ifdef DEBUG
/*
 * Functions below can be used to debug malloc.
 */

static void walk_new_small_malloced(void (*func) (POINTER, int))
{
    int i;
    u *p, *q;

    for (i = 0; i < SMALL_BLOCK_MAX; i++) {
        for (p = sfltable[i]; p; p = *(u **) (p + 1)) {
            *s_size_ptr(p) |= NO_REF;
        }
    }
    if (unused_size)
        *next_unused = 0;
    for (p = last_small_chunk; p; p = *(u **) p) {
        u *end = p - 1 + (p[-1] & MASK);

        debug_message("scanning chunk %x, end %x\n", (u) (p - 1), (u) end);
        for (q = p + 1; q < end;) {
            u size = *s_size_ptr(q);

            if (!size)
                break;
            if (!(size & NO_REF)) {
                (*func) ((char *) s_next_ptr(q), (size & MASK) << 2);
                *s_size_ptr(q) |= NO_REF;
            }
            q += size & MASK;
        }
    }
    for (i = 0; i < SMALL_BLOCK_MAX; i++) {
        for (p = sfltable[i]; p; p = *(u **) (p + 1)) {
            *s_size_ptr(p) &= ~NO_REF;
        }
    }
}
#endif