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.     *
 ***************************************************************************/

/***************************************************************************
 * string_handler.c: All string functions merged from other files into here
 * for easier location and management - Kregor
 ***************************************************************************/

#include <unistd.h>
#include <stdarg.h>

#include "mud.h"

char		ansi_strip_txt[MAX_STRING_LENGTH];

/*
	Removes the tildes from a string.
	Used for player-entered strings that go into disk files.
*/
void smash_tilde( char *str )
{
	push_call("smash_tilde(%p)",str);

	for ( ; *str != '\0' ; str++)
	{
		if (*str == '~')
		{
			*str = '-';
		}
	}
	pop_call();
	return;
}


/*
	gives back string length not including color codes - Scandum 10-05-2002
*/

int ansi_strlen(char *text)
{
	int length = 0;

	push_call("ansi_strlen(%p)",text);

	while (*text != '\0')
	{
		if (*text == '{')
		{
			if (*(text+1) >= '0' && *(text+1) <= '8'
			&&  *(text+2) >= '0' && *(text+2) <= '8'
			&&  *(text+3) >= '0' && *(text+3) <= '8')
			{
				if (*(text+4) == '}')
				{
					text += 5;
					continue;
				}
			}
		}
		text++;
		length++;
	}
	pop_call();
	return length;
}

bool str_prefix( const char *astr, const char *bstr )
{
	return strncasecmp(astr, bstr, strlen(astr));
}

/*
	Compare strings, case insensitive, for match anywhere.
	Returns TRUE is astr not part of bstr.
	(compatibility with historical functions).
*/

bool str_infix( const char *astr, const char *bstr )
{
	int sstr1;
	int sstr2;
	int ichar;
	char c0;

	push_call("str_infix(%p,%p)",astr,bstr);

	if ((c0 = LOWER(astr[0])) == '\0')
	{
		pop_call();
		return FALSE;
	}

	sstr1 = strlen(astr);
	sstr2 = strlen(bstr);

	for (ichar = 0 ; ichar <= sstr2 - sstr1 ; ichar++)
	{
		if (c0 == LOWER(bstr[ichar]) && !str_prefix(astr, bstr + ichar))
		{
			pop_call();
			return FALSE;
		}
	}
	pop_call();
	return TRUE;
}

/*
	Compare strings, case insensitive, for suffix matching.
	Return TRUE if astr not a suffix of bstr
	(compatibility with historical functions).
*/

bool str_suffix( const char *astr, const char *bstr )
{
	int sstr1;
	int sstr2;

	push_call("str_suffix(%p,%p)",astr,bstr);

	sstr1 = strlen(astr);
	sstr2 = strlen(bstr);

	if (sstr1 <= sstr2 && !strcasecmp((char *)astr, (char *) (bstr + sstr2 - sstr1)))
	{
		pop_call();
		return FALSE;
	}
	else
	{
		pop_call();
		return TRUE;
	}
}

/*
	Returns a string of the specified length, containing at most the first
	length number of characters of st, will pad if necessary
	if length is positive, string will be right justified, if length is
	negative it will left justify.
	Edited to ignore color codes - Kregor 5/15/10
*/

char *str_resize(const char *st, char *buf, int length)
{
	const char *f;
	char *t;
	int  stLen;
	bool rightJustified;

	push_call("str_resize(%p,%p,%p)",st,buf,length);

	buf[0] = '\0';
	rightJustified = (length >= 0);

	if (!rightJustified)
	{
		length =- length;
	}
	stLen = ansi_strlen((char*)st);

	if ((!rightJustified) || (stLen >= length))
	{
		for (f = st, t = buf ; (*f != 0) && (length > 0) ; f++, t++, length--)
		{
			if (*f == '{' && *(f+4) == '}')
				length += 5;
			*t = *f;
		}
		if (length > 0)
		{
			for ( ; length > 0 ; length--, t++)
			{
				*t = ' ';
			}
		}
		*t = '\0';
	}
	else if (length != 0)
	{
		for (t = buf ; length > stLen ; t++, length--)
		{
			*t = ' ';
		}
		if (length != 0)
		{
			for (f = st ; (*f != 0) && (length > 0) ; f++, t++, length--)
			{
				if (*f == '{' && *(f+4) == '}')
					length += 5;
				*t = *f;
			}
		}
		*t = '\0';
	}
	pop_call();
	return buf;
}

/*
	Get a or an depending on input
*/

char *a_an( const char *argument )
{
	static char prefix[3];

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

	switch (tolower(argument[0]))
	{
		case 'a':
		case 'e':
		case 'i':
		case 'o':
		case 'u':
			strcpy(prefix, "an");
			break;
		default:
			strcpy(prefix, "a");
			break;
	}
	pop_call();
	return prefix;
}

/*
 * Format number with commas
 * (credit to jose@luisso.net) - Kregor
 */
char *format_number(int num)
{
	int index, ptr, rest;
	char buf1[20];
	static char buf2[20];
	
	push_call("format_number(%p)",num);

	sprintf(buf1, "%d", num);
	rest = strlen(buf1) % 3;
	
	for (index = ptr = 0 ; index < strlen(buf1) ; index++ , ptr++)
	{
		if (index != 0 && (index - rest) % 3 == 0 )
		{
			buf2[ptr]=',';
			ptr++;
			buf2[ptr]=buf1[index];	
		}
		else
			buf2[ptr] = buf1[index];
	}
	buf2[ptr] = '\0';
	
	pop_call();
	return buf2;
}

/*
	Return first part of an IP address
*/

char *get_domain( const char *str )
{
	static char strbuf[MAX_INPUT_LENGTH];
	int i;

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

	strcpy(strbuf, str);

	for (i = 0 ; strbuf[i] != 0 ; i++)
	{
		if (strbuf[i] == '.')
		{
			break;
		}
	}

	for (i++ ; strbuf[i] != 0 ; i++)
	{
		if (strbuf[i] == '.')
		{
			break;
		}
	}

	strbuf[i] = 0;

	pop_call();
	return strbuf;
}

/*
	Convert a short description into a name - Scandum
*/

char *short_to_name( const char *str, int amount )
{
	static char strstn[MAX_INPUT_LENGTH];
	char clr[MAX_INPUT_LENGTH];
	char strbuf[MAX_INPUT_LENGTH];
	char *strpt;

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

	if (str == NULL)
	{
		pop_call();
		return amount == 1 ? "trash" : "pieces of trash";
	}
	
	if (!str_prefix("{", str))
	{
		strcpy(clr, str);
		clr[5] = '\0';
		str = &str[5];
	}
	else
	{
		strcpy(clr, "");
	}	

	if (!str_prefix("an ", str))
	{
		strcpy(strstn, &str[3]);
	}
	else if (!str_prefix("a ", str))
	{
		strcpy(strstn, &str[2]);
	}
	else if (!str_prefix("the ", str))
	{
		strcpy(strstn, &str[4]);
	}
	else if (!str_prefix("some ", str))
	{
		strcpy(strstn, &str[5]);
	}
	else
	{
		strcpy(strstn, str);
	}

	if (amount == 1)
	{
		pop_call();
		return strstn;
	}

	if ((strpt = strstr(strstn, " of ")) != NULL)
	{
		strcpy(strbuf, strpt);
		*strpt = '\0';
	}

	if (!str_suffix("ife", strstn))
	{
		strstn[strlen(strstn)-2] = 'v';
	}

	if (!str_suffix("ff", strstn))
	{
		strstn[strlen(strstn)-2] = 'v';
		strstn[strlen(strstn)-1] = 'e';
	}

	if (!str_suffix("f", strstn))
	{
		strstn[strlen(strstn)-1] = 'v';

		strcat(strstn, "e");
	}

	if (!str_suffix("ch", strstn))
	{
		strcat(strstn, "es");
	}

	if (!str_suffix("x", strstn))
	{
		strcat(strstn, "es");
	}

	if (str_suffix("s", strstn))
	{
		strcat(strstn, "s");
	}

	if (strpt)
	{
		strcat(strstn, strbuf);
	}
	
	strcat(clr, strstn);
	sprintf(strstn, "%s", clr);

	pop_call();
	return strstn;
}


/*
	Turn given integer into a time string - Scandum
*/

char *get_time_string( long time )
{
	char *time_string;

	push_call("get_time_string(%p)",time);

	time_string = ctime(&time);

	time_string[strlen(time_string)-1] = '\0';

	pop_call();
	return time_string;
}

/*
	Add th,st,nd,rd to numbers - Scandum
*/

char *numbersuf( int number )
{
	static char time[100];

	push_call("numbersuf(%d)",number);

	if (number > 4 && number <  20)
	{
		sprintf(time, "%dth", number);
	}
	else if (number % 10 ==  1)
	{
		sprintf(time, "%dst", number);
	}
	else if (number % 10 ==  2)
	{
		sprintf(time, "%dnd", number);
	}
	else if (number % 10 ==  3)
	{
		sprintf(time, "%drd", number);
	}
	else
	{
		sprintf(time, "%dth", number);
	}
	pop_call();
	return time;
}

/*
	Turns military time into civilian time - Scandum
*/

char *tocivilian( int hour )
{
	static char time[10];

	push_call("tocivilian(%d)",hour);

	sprintf(time, "%d %s", hour % 12 != 0 ? hour % 12 : 12, hour >= 12 ? "pm" : "am");

	pop_call();
	return time;
}

char *capitalize_all( const char *str )
{
	static char strcap[MAX_STRING_LENGTH];
	char *pti, *pto;

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

	if (str == NULL)
	{
		*strcap = '\0';
		pop_call();
		return strcap;
	}
	pti = (char *)str;
	pto = (char *)strcap;
	for ( ; *pti != '\0' ; pti++, pto++)
	{
		*pto = UPPER(*pti);
	}
	*pto = '\0';
	pop_call();
	return strcap;
}

char *lower_all( const char *str )
{
	static char strcap[MAX_STRING_LENGTH];
	char *pti, *pto;

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

	if (str == NULL)
	{
		*strcap = '\0';
		pop_call();
		return strcap;
	}
	pti = (char *)str;
	pto = (char *)strcap;
	for ( ; *pti != '\0' ; pti++, pto++)
	{
		*pto = LOWER(*pti);
	}
	*pto = '\0';
	pop_call();
	return strcap;
}

/*
	Returns an initial-capped string.
	!!!!!  Do not use more than one capitalize in a sprintf or other
	similar command.  Only the last one is read for all values,
	since the static variables are all set before the sprintf puts
	everything together.         Chaos 12/26/94
*/


char *capitalize( const char *str )
{
	static char strcap[MAX_STRING_LENGTH];
	char *pti, *pto;
	int x;

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

	if (str == NULL)
	{
		*strcap = '\0';
		pop_call();
		return strcap;
	}

	pti = (char *)str;
	pto = (char *)strcap;

	for ( ; *pti != '\0' ; pti++, pto++ )
	{
		*pto = *pti;
	}
	*pto = '\0';

	for (x = 0 ; strcap[x] != '\0' ; x++)
	{
		if (isalpha(strcap[x]))
		{
			*(strcap+x) = UPPER(*(strcap+x));
			break;
		}
	}
	pop_call();
	return strcap;
}

char *capitalize_name( const char *str )
{
	static char strcap[MAX_STRING_LENGTH];
	char *pti, *pto;

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

	if (str == NULL)
	{
		*strcap = '\0';
		pop_call();
		return strcap;
	}
	pti=(char *)str;
	pto=(char *)strcap;
	for ( ; *pti != '\0'; pti++, pto++ )
	{
		*pto=LOWER(*pti);
	}
	*pto = '\0';
	*strcap = UPPER(*strcap);
	pop_call();
	return strcap;
}

char *capitalize_title( const char *str )
{
	static char strcap[MAX_STRING_LENGTH];
	char *pti, *pto;
	int x;

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

	if (str == NULL)
	{
		*strcap = '\0';
		pop_call();
		return strcap;
	}

	pti = (char *)str;
	pto = (char *)strcap;

	for ( ; *pti != '\0' ; pti++, pto++ )
	{
		*pto = *pti;
	}
	*pto = '\0';

	for (x = 0 ; strcap[x] != '\0' ; x++)
	{
		if (isalpha(strcap[x]))
		{
			*(strcap+x) = UPPER(*(strcap+x));
			break;
		}
	}
	for (x = 0 ; strcap[x] != '\0' ; x++)
	{
		if (isalpha(strcap[x]) && strcap[x-1] == ' ')
		{
			*(strcap+x) = UPPER(*(strcap+x));
		}
	}
	pop_call();
	return strcap;
}

/*
	Returns a lowercase string.
*/

char *strlower( const char *str )
{
	static char strlow[MAX_STRING_LENGTH];
	int i;

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

	strlow[0] = '\0';
	
	for (i = 0 ; str[i] != '\0' ; i++)
	{
		strlow[i] = tolower(str[i]);
	}
	strlow[i] = '\0';

	pop_call();
	return strlow;
}

/*
	Returns an uppercase string.
*/

char *strupper( const char *str )
{
	static char strup[MAX_STRING_LENGTH];
	int i;

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

	for (i = 0 ; str[i] != '\0' ; i++)
	{
		strup[i] = toupper(str[i]);
	}
	strup[i] = '\0';

	pop_call();
	return strup;
}

int str_cat_max( const char *out_str, const char *add_str, int max_size )
{
	register char *str_pt1, *str_pt2;
	register int str_actual, str_size;

	push_call("str_cat_max(%p,%p,%p)",out_str,add_str,max_size);

	/*
		Set limits of size, and subtract for the terminator
	*/
	str_actual = UMIN(UMAX(1, max_size ), MAX_STRING_LENGTH) - 1;

	for (str_size = 0, str_pt1 = (char *)out_str ; *str_pt1 != '\0' ; str_pt1++, str_size++)
	{
		if (str_size == str_actual)
		{
			*str_pt1 = '\0';
			pop_call();
			return( str_size );
		}
	}
	for (str_pt2 = (char *)add_str ; *str_pt2 != '\0' ; str_pt1++, str_pt2++, str_size++)
	{
		if (str_size == str_actual)
		{
			*str_pt1= '\0';
			pop_call();
			return( str_size );
		}
		else
		{
			*str_pt1=*str_pt2;
		}
	}
	*str_pt1='\0';
	pop_call();
	return( str_size );
}


int str_apd_max( const char *out_str, const char *add_str, int start, int max_size )
{
	register char *str_pt1, *str_pt2;
	register int str_actual, str_size;

	push_call("str_apd_max(%p,%p,%d,%d)",out_str,add_str,start,max_size);

	if (out_str == NULL)
	{
		log_printf("str_apd_max(): out_str = NULL.");
		pop_call();
		return 0;
	}

	str_actual = URANGE(1, max_size - 1, MAX_STRING_LENGTH - 1);

	if (str_actual <= start)
	{
		*((char *) out_str + str_actual) = '\0';

		pop_call();
		return( str_actual );
	}

	str_pt1	= (char *) (out_str + start);
	str_size	= start;

	for (str_pt2 = (char *) add_str ; *str_pt2 != '\0' ; str_pt1++, str_pt2++, str_size++)
	{
		if (str_size == str_actual)
		{
			break;
		}
		else
		{
			*str_pt1 = *str_pt2;
		}
	}
	*str_pt1 = '\0';

	pop_call();
	return( str_size );
}

int str_cpy_max( const char *out_str, const char *add_str, int max_size )
{
	register char *str_pt1, *str_pt2;
	register int str_actual, str_size;

	push_call("str_cpy_max(%p,%p,%p)",out_str,add_str,max_size);

	/*
		Set limits of size, and subtract for the terminator
	*/

	str_actual = URANGE(0, max_size, MAX_STRING_LENGTH-1);

	str_pt1 = (char *)out_str;
	str_pt2 = (char *)add_str;

	for (str_size = 0 ; *str_pt2 != '\0' ; str_pt1++, str_pt2++, str_size++)
	{
		if (str_size == str_actual)
		{
			*str_pt1 = '\0';
			pop_call();
			return( str_size );
		}
		else
		{
			*str_pt1 = *str_pt2;
		}
	}
	*str_pt1 = '\0';

	pop_call();
	return( str_size );
}


/*
 * Sprintf a string with act targets to buffer.
 * A cool hack of act for neat pose and affects descs - Kregor
 */
void act_sprintf( char *dest, const char *format, CHAR_DATA *ch, const void *arg1, const void *arg2 )
{
	char txt[MAX_STRING_LENGTH];
	CHAR_DATA *vch = (CHAR_DATA *) arg2;
	OBJ_DATA *obj1 = (OBJ_DATA  *) arg1;
	OBJ_DATA *obj2 = (OBJ_DATA  *) arg2;
	const char *str;
	const char *i;
	char *point;

	push_call("act( %p,%p,%p,%p,%p)",format,ch,arg1,arg2);

	/*
		Discard null and zero-length messages.
	*/
	if (format == NULL || format[0] == '\0')
	{
		pop_call();
		return;
	}

	if (ch == NULL)
	{
		bug( "Act_sprintf: null ch.", 0 );
		pop_call();
		return;
	}

	point = txt;
	str = format;

	while ( *str != '\0' )
	{
		if (*str != '$')
		{
			*point++ = *str++;
			continue;
		}
		++str;

		if (arg1 == NULL && *str == 'p')
		{
			log_printf("Act_sprintf: missing arg1 for code %d.", *str);
			i = "<ppp>";
		}
		else if ( arg2 == NULL && *str >= 'A' && *str <= 'Z' )
		{
			log_printf("Act_sprintf: missing arg2 for code %d.", *str);
			i = "<A-Z>";
		}
		else
		{
			switch ( *str )
			{
				default:
					log_printf("Act: act bad code %d.", *str);
					i = "<? ?>";
					break;
				case 't':
					i = (char *) arg1;
					break;
				case 'T':
					i = (char *) arg2;
					break;
				case 'n':
					i = PERS( ch, vch );
					break;
				case 'N':
					i = PERS( vch, ch );
					break;
				case 'e':
					i = he_she  [URANGE(0, ch->sex,  2)];
					break;
				case 'E':
					i = he_she  [URANGE(0, vch->sex, 2)];
					break;
				case 'm':
					i = him_her [URANGE(0, ch->sex,  2)];
					break;
				case 'M':
					i = him_her [URANGE(0, vch->sex, 2)];
					break;
				case 's':
					i = his_her [URANGE(0, ch->sex,  2)];
					break;
				case 'S':
					i = his_her [URANGE(0, vch->sex, 2)];
					break;
				case 'p':
					i = OBJD( obj1, ch );
					break;
				case 'P':
					i = OBJD( obj2, ch );
					break;
				case '/':
					i = "\n\r";
					break;
			}
		}
		if (i == NULL)
		{
			log_string("act_sprintf: i == NULL");
			dump_stack();
			i = "nothing";
		}
		++str;
		while ((*point = *i) != '\0')
		{
			++point, ++i;
		}
	}
	*point++ = '{';
	*point++ = '3';
	*point++ = '0';
	*point++ = '0';
	*point++ = '}';
	*point++ = '\0';

	if (txt[0] == '{')
		txt[5] = UPPER(txt[5]);
	else
		txt[0] = UPPER(txt[0]);

	strcat(dest, txt);

	pop_call();
	return;
}


void cat_sprintf(char *dest, const char *fmt, ...)
{
	char buf[MAX_STRING_LENGTH];

	va_list args;

	va_start(args, fmt);
	vsprintf(buf, fmt, args);
	va_end(args);

	strcat(dest, buf);
}

void cat_snprintf(char *dest, size_t leng, char *fmt, ...)
{
	char buf[MAX_STRING_LENGTH];

	va_list args;

	va_start(args, fmt);
	vsprintf(buf, fmt, args);
	va_end(args);

	strncat(dest, buf, leng);
}

/*
 * MUCH thanks to http://www.auricmud.com/snippets/functions.html
 * for these three line saving printf functions! - Kregor
 */
void command( CHAR_DATA *ch, DO_FUN *command, char *fmt, ...)
{
    char buf[MAX_STRING_LENGTH*2];
    va_list args;

    va_start(args, fmt);
    vsprintf(buf, fmt, args);
    va_end(args);
	
    (command)(ch, buf);
}

// Simple function to add a single letter to the end of something.
void add_letter( char *string, char letter )
{
  char buf[MAX_STRING_LENGTH];

  sprintf( buf, "%c", letter );
  strcat( string, buf );
  return;
}

char *format( char *fmt, ...)
{
  static char newstring[MAX_INPUT_LENGTH];
  char buf[MAX_STRING_LENGTH*2];	/* better safe than sorry */
  va_list args;

  newstring[0] = '\0';

  if (fmt[0] == '\0')
  	return " ";

  va_start(args, fmt);
  vsprintf(buf, fmt, args);
  va_end(args);
	
  if (buf[0] == '\0')
  	return " ";
  strcpy( newstring, buf);
  return newstring;
}


/*
 * One function to check a string, instead of having to worry
 * about whether it's a NULL or empty string - Kregor
 */
bool is_string( char *str )
{
	push_call("is_string(%p)",str);
	
	if (str == NULL || str[0] == '\0')
	{
		pop_call();
		return FALSE;
	}
	pop_call();
	return TRUE;
}
	

/*
	See if a string is one of the names of an object.
*/
bool is_name( const char *str, char *namelist )
{
	char name[MAX_INPUT_LENGTH];

	push_call("is_name(%p,%p)",str,namelist);

	for ( ; ; )
	{
		namelist = one_argument_nolower(namelist, name);

		if (*name == '\0')
		{
			pop_call();
			return FALSE;
		}

		if (!strcasecmp(str, name))
		{
			pop_call();
			return TRUE;
		}
	}
	pop_call();
	return FALSE;
}

bool is_name_short( const char *str, char *namelist )
{
	char name[MAX_INPUT_LENGTH];

	push_call("is_name_short(%p,%p)",str,namelist);

	if (strlen(str) < 2)
	{
		pop_call();
		return FALSE;
	}

	for ( ; ; )
	{
		namelist = one_argument_nolower(namelist, name);

		if (*name == '\0')
		{
			pop_call();
			return FALSE;
		}

		if (!str_prefix(str, name))
		{
			pop_call();
			return TRUE;
		}
	}
	pop_call();
	return FALSE;
}


/*
	Checks if str is a name in namelist supporting multiple keywords
*/

bool is_name_list( char *str, char *namelist )
{
	char name[MAX_INPUT_LENGTH];

	push_call("is_name_list(%p,%p)",str,namelist);

	for ( ; ; )
	{
		str = one_argument_nolower(str, name);

		if (name[0] == '\0')
		{
			pop_call();
			return FALSE;
		}

		if (is_name(name, namelist))
		{
			pop_call();
			return TRUE;
		}
	}
	pop_call();
	return FALSE;
}

/*
	Check if all words in str appear in the namelist - Scandum
*/

bool is_multi_name_list( char *str, char *namelist )
{
	char name[MAX_INPUT_LENGTH];

	push_call("is_multi_name(%p,%p)",str,namelist);

	if (namelist[0] == '\0')
	{
		pop_call();
		return FALSE;
	}

	for ( ; ; )
	{
		str = one_argument_nolower(str, name);

		if (name[0] == '\0')
		{
			pop_call();
			return TRUE;
		}

		if (!is_name(name, namelist))
		{
			pop_call();
			return FALSE;
		}
	}
	pop_call();
	return TRUE;
}

bool is_multi_name_list_short( char *str, char *namelist )
{
	char name[MAX_INPUT_LENGTH];

	push_call("is_multi_name_list(%p,%p)",str,namelist);

	if (namelist[0] == '\0')
	{
		pop_call();
		return FALSE;
	}

	for ( ; ; )
	{
		str = one_argument_nolower(str, name);

		if (name[0] == '\0')
		{
			pop_call();
			return TRUE;
		}

		if (!is_name_short(name, namelist))
		{
			pop_call();
			return FALSE;
		}
	}
	pop_call();
	return TRUE;
}


/*
	Some nice abreviation for multi key words - Scandum
*/

bool is_multi_name_short( char *str, char *namelist )
{
	char name[MAX_INPUT_LENGTH];
	char list[MAX_INPUT_LENGTH];

	push_call("is_name_list(%p,%p)",str,namelist);

	if (*str == '\0' || *(str+1) == '\0')
	{
		pop_call();
		return FALSE;
	}

	for ( ; ; )
	{
		str		= one_argument(str, name);
		namelist	= one_argument(namelist, list);

		if (name[0] == '\0')
		{
			break;
		}

		if (str_prefix(name, list))
		{
			pop_call();
			return FALSE;
		}
	}
	pop_call();
	return TRUE;
}

/*
	rewritten, will mainly be replaced by _def version - Scandum 10-05-2002
*/

char *ansi_translate_text( CHAR_DATA *ch, const char *text_in )
{
	static char ansi_translate_buffer[MAX_STRING_LENGTH];
	const char *pti;
	char *pto, *pt2;
	bool val1, val2, val3;

	push_call("ansi_translate_text(%p,%p)",ch,text_in);

	pti  = text_in;
	pto  = ansi_translate_buffer;
	val1 = val2 = val3 = 0;

	if (ch->desc == NULL)
	{
		pop_call();
		return "";
	}

	while (*pti != '\0')
	{
		if (*(pti+0) == '{'
		&&  *(pti+1) >= '0' && *(pti+1) <= '8'
		&&  *(pti+2) >= '0' && *(pti+2) <= '8'
		&&  *(pti+3) >= '0' && *(pti+3) <= '8'
		&&  *(pti+4) == '}')
		{
			val1 = *(pti+1) - '0';
			val2 = *(pti+2) - '0';
			val3 = *(pti+3) - '0';

			pti += 5;

			if (val1 == 3)
			{
				val1 = VT102_BOLD;
				val2 = CH(ch->desc)->pcdata->color[COLOR_TEXT] % 10;
				val3 = CH(ch->desc)->pcdata->color[COLOR_TEXT] / 10;
			}

			pt2 = get_color_diff(ch, 8, 8, 8, val2, val3, val1);

			for ( ; *pt2 != '\0' ; pt2++, pto++)
			{
				*pto = *pt2;
			}
			continue;
		}
		*pto = *pti;
		pti++;
		pto++;
	}
	*pto = '\0';

	pop_call();
	return( ansi_translate_buffer );
}

/*
	Uses minimal amount of color codes - Scandum
*/

char *ansi_compress( CHAR_DATA *ch, char *txt, bool color, bool code )
{
	static char buf[MAX_STRING_LENGTH];
	char *pti, *pto, *ptt;
	bool val[3], old[3];

	push_call("ansi_compress(%p,%p,%p,%p)",ch,txt,color,code);

	pti  = txt;
	pto  = buf;

	memset(val, 0, 3);
	memset(old, 8, 3);

	if (ch->desc == NULL)
	{
		pop_call();
		return "";
	}

	while (*pti != '\0')
	{
		if (*(pti+0) == '{'
		&&  *(pti+1) >= '0' && *(pti+1) <= '8'
		&&  *(pti+2) >= '0' && *(pti+2) <= '8'
		&&  *(pti+3) >= '0' && *(pti+3) <= '8'
		&&  *(pti+4) == '}')
		{
			val[0] = *(pti+1) - '0';
			val[1] = *(pti+2) - '0';
			val[2] = *(pti+3) - '0';

			pti += 5;

			if (val[0] == 2)
			{
				val[0] = code;
				val[1] = CH(ch->desc)->pcdata->color[COLOR_ACCENT] % 10;
				val[2] = CH(ch->desc)->pcdata->color[COLOR_ACCENT] / 10;
			}
			else if (val[0] == 3)
			{
				val[0] = code;
				val[1] = CH(ch->desc)->pcdata->color[color] % 10;
				val[2] = CH(ch->desc)->pcdata->color[color] / 10;
			}

			ptt = get_color_diff(ch, old[1], old[2], old[0], val[1], val[2], val[0]);

			for ( ; *ptt != '\0' ; ptt++, pto++)
			{
				*pto = *ptt;
			}
			memcpy(old, val, 3);

			continue;
		}
		else if (*pti == '\n')
		{
			memset(old, 8, 3);
		}
		*pto = *pti;
		pti++;
		pto++;
	}
	*pto = '\0';

	pop_call();
	return buf;
}

/*
	Basic color translator for internal usage - Scandum 21-05-2002
*/

char *ansi_translate(char *text_in)
{
	static char ansi_translate_buffer[MAX_STRING_LENGTH];

	char *pti, *pto;
	char pt2[11];
	bool val1, val2, val3, cnt;

	push_call("ansi_translate(%p)",text_in);

	pti  = text_in;
	pto  = ansi_translate_buffer;
	val1 = val2 = val3 = 0;

	while (*pti != '\0')
	{
		if (*(pti+0) == '{'
		&&  *(pti+1) >= '0' && *(pti+1) <= '8'
		&&  *(pti+2) >= '0' && *(pti+2) <= '8'
		&&  *(pti+3) >= '0' && *(pti+3) <= '8'
		&&  *(pti+4) == '}')
		{
			val1 = *(pti+1) - '0';
			val2 = *(pti+2) - '0';
			val3 = *(pti+3) - '0';

			pti += 5;

			if (val1 == 8 && val2 == 8 && val3 == 8)
			{
				continue;
			}
			sprintf(pt2, "\033[");

			if (val1 < 8)
			{
				cat_sprintf(pt2, "%d", val1);
			}

			if (val2 < 8)
			{
				cat_sprintf(pt2, "%s%d", (val1 < 8) ? ";" : "", 30 + val2);
			}

			if (val3 < 8)
			{
				cat_sprintf(pt2, "%s%d", (val1 < 8 || val2 < 8) ? ";" : "", 40 + val3);
			}
			strcat(pt2, "m");

			for (cnt = 0 ; pt2[cnt] != '\0' ; cnt++, pto++)
			{
				*pto = pt2[cnt];
			}
			continue;
		}
		*pto = *pti;
		pti++;
		pto++;
	}
	*pto = '\0';

	pop_call();
	return( ansi_translate_buffer );
}

/*
	Translates color codes setting {300} to given def - Scandum 14-05-2002
*/

char *ansi_translate_def( CHAR_DATA *ch, char *text_in, char *def )
{
	static char ansi_translate_buffer[MAX_STRING_LENGTH];
	char *pti, *pto, *pt2;
	int val1, val2, val3;

	push_call("ansi_translate_def(%p,%p,%p)",ch,text_in,def);

	pti  = text_in;
	pto  = ansi_translate_buffer;
	val1 = val2 = val3 = 0;

	while (*pti != '\0')
	{
		if (*(pti+0) == '{'
		&&  *(pti+1) >= '0' && *(pti+1) <= '8'
		&&  *(pti+2) >= '0' && *(pti+2) <= '8'
		&&  *(pti+3) >= '0' && *(pti+3) <= '8'
		&&  *(pti+4) == '}')
		{
			val1 = *(pti+1) - '0';
			val2 = *(pti+2) - '0';
			val3 = *(pti+3) - '0';

			pti += 5;

			if (val1 == 3)
			{
				pt2 = def;
				for ( ; *pt2 != '\0' ; pt2++, pto++)
				{
					*pto = *pt2;
				}
			}
			else
			{
				pt2 = get_color_diff(ch, 8, 8, 8, val2, val3, val1);
				for ( ; *pt2 != '\0' ; pt2++, pto++)
				{
					*pto = *pt2;
				}
			}
			continue;
		}
		*pto = *pti;
		pti++;
		pto++;
	}
	*pto = '\0';

	pop_call();
	return( ansi_translate_buffer );
}


char *ansi_strip(char *txi)
{
	register char *pti, *pto;

	push_call("ansi_strip(%p)",txi);

	pti = (char *)txi;
	pto = (char *)ansi_strip_txt;

	for ( ; *pti != '\0' ; pti++)
	{
		if (*pti == '\033' && *(pti+1) == '[')
		{
			while (*pti != 'm' && *pti != '\0')
			{
				pti++;
			}
			continue;
		}
		else if (*pti == '{')
		{
			while (*pti != '}')
			{
				pti++;
			}
			pti++;
			continue;
		}
		*pto = *pti;
		pto++;
	}
	*pto = '\0';

	pop_call();
	return (ansi_strip_txt);
}


/*
	Returns centered buffer - Scandum
*/
char *center (char *inp, int length)
{
	static char center_buf[MAX_STRING_LENGTH];
	int lead_cnt, cnt;

	push_call("center(%p,%p)",inp,length);

	lead_cnt = (length - strlen(inp)) / 2;

	for (center_buf[0] = cnt = 0 ; cnt < lead_cnt ; cnt++)
	{
		strcat(center_buf, " ");
	}

	strcat(center_buf, inp);

	pop_call();
	return center_buf;
}

/*
	Returns justified buffer for ansi translated text - Scandum 13-05-2002
*/

char *ansi_justify (char *inp, int length)
{
	static char justified_buf[MAX_STRING_LENGTH];
	char *pti, *pto, *last_i_space, *last_o_space;
	int cnt, skp;

	push_call("ansi_justify(%p)",inp);

	last_o_space = pto = (char *) justified_buf;
	last_i_space = pti = inp;
	cnt = skp = 0;

	while (TRUE)
	{
		*pto = *pti;
		switch (*pto)
		{
			case '\0':
				pop_call();
				return ((char *) justified_buf);
				break;
			case ' ':
				last_o_space = pto;
				last_i_space = pti;
				break;
			case '\n':
			case '\r':
				cnt = 0;
				skp = 0;
				pto++;
				pti++;
				continue;
				break;
			case '{':
				if (*(pti+1) >= '0'	&& *(pti+1) <= '8'
				&&  *(pti+2) >= '0' && *(pti+2) <= '8'
				&&  *(pti+3) >= '0' && *(pti+3) <= '8'
				&&  *(pti+4) == '}')
				{
					pto++; pti++; *pto = *pti;
					pto++; pti++; *pto = *pti;
					pto++; pti++; *pto = *pti;
					pto++; pti++; *pto = *pti;
					pto++;
					pti++;
					skp += 5;
					continue;
				}
				break;
		}
		pto++;
		pti++;
		cnt++;
		if (cnt >= length)
		{
			if (*pti == '\n' || *pti == '\0')
			{
				continue;
			}
			if (*pti == ' ')
			{
				last_o_space = pto;
				last_i_space = pti;
			}
			if (pto - last_o_space > 20 + skp)
			{
				*pto = '\n';
				pto++;
				*pto = '\r';
				pto++;
				cnt  = 0;
				skp  = 0;
			}
			else
			{
				pto  = last_o_space;
				*pto = '\n';
				pto++;
				*pto = '\r';
				pto++;
				pti  = last_i_space;
				pti++;
				cnt  = 0;
				skp  = 0;
			}
		}
	}
	pop_call();
	return ((char *)justified_buf);
}

/*
	Switched to flawless protocol - Scandum 13-05-2002
*/

char *justify (char *inp, int length)
{
	static char justified_buf[MAX_STRING_LENGTH];
	char *pti, *pto, *last_i_space, *last_o_space;
	int cnt;

	push_call("justify(%p)",inp);

	last_o_space = pto = (char *) justified_buf;
	last_i_space = pti = inp;
	cnt = 0;

	while (TRUE)
	{
		*pto = *pti;
		switch (*pto)
		{
			case '\0':
				pop_call();
				return ((char *) justified_buf);
				break;
			case ' ':
				last_o_space = pto;
				last_i_space = pti;
				break;
			case '\n':
			case '\r':
				cnt = 0;
				pto++;
				pti++;
				continue;
		}
		pto++;
		pti++;
		cnt++;
		if (cnt >= length)
		{
			if (*pti == '\n' || *pti == '\0')
			{
				continue;
			}
			if (*pti == ' ')
			{
				last_o_space = pto;
				last_i_space = pti;
			}
			if (pto - last_o_space > 20)
			{
				*pto = '\n';
				pto++;
				*pto = '\r';
				pto++;
				cnt  = 0;
			}
			else
			{
				pto  = last_o_space;
				*pto = '\n';
				pto++;
				*pto = '\r';
				pto++;
				pti  = last_i_space;
				pti++;
				cnt  = 0;
			}
		}
	}
	pop_call();
	return ((char *)justified_buf);
}


/* 
 * This function is used to format a piece of text so that it doesn't wrap
 * over the line. It also allows you to specify the line width and left.
 *
 * pszText:     A pointer to the string to be justified.
 * columns: The width in characters of the formatted text. Pass -1 to
 * leave the text without returns.
 *
 * The return value is a pointer to a non-stack based string which contains
 * the newly formatted text.
 ******************************************************************************
 This code is copyright (C) 1999 by Richard Woolcock.  It may be used and
 distributed freely, as long as you don't remove this copyright notice.
 *****************************************************************************
 */
typedef enum
{	
	justify_left = 0,
	justify_right,
	justify_center
} justify_flags;

char *text_wrap( char *pszText, int columns )
{
   static char s_szResult[4096];
   char *      pszResult = &s_szResult[0];
   char        szStore[4096];
   int         iMax;
   int         iLength = columns-1;
   int         iLoop = 0;

   push_call("text_wrap()");

   if ( strlen( pszText ) < 10 )
   {
      /* You may want to add your own error message routine in here */
      strcpy( s_szResult, "" );
      pop_call();
      return( &s_szResult[0] );
   }

   /* Discard all leading spaces */
   while ( *pszText == ' ' ) pszText++;

   /* Store the character */
   szStore[iLoop++] = *pszText++;

   if ( szStore[iLoop-1] >= 'a' && szStore[iLoop-1] <= 'z' )
   {
      /* Capitalize the first character if it's a letter */
      szStore[iLoop-1] &= ~32;
   }

   /* The first loop goes through the string, copying it into szStore.  The
    * string is formatted to remove all newlines, capitalise new sentences,
    * remove excess white spaces and ensure that full stops, commas and
    * exclaimation marks are all followed by two white spaces.
    */
   while ( *pszText )
   {
      switch ( *pszText )
      {
         default:
            /* Store the character */
            szStore[iLoop++] = *pszText++;
            break;
         case ' ':
            /* There shall only be one space between non-space characters */
            if ( *(pszText+1) != ' ' )
            {
               /* Store the character */
               szStore[iLoop++] = *pszText;
            }
            pszText++;
            break;
         case '.':
         case '?':
         case '!':
         case ',':
            /* Store the character */
            szStore[iLoop++] = *pszText++;
            /* Discard all leading spaces */
            while ( *pszText == ' ' ) pszText++;
            /* Commas shall be followed by one space */
            szStore[iLoop++] = ' ';
            break;
         case '$':
            /* Store the character */
            szStore[iLoop++] = *pszText++;
            /* Discard all leading spaces */
            while ( *pszText == ' ' ) pszText++;
            break;
         case '\n':
             /* Discard newlines */
            pszText++;
            break;
        case '\r':
            /* Discard returns */
            pszText++;
            /* returns are followed by one space */
            szStore[iLoop++] = ' ';
            break;
      }
   }

   /* Terminate the string */
   szStore[iLoop] = '\0';

   /* Initialise iMax to the size of szStore */
   iMax = strlen( szStore );

   /* The second loop goes through the string, inserting newlines at every
    * appropriate point.
    */
   while ( iLength < iMax )
   {
      /* Go backwards through the current line searching for a space */
      while ( szStore[iLength] != ' ' && iLength > 1 )
      {
         iLength--;
      }

      if ( szStore[iLength] == ' ' )
      {
         /* If a space is found, replace it with a newline */
         szStore[iLength] = '\n';
         iLength += columns;
      }
      else
      {
         /* If no space is found, drop out of the loop */
         break;
      }
   }

   /* Reset the counter */
   iLoop = 0;

   /* The third and final loop goes through the string, making sure that there
    * is a \r (return to beginning of line) following every newline, with no
    * white spaces at the beginning of a particular line of text.
    */
   while ( iLoop < iMax )
   {
      /* Store the character */
      *pszResult++ = szStore[iLoop];
      switch ( szStore[iLoop] )
      {
         default:
            break;
         case '\n':
            /* Insert a return after the newline and remove any leading spaces */
            *pszResult++ = '\r';
            while ( szStore[iLoop+1] == ' ' ) iLoop++;
            break;
      }
      iLoop++;
   }

   /* Add return if column == -1 */
   if (columns == -1)
   {
		 *pszResult++ = '\n';
		 *pszResult++ = '\r';
   }
   /* Terminate the string */
   *pszResult++ = '\0';

   return( &s_szResult[0] );
}

/*
	Return true if an argument is completely numeric.
*/

bool is_number( char *argument )
{
	push_call("is_number(%p)",argument);

	if (*argument == '\0')
	{
		pop_call();
		return FALSE;
	}

	for ( ; *argument != '\0'; argument++ )
	{
		if (!isdigit(*argument) && (*argument != '-') && (*argument != '+'))
		{
			pop_call();
			return FALSE;
		}
	}
	pop_call();
	return TRUE;
}


bool is_number_argument( char *argument )
{
	push_call("is_number_argument(%p)",argument);

	if (*argument != '\0')
	{
		for ( ; *argument != '\0'; argument++ )
		{
			if (!isdigit(*argument) && *argument != '-' && *argument != '+' && *argument != '.')
			{
				pop_call();
				return FALSE;
			}
		}
	}
	pop_call();
	return TRUE;
}


/*
	Given a string like 14.foo, Return 14 and 'foo'
*/

int number_argument( char *argument, char *arg )
{
	char *pdot;
	int number;

	push_call("number_argument(%p,%p)",argument,arg);

	if ((pdot = strstr(argument, ".")) != NULL)
	{
		*pdot	= '\0';
		number	= atol(argument);
		*pdot	= '.';
		strcpy(arg, pdot+1);

		pop_call();
		return number;
	}
	strcpy(arg, argument);

	pop_call();
	return 1;
}

/*
 * Grab_token: Grabs the first token off a string as noted by a delimiter.
 *
 * Return: Puts token in end_buf string. Returns advanced src pointer.
 *         Returns NULL if supplied bad data or if the src string is exausted of tokens.
 * by Nick "Odis" Cash.
 */
char *grab_token( char *src, char* end_buf, char delimiter )
{
  char buf[MAX_STRING_LENGTH+1];
  char* buf_ptr = buf;
  char flag = 0;

  /* check data */
  if ( !src || !end_buf )
   return NULL;

  /* copy token */
  while ( *src != '\0' )
  {
    /* check for the end of the token */
    if (*src == delimiter )
    {
      src++; /* chop off delimiter */
      flag = 1;
      break;
    }

    /* copy */
    *buf_ptr++ = *src++;
  }

  /* close end_buf */
  *buf_ptr = '\0';

  /* copy string if delimiter was found */
  if ( flag == 1 )
   strcpy( end_buf, buf );

  /* return advanced src ptr */
  if ( src && src[0] != '\0' )
    return src;
  else
    return NULL;
}

/*
 * Replace_str: Replace all instances of "replace" with "new_str" within "src"
 *
 * Return: Pointer to static character array with new string.
 *         Returns NULL if supplied bad data.
 *
 * Notes: Not thread safe.
 * Nick "Odis" Cash.
 */
char *replace_str( const char *new_str, const char *replace, const char *src )
{
  static char buf[MAX_STRING_LENGTH+1];
  char *ri = (char *)replace;
  int bi = 0; /* buf index */
  int ns_length = strlen(new_str); /* new string length */

  /* check input */
  if ( !new_str || !replace || !src )
   return NULL;

  /* iterate while we have data */
  while ( *src != '\0' && bi <= MAX_STRING_LENGTH )
  {
    if ( *src == *ri ) /* initiate sub scan? */
    {
      short found = 0; /* flag is set if the string turns not to match */
      char *si_sub = (char *)src;

      si_sub++;
      ri++;

      /* serach for the rest of replace */
      for ( ; *ri != '\0'; ri++, si_sub++ )
      {
        if ( *ri != *si_sub )
        {
          found = 1; /* no match */
          break;
        }
      }

      /* matched */
      if ( found == 0 )
      {
        int x;

        /* put in the new string to replace the old string */
        for ( x = 0; x < ns_length; x++ )
        {
          buf[bi++] = new_str[x];

          /* buffer overflow protection */
          if ( bi == (MAX_STRING_LENGTH+1) )
          {
            buf[bi] = '\0';
            return buf;
          }
        }

        src = si_sub; /* advance src ptr to skip the matched portion */
      }

      /* reset ri */
      ri = (char *)replace;
    }

    buf[bi++] = *src;
    src++;
  } /* end while */

  buf[bi] = '\0';
  return buf;
}

/*
	Pick off one argument from a string and Return the rest.
	Understands quotes, lowercases.
*/
char *one_argument( char *argument, char *arg_first )
{
	char cEnd;

	push_call("one_argument(%p,%p)",argument,arg_first);

	if (argument == NULL)
	{
		log_string("one_argument: argument == NULL");
		dump_stack();
		pop_call();
		return NULL;
	}

	while (*argument == ' ' || *argument == '\n' || *argument == '\r' || *argument == 27)
	{
    		argument++;
	}

	cEnd = ' ';

	if (*argument == '\'' || *argument == '"')
	{
		cEnd = *argument++;
	}

	while (*argument != '\0' && *argument != '\n' && *argument != '\r')
	{
		if (*argument == cEnd)
		{
			argument++;
			break;
		}

		*arg_first = tolower(*argument);

		arg_first++;
		argument++;
	}
	*arg_first = '\0';

	while (*argument == ' ' || *argument == '\n' || *argument == '\r' || *argument == 27)
	{
		argument++;
	}
	pop_call();
	return argument;
}


char *one_argument_nolower( char *argument, char *arg_first )
{
	char cEnd;

	push_call("one_argument(%p,%p)",argument,arg_first);

	if (argument == NULL)
	{
		log_string("one_argument_nolower(), argument is NULL");
		pop_call();
		return NULL;
	}

	while ( *argument==' ' || *argument=='\n' || *argument=='\r' || *argument==27)
	{
    		argument++;
	}
	cEnd = ' ';
	if ( *argument == '\'' || *argument == '"' )
	{
		cEnd = *argument++;
	}

	while ( *argument != '\0' && *argument != '\n' && *argument != '\r' )
	{
		if ( *argument == cEnd )
		{
			argument++;
			break;
		}

		*arg_first = *argument;

		arg_first++;
		argument++;
	}
	*arg_first = '\0';

	while ( *argument==' ' || *argument=='\n' || *argument=='\r' || *argument==27)
	{
		argument++;
	}
	pop_call();
	return argument;
}

/*
 * Same as one_argument except that it takes two args and returns the rest;
 * ignores fill words (Thanks CircleMUD)
 */
char *two_arguments(char *argument, char *first_arg, char *second_arg)
{
  return (one_argument(one_argument(argument, first_arg), second_arg));
}