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