/
Crimson2/alias/
Crimson2/area.tmp/
Crimson2/area.tmp/AnomalySpaceDock/
Crimson2/area.tmp/AnomalyStation/
Crimson2/area.tmp/AntHill/
Crimson2/area.tmp/ArcticTerrarium/
Crimson2/area.tmp/BuilderCity/
Crimson2/area.tmp/Dungeon/
Crimson2/area.tmp/MiningDock/
Crimson2/area.tmp/PipeSystem/
Crimson2/area.tmp/RattArea/
Crimson2/area.tmp/RobotFactory/
Crimson2/area.tmp/SilverDale/
Crimson2/area.tmp/StarshipFearless/
Crimson2/area.tmp/StationConduits/
Crimson2/area.tmp/TerrariumAlpha/
Crimson2/area.tmp/TerrariumBeta/
Crimson2/area.tmp/TestArea/
Crimson2/area.tmp/Void/
Crimson2/area/
Crimson2/area/AnomalySpaceDock/
Crimson2/area/AnomalyStation/
Crimson2/area/MiningDock/
Crimson2/area/PipeSystem/
Crimson2/area/SilverDale/
Crimson2/area/StationConduits/
Crimson2/area/Void/
Crimson2/board/
Crimson2/clone/
Crimson2/lib/
Crimson2/mole/
Crimson2/mole/mole_src/HELP/
Crimson2/player/
Crimson2/util/
Crimson2/wldedit/
Crimson2/wldedit/res/
/* Crimson2 Mud Server
 * All source written/copyright Ryan Haksi 1995 *
 * This source code is proprietary. Use in whole or in part without
 * explicity permission by the author is strictly prohibited
 *
 * Current email address(es): cryogen@infoserve.net
 * Phone number: (604) 591-5295
 *
 * C4 Script Language written/copyright Cam Lesiuk 1995
 * Email: clesiuk@engr.uvic.ca
 */

/* file.c */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h> /* both for stat */

#include "crimson2.h"
#include "macro.h"
#include "mem.h"
#include "str.h"
#include "log.h"
#include "file.h"

BYTE fileVerbose = 1;
BYTE fileError = FALSE;

FILELIST fileList[] = {
  {"msg/greeting.msg", NULL, 0},
  {"msg/ciao.msg",     NULL, 0},
  {"msg/news.msg",     NULL, 0},
  {"msg/motd.msg",     NULL, 0},
  {"msg/quit.msg",     NULL, 0},
  {"msg/credit.msg",   NULL, 0},
  {"msg/death.msg",    NULL, 0},
  {"msg/banned.msg",   NULL, 0},
  {"msg/bannew.msg",   NULL, 0},
  {"msg/offsite.msg",  NULL, 0},
  {"",                 NULL, 0}
};

#define FILE_STR_MAX 1<<14 /* 32K character strings can be saved/read */

void FileInit(void) {
  WORD i;
  BYTE buf[256];

  Log(LOG_BOOT, "Initing Files\n");
  sprintf(buf, "Maximum file string size: %d\n", FILE_STR_MAX);
  Log(LOG_BOOT, buf);
  for (i=0; *fileList[i].fileName; i++) {
    sprintf(buf, "Reading: %s\n", fileList[i].fileName);
    Log(LOG_BOOT, buf);
    FileRead(&fileList[i]);
  }
}

void FileRead(FILELIST *fileList){ /* read in whole file as a string */
  /* stat the file, malloc a buffer equal to its length, yes MALLOC
     if we called MemAlloc, then it would be stored in a chunk of the
     initial mem space allocation (which we dont want) cuz this is just
     temporary */
  /* read the whole thing in with fread or whatever */
  /* then StrAlloc buffer - hmm possibly a special case do we want a STR or char *
     chances of multiple instances are slim to none, except editor only works
     on STR so STR it is...
   */
#define STAT_ERROR -1

  struct stat theStat;
  WORD        error;
  FILE       *theFile;
  BYTE       *fileBuf; /* no translation necessary from *UNIX* format */
  BYTE        buf[256];
  STR        *fileStr;

  fileError = FALSE;
  error = stat(fileList->fileName, &theStat);
  if (error == STAT_ERROR) {
    sprintf(buf, "WARNING! FileRead(%s): Read Error (file not found?)\n", fileList->fileName);
    Log(LOG_ERROR, buf);
    PERROR("FileRead");
    fileError = TRUE;
    return;
  }
  MALLOC(fileBuf, char, theStat.st_size+1);
  theFile=fopen(fileList->fileName, "rb");
  if (!theFile) {
    sprintf(buf, "FileRead(%s): Read Error! (file does exist though)\n", fileList->fileName);
    Log(LOG_ERROR, buf);
    PERROR("FileRead");
    fileError = TRUE;
    return;
  }
  fread(fileBuf, theStat.st_size+1, 1, theFile);
  fileBuf[theStat.st_size]='\0'; /*should have got this as EOF char of file but doesnt hurt */
  fclose(theFile);

  fileStr = STRCREATE(fileBuf);

  fileList->fileStr = fileStr;
  FREE(fileBuf, theStat.st_size+1);
  fileList->fileDate= theStat.st_mtime;
}

STR  *FileBinaryRead   (FILE *file){
  BYTE         *buf;
  BYTE          line[256];
  unsigned int  hexValue;
  BYTE          sText[FILE_STR_MAX];
  LWORD         sLen = 0;
  LWORD         i;

  fileError = FALSE;
  printf("FileBinaryRead: Untested!\n");
  while (1) {
    fgets(line, 256, file);
    if (feof(file)) {
      Log(LOG_ERROR, "FileBinaryRead(file.c): Unexpected End of File\n");
      fileError = TRUE;
      break;
    }
    
    buf = line; while(*buf==' ') buf++;
    while (*buf && *buf!='\n') {
      if (*buf == '~') { /* end of str found */
  /* see if there is crap floating on the end of the str */
  for(i=1;((buf[i]=='\n') || (buf[i]==' ')) && buf[i] !='\0'; i++);
  if (buf[i] != '\0') {
    Log(LOG_ERROR, "FileBinaryRead(file.c): Ignoring extraneous chars (\"");
    LogPrintf(LOG_ERROR, sText);
    LogPrintf(LOG_ERROR, "\")\n");
          fileError = TRUE;
  }
  return StrCreate(sText, sLen-1, DONTHASH);
      }

      /* copy the just read hex value into str */
      sscanf(buf, " %x", &hexValue);
      sText[sLen] = hexValue;
      sLen++;
      buf = StrOneWord(buf, NULL);
    }
  }
  /*
   * dont believe we'll ever fall through to here 
   * but compiler will generate warnings
   */
  return StrCreate(sText, sLen-1, DONTHASH);
}

/* read a string line at a time until a tilda is read,
   NOTE: anything after the ~ on the SAME line will be IGNORED! (I'll warn you dont worry)
   other than that can format the data files however you like with whitespace */
STR  *FileStrRead(FILE *file){
  BYTE  buf[256];
  BYTE  sText[FILE_STR_MAX];
  LWORD sLen = 0;
  LWORD i;

  fileError = FALSE;
  while (1) {
    fgets(buf, 256, file);
    if (feof(file)) {
      Log(LOG_ERROR, "FStrRead(file.c): Unexpected End of File\n");
      fileError = TRUE;
      break;
    }
    /* copy the just read str */
    for(i=0; buf[i] != '\0' && buf[i] != '~'; i++) {
      sText[sLen] = buf[i];
      sLen++;
    }
    if (buf[i] == '~') { /* end of str found */
      /* see if its binary */
      if (!strcmp(buf+i+1, "BINARY")) {
        return FileBinaryRead(file);
      }
      /* see if there is crap floating on the end of the str */
      for(i++;((buf[i]=='\n') || (buf[i]==' ') || (buf[i]=='\r')) && buf[i] !='\0'; i++);
      if (buf[i] != '\0') {
        sText[sLen] = '\0';
        Log(LOG_ERROR, "FStrRead(file.c): Ignoring extraneous chars (\"");
        LogPrintf(LOG_ERROR, sText);
        LogPrintf(LOG_ERROR, "\")\n");
        fileError = TRUE;
      }
      break;
    }
  }
  sText[sLen] = '\0';
  /* return STRCREATE(sText); */
  return StrCreate(sText, SLEN_UNKNOWN, HASH);
}

LWORD FileFlagRead(FILE *file, BYTE *fList[]) {
  BYTE  buf[FILE_STR_MAX];
  FLAG  flag;

  fileError = FALSE;
  fscanf(file, " %s", buf);
  if (StrIsNumber(buf)) {
    return atol(buf);
  } else {
    flag = FlagSscanf(buf, fList);
  }
  return flag;
}

LWORD FileTypeRead(FILE *file, ULWORD tList, LWORD tSize) {
  BYTE  buf[FILE_STR_MAX];
  LWORD type;

  fileError = FALSE;
  fscanf(file, " %s", buf);
  type = TypeSscanf(buf, tList,tSize);
  if (type == -1) {
    type = 0;
    Log(LOG_ERROR, "Unknown type entry encountered on FileTypeRead:");
    LogPrintf(LOG_ERROR, *((BYTE**)tList));
    LogPrintf(LOG_ERROR, "\n");
    Log(LOG_ERROR, buf);
    LogPrintf(LOG_ERROR, "\n");
    fileError = TRUE;
  }
  return type;
}

BYTE FileByteRead(FILE *file) {
  WORD temp=0;

  fileError = FALSE;
  fscanf(file, " %hd", &temp);
  return (BYTE)temp;
}


/* write modes, if verbose is selected the routines will expand the flag/type etc
   to the name, thus making it much easier to text edit the files */

/* currently Writing is not asynchronous (although it probably should be) so beware
   performance implications! (although disk should buffer output streams so that it is sorta) */
BYTE FileStrWrite(FILE *file, STR *str){

  fileError = FALSE;
  /* this one is easy */
  if (!file) {
    Log(LOG_ERROR, "FStrWrite: No file defined\n");
    return FALSE;
  }
  if (!str) { /* this should NEVER HAPPEN! */
    Log(LOG_ERROR, "FStrWrite(file.c): Null STR passed!\n");
    fprintf(file,"~\n");
    return TRUE; /* well it worked didnt it? */
  }
  if (str->sLen > FILE_STR_MAX) { /* this should NEVER HAPPEN! */
    Log(LOG_ERROR, "WARNING! FStrWrite(file.c): STR too long for read!\n");
  }
  fprintf(file, "%s~\n", str->sText);
  return TRUE;
}

/* Write a string out in Binary format */
BYTE FileBinaryWrite(FILE *file, STR *str){
  LWORD i;

  fileError = FALSE;
  /* this one is easy */
  if (!file) {
    Log(LOG_ERROR, "FStrWrite: No file defined\n");
    return FALSE;
  }
  if (!str) { /* this should NEVER HAPPEN! */
    Log(LOG_ERROR, "FStrWrite(file.c): Null STR passed!\n");
    fprintf(file,"~\n");
    return TRUE; /* well it worked didnt it? */
  }
  if (str->sLen > FILE_STR_MAX) { /* this should NEVER HAPPEN! */
    Log(LOG_ERROR, "WARNING! FStrWrite(file.c): STR too long for read!\n");
  }

  fprintf(file, "~BINARY\n");
  for(i=0; 1; i++) {
    fprintf(file, " %02X", str->sText[i]);
    if (i == str->sLen-1) break;
    if (!i%26) fprintf(file, "\n");
  }
  fprintf(file, "\n~\n");
  return TRUE;
}

void  FileTypeWrite(FILE *file, LWORD type, ULWORD tList, LWORD tSize, BYTE next){
  BYTE buf[512];

  fileError = FALSE;
  if (fileVerbose) {
    TypeSprintf(buf, type, tList, tSize, 512);
    if (!buf[0]) strcpy(buf, "0");
    fprintf(file, "%s%c", buf, next);
  } else {
    fprintf(file, "%ld%c", type, next);
  }
}

void  FileFlagWrite(FILE *file, FLAG flag, BYTE *fList[], BYTE next){
  BYTE buf[512];

  fileError = FALSE;
  if (fileVerbose) {
    FlagSprintf(buf, flag, fList, '|', 512);
    if (!buf[0]) strcpy(buf, "0");
    fprintf(file, "%s%c", buf, next);
  } else {
    fprintf(file, "%ld%c", flag, next);
  }
}


void FileByteWrite(FILE *file, BYTE value, BYTE separator) {
  WORD temp;

  fileError = FALSE;
  temp=value;
  fprintf(file, "%hd%c", temp, separator);
}