1stMud4.5.3/
1stMud4.5.3/backup/
1stMud4.5.3/bin/
1stMud4.5.3/bin/extras/
1stMud4.5.3/data/i3/
1stMud4.5.3/doc/1stMud/
1stMud4.5.3/doc/Diku/
1stMud4.5.3/doc/MPDocs/
1stMud4.5.3/doc/Rom/
1stMud4.5.3/notes/
/**************************************************************************
*  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-2004 by Markanth                *
*            http://www.firstmud.com/  <markanth@firstmud.com>            *
*         By using this code you have agreed to follow the term of        *
*             the 1stMud license in ../doc/1stMud/LICENSE                 *
***************************************************************************/

#include "merc.h"
#include "recycle.h"

void write_string(FileData * fp, const char *name, const char *str,
				  const char *def)
{
	if (NullStr(name))
		f_printf(fp, "%s~" LF, fix_string(str));
	else if (!NullStr(str) && (NullStr(def) || str_cmp(str, def)))
		f_printf(fp, "%s%s%s~" LF, name, format_tabs(strlen(name)),
				 fix_string(str));
}

void write_word(FileData * fp, const char *name, const char *str,
				const char *def)
{
	if (NullStr(name))
		f_printf(fp, "'%s'" LF, fix_string(str));
	else if (!NullStr(str) && (NullStr(def) || str_cmp(str, def)))
		f_printf(fp, "%s%s'%s'" LF, name, format_tabs(strlen(name)),
				 fix_string(str));
}

void write_bit(FileData * fp, const char *name, flag_t bit, flag_t def)
{
	if (NullStr(name))
		f_printf(fp, "%s" LF, write_flags(bit));
	else if (bit != def)
		f_printf(fp, "%s%s%s" LF, name, format_tabs(strlen(name)),
				 write_flags(bit));
}

void write_header(FileData * fp, const char *head)
{
	if (!NullStr(head))
		f_printf(fp, "%s%s", head, format_tabs(strlen(head)));
}

void f_writef(FileData * fp, const char *name, const char *format, ...)
{
	if (!NullStr(format))
	{
		va_list args;
		char buf[MPL];

		va_start(args, format);

		vsnprintf(buf, sizeof(buf), format, args);
		va_end(args);
		if (!NullStr(name))
			f_printf(fp, name);
		f_printf(fp, "%s%s", format_tabs(strlen(name)), buf);
	}
	else if (!NullStr(name))
	{
		f_printf(fp, name);
	}
}

void write_time(FileData * fp, const char *name, time_t time, bool fTime)
{
	if (!NullStr(name))
		f_printf(fp, "%s%s", name, format_tabs(strlen(name)));
	else
		f_printf(fp, " ");

	f_printf(fp, TIME_T_FMT, time);

	f_printf(fp, " (%s)" LF,
			 !fTime ? str_time(time, -1, NULL) : timestr(current_time - time,
														 false));
}

void read_time(FileData * fp, time_t * tptr)
{
	*tptr = read_long(fp);
	read_to_eol(fp);
}

void read_dice(FileData * fp, int *dice)
{
	int i;

	for (i = 0; i < DICE_MAX - 1; i++)
	{
		dice[i] = read_number(fp);
		read_letter(fp);
	}
	dice[i] = read_number(fp);
}

void write_dice(FileData * fp, int *dice)
{
	int i;

	for (i = 0; i < DICE_MAX - 1; i++)
	{
		f_printf(fp, "%dd", dice[i]);
	}
	f_printf(fp, "%d", dice[i]);
}

bool is_space(char c)
{
	if (isspace(c))
	{
		switch (c)
		{
			case CUSTOMSTART:
			case CUSTOMEND:
			case MXP_BEGc:
			case MXP_ENDc:
				return false;
			default:
				return true;
		}
	}
	else
		return false;
}

#define MLR (MAX_STRING_LENGTH * 25)

const char *read_file(FileData * fp)
{
	char buf[MLR + 2];
	char c;
	size_t i = 0;
	bool sFull = false;

	memset(buf, 0, sizeof(buf));

	for (;;)
	{
		if (i >= MLR && !sFull)
		{
			bugf("file size exceeded %d maximum.", MLR);
			sFull = true;
		}

		switch (c = f_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 NUL:
				return str_dup(buf);

		}
	}
}

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;
}

void file_close(FILE * fp)
{
	if (fp != NULL)
	{
		fflush(fp);
		fclose(fp);
	}
	fp = NULL;

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

char read_letter(FileData * fp)
{
	char c;

	do
	{
		c = f_getc(fp);
	}
	while (is_space(c));

	return c;
}

int read_number(FileData * fp)
{
	int number;
	bool sign;
	char c;

	do
	{
		c = f_getc(fp);
	}
	while (is_space(c));

	number = 0;

	sign = false;
	if (c == '+')
	{
		c = f_getc(fp);
	}
	else if (c == '-')
	{
		sign = true;
		c = f_getc(fp);
	}

	if (!isdigit(c))
	{
		bugf("bad format '%c'... %s.", c,
			 AttemptJump ? "attempting longjmp" : "aborting");
		if (AttemptJump)
		{
			longjmp(jump_env, 1);
		}
		else
			abort();
	}

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

	if (sign)
		number = 0 - number;

	if (c == '|')
		number += read_number(fp);
	else if (c != ' ')
		f_ungetc(c, fp);

	return number;
}

long read_long(FileData * fp)
{
	long number;
	bool sign;
	char c;

	do
	{
		c = f_getc(fp);
	}
	while (is_space(c));

	number = 0;

	sign = false;
	if (c == '+')
	{
		c = f_getc(fp);
	}
	else if (c == '-')
	{
		sign = true;
		c = f_getc(fp);
	}

	if (!isdigit(c))
	{
		bugf("bad format '%c'... %s.", c,
			 AttemptJump ? "attempting longjmp" : "aborting");
		if (AttemptJump)
		{
			longjmp(jump_env, 1);
		}
		else
			abort();
	}

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

	if (sign)
		number = 0 - number;

	if (c == '|')
		number += read_long(fp);
	else if (c != ' ')
		f_ungetc(c, fp);

	return number;
}

flag_t read_flag(FileData * fp)
{
	flag_t number;
	flag_t flag;
	flag_t temp = 1;
	char c;
	bool negative = false;

	do
	{
		c = f_getc(fp);
	}
	while (is_space(c));

	if (c != '+')
	{
		if (c == '-')
		{
			negative = true;
			c = f_getc(fp);
		}

		number = 0;

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

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

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

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

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

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

		return flag;
	}
}

void read_to_eol(FileData * fp)
{
	char c;

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

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

	f_ungetc(c, fp);
	return;
}

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

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

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

	for (; pword < word + MIL; pword++)
	{
		*pword = f_getc(fp);
		if (cEnd == ' ' ? is_space(*pword) : *pword == cEnd)
		{
			if (cEnd == ' ')
				f_ungetc(*pword, fp);
			*pword = NUL;
			return word;
		}
	}

	bugf("word too long... %s.",
		 AttemptJump ? "attempting longjmp" : "aborting");

	if (AttemptJump)
	{
		longjmp(jump_env, 1);
	}
	else
		abort();
	return NULL;
}

const char *read_string(FileData * fp)
{
	static char buf[MLR + 2];
	size_t i = 0;
	register char c;
	bool sFull = false;

	do
	{
		c = f_getc(fp);
	}
	while (is_space(c));

	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 = f_getc(fp))
		{
			default:
				if (!sFull)
				{
					buf[i++] = c;
				}
				break;

			case NUL:

				bugf("EOF reached... %s.",
					 AttemptJump ? "attempting longjmp" : "aborting");
				if (AttemptJump)
				{
					longjmp(jump_env, 1);
				}
				else
					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;
		}
	}
}

void read_strfree(FileData * fp, const char **pstr)
{
	free_string(*pstr);
	*pstr = read_string(fp);
}

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

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

	do
	{
		if (f_eof(fp))
		{
			bug("EOF encountered on read.");
			strcpy(line, "");
			return line;
		}
		c = f_getc(fp);
	}
	while (is_space(c));

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

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

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

#ifdef STFILEIO

stFile *stopen(const char *file, const char *mode)
{
	struct stat buf;
	FileData *stfp;

	if (NullStr(file))
		return NULL;

	stfp = new_stfile();
	if (stfp == NULL)
		return NULL;

	stfp->file = str_dup(file);
	stfp->mode = str_dup(mode);

	if (mode[0] == NUL || tolower(mode[0]) == 'r')
	{
		if (stat(file, &buf) == -1 || !S_ISREG(buf.st_mode))
		{
			free_stfile(stfp);
			return NULL;
		}

		if ((stfp->stream = file_open(file, mode)) == NULL)
		{
			free_stfile(stfp);
			return NULL;
		}

		stfp->pos = 0;
		stfp->size = buf.st_size;
		alloc_mem(stfp->str, char, stfp->size + 1);
		fread(stfp->str, stfp->size + 1, 1, stfp->stream);
		stfp->str[stfp->size] = NUL;
	}
	else
	{
		static int count = 0;

		++count, count %= 999;

#if !defined WIN32 && !defined __CYGWIN__

		stfp->temp = str_dupf("%s.tmp%03d", stfp->file, count);
		if ((stfp->stream = file_open(stfp->temp, mode)) == NULL)
#else

		if ((stfp->stream = file_open(stfp->file, mode)) == NULL)
#endif

		{
			free_stfile(stfp);
			return NULL;
		}
	}
	Link(stfp, stfile, next, prev);
	return stfp;
}

int stclose(stFile * fp)
{
#if !defined WIN32 && !defined __CYGWIN__
	if (!NullStr(fp->temp) && rename(fp->temp, fp->file) == -1)
	{
		bugf("error renaming %s -> %s", fp->temp, fp->file);
	}
#endif
	free_stfile(fp);
	fp = NULL;
	return 0;
}

int stflush(stFile * fp)
{
	if (fp != NULL)
	{
		if (!NullStr(fp->mode) && fp->mode[0] != 'r')
		{
			fprintf(fp->stream, "%s\n", fp->str);
		}
		fflush(fp->stream);
	}
	else
		for (fp = stfile_first; fp; fp = fp->next)
			stflush(fp);

	return 0;
}

int steof(FileData * fp)
{
	return (fp->pos >= fp->size) ? EOF : 0;
}

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

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

	return c;
}

int stungetc(int c, stFile * fp)
{
	if (fp->pos > 0)
		fp->pos--;
	return fp->str[fp->pos];
}

size_t stread(void *ptr, size_t size, size_t nmemb, stFile * fp)
{
	size_t nsize;

	if (!fp->str || steof(fp))
		return 0;

	nsize = Min(fp->pos + size, fp->size);

	memcpy(ptr, &fp->str[fp->pos], nsize);
	return nsize;
}

int stprintf(stFile * fp, const char *fmt, ...)
{
	va_list args;
	int len;

	if (!fp || NullStr(fmt) || NullStr(fp->mode)
		|| tolower(fp->mode[0]) == 'r' || !fp->stream)
		return 0;

	va_start(args, fmt);
	len = vfprintf(fp->stream, fmt, args);
	va_end(args);

	return len;
}

int stseek(stFile * fp, long offset, int whence)
{
	if (!fp)
		return -1;

	switch (whence)
	{
		case SEEK_SET:
			fp->pos = 0;
			break;
		default:
		case SEEK_CUR:
			break;
		case SEEK_END:
			fp->pos = fp->size;
			break;
	}

	if (fp->pos + offset < 0 || fp->pos + offset >= fp->size)
		return -1;

	fp->pos += offset;
	return 0;
}

#endif