fbmuck-6.05/auto/
fbmuck-6.05/contrib/jresolver/
fbmuck-6.05/contrib/jresolver/org/
fbmuck-6.05/contrib/jresolver/org/fuzzball/
fbmuck-6.05/docs/devel/
fbmuck-6.05/game/
fbmuck-6.05/game/logs/
fbmuck-6.05/game/muf/
fbmuck-6.05/scripts/
fbmuck-6.05/src_docs/
/* {{{ crt_malloc.c -- CrT's own silly malloc wrappers for debugging.	*/

/* This file is formatted for use with folding.el for emacs, sort	*/
/* of an outline-mode for programmers, ftp-able from elisp archives	*/
/* such as tut.cis.ohio-state.edu (128.146.8.52).  If you don't use	*/
/* folding-mode and/or emacs, you may want to prepare a table of	*/
/* contents for this file by doing "grep '{{{' thisfile.c".		*/

/* Can be used to generate malloc statistic listing looking like:


         File Line CurBlks CurBytes MaxBlks MaxBytes MxByTime TotBlks TotBytes
------------- ---- ------- -------- ------- -------- -------- ------- --------
         db.c  377:      0        0       2      197 06232835     366     7174
         db.c 1316:      0        0       1       33 06232836       1       33
         db.c 1376:      0        0       1       17 06232900       1       17
         db.c  873:      0        0    2554    30648 06232919    4954    59448
         db.c  899:      0        0    2554    72068 06232919    4954   131094
    compile.c  242:      0        0      50     1297 06232909     517    11317
    compile.c  503:      0        0       1      106 06232919    4938   130373
    compile.c  542:      0        0       5       41 06232912   12155    67649
    compile.c 1768:      0        0    7443   148860 06232924   13703   274060
    compile.c 1326:      0        0     181     2172 06232924     342     4104
    compile.c 1327:      0        0     181     2438 06232924     342     4357
    compile.c 1339:      0        0       5       60 06232923     577     6924
    compile.c  847:      0        0       1       97 06232909    1493    28733
       edit.c  168:      0        0       1       79 06232908     184     3844
    compile.c  575:      0        0       2      177 06232921     795    33994
    compile.c 1365:      0        0       2       24 06232914      14      168
    compile.c 1378:      0        0       2       24 06232914      15      180
    compile.c  220:      0        0       1       49 06232910     612     9619
    compile.c 1352:      0        0       4       48 06232911     233     2796
     interp.c  155:      0        0       1      432 06232900      11     4752
  interface.c 1208:      0        0       1     1024 06232907       4     4096
     interp.c  578:      0        0       2      864 06232913       9     3888
    compile.c 1532:      0        0       4       38 06232913       6       56
  interface.c 1008:     27     2012      27     2012 06233122      79     5060
  timequeue.c   83:      1       14       3       42 06232900       4       56
  interface.c  961:      1       14       1       14 06232907       1       14
       game.c  435:      1       15       1       15 06232835       1       15
        reg.c  352:      1       16       1       16 06232835       1       16
       game.c  466:      1       16       1       16 06232900       1       16
  timequeue.c   82:      1       17       3       25 06232900       4       41
    boolexp.c   95:      1       20       1       20 06232907       1       20
  interface.c 1007:     35      560      35      560 06233122      87     1392
    compile.c 1125:      4       47       4       47 06232914       4       47
    compile.c 1123:      4       48       4       48 06232914       4       48
  interface.c  940:      1       92       1       92 06232907       1       92
  timequeue.c   72:      3      168       3      168 06232900       3      168
    compile.c 1138:     22      264      22      264 06232914      22      264
    compile.c 1141:     22      340      22      340 06232914      22      340
       edit.c  183:    183     1605     183     1605 06232835     183     1605
       edit.c  176:    183     3660     183     3660 06232835     183     3660
       edit.c  184:    183     5569     183     5569 06232835     183     5569
     interp.c  127:      1    13200       1    13200 06232900       1    13200
   property.c  124:   1493    30167    1493    30167 06232926    1494    30181
         db.c 1256:   5440    38387    5440    38387 06232900    5440    38387
    hashtab.c  102:   5711    42144    5761    42602 06232912    6228    46528
 stringutil.c  386:   1759    50761    2768    82507 06232924    3667   104609
      props.c  154:   1643    56120    1643    56120 06232926    1643    56120
    hashtab.c   96:   5711    68532    5761    69132 06232909    6228    74736
         db.c 1246:  22861    91484   22861    91484 06232900   22861    91484
    compile.c 1721:     16   109752      16   109752 06232924      16   109752
         db.c 1129:  56911   793132   56911   793132 06232900   56911   793132
         db.c  167:      1  9420800       1  9420800 06232836       1  9420800
 Cumulative totals: 102221 10728956                            151500 11586028

 * First two columns are source file and line number of a [cm]alloc() call;
 * 
 * 'CurBlks' is number of ram blocks currently in existence
 *      created by that call;
         File Line CurBlks CurBytes MaxBlks MaxBytes MxByTime TotBlks TotBytes
 * 'CurBytes' is number of ram bytes current in existence
 *      created by that call;
 * 'TotBlks' is total number of ram blocks ever created by that call;
 * 'TotBytes' is total number of ram bytes ever allocated by that call.
 * 'MaxBytes' is max value 'CurBytes' has ever had for that call.
 * 'MxByTime' is time 'MaxBytes' value was recorded, as day:hour:minute.
 * 
 * The code adds 8 bytes overhead per ram block allocated.
 *
 * In addition, by defining MALLOC_PROFILING_EXTRA to be TRUE, this file
 * can be configured to check for heap-trashing bugs, free()s of
 * unallocated memory, and so forth.  As configured, (CRT_NEW_TO_CHECK
 * and CRT_OLD_TO_CHECK both set to 128) this option takes ABOUT 10x
 * MORE CPU TIME THAN VANILLA FUZZBALL.  You may reduce these numbers
 * to reduce the CPU overhead, at the cost of decreased likelihood of
 * detecting heap-trashing bugs promptly.  This option adds an additional
 * 13 bytes of overhead per string allocated.
 *
 * Together, the above two options can DOUBLE FUZZBALL'S RAM CONSUMPTION.
 */
/* 
 *  History
 *                                                            \|/
 * 94May08CrT: Nasty compile.c bug successfully pinpointed:  CD08<  (Splat!)
 * 94May06CrT: Debug check option.                            /|\
 * 94Feb16CrT: Added Whitefire's (excellent) idea of tracking peak ram usage.
 * 93Oct16(?)CrT: Created.
 */

/* }}} */

/* {{{ Header stuff							*/

/* {{{ #includes							*/

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

#ifdef MALLOC_PROFILING

/* }}} */
/* {{{ #defines you might want to configure.				*/

/* Select whether to do debug checks also. */
/* These checks eat an additional 8 bytes  */
/* per allocated block, but can be some    */
/* help in tracking down obscure memory    */
/* trashing pointer bugs.                  */
/* #define MALLOC_PROFILING_EXTRA                  */

/* When debugging is selected, we check the */
/* last CRT_NEW_TO_CHECK blocks allocated   */
/* each time we are called, on the theory   */
/* that they are the most likely to have    */
/* been trashed by buggy code:              */
#ifndef CRT_NEW_TO_CHECK
#define CRT_NEW_TO_CHECK (128)	/* Make it a nonzero power of two.  */
#endif

/* When debugging is selected we also check */
/* CRT_OLD_TO_CHECK blocks on the used-ram  */
/* cycling through all allocated blocks in  */
/* time:                                    */
#ifndef CRT_OLD_TO_CHECK
#define CRT_OLD_TO_CHECK (128)
#endif

/* When MALLOC_PROFILING_EXTRA is true, we add the  */
/* following value to the end of block, so  */
/* we can later check to see if it got      */
/* overwritten by something:                */
#ifndef CRT_MAGIC
#define CRT_MAGIC ((char)231)
#endif
/* Something we write into the magic byte  */
/* of a block just before free()ing it, so */
/* as to maybe diagnose repeated free()s:  */
#ifndef CRT_FREE_MAGIC
#define CRT_FREE_MAGIC ((char)~CRT_MAGIC)
#endif

/* }}} */
/* {{{ block_list, a list of all malloc/free/etc calls in host program.	*/

/* Central data structure: a blocklist with one entry  */
/* for each textually distinct [mc]alloc() call:       */

struct CrT_block_rec {
	const char *file;
	int line;

	long tot_bytes_alloc;
	long tot_allocs_done;
	long live_blocks;
	long live_bytes;
	long max_blocks;
	long max_bytes;
	time_t max_bytes_time;

	struct CrT_block_rec *next;
};
typedef struct CrT_block_rec A_Block;
typedef struct CrT_block_rec *Block;

static Block block_list = NULL;

/* }}} */
/* {{{ Header, a header we add to each block allocated: 		*/

struct CrT_header_rec {
	Block b;
	size_t size;
#ifdef MALLOC_PROFILING_EXTRA
	struct CrT_header_rec *next;
	struct CrT_header_rec *prev;
	char *end;
#endif
};
typedef struct CrT_header_rec A_Header;
typedef struct CrT_header_rec *Header;

/* }}} */
/* {{{ Globals supporting debug functionality.				*/

#ifdef MALLOC_PROFILING_EXTRA
static A_Block Root_Owner = {

	__FILE__,					/* file */
	__LINE__,					/* line */

	0,							/* tot_bytes_alloc */
	0,							/* tot_allocs_done */
	0,							/* live_blocks     */
	0,							/* live_bytes      */
	0,							/* max_blocks      */
	0,							/* max_bytes       */
	0,							/* max_bytes_time  */

	NULL						/* next            */
};

static char root_end = CRT_MAGIC;

static A_Header root = {
	&Root_Owner,				/* b    */
	0,							/* size */
	&root,						/* next */
	&root,						/* prev */
	&root_end,					/* end  */
};

/* Clockhand that we run circularly around  */
/* allocated-block list, looking for probs: */
static Header rover = &root;

/* Macro to insert block m into 'root' linklist: */
#undef  INSERT
#define INSERT(m) {			\
    root. next->prev =  (m);		\
   (m)        ->next =  root.next;	\
   (m)        ->prev = &root;		\
    root.       next =  (m);		\
    }

/* Macro to remove block m from 'root' linklist: */
#undef  REMOVE
#define REMOVE(m) {			\
   (m)->next->prev = (m)->prev;		\
   (m)->prev->next = (m)->next;		\
    }

/* An array tracking last CRT_NEW_TO_CHECK blocks touched: */
static Header just_touched[CRT_NEW_TO_CHECK] = {
	/* I can't think of an elegant way of generating the */
	/* right number of initializers automatically via    */
	/* cpp :( so:                                        */
	&root, &root, &root, &root,
	&root, &root, &root, &root,
	&root, &root, &root, &root,
	&root, &root, &root, &root,
	&root, &root, &root, &root,
	&root, &root, &root, &root,
	&root, &root, &root, &root,
	&root, &root, &root, &root,

	&root, &root, &root, &root,
	&root, &root, &root, &root,
	&root, &root, &root, &root,
	&root, &root, &root, &root,
	&root, &root, &root, &root,
	&root, &root, &root, &root,
	&root, &root, &root, &root,
	&root, &root, &root, &root,

	&root, &root, &root, &root,
	&root, &root, &root, &root,
	&root, &root, &root, &root,
	&root, &root, &root, &root,
	&root, &root, &root, &root,
	&root, &root, &root, &root,
	&root, &root, &root, &root,
	&root, &root, &root, &root,

	&root, &root, &root, &root,
	&root, &root, &root, &root,
	&root, &root, &root, &root,
	&root, &root, &root, &root,
	&root, &root, &root, &root,
	&root, &root, &root, &root,
	&root, &root, &root, &root,
	&root, &root, &root, &root,

};
static int next_touched = 0;	/* Always indexes above. */

#endif

/* }}} */
/* {{{ Random internal macro stuff					*/

/* Undefine the macros which make the rest */
/* of the system call our wrappers instead */
/* of calling malloc &Co directly:	   */
#undef malloc
#undef calloc
#undef realloc
#undef free

/* Number of bytes of overhead we add to a block: */
#ifdef MALLOC_PROFILING_EXTRA
#define CRT_OVERHEAD_BYTES (sizeof(A_Header) +1)
#else
#define CRT_OVERHEAD_BYTES (sizeof(A_Header)   )
#endif

/* }}} */

/* }}} */

/* {{{ sorting -- Some fns to implement a simple block_list merge-sort. */

/* Currently, sorts on live_bytes field. */

/* {{{ block_count -- Count number of blocks in a blocklist.		*/

static int
block_count(Block b)
{
	int i;

	for (i = 0; b; b = b->next)
		++i;
	return i;
}

/* }}} */
/* {{{ blocks_nth -- Return nth block in a blocklist.			*/

static Block
blocks_nth(						/* Return nth block in list, first is #0. */
			  Block b, int n)
{
	int i;

	for (i = 0; i < n; b = b->next)
		++i;
	return b;
}

/* }}} */
/* {{{ blocks_split -- Split blocklist 'b' into two lists, return 2nd. 	*/

static Block
blocks_split(Block b, int n		/* Nth block becomes first in 2nd list. */
		)
{
	Block tail = blocks_nth(b, n - 1);
	Block head = tail->next;

	tail->next = NULL;
	return head;
}

/* }}} */
/* {{{ blocks_merge -- Merge two sorted lists into one sorted list. 	*/

static Block
blocks_merge(					/* Merge two sorted lists into one. */
				Block b0, Block b1)
{
	A_Block head;
	Block tail = &head;

	while (b0 || b1) {
		Block nxt;

		if (!b1) {
			nxt = b0;
			b0 = b0->next;
		} else if (!b0) {
			nxt = b1;
			b1 = b1->next;
		} else if (b0->live_bytes < b1->live_bytes) {
			nxt = b0;
			b0 = b0->next;
		} else {
			nxt = b1;
			b1 = b1->next;
		}

		tail->next = nxt;
		tail = nxt;
	}

	tail->next = NULL;

	return head.next;
}

/* }}} */
/* {{{ blocks_merge -- Sort blocklist on 'live_bytes'.		 	*/

static Block
blocks_sort(					/* Sort 'b1' on 'live_bytes'. */
			   Block b1)
{
	int len = block_count(b1);

	if (len < 2)
		return b1;

	{
		Block b2 = blocks_split(b1, len / 2);

		return blocks_merge(blocks_sort(b1), blocks_sort(b2)
				);
	}
}

/* }}} */

/* }}} */

/* {{{ blocks_alloc -- Alloc block for given file/line.			*/

static Block
block_alloc(const char *file, int line)
{
	Block b = malloc(sizeof(A_Block));

	b->file = file;
	b->line = line;

	b->tot_bytes_alloc = 0;
	b->tot_allocs_done = 0;
	b->live_blocks = 0;
	b->live_bytes = 0;
	b->max_blocks = 0;
	b->max_bytes = 0;

	b->next = block_list;
	block_list = b;
	return b;
}

/* }}} */
/* {{{ blocks_find -- Find block for file/line, maybe creating.		*/

static Block
block_find(const char *file, int line)
{
	Block b;

	for (b = block_list; b; b = b->next) {
		if (b->line == line && !strcmp(b->file, file)
				) {
			return b;
		}
	}
	return block_alloc(file, line);
}

/* }}} */

/* Report generation functions:						*/
/* {{{ CrT_summarize -- Summarize ram usage statistics.			*/

/* {{{ CrT_timestr -- Return ascii timestring in static buffer.		*/

const char *
CrT_timestr(time_t when)
{
	static char buf[20];
	struct tm *da_time;
#ifndef WIN32
	da_time = localtime(&when);
#else
	da_time = uw32localtime(&when);
#endif
	snprintf(buf, sizeof(buf), "%02d%02d%02d%02d",
			da_time->tm_mday, da_time->tm_hour, da_time->tm_min, da_time->tm_sec);
	return buf;
}

/* }}} */

static dbref summarize_player;

static void
summarize(void (*fn) (char *)
		)
{
	Block b;

	int sum_blks = 0;
	int sum_byts = 0;
	int sum_totblks = 0;
	int sum_totbyts = 0;

	char buf[256];

	block_list = blocks_sort(block_list);

#undef  X
#define X(t) (*fn)(t);
	X("         File Line CurBlks CurBytes MaxBlks MaxBytes MxByTime TotBlks TotBytes");
	X("------------- ---- ------- -------- ------- -------- -------- ------- --------")

			for (b = block_list; b; b = b->next) {

		sum_blks += b->live_blocks;
		sum_byts += b->live_bytes;

		sum_totblks += b->tot_allocs_done;
		sum_totbyts += b->tot_bytes_alloc;

		snprintf(buf, sizeof(buf),
				"%13s%5d:%7d %8d %7d %8d %8s %7d %8d",
				b->file,
				b->line,
				b->live_blocks,
				b->live_bytes,
				b->max_blocks,
				b->max_bytes,
				CrT_timestr(b->max_bytes_time), b->tot_allocs_done, b->tot_bytes_alloc);
		X(buf);
	}
	snprintf(buf, sizeof(buf), " Cumulative totals:%7d %8d                           %7d %8d",
			sum_blks, sum_byts, sum_totblks, sum_totbyts);
	X(buf);
}

static void
summarize_notify(char *t)
{
	notify(summarize_player, t);
}

void
CrT_summarize(dbref player)
{
	summarize_player = player;
	summarize(summarize_notify);
}

/* }}} */
/* {{{ CrT_summarize_to_file -- Summarize ram usage in given logfile.	*/

static FILE *summarize_fd;

static void
summarize_to_file(char *t)
{
	fprintf(summarize_fd, "%s\n", t);
}

void
CrT_summarize_to_file(const char *file, const char *comment)
{
	if ((summarize_fd = fopen(file, "a")) == 0)
		return;
	if (comment && *comment) {
		fprintf(summarize_fd, "%s\n", comment);
	} {
		time_t lt = time(NULL);

		fprintf(summarize_fd, "%s", ctime(&lt));
	}

	summarize(summarize_to_file);

	fclose(summarize_fd);
}

/* }}} */

#ifdef MALLOC_PROFILING_EXTRA

/* Debug support functions: */
/* {{{ CrT_check -- abort if we can find any trashed malloc blocks.	*/

/* {{{ crash -- coredump with diagnostic.				*/

static void
crash2(char *err)
{
	abort();
}

static void
crash(char *err, Header m, const char *file, int line)
{
	char buf[256];

	snprintf(buf, sizeof(buf), "Err found at %s:%d in block from %s:%d", file, line, m->b->file, m->b->line);
	crash2(buf);				/* Makes above easy to read from dbx 'where'.   */
}

/* }}} */
/* {{{ check_block							*/

static void
check_block(Header m, const char *file, int line)
{
	if (*m->end != CRT_MAGIC)
		crash("Bottom overwritten", m, file, line);
	if (m->next->prev != m)
		crash("next->prev != m", m, file, line);
	if (m->prev->next != m)
		crash("prev->next != m", m, file, line);
}

/* }}} */
/* {{{ check_old_blocks							*/

static void
check_old_blocks(const char *file, int line)
{
	int i = CRT_OLD_TO_CHECK;

	while (i-- > 0) {
		check_block(rover, file, line);
		rover = rover->next;
	}
}

/* }}} */
/* {{{ check_new_blocks							*/

static void
check_new_blocks(const char *file, int line)
{
	int i = CRT_NEW_TO_CHECK;

	while (i-- > 0)
		check_block(just_touched[i], file, line);
}

/* }}} */

void
CrT_check(const char *file, int line)
{
	check_old_blocks(file, line);
	check_new_blocks(file, line);
}

/* }}} */
/* {{{ CrT_check_everything -- same, but check entire ram arena.	*/

int
CrT_check_everything(const char *file, int line)
{
	Header m = root.next;
	int i = 0;;
	for (; m != &root; ++i, m = m->next)
		check_block(m, file, line);
	return i;
}

/* }}} */
#endif							/* CRT_DEUG_ALSO */

/* The actual wrappers for malloc/calloc/realloc/free: */
/* {{{ CrT_malloc							*/

void *
CrT_malloc(size_t size, const char *file, int line)
{
	Block b = block_find(file, line);

	Header m = (Header) malloc(size + CRT_OVERHEAD_BYTES);

	if (!m) {
		fprintf(stderr, "CrT_malloc(): Out of Memory!\n");
		abort();
	}

	m->b = b;
	m->size = size;



#ifdef MALLOC_PROFILING_EXTRA
	/* Look around for trashed ram blocks: */
	CrT_check(file, line);

	/* Remember where end of block is: */
	m->end = &((char *) m)[size + (CRT_OVERHEAD_BYTES - 1)];

	/* Write a sacred value at end of block: */
	*m->end = CRT_MAGIC;

	/* Thread m into linklist of allocated blocks: */
	INSERT(m);

	/* Remember we've touched 'm' recently: */
	just_touched[++next_touched & (CRT_NEW_TO_CHECK - 1)] = m;

#endif


	b->tot_bytes_alloc += size;
	b->tot_allocs_done++;
	b->live_blocks++;
	b->live_bytes += size;

	if (b->live_bytes > b->max_bytes) {
		b->max_bytes = b->live_bytes;
		b->max_bytes_time = time(NULL);
	}
	if (b->live_blocks > b->max_blocks)
		b->max_blocks = b->live_blocks;

	return (void *) (m + 1);
}

/* }}} */
/* {{{ CrT_calloc							*/

void *
CrT_calloc(size_t num, size_t siz, const char *file, int line)
{
	size_t size = siz * num;
	Block b = block_find(file, line);
	Header m = (Header) calloc(size + CRT_OVERHEAD_BYTES, 1);

	if (!m) {
		fprintf(stderr, "CrT_calloc(): Out of Memory!\n");
		abort();
	}

	m->b = b;
	m->size = size;



#ifdef MALLOC_PROFILING_EXTRA

	/* Look around for trashed ram blocks: */
	CrT_check(file, line);

	/* Remember where end of block is: */
	m->end = &((char *) m)[size + (CRT_OVERHEAD_BYTES - 1)];

	/* Write a sacred value at end of block: */
	*m->end = CRT_MAGIC;

	/* Thread m into linklist of allocated blocks: */
	INSERT(m);

	/* Remember we've touched 'm' recently: */
	just_touched[++next_touched & (CRT_NEW_TO_CHECK - 1)] = m;

#endif



	b->tot_bytes_alloc += size;
	b->tot_allocs_done++;
	b->live_blocks++;
	b->live_bytes += size;

	if (b->live_bytes > b->max_bytes) {
		b->max_bytes = b->live_bytes;
		b->max_bytes_time = time(NULL);
	}
	if (b->live_blocks > b->max_blocks)
		b->max_blocks = b->live_blocks;

	return (void *) (m + 1);
}

/* }}} */
/* {{{ CrT_realloc							*/

void *
CrT_realloc(void *p, size_t size, const char *file, int line)
{
	Header m = ((Header) p) - 1;
	Block b = m->b;

#ifdef MALLOC_PROFILING_EXTRA
	/* Look around for trashed ram blocks: */
	check_block(m, __FILE__, __LINE__);
	CrT_check(file, line);
	/* Don't clobber 'rover': */
	if (rover == m) {
		rover = rover->next;
	}
	/* Remove m from linklist of allocated blocks: */
	REMOVE(m);
	/* Remove m from just_touched[], if present: */
	{
		int i = CRT_NEW_TO_CHECK;

		while (i-- > 0) {
			if (just_touched[i] == m) {
				just_touched[i] = &root;
			}
		}
	}
#endif

	m = (Header) realloc(m, size + CRT_OVERHEAD_BYTES);

	if (!m) {
		fprintf(stderr, "CrT_realloc(): Out of Memory!\n");
		abort();
	}

	b->live_bytes -= m->size;
	b->live_bytes += size;

	m->size = size;

#ifdef MALLOC_PROFILING_EXTRA

	/* Remember where end of block is: */
	m->end = &((char *) m)[size + (CRT_OVERHEAD_BYTES - 1)];

	/* Write a sacred value at end of block: */
	*m->end = CRT_MAGIC;

	/* Thread m into linklist of allocated blocks: */
	INSERT(m);

	/* Remember we've touched 'm' recently: */
	just_touched[++next_touched & (CRT_NEW_TO_CHECK - 1)] = m;

#endif



	if (b->live_bytes > b->max_bytes) {
		b->max_bytes = b->live_bytes;
		b->max_bytes_time = time(NULL);
	}

	return (void *) (m + 1);
}

/* }}} */
/* {{{ CrT_free								*/

void
CrT_free(void *p, const char *file, int line)
{
	Header m = ((Header) p) - 1;
	Block b = m->b;

#ifdef MALLOC_PROFILING_EXTRA
	/* Look around for trashed ram blocks: */
	if (*m->end == CRT_FREE_MAGIC)
		crash("Duplicate free()", m, file, line);

	check_block(m, __FILE__, __LINE__);
	CrT_check(file, line);
	/* Don't clobber 'rover': */
	if (rover == m) {
		rover = rover->next;
	}
	/* Remove m from linklist of allocated blocks: */
	REMOVE(m);
	/* Remove m from just_touched[], if present: */
	{
		int i = CRT_NEW_TO_CHECK;

		while (i-- > 0) {
			if (just_touched[i] == m) {
				just_touched[i] = &root;
			}
		}
	}
	/* Mark m so as to give some chance of */
	/* diagnosing repeat free()s of same   */
	/* block:                              */
	*m->end = CRT_FREE_MAGIC;
#endif

	b->live_bytes -= m->size;
	b->live_blocks--;

	free(m);
}

/* }}} */

/* Some convenience functions:						*/
/* {{{ CrT_alloc_string							*/

char *
CrT_alloc_string(const char *string, const char *file, int line)
{
	char *s;

	/* NULL, "" -> NULL */
	if (!string || !*string)
		return 0;

	if ((s = (char *) CrT_malloc(strlen(string) + 1, file, line)) == 0) {
		abort();
	}
	strcpy(s, string);
	return s;
}

/* }}} */
/* {{{ CrT_alloc_prog_string							*/

struct shared_string *
CrT_alloc_prog_string(const char *s, const char *file, int line)
{
	struct shared_string *ss;
	int length;

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

	length = strlen(s);
	if ((ss = (struct shared_string *)
		 CrT_malloc(sizeof(struct shared_string) + length, file, line)) == NULL)
		abort();

	ss->links = 1;
	ss->length = length;
	bcopy(s, ss->data, ss->length + 1);
	return (ss);
}

/* }}} */
/* {{{ CrT_string_dup							*/

char *
CrT_string_dup(const char *s, const char *file, int line)
{
	char *p;

	p = (char *) CrT_malloc(1 + strlen(s), file, line);
	if (p)
		strcpy(p, s);
	return (p);
}

/* }}} */

#endif							/* MALLOC_PROFILING */

/* {{{ File variables							*/
/*

Local variables:
case-fold-search: nil
folded-file: t
fold-fold-on-startup: nil
End:
*/
/* }}} */