static char rcsid[] = "$Id: fileio.c,v 1.6 1993/08/24 14:53:42 mike Exp $";

/* $Log: fileio.c,v $
 * Revision 1.6  1993/08/24  14:53:42  mike
 * - Catch *all* write errors now! (Hell, I'm glad that it's me who
 *   found this lurking horror and nobody else seems to have noticed it ...).
 * - Files with missing newlines at the end are read correctely now
 *   (and complained about).
 * - New function `ffcleanup': Closes and removes the temporary output file
 *   on write failure.
 *
 * Revision 1.5  1992/12/17  23:07:22  mike
 * - Fixed bug: A fence post error in `ffputline' caused occasional
 *   bombs.
 *
 * Revision 1.4  1992/11/10  21:46:58  mike
 * - Complain about too long text lines.
 *
 * Revision 1.3  1992/11/08  23:04:28  mike
 * - Added safe file-save.
 *
 * Revision 1.2  1992/10/27  23:53:02  mike
 * - Completely rewritten to speedup file access. This version is not
 *   portable anymore, it just works for the Atari ST/TT!
 *
 * Revision 1.1  1992/09/05  01:13:32  mike
 * Initial revision
 *
 */

/*
 * FILEIO.C
 * The routines in this file read and write ASCII files from the disk.  All
 *   of the knowledge about files are here.  A better message writing scheme
 *   should be used.
 * Well, the above is not quite true anymore.  os.c knows something about
 *   files as does the Mutt Machine but I've tried to keep it portable.
 */

/* C Durland	Public Domain
 *   Distributed "as is", without warranties of any kind, but comments,
 *     suggestions and bug reports are welcome.
 */

#include <fcntl.h>
#include <osbind.h>

#include "me2.h"


#define BSIZE	65536		/* Size of the IO buffer		    */

static int    Fp;		/* File pointer, all functions. (sleaze)    */
static short  Output_buffer;	/* Is the buffer currently used for output? */
static char   IObuffer[BSIZE];	/* The IO buffer			    */
static char  *Watermark;	/* First unused byte in `IObuffer'	    */
static char  *IOindex;		/* Next byte to read or write		    */
static char   O_filename[NFILEN];	/* Original GEMDOS filename	    */
static char   Filename[NFILEN];		/* Name of GEMDOS tmp file	    */
static short  Complain = 0;	/* Complain about a too long line?	    */



static void convert(fn)
char *fn;
{
  register char *p;

  p = Filename;
  strcpy(Filename,fn);
  while (*p)
  {
    if (*p == '/')
      *p++ = '\\';
    else
      p++;
  }
}



/*
 *	Open a file for reading
 */

int ffropen(fn)
char *fn;
{
  convert(fn);
  if ((Fp = Fopen(Filename,0)) < 0)
    return FIOFNF;
  Watermark = IOindex = IObuffer;
  Output_buffer = 0;
  Complain = 1;
  return FIOSUC;
}



/*
 *	Open a file for writing
 */

int ffwopen(fn)
char *fn;
{
  register char *p;
  register char  c;

  convert(fn);
  strcpy(O_filename,Filename);
  p  = Filename + strlen(fn) - 1;
  c  = *p;
  *p = '$';
  if (access(Filename,F_OK))
  {
    if (!access(O_filename,F_OK) && access(O_filename,W_OK))
    {
      mlwrite("[Cannot open file for writing]");
      return FIOFNF;
    }
  }
  else
  {
    *p = c;
    O_filename[0] = '\0';
  }
  if ((Fp = Fcreate(Filename,0)) < 0)
  {
    mlwrite("Cannot open temporary file for writing");
    return FIOFNF;
  }
  Watermark = (IOindex = IObuffer) + BSIZE;
  Output_buffer = 1;
  Complain = 1;
  return FIOSUC;
}



/*
 *	Close a file. Should look at the status on all systems
 */

int ffclose()
{
  if (Output_buffer && IOindex > IObuffer)
  {
    if (Fwrite(Fp, (long) (IOindex - IObuffer), IObuffer) != IOindex - IObuffer)
    {
      mlwrite("WRITE ERROR!");
      t_beep();
      Fclose(Fp);
      return FIOERR;
    }
  }
  if (Fclose(Fp))
  {
    mlwrite("Error closing file");
    return FIOERR;
  }
  if (Output_buffer && O_filename[0])
  {
    if (!access(O_filename,F_OK) && Fdelete(O_filename))
    {
      mlwrite("[Cannot delete old file -- text saved to temporary file]");
      return FIOERR;
    }
    if (Frename(0,Filename,O_filename))
    {
      mlwrite("[Cannot rename temporary file]");
      return FIOERR;
    }
  }
  return FIOSUC;
}



/*
 *	Clean up after a read or write error.
 */

void ffcleanup()
{
  Fclose(Fp);
  if (Output_buffer && O_filename[0])
    Fdelete(Filename);
}



/*
 *	Write a line to the already opened file.
 *	n is the line length, less the free newline. Return the status.
 *	Check only at the newline.
 */

int ffputline(buf,n)
unsigned char *buf;
int n;
{
  if (IOindex + n + 2 >= Watermark)
  {
    if (Fwrite(Fp, (long) (IOindex - IObuffer), IObuffer) != IOindex - IObuffer)
    {
      mlwrite("WRITE ERROR!");
      t_beep();
      return FIOERR;
    }
    IOindex = IObuffer;
  }
  strncpy(IOindex,buf,n);
  IOindex += n;
  *IOindex++ = '\r';
  *IOindex++ = '\n';
  return FIOSUC;
}



/*
 *	Read a line from a file and store the bytes in the supplied buffer.
 *	n is the length of the buffer, counting the '\0'.
 *	Complain about long lines and lines at the end of the file that don't
 *	have a newline present. Check for I/O errors too. Return status.
 */

int ffgetline(buf,n)
register char *buf;
register int   n;
{
  register char *ptr;
  register long  read;
  register char  c;

  for (ptr = buf; ptr - buf < n;)
  {
    if (IOindex >= Watermark)
    {
      if ((read = Fread(Fp,BSIZE,IObuffer)) == BSIZE)
      {
	IOindex = IObuffer;
	Watermark = IObuffer + BSIZE;
      }
      else if (read > 0)
      {
	Watermark = IObuffer + read;
	IOindex   = IObuffer;
	if (Watermark[-1] != '\n')
	{
	  mlwrite("[Warning: Missing newline at end of file]");
	  Watermark[-1] = '\n';
	}
      }
      else if (read < 0)
      {
        Watermark = IOindex = IObuffer;
	*ptr = '\0';
	mlwrite("File read error");
	return FIOEOF;
      }
      else	/* read == 0 */
        return FIOEOF;
    }
    if ((c = *IOindex++) == '\r')
      continue;
    if (c == '\n')
    {
      *ptr = '\0';
      return FIOSUC;
    }
    *ptr++ = c;
  }
  if (Complain)
  {
    mlwrite("[WARNING: Too long text line splitted!]");
    t_beep();
    Complain = 0;
  }
  *ptr = '\0';
  return FIOSUC;
}
