1stMud/CVS/
1stMud/area/CVS/
1stMud/backup/CVS/
1stMud/bin/
1stMud/bin/CVS/
1stMud/bin/extras/
1stMud/bin/extras/CVS/
1stMud/data/CVS/
1stMud/data/i3/CVS/
1stMud/doc/1stMud/
1stMud/doc/1stMud/CVS/
1stMud/doc/CVS/
1stMud/doc/Diku/
1stMud/doc/Diku/CVS/
1stMud/doc/MPDocs/CVS/
1stMud/doc/Merc/CVS/
1stMud/doc/Rom/
1stMud/doc/Rom/CVS/
1stMud/log/CVS/
1stMud/notes/
1stMud/notes/CVS/
1stMud/player/CVS/
1stMud/player/backup/CVS/
1stMud/player/deleted/CVS/
1stMud/src/CVS/
1stMud/src/config/CVS/
1stMud/src/h/CVS/
1stMud/src/o/CVS/
1stMud/win/CVS/
/**************************************************************************
*  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)
{
  dice[DICE_NUMBER] = read_number (fp);
  read_letter (fp);
  dice[DICE_TYPE] = read_number (fp);
  read_letter (fp);
  dice[DICE_BONUS] = read_number (fp);
}

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