/*  -*- Mode: C -*-  */

/* stream.h ---  */

/* Author:	       Gary V. Vaughan <gvv@techie.com>
 * Maintainer:	       Gary V. Vaughan <gvv@techie.com>
 * Created:	       Thu Apr 22 22:49:48 1999
 * Last Modified:      Wed Jul 14 15:08:16 1999
 *            by:      Gary V. Vaughan <gvv@techie.com>
 * ---------------------------------------------------------------------
 * @(#) $Id$
 * ---------------------------------------------------------------------
 */

/* Copyright (C) 1999 Gary V. Vaughan */

/* This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program 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
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; see the file COPYING.  If not, write to
 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 *
 * As a special exception to the GNU General Public License, if you
 * distribute this file as part of a program that also links with and
 * uses the libopts library from AutoGen, you may include it under
 * the same distribution terms used by the libopts library.
 */

/* Code: */

#ifndef STREAM_H
#define STREAM_H 1

#ifndef PARAMS
#  if __STDC__
#    ifndef NOPROTOS
#      define PARAMS(args)	args
#    endif
#  endif
#  ifndef PARAMS
#    define PARAMS(args)	()
#  endif
#endif

#define STREAM_READABLE		(1 << 0)
#define STREAM_WRITABLE		(1 << 1)

#ifdef __cplusplus
extern "C" {
#if 0
/* This brace is so that emacs can still indent properly: */ }
#endif
#endif /* __cplusplus */

#ifdef __STDC__
/**
 * stream_gpointer:
 * A portable generic pointer which works with K&R compilers too.
 * We use a different generic pointer typedef to the rest of snprintfv,
 * to make it easy for anyone who wants to extract the stream files
 * from this dist' and use them without pulling in all the compat.h
 * generation code and associated dependencies.
 **/
typedef void *stream_gpointer;
#else
typedef char *stream_gpointer;
#endif

/**
 * STREAM:
 * Data type used to pass details of streams between functions,
 * much like stdio's FILE, but more flexible.  A STREAM can be uni- or
 * bi-directional depending on how it is initialised.
 **/
typedef struct stream STREAM;

/**
 * stream_put_function:
 * @ch: The character to write to @stream cast to an int.
 * @stream:  The stream being written to.
 *
 * Type of the function to put a character in a writeable stream.
 *
 * Return value:
 * The function should return the character written to the
 * stream, cast to an int if it was written successfully, or
 * else EOF, if the write failed.
 **/
typedef int stream_put_function PARAMS((int ch, STREAM *stream));

/**
 * stream_get_function:
 * @stream:  The stream being read from.
 *
 * Type of the function to get a character from a readable stream.
 *
 * Return value:
 * The function should return the character read from the
 * stream, cast to an int if it was read successfully, or
 * else EOF, if the read failed.
 **/
typedef int stream_get_function PARAMS((STREAM *stream));

/**
 * stream_finalize_function:
 * @dets: User supplied stream details now pending deletion.
 *
 * Type of the function to clean up any user supplied stream
 * details (such as closing file descriptors) before recycling
 * the containing structure.
 *
 * Return value:
 * Should eturns 0 if @dets is successfully finalized, or else -1.
 */
typedef int stream_finalize_function PARAMS((stream_gpointer *dets));

struct stream {
    stream_gpointer stream;
    unsigned long limit;

    stream_get_function *get_func;
    stream_put_function *put_func;
    stream_finalize_function *finalize_func;
};

/**
 * stream_new:  constructor 
 * @dets: user supplied stream details to be passed into the various funcs.
 * @limit: the maximum number of consecutive bytes to fit in @dets.
 * @get_func: function to get a character from @dets stream.
 * @put_func: function to put a character in @dets stream.
 * @finalize_func: function to finalize @dets before the stream is recycled.
 * 
 * Allocate and initialize a new STREAM data type.
 * 
 * Return value:
 * The address of the newly allocated and initialised stream is returned.
 **/
extern STREAM* stream_new PARAMS((stream_gpointer dets, unsigned long limit, stream_get_function *get_func, stream_put_function *put_func, stream_finalize_function *finalize_func));

/**
 * stream_init:   
 * @stream: The stream to be initialized.
 * @dets: user supplied stream details to be passed into the various funcs.
 * @limit: the maximum number of consecutive bytes to fit in @dets.
 * @get_func: function to get a character from @dets stream.
 * @put_func: function to put a character in @dets stream.
 * 
 * Initialize @stream with the data contained in the arguments to this
 * function.
 **/
extern void stream_init PARAMS((STREAM *stream, stream_gpointer dets, unsigned long limit, stream_get_function *get_func, stream_put_function *put_func));

/**
 * stream_delete:  destructor 
 * @stream: The stream pending deletion
 * 
 * The finalization function specified when @stream was created (if any)
 * is called, and then the memory associated with @stream is recycled.
 * It is the responsibility of the finalization function to recycle, or
 * otherwise manage, any memory associated with the user supplied %dets.
 **/
extern void stream_delete PARAMS((STREAM *stream));

/**
 * stream_put:   
 * @ch: A single character to be placed in @stream.
 * @stream: The stream to be written to.
 * 
 * This function will @ch in @stream if that stream's output limit will
 * not be exceeded.
 * 
 * Return value:
 * If @stream is full, or any other error occurs, that error code is
 * returned unchanged.  This is of course dependant on what the handler
 * function uses to indicate an error.  Otherwise, 1 (the number of
 * characters emitted!) is returned.
 **/
extern int stream_put PARAMS((int ch, STREAM *stream));

/**
 * stream_get:   
 * @stream: The stream to be read from.
 * 
 * This function will try to read a single character from @stream.
 * 
 * Return value:
 * If an error occurs or the end of @stream is reached, -1 is returned.
 * Under normal circumstances the value if the character read (cast to
 * an int) is returned.
 **/
extern int stream_get PARAMS((STREAM *stream));


#ifdef __cplusplus
#if 0
/* This brace is so that emacs can still indent properly: */ {
#endif
}
#endif /* __cplusplus */

#endif /* STREAM_H */
