1stMUD4.0/bin/
1stMUD4.0/doc/MPDocs/
1stMUD4.0/player/
1stMUD4.0/win32/
1stMUD4.0/win32/rom/
/**************************************************************************
*  Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,        *
*  Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe.   *
*                                                                         *
*  Merc Diku Mud improvements copyright (C) 1992, 1993 by Michael         *
*  Chastain, Michael Quan, and Mitchell Tse.                              *
*                                                                         *
*  In order to use any part of this Merc Diku Mud, you must comply with   *
*  both the original Diku license in 'license.doc' as well the Merc       *
*  license in 'license.txt'.  In particular, you may not remove either of *
*  these copyright notices.                                               *
*                                                                         *
*  Much time and thought has gone into this software and you are          *
*  benefiting.  We hope that you share your changes too.  What goes       *
*  around, comes around.                                                  *
***************************************************************************
*       ROM 2.4 is copyright 1993-1998 Russ Taylor                        *
*       ROM has been brought to you by the ROM consortium                 *
*           Russ Taylor (rtaylor@hypercube.org)                           *
*           Gabrielle Taylor (gtaylor@hypercube.org)                      *
*           Brian Moore (zump@rom.org)                                    *
*       By using this code, you have agreed to follow the terms of the    *
*       ROM license, in the file Rom24/doc/rom.license                    *
***************************************************************************
*       1stMUD ROM Derivative (c) 2001-2003 by Ryan Jennings              *
*            http://1stmud.dlmud.com/  <r-jenn@shaw.ca>                   *
***************************************************************************/
#include "merc.h"
#include "globals.h"
#include "recycle.h"
#include "save.h"

char *timestr(time_t time, bool fShort)
{
	static char timebuf[3][MSL];
	static int pindex;			// used to rotate around 3 buffers, so timestr can 
	long dsec, dmin, dhour, dday;
	long dweek, dmonth, dyear;
	char working[MSL];
	char *trim;
	// be used up to 3 times in one context without
	// overwriting a previous buffer 
	++pindex;
	pindex %= 3;				// rotate the pindex
	timebuf[pindex][0] = NUL;	// clear the previous string 

	// calculate the difference in time, and break it down 
	dsec = abs(time);

	dday = dsec / (DAY);
	dsec %= DAY;

	dyear = dday / 365;
	dday %= 365;

	dweek = dday / 7;
	dday %= 7;

	dmonth = dweek * 12 / 52;
	dweek -= dmonth * 52 / 12;

	dhour = dsec / (HOUR);
	dsec %= HOUR;

	dmin = dsec / MINUTE;
	dsec = dsec % MINUTE;

	// format the result up
	working[0] = NUL;

	if (dyear != 0)
	{
		if (!fShort)
			sprintf(working, "%ld year%s, ", dyear, ((dyear != 1) ? "s" : ""));
		else
			sprintf(working, "%ld:", dyear);
		strcat(timebuf[pindex], working);
	}

	if (dmonth != 0)
	{
		if (!fShort)
			sprintf(working, "%ld month%s, ", dmonth,
					((dmonth != 1) ? "s" : ""));
		else
			sprintf(working, "%ld:", dmonth);
		strcat(timebuf[pindex], working);
	}

	if (dweek != 0)
	{
		if (!fShort)
			sprintf(working, "%ld week%s, ", dweek, ((dweek != 1) ? "s" : ""));
		else
			sprintf(working, "%ld:", dweek);
		strcat(timebuf[pindex], working);
	}

	if (dday != 0)
	{
		if (!fShort)
			sprintf(working, "%ld day%s, ", dday, ((dday != 1) ? "s" : ""));
		else
			sprintf(working, "%ld:", dday);
		strcat(timebuf[pindex], working);
	}

	if (dhour != 0)
	{
		if (!fShort)
			sprintf(working, "%ld hour%s, ", dhour, ((dhour != 1) ? "s" : ""));
		else
			sprintf(working, "%ld:", dhour);
		strcat(timebuf[pindex], working);
	}

	if (dmin != 0)
	{
		if (!fShort)
			sprintf(working, "%ld minute%s, ", dmin, ((dmin != 1) ? "s" : ""));
		else
			sprintf(working, "%ld:", dmin);
		strcat(timebuf[pindex], working);
	}

	if (dsec != 0)
	{
		if (!fShort)
			sprintf(working, "%ld second%s", dsec, ((dsec != 1) ? "s" : ""));
		else
			sprintf(working, "%ld:", dsec);
		strcat(timebuf[pindex], working);
	}

	// remove a space and comma that could be at the end of the line 
	trim = &timebuf[pindex][strlen(timebuf[pindex]) - 1];
	if (*trim == ' ' || *trim == ',' || *trim == ':')
	{
		*trim = NUL;
		trim--;
		if (*trim == ' ' || *trim == ',' || *trim == ':')
			*trim = NUL;
	}

	return (timebuf[pindex]);
}

void fwrite_time(FILE * fp, const char *name, time_t time, bool fTime)
{
	if (!IS_NULLSTR(name))
		fprintf(fp, "%s%s", name, format_tabs(strlen(name)));
	else
		fprintf(fp, " ");

	fprintf(fp, "%ld", time);

	fprintf(fp, "(%s)\n",
			!fTime ? str_time(time, -1, NULL) : timestr(current_time - time,
														FALSE));
}

void fread_time(FILE * fp, time_t * tptr)
{
	*tptr = fread_long(fp);
	fread_to_eol(fp);
}

void read_time(READ_DATA * str, time_t * tptr)
{
	*tptr = read_long(str);
	read_to_eol(str);
}

WRITE_DATA *open_w_a(const char *file, const char *mode)
{
	WRITE_DATA *fp;
	static int count = 0;

	if (IS_NULLSTR(file))
		return NULL;

	alloc_mem(fp, WRITE_DATA, 1);

	if (!fp)
		return NULL;

	if (++count > 999)
		count = 0;

	fp->file = str_dup(file);
#if !defined(WIN32)
	fp->temp = str_dup(FORMATF("%s.tmp%03d", file, count));
	if ((fp->stream = file_open(fp->temp, mode)) == NULL)
#else
	if ((fp->stream = file_open(fp->file, mode)) == NULL)
#endif
	{
		file_close(fp->stream);
		free_string(fp->temp);
		free_string(fp->file);
		free_mem(fp);
		return NULL;
	}
	return fp;
}

WRITE_DATA *open_write(const char *path, ...)
{
	char file[1024];
	va_list args;

	if (IS_NULLSTR(path))
		return NULL;

	va_start(args, path);
	vsnprintf(file, sizeof(file), path, args);
	va_end(args);

	return open_w_a(file, "w+");
}

WRITE_DATA *open_append(const char *path, ...)
{
	char file[1024];
	va_list args;

	if (IS_NULLSTR(path))
		return NULL;

	va_start(args, path);
	vsnprintf(file, sizeof(file), path, args);
	va_end(args);

	return open_w_a(file, "a+");
}

void close_write(WRITE_DATA * fp)
{
	if (fp)
	{
		file_close(fp->stream);
#if !defined(WIN32)
		if (rename(fp->temp, fp->file))
		{
			bugf("error renaming %s -> %s", fp->temp, fp->file);
			log_error("rename");
		}
#endif
		free_string(fp->temp);
		free_string(fp->file);
		free_mem(fp);
	}
	fp = NULL;
}

void close_append(WRITE_DATA * fp)
{
	close_write(fp);
}

#define MLR (MAX_STRING_LENGTH * 25)

const char *fread_file(FILE * fp)
{
	char buf[MLR + 2];			/* extra 2 bytes on the end for \0 and 1b slack */
	char c;
	long i = 0;
	bool sFull = FALSE;

	/* clearing the buffer means we don't have to append \0 on the end */
	memset(buf, 0, sizeof(buf));

	for (;;)
	{
		if (i >= MLR && !sFull)
		{
			bugf("String [%20.20s...] exceeded %db size [MLR]", buf, MLR);
			sFull = TRUE;
		}

		switch (c = getc(fp))
		{
		default:
			if (!sFull)
			{
				buf[i] = c;
				i++;
			}
			break;

		case '\n':
			if (!sFull)
			{
				buf[i] = '\n';
				i++;
				buf[i] = '\r';
				i++;
			}
			break;

		case '\r':
			break;

		case EOF:
			return str_dup(buf);

		}
	}
}

const char *read_file(READ_DATA * str)
{
	char buf[MLR + 2];			/* extra 2 bytes on the end for \0 and 1b slack */
	char c;
	long i = 0;
	bool sFull = FALSE;

	/* clearing the buffer means we don't have to append \0 on the end */
	memset(buf, 0, sizeof(buf));

	for (;;)
	{
		if (i >= MLR && !sFull)
		{
			bugf("FILE: %s: String [%20.20s...] exceeded %db size [MLR]",
				 str->file, buf, MLR);
			sFull = TRUE;
		}

		switch (c = stgetc(str))
		{
		default:
			if (!sFull)
			{
				buf[i] = c;
				i++;
			}
			break;

		case '\n':
			if (!sFull)
			{
				buf[i] = '\n';
				i++;
				buf[i] = '\r';
				i++;
			}
			break;

		case '\r':
			break;

		case NUL:
			return str_dup(buf);

		}
	}
}

/* Function Name: FILE *file_open (const char *mode, char *fmt,...)

 * this function closes fpReserve (if open), and opens a stream to the
 * file specified, with the specified modes.
 */
FILE *file_open(const char *file, const char *mode)
{
	FILE *fp;

	if (fpReserve != NULL)
	{
		fclose(fpReserve);
		fpReserve = NULL;
	}

	if (!(fp = fopen(file, mode)))
	{
		fpReserve = fopen(NULL_FILE, "r");
		return NULL;
	}
	return fp;
}

/* Function Name: void file_close (FILE *fp)

 * this function closes the stream specified, and attempts to re-open
 * fpReserve, if it's not already open.
 */
void file_close(FILE * fp)
{
	if (fp != NULL)
		fclose(fp);

	fp = NULL;

	if (fpReserve == NULL)
		fpReserve = fopen(NULL_FILE, "r");
}

READ_DATA *open_read(const char *path, ...)
{
	struct stat buf;
	READ_DATA *str;
	va_list args;
	char file[1024];
	FILE *fp;

	if (IS_NULLSTR(path))
		return NULL;

	va_start(args, path);
	vsnprintf(file, sizeof(file), path, args);
	va_end(args);

	if (stat(file, &buf) == -1 || !S_ISREG(buf.st_mode))
		return NULL;

	if ((fp = file_open(file, "r")) == NULL)
	{
		file_close(fp);
		return NULL;
	}

	alloc_mem(str, READ_DATA, 1);
	str->pos = 0;
	str->size = buf.st_size;
	str->file = str_dup(file);
	alloc_mem(str->str, char, str->size + 1);
	fread(str->str, str->size + 1, 1, fp);
	file_close(fp);
	str->str[str->size] = NUL;
	return str;
}

void close_read(READ_DATA * str)
{
	if (str)
	{
		free_mem(str->str);
		free_string(str->file);
		free_mem(str);
	}
	str = NULL;
}

char fread_letter(FILE * fp)
{
	char c;

	do
	{
		c = getc(fp);
	}
	while (isspace(c));

	return c;
}

char read_letter(READ_DATA * str)
{
	char c;

	do
	{
		c = stgetc(str);
	}
	while (isspace(c));

	return c;
}

int fread_number(FILE * fp)
{
	int number;
	bool sign;
	char c;

	do
	{
		c = getc(fp);
	}
	while (isspace(c));

	number = 0;

	sign = FALSE;
	if (c == '+')
	{
		c = getc(fp);
	}
	else if (c == '-')
	{
		sign = TRUE;
		c = getc(fp);
	}

	if (!isdigit(c))
	{
		bug("bad format.");
		abort();
	}

	while (isdigit(c))
	{
		number = number * 10 + c - '0';
		c = getc(fp);
	}

	if (sign)
		number = 0 - number;

	if (c == '|')
		number += fread_number(fp);
	else if (c != ' ')
		ungetc(c, fp);

	return number;
}

int read_number(READ_DATA * str)
{
	int number;
	bool sign;
	char c;

	do
	{
		c = stgetc(str);
	}
	while (isspace(c));

	number = 0;

	sign = FALSE;
	if (c == '+')
	{
		c = stgetc(str);
	}
	else if (c == '-')
	{
		sign = TRUE;
		c = stgetc(str);
	}

	if (!isdigit(c))
	{
		bugf("FILE: %s: bad format.", str->file);
		abort();
	}

	while (isdigit(c))
	{
		number = number * 10 + c - '0';
		c = stgetc(str);
	}

	if (sign)
		number = 0 - number;

	if (c == '|')
		number += read_number(str);
	else if (c != ' ')
		str->pos--;

	return number;
}

long fread_long(FILE * fp)
{
	long number;
	bool sign;
	char c;

	do
	{
		c = getc(fp);
	}
	while (isspace(c));

	number = 0;

	sign = FALSE;
	if (c == '+')
	{
		c = getc(fp);
	}
	else if (c == '-')
	{
		sign = TRUE;
		c = getc(fp);
	}

	if (!isdigit(c))
	{
		bug("bad format.");
		abort();
	}

	while (isdigit(c))
	{
		number = number * 10 + c - '0';
		c = getc(fp);
	}

	if (sign)
		number = 0 - number;

	if (c == '|')
		number += fread_long(fp);
	else if (c != ' ')
		ungetc(c, fp);

	return number;
}

long read_long(READ_DATA * str)
{
	long number;
	bool sign;
	char c;

	do
	{
		c = stgetc(str);
	}
	while (isspace(c));

	number = 0;

	sign = FALSE;
	if (c == '+')
	{
		c = stgetc(str);
	}
	else if (c == '-')
	{
		sign = TRUE;
		c = stgetc(str);
	}

	if (!isdigit(c))
	{
		bugf("FILE: %s: bad format.", str->file);
		abort();
	}

	while (isdigit(c))
	{
		number = number * 10 + c - '0';
		c = stgetc(str);
	}

	if (sign)
		number = 0 - number;

	if (c == '|')
		number += read_long(str);
	else if (c != ' ')
		str->pos--;

	return number;
}

flag_t fread_flag(FILE * fp)
{
	flag_t number;
	flag_t flag;
	flag_t temp = 1;
	char c;
	bool negative = FALSE;

	do
	{
		c = getc(fp);
	}
	while (isspace(c));

	if (c != '+')
	{
		if (c == '-')
		{
			negative = TRUE;
			c = getc(fp);
		}

		number = 0;

		if (!isdigit(c))
		{
			while (('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z'))
			{
				number += flag_convert(c);
				c = getc(fp);
			}
		}

		while (isdigit(c))
		{
			number = number * 10 + c - '0';
			c = getc(fp);
		}

		if (c == '|')
			number += fread_flag(fp);

		else if (c != ' ')
			ungetc(c, fp);

		if (negative)
			return -1 * number;
		return number;
	}
	else
	{
		number = 0;
		flag = 0;
		do
		{
			c = getc(fp);
			flag += (temp << number) * (c == 'Y');
			number++;
		}
		while (c == 'Y' || c == 'n');

		if (c == '\n' || c == '\r')
			ungetc(c, fp);

		return flag;
	}
}

flag_t read_flag(READ_DATA * str)
{
	flag_t number;
	flag_t flag;
	flag_t temp = 1;
	char c;
	bool negative = FALSE;

	do
	{
		c = stgetc(str);
	}
	while (isspace(c));

	if (c != '+')
	{
		if (c == '-')
		{
			negative = TRUE;
			c = stgetc(str);
		}

		number = 0;

		if (!isdigit(c))
		{
			while (('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z'))
			{
				number += flag_convert(c);
				c = stgetc(str);
			}
		}

		while (isdigit(c))
		{
			number = number * 10 + c - '0';
			c = stgetc(str);
		}

		if (c == '|')
			number += read_flag(str);

		else if (c != ' ')
			str->pos--;

		if (negative)
			return -1 * number;
		return number;
	}
	else
	{
		number = 0;
		flag = 0;
		do
		{
			c = stgetc(str);
			flag += (temp << number) * (c == 'Y');
			number++;
		}
		while (c == 'Y' || c == 'n');

		if (c == '\n' || c == '\r')
			str->pos--;

		return flag;
	}
}

void fread_to_eol(FILE * fp)
{
	char c;

	do
	{
		c = getc(fp);
	}
	while (c != '\n' && c != '\r');

	do
	{
		c = getc(fp);
	}
	while (c == '\n' || c == '\r');

	ungetc(c, fp);
	return;
}

void read_to_eol(READ_DATA * str)
{
	char c;

	do
	{
		c = stgetc(str);
	}
	while (c != '\n' && c != '\r');

	do
	{
		c = stgetc(str);
	}
	while (c == '\n' || c == '\r');

	str->pos--;
	return;
}

char *fread_word(FILE * fp)
{
	static char word[MIL];
	char *pword;
	char cEnd;

	do
	{
		if (feof(fp))
		{
			bug(" EOF encountered on read.");
			if (run_level == RUNLEVEL_BOOTING)
				exit(1);
			word[0] = NUL;
			return word;
		}
		cEnd = getc(fp);
	}
	while (isspace(cEnd));

	if (cEnd == '\'' || cEnd == '"')
	{
		pword = word;
	}
	else
	{
		word[0] = cEnd;
		pword = word + 1;
		cEnd = ' ';
	}

	for (; pword < word + MIL; pword++)
	{
		*pword = getc(fp);
		if (cEnd == ' ' ? isspace(*pword) : *pword == cEnd)
		{
			if (cEnd == ' ')
				ungetc(*pword, fp);
			*pword = NUL;
			return word;
		}
	}

	bug("word too long.");

	abort();
	return NULL;
}

char *read_word(READ_DATA * fp)
{
	static char word[MIL];
	char *pword;
	char cEnd;

	do
	{
		if (steof(fp))
		{
			bugf(" EOF encountered on read. %d/%d chars.", fp->pos, fp->size);
			if (run_level == RUNLEVEL_BOOTING)
				exit(1);
			word[0] = NUL;
			return word;
		}
		cEnd = stgetc(fp);
	}
	while (isspace(cEnd));

	if (cEnd == '\'' || cEnd == '"')
	{
		pword = word;
	}
	else
	{
		word[0] = cEnd;
		pword = word + 1;
		cEnd = ' ';
	}

	for (; pword < word + MIL; pword++)
	{
		*pword = stgetc(fp);
		if (cEnd == ' ' ? isspace(*pword) : *pword == cEnd)
		{
			if (cEnd == ' ')
				fp->pos--;
			*pword = NUL;
			return word;
		}
	}

	bug("word too long.");

	abort();
	return NULL;
}

const char *fread_string(FILE * fp)
{
	char buf[MLR + 2];			/* extra 2 bytes on the end for \0 and 1b slack */
	long i = 0;
	register char c;
	bool sFull = FALSE;

	/* skip blanks */
	do
	{
		c = getc(fp);
	}
	while (isspace(c));

	/* empty string */
	if (c == '~')
		return str_dup("");

	buf[i++] = c;

	for (;;)
	{
		if (i >= MLR && !sFull)
		{
			bugf("String [%20.20s...] exceeded [%d] MLR", buf, MLR);
			sFull = TRUE;
		}

		switch (c = getc(fp))
		{
		default:
			if (!sFull)
			{
				buf[i++] = c;
			}
			break;

		case EOF:
			/* temp fix */
			bugf("String [%20.20s...] EOF", buf);
			abort();
			break;

		case '\n':
			if (!sFull)
			{
				buf[i++] = '\n';
				buf[i++] = '\r';
			}
			break;

		case '\r':
			break;

		case '~':
			buf[i] = NUL;
			return str_dup(buf);
			break;
		}
	}
}

const char *read_string(READ_DATA * str)
{
	static char buf[MLR + 2];	/* extra 2 bytes on the end for \0 and 1b slack */
	long i = 0;
	register char c;
	bool sFull = FALSE;

	/* skip blanks */
	do
	{
		c = stgetc(str);
	}
	while (isspace(c));

	/* empty string */
	if (c == '~')
		return str_dup("");

	buf[i++] = c;

	for (;;)
	{
		if (i >= MLR && !sFull)
		{
			bugf("FILE: %s: String [%20.20s...] exceeded [%d] MLR", str->file,
				 buf, MLR);
			sFull = TRUE;
		}

		switch (c = stgetc(str))
		{
		default:
			if (!sFull)
			{
				buf[i++] = c;
			}
			break;

		case NUL:
			/* temp fix */
			bugf("FILE: %s: String [%20.20s...] EOF pos %d", str->file, buf,
				 str->pos);
			abort();
			break;

		case '\n':
			if (!sFull)
			{
				buf[i++] = '\n';
				buf[i++] = '\r';
			}
			break;

		case '\r':
			break;

		case '~':
			buf[i] = NUL;
			return str_dup(buf);
			break;
		}
	}
}

/*
 * Read to end of line into static buffer
 */
const char *fread_line(FILE * fp)
{
	static char line[MSL];
	char *pline;
	char c;
	int ln;

	pline = line;
	line[0] = NUL;
	ln = 0;

	/*
	 * Skip blanks.
	 * Read first char.
	 */
	do
	{
		if (feof(fp))
		{
			bug("EOF encountered on read.");
			strcpy(line, "");
			return line;
		}
		c = getc(fp);
	}
	while (isspace(c));

	ungetc(c, fp);
	do
	{
		if (feof(fp))
		{
			bug("EOF encountered on read.");
			*pline = NUL;
			return line;
		}
		c = getc(fp);
		*pline++ = c;
		ln++;
		if (ln >= (MSL - 1))
		{
			bug("line too long");
			break;
		}
	}
	while (c != '\n' && c != '\r');

	do
	{
		c = getc(fp);
	}
	while (c == '\n' || c == '\r');

	ungetc(c, fp);
	*pline = NUL;
	return line;
}

const char *read_line(READ_DATA * str)
{
	static char line[MSL];
	char *pline;
	char c;
	int ln;

	pline = line;
	line[0] = NUL;
	ln = 0;

	/*
	 * Skip blanks.
	 * Read first char.
	 */
	do
	{
		if (steof(str))
		{
			bugf("EOF encountered on read. pos %d.", str->pos);
			strcpy(line, "");
			return line;
		}
		c = stgetc(str);
	}
	while (isspace(c));

	str->pos--;
	do
	{
		if (steof(str))
		{
			bug("EOF encountered on read.");
			*pline = NUL;
			return line;
		}
		c = stgetc(str);
		*pline++ = c;
		ln++;
		if (ln >= (MSL - 1))
		{
			bug("line too long");
			break;
		}
	}
	while (c != '\n' && c != '\r');

	do
	{
		c = stgetc(str);
	}
	while (c == '\n' || c == '\r');

	str->pos--;
	*pline = NUL;
	return line;
}

bool steof(READ_DATA * fp)
{
	return (fp->pos >= fp->size);
}

char stgetc(READ_DATA * fp)
{
	char c = fp->str[fp->pos];

	if (!steof(fp))
		fp->pos++;

	return c;
}