Mud20/accounts/
Mud20/accounts/c/
Mud20/accounts/f/
Mud20/accounts/k/
Mud20/accounts/s/
Mud20/accounts/t/
Mud20/area_current/
Mud20/area_current/newareas/
Mud20/bin/
Mud20/clans/
Mud20/gods/
Mud20/old-sources/
Mud20/player/
Mud20/player/a/del/
Mud20/player/b/
Mud20/player/b/bak/
Mud20/player/b/del/
Mud20/player/f/
Mud20/player/f/bak/
Mud20/player/f/del/
Mud20/player/k/
Mud20/player/k/bak/
Mud20/player/k/del/
Mud20/player/k/dmp/
Mud20/player/m/
Mud20/player/m/bak/
Mud20/player/o/
Mud20/player/o/bak/
Mud20/player/p/
Mud20/player/s/
Mud20/player/s/bak/
Mud20/player/s/del/
Mud20/player/t/
Mud20/player/t/del/
Mud20/player/v/
Mud20/public_html/
Mud20/races/
Mud20/skilltables/
__MACOSX/Mud20/accounts/
__MACOSX/Mud20/accounts/c/
__MACOSX/Mud20/accounts/f/
__MACOSX/Mud20/accounts/k/
__MACOSX/Mud20/accounts/s/
__MACOSX/Mud20/area_current/
__MACOSX/Mud20/area_current/core_areas/
__MACOSX/Mud20/area_current/helps/
__MACOSX/Mud20/area_current/newareas/
__MACOSX/Mud20/backups/
__MACOSX/Mud20/bin/
__MACOSX/Mud20/clans/
__MACOSX/Mud20/gods/
__MACOSX/Mud20/log/
__MACOSX/Mud20/old-sources/
__MACOSX/Mud20/player/
__MACOSX/Mud20/player/a/del/
__MACOSX/Mud20/player/b/
__MACOSX/Mud20/player/b/bak/
__MACOSX/Mud20/player/f/
__MACOSX/Mud20/player/f/bak/
__MACOSX/Mud20/player/f/del/
__MACOSX/Mud20/player/k/
__MACOSX/Mud20/player/k/bak/
__MACOSX/Mud20/player/k/del/
__MACOSX/Mud20/player/k/dmp/
__MACOSX/Mud20/player/m/
__MACOSX/Mud20/player/m/bak/
__MACOSX/Mud20/player/o/
__MACOSX/Mud20/player/o/bak/
__MACOSX/Mud20/player/p/
__MACOSX/Mud20/player/s/
__MACOSX/Mud20/player/s/bak/
__MACOSX/Mud20/player/t/del/
__MACOSX/Mud20/player/v/
__MACOSX/Mud20/public_html/
__MACOSX/Mud20/races/
__MACOSX/Mud20/skilltables/
/***************************************************************************
 * Mud20 1.0 by Todd H. Johnson (Kregor) a derivative of the Open Gaming   *
 * License by Wizards of the Coast. All comments referring to D20, OGL,    *
 * and SRD refer to the System Reference Document for the Open Gaming      *
 * system. Any inclusion of these derivatives must include credit to the   *
 * Mud20 system, the full and complete Open Gaming LIcense, and credit to  *
 * the respective authors. See ../doc/srd.txt for more information.        *
 *                                                                         *
 * Emud  2.2 by Igor van den Hoven, Michiel Lange, and Martin Bethlehem.   *
 *                                                                         *
 * MrMud 1.4 by David Bills, Dug Michael and Martin Gallwey                *
 *                                                                         *
 * Merc  2.1 Diku Mud improvments copyright (C) 1992, 1993 by Michael      *
 * Chastain, Michael Quan, and Mitchell Tse.                               *
 *                                                                         *
 * Original Diku Mud copyright (C) 1990 1991 by Sebastian Hammer,          *
 * Michael Seifert, Hans Henrik St{rfeld, Tom Madsen, and Katje Nyboe.     *
 ***************************************************************************/

#include "mud.h"

#define MAX_STR_HASH	100000

STR_HASH_DATA *str_hash[MAX_STR_HASH];

unsigned short str_leng_alloc = 0;

/*
	Generate a kinky hash index - Scandum
*/

unsigned int get_hash( char *str)
{
	unsigned int h;

	for (h = str_leng_alloc = 0 ; *str != 0 ; str++, str_leng_alloc++)
	{
		h -= (4 - (h >> 7)) * *str;
	}

	h = (h + str_leng_alloc) % MAX_STR_HASH;

	return h;
}


char *str_alloc( char *str )
{
	unsigned int hash;
	STR_HASH_DATA *hash_ptr;

	push_call("str_alloc(%p)",str);

	hash  = get_hash(str);

	for (hash_ptr = str_hash[hash] ; hash_ptr ; hash_ptr = hash_ptr->next)
	{
		if (*str == *((char *) hash_ptr+mud->str_hash_size) && !strcmp(str, (char *) hash_ptr+mud->str_hash_size))
		{
			hash_ptr->links++;

			pop_call();
			return (char *) hash_ptr+mud->str_hash_size;
		}
	}

	ALLOCMEM(hash_ptr, unsigned char, str_leng_alloc + mud->str_hash_size + 1);

	hash_ptr->links  = 1;
	hash_ptr->hash   = hash;

	strcpy( (char *) hash_ptr+mud->str_hash_size, str );

	if (str_hash[hash] != NULL)
	{
		hash_ptr->next = str_hash[hash];
		str_hash[hash]->prev = hash_ptr;
	}
	str_hash[hash] = hash_ptr;

	pop_call();
	return (char *) hash_ptr+mud->str_hash_size;
}


char *str_dupe( char *str )
{
	STR_HASH_DATA *str_ptr;

	push_call("str_dupe(%p)",str);

	str_ptr = (STR_HASH_DATA *) (str - mud->str_hash_size);

	str_ptr->links++;

	pop_call();
	return str;
}


void str_free( char *str )
{
	STR_HASH_DATA *str_ptr;

	push_call("str_free(%p)",str);

	if (str == NULL)
	{
		pop_call();
		return;
	}

	str_ptr = (STR_HASH_DATA *) (str - mud->str_hash_size);

	if (--str_ptr->links == 0)
	{
		if (str_ptr->prev)
		{
			str_ptr->prev->next = str_ptr->next;
		}
		else
		{
			str_hash[str_ptr->hash] = str_ptr->next;
		}
		if (str_ptr->next)
		{
			str_ptr->next->prev = str_ptr->prev;
		}
		FREEMEM(str_ptr);
	}
	pop_call();
	return;
}


char *str_hash_status( char *argument )
{
	STR_HASH_DATA *hash_ptr;
	static char buf[MAX_STRING_LENGTH];
	bool hashamounts[MAX_STR_HASH];
	int hihash, hihashcnt, usedhash, cnt, strings, links, ulinks, memoryused, memorysaved, maxlink, maxlinkcnt;

	push_call("str_hash_status(%p)",argument);

	memorysaved = maxlink = maxlinkcnt = strings = ulinks = links = memoryused = hihashcnt = hihash = usedhash = 0;

	memset(hashamounts, 0, MAX_STR_HASH);

	if (is_number(argument))
	{
		for (buf[0] = '\0', hash_ptr = str_hash[URANGE(0, atol(argument), MAX_STR_HASH - 1)] ; hash_ptr ; hash_ptr = hash_ptr->next)
		{
			cat_sprintf(buf, "- %s\n", (char *) hash_ptr+mud->str_hash_size);
		}
		pop_call();
		return buf;
	}

	for (buf[0] = cnt = 0 ; cnt < MAX_STR_HASH ; cnt++)
	{
		for (hash_ptr = str_hash[cnt] ; hash_ptr ; hash_ptr = hash_ptr->next)
		{
			hashamounts[cnt]++;

			if (hash_ptr->links == 1)
			{
				ulinks++;
			}

			if (*argument == 'd')
			{
				if (hash_ptr->links > 500)
				{
					cat_sprintf(buf, "{078}[%6d] links: %s\n\r", hash_ptr->links, (char *) hash_ptr+mud->str_hash_size);
				}

				if (get_hash((char *) hash_ptr+mud->str_hash_size) != cnt)
				{
					log_printf("Found a bad string in hash table index: %d", cnt);
					log_printf("-- current string  --");
					log_printf("%s", (char *) hash_ptr+mud->str_hash_size);
					log_printf("-- previous string --");
					log_printf("%s", hash_ptr->prev ? (char *) hash_ptr->prev+mud->str_hash_size : "(null");
					log_printf("-- adjacent string --");
					log_printf("%s", hash_ptr->next ? (char *) hash_ptr->next+mud->str_hash_size : "(null");
				}
			}

			if (hash_ptr->links > maxlink)
			{
				maxlink    = hash_ptr->links;
				maxlinkcnt = cnt;
			}

			links       += hash_ptr->links;
			memoryused  += strlen((char *) hash_ptr + mud->str_hash_size) + mud->str_hash_size + 1;
			memorysaved += hash_ptr->links * (1 + strlen((char *) hash_ptr + mud->str_hash_size));
		}
	}

	for (cnt = 0 ; cnt < MAX_STR_HASH ; cnt++)
	{
		strings += hashamounts[cnt];

		if (hashamounts[cnt] > hihash)
		{
			hihash    = hashamounts[cnt];
			hihashcnt = cnt;
		}
		if (hashamounts[cnt] > 0)
		{
			usedhash++;
		}
	}

	cat_sprintf(buf,
		"{078}Strings allocated :%10d   Total links     :%10d\n\r"
		"{078}Memory allocated  :%10d   Memory saved    :%10d\n\r"
		"{078}Unique links      :%10d   Average hash    :%10.3f\n\r"
		"{078}Maximum links     :%10d   Max links index :%10d\n\r"
		"{078}Maximum Hash      :%10d   Max hash index  :%10d\n\r"
		"{078}Used Hash:        :%10d   Hash size       :%10d\n\r",
		strings,
		links,
		memoryused,
		memorysaved - memoryused,
		ulinks,
		(float) strings / (float) usedhash,
		maxlink,
		maxlinkcnt,
		hihash,
		hihashcnt,
		usedhash,
		MAX_STR_HASH);

	pop_call();
	return buf;
}