Metropoli BBS
VIEWER: fileio.c MODE: TEXT (ASCII)
/***
*fileio.c - disked file I/O
*
*Copyright (c) 1991-1995, Gregg Jennings.  All wrongs reserved.
*   P O Box 200, Falmouth, MA 02541-0200
*
*Purpose:
*   File read/write functions.
*
*Notice:
*   This progam may be freely used and distributed.  Any distrubution
*   with modifications must retain the above copyright statement and
*   modifications noted.
*   No pulp-publication, in whole or in part, permitted without
*   permission (magazines or books).
*******************************************************************************/

/*
   Versions

   1.0   10-Nov-1994    added calls to new error functions (see ERROR.C)
   0.1   07-Sep-1994    created
*/

#include <stdio.h>
#include <conio.h>         /* for kbhit() */
#include <stdlib.h>
#include <ctype.h>
#include <fcntl.h>         /* uses both stream and handle */
#include <io.h>
#include <sys\types.h>
#include <sys\stat.h>
#include <errno.h>
#include <setjmp.h>

#include "disked.h"        /* append() declaration */
#include "diskio.h"        /* drive parameters */
#include "console.h"       /* print(), output(), */
#include "error.h"         /* error handling */

/* globals referenced here 

   data_buf
   byte_cnt
   max_bytes
   log_sector
   num_sectors
   sec_buf
   sec_size
   Display
   harderr_list

*/

/* NO globals defined here */


/* internal data */

static FILE *fh;
static int fd;
static jmp_buf mark;                /* address for long jump to jump to */
static int jmpret;

/*
   I think I finally found a good use for setjmp() and longjump().
   All examples I have found is based on a simple floating point
   error handler.

   For each of the file I/O functions, the stack is saved via
   setjmp().  On error fio_error() is called which returns via
   longjmp().

   The next level of abstraction would to be somehow return
   directly to the caller!
*/

static void fio_error(char *);

/***
*putfile -
*
****/

extern int putfile(char *filename, int xlate, int m, int s, int c)
{
register int ch;
unsigned int i;
char *func = "putfile";

   errno = 0;
   jmpret = setjmp(mark);

   if (jmpret == 0)
   {
      if ((fh = fopen(filename,"w+b")) == NULL)
         fio_error(func);
      for (i = 0; i < byte_cnt; i++)
      {
         if (kbhit())
            break;

         ch = data_buf[i]&0xff;
         if (xlate && !isprint(ch) && !isspace(ch))
         {
            if (s)                              /* do we strip? */
               continue;
            else if (m)                         /* do we mask ? */
            {
               ch &= 0x7F;
               if ((ch = putc(ch,fh)) != ch)
                  break;
            }
            else if (c)                         /* do we convert? */
            {
               if (fprintf(fh,"<%02x>",ch) != 4)
                  break;
            }
         }
         else if ((ch = putc(ch,fh)) != ch)     /* no mask, just put */
            break;
      }
      if (fclose(fh) == -1)
      {
         fh = NULL;
         fio_error(func);
      }
      return 1;
   }
   return -1;
}

#ifdef __BORLANDC__
#pragma warn +par
#endif

/***
*getfile -
*
****/

extern int getfile(char *filename, int xlate, int m, int s, int c)
{
int i;
char *func = "getfile";
unsigned char buffer[512];

   errno = 0;

   jmpret = setjmp(mark);

   if (jmpret == 0)
   {
      if ((fd = _open(filename,_O_RDONLY|_O_BINARY)) == -1)
      {
         if (error.num != -1)
            return -1;
         fio_error(func);
      }
      while ((i = _read(fd,buffer,512)) > 0)
      {
         if (kbhit())
            break;

         if (xlate)
            append(s,m,c,buffer,i);
         else
            append(0,0,0,buffer,i);
         if (byte_cnt == max_bytes)
            return -2;
      }
      if (i == -1)
         fio_error(func);
      if (close(fd) == -1)
         fio_error(func);
      return 1;
   }
   return -1;
}

/***
*putsectors -  put sectors to a file
*
****/

#define o_flag (_O_CREAT|_O_TRUNC|_O_BINARY|_O_RDWR)
#define p_mode (_S_IWRITE|_S_IREAD)

extern int putsectors(char *file, long start, int num)
{
int i;
char *func = "putsects";

   errno = 0;
   jmpret = setjmp(mark);
   savesector();

   if (jmpret == 0)
   {
      if ((fd = _open(file,o_flag,p_mode)) == ERROR)
         fio_error(func);
      if (start == 0)
         log_sector = num_sectors-1;
      else
         log_sector = start-1;
      for (i = 0; i < num; i++)
      {
         if (kbhit())            /* abort if like errors or something */
            break;

         if (Display)
            put(print("%d",i),8);

         nextsector();
         if (_write(fd,sec_buf,sec_size) != (int)sec_size)
            fio_error(func);
      }
      _close(fd);
      restoresector();
      return 1;
   }
   restoresector();
   return -1;
}

/***
*fio_error  -  error handler
*
****/

static void fio_error(char *func)
{
char *msg;

   if (fh)                             /* close file stream if open */
      fclose(fh);
   if (fd > 0)                         /* close file handle if open */
      close(fd);
   if (!errno)                         /* if errno NOT set, set it now */
      errno = exterror();
   if (errno < 16)                     /* sys_nerr is 37! */
      msg = sys_errlist[errno];
   else if (errno >= 19 && errno <= 31)
      msg = (char *)harderr_list[errno-19];
   else
   {
      msg = "DOS error code: ";
      set_err_arg("%02Xh",errno);
   }
   set_error(msg,"fileio",errno,func);
   longjmp(mark,-1);
}

/***
*append  -  Append bytes into the databuffer.  The bytes are from the
*           sectorbuffer or a file.
*
*           returns OK or ERROR if full
****/

extern int append(int s, int m, int c, unsigned char *buffer, unsigned int nbytes)
{
register int ch;
register int h;
unsigned int i;

   for (i = 0; i < nbytes; i++)
   {
      ch = buffer[i]&0xff;
      if (!isprint(ch) && !isspace(ch))
      {
         if (s)                              /* do we strip? */
            continue;
         if (m && ch > 0x7f)                 /* do we mask ? */
         {
            data_buf[byte_cnt++] = (char)(ch&0x7f);
            continue;
         }
         if (c && byte_cnt < max_bytes-4)    /* do we convert? */
         {
            data_buf[byte_cnt++] = '<';
            h = (ch>>4)&0x0f;
            data_buf[byte_cnt++] = (unsigned char)((h>9) ? (h+'a'-10) : (h+'0'));
            h = ch&0x0f;
            data_buf[byte_cnt++] = (unsigned char)((h>9) ? (h+'a'-10) : (h+'0'));
            data_buf[byte_cnt++] = '>';
         }
         else
            data_buf[byte_cnt++] = (char)ch; /* no mask, just put */
      }
      else
         data_buf[byte_cnt++] = (char)ch;    /* no mask, just put */
      if (byte_cnt == max_bytes)
         return ERROR;
   }
   return 1;
}

extern long filesize(const char *file)
{
int fd;
long l;

   if ((fd = _open(file,0)) != -1)
   {
      l = _filelength(fd);
      _close(fd);
   }
   else
      l = -1L;

   return l;
}
[ RETURN TO DIRECTORY ]