/* $Id: h,v.direct-io 1.1 1998/07/31 14:58:28 stoklund Exp stoklund $ */
/* direct-io.h: Reading and writing files without the C library.

   Copyright (C) 1998 Jakob Stoklund Olesen

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public
   License along with this library; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */

#ifndef DIRECTIO_H
#define DIRECTIO_H

/* A file handle, equivalent to FILE* */
typedef struct dio__descriptor *dio_handle;

/* No members of this struct should be accessed by users. */
struct dio__descriptor
  {
    /* All open files are kept in a doubly linked list */
    dio_handle prev, next;

    /* Flags */
    enum
      {
	dio__INPUT = 1,		/* open for input */
	dio__OUTPUT = 2,	/* open for output */
	dio__EOF = 4,		/* EOF met */
	dio__ERROR = 8		/* some error occured */
      }
    flags;
    /* The buffer */
    char *buffer;
    size_t buffer_size;		/* Allocated buffer size */
    size_t count;		/* How many bytes in the inbuffer? */
    size_t pointer;		/* Current position in buffer */
    unsigned offset;		/* offset in file of buffer[0] */

    int handle;			/* file handle returned by OS_Find */
    size_t extent;		/* How big is this file */
  };

#ifndef EOF
#define EOF (-1)
#endif

/* These two functios are for internal use. */
extern int dio__refill (dio_handle, int);
extern int dio__flush (dio_handle, int);


/***************
   Input files.
 ***************/

/*
   Open a file for input.
   Returns: A handle for the opened file, or NULL.
   If the file cannot be opened or doesn't have read access,
   NULL is returned.
 */
extern dio_handle dio_openin (const char * /* filename */ );

/*
   Read a byte from FILE.
   Returns: The byte read or EOF on error or EOF.
 */
extern int dio_fgetc (dio_handle /* file */ );

/* Same as dio_fgetc, except a macro */
#define dio_getc(F) ( (F)->pointer < (F)->count ? \
  (F)->buffer[(F)->pointer++] : dio__refill((F),1) )

/*
   Read a line from FILE into BUFFER of size SIZE.
   Line terminators are not placed in the buffer.
   Returns: The number of bytes placed in buffer, excluding the terminator.
   If the buffer overflows, SIZE is returned and no terminator is added.
 */
extern size_t dio_gets (dio_handle /* file */ ,
			char * /* buffer */ , size_t /* size */ );

/*
   Peek the next byte from the input stream.
   Returns: The next byte to be read or EOF.
 */
#define dio_peek(F) ( (F)->pointer < (F)->count ? \
  (F)->buffer[(F)->pointer] : dio__refill((F),0) )

/*
   Check if end-of-file was met.
   Returns: non-zero if EOF was already met.
 */
#define dio_eof(F) ((F)->flags & dio__EOF)

/*
   Check if we are at the end of file.
   Returns: non-zero if EOF was met or the file pointer is at the end.
 */
#define dio_pascal_eof(F) ( dio_eof((F)) || (dio_tell((F)) >= (F)->extent) )

/*
   Check if we are at the end of a line.
   Returns: non-zoer if at EOF or at the end of a line.
 */
#define dio_pascal_eoln(F) ( dio_pascal_eof((F))\
  || dio_peek((F)) == '\n' || dio_peek((F)) == '\r' )

/****************
   Output Files.
 ****************/

/*
   Open a file for output. Create a new file if it doesn't exist.
   The file is truncated to zero length.
   Returns: A handle for the new file.
   If the open fails or the file does not have write access,
   NULL is returned.
 */
extern dio_handle dio_openout (const char * /* filename */ ,
			       int /* filetype */ );

/*
   Write a byte to FILE. Note that arguments are not like fputc().
   Returns: The byte written or EOF on error.
 */
extern int dio_fputc (dio_handle /* file */ , int /* char */ );

/* Same as dio_fputc, except a macro */
#define dio_putc(F,C) ( (F)->pointer < (F)->buffer_size ?\
  (F)->buffer[(F)->pointer++] = (C) : dio__flush((F),(C)) )

/*******************
  Input and Output.
 *******************/

/*
   Close a file that was opened with dio_openin or dio_openout.
   Buffered data is written to disk for output files.
   Returns: zero on success, non-zero of something goes wrong.
 */
extern int dio_close (dio_handle);

/*
   Check if an error has occurred on the stream.
   Returns: non-zero if a read or write error has occurred.
 */
#define dio_error(F) ((F)->flags & dio__ERROR)

/*
   Return the current position.
 */
#define dio_tell(F) ((F)->offset + (F)->pointer)

#endif /* not DIRECTIO_H */
