/* libsizzle/port.h - port function declarations
 
  Copyright (C) 1999, 2000 Martin Grabmueller <mgrabmue@cs.tu-berlin.de>
 
  This 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, or (at your option)
  any later version.
  
  This software 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 package; see the file COPYING.  If not, write to the
  Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
  MA 02111-1307, USA.  */

#ifndef __SIZZLE_PORT_H__
#define __SIZZLE_PORT_H__

#if HAVE_CONFIG_H
# include <config.h>
#endif 

#if __SIZZLE_IMPORT__
# define SIZZLE_API __declspec (dllimport)
#elif __SIZZLE_EXPORT__ 
# define SIZZLE_API __declspec (dllexport)
#else
# define SIZZLE_API
#endif

#include "node.h"

/* Port type descriminator and accessor macros.  */
#define port_p(c)           (tagged_p(c) && \
                             tagged_type(c) == zzz_tagged_type_port)
#define port_ptype(c)       (((port_desc_t) tagged_data0(c))->port_type)
#define port_open_p(c)      (((port_desc_t) tagged_data0(c))->is_open)
#define port_write_p(c)     (((port_desc_t) tagged_data0(c))->can_write)
#define port_read_p(c)      (((port_desc_t) tagged_data0(c))->can_read)
#define port_line_number(c) (((port_desc_t) tagged_data0(c))->line_number)
#define port_col_number(c)  (((port_desc_t) tagged_data0(c))->col_number)
#define port_saved_col(c)   (((port_desc_t) tagged_data0(c))->saved_col)
#define port_filename(c)    (((port_desc_t) tagged_data0(c))->filename)
#define port_flags(c)       (((port_desc_t) tagged_data0(c))->flags)
#define port_tty_p(c)       (((port_desc_t) tagged_data0(c))->tty_p)
#define port_info(c)        (((port_desc_t) tagged_data0(c))->info)

/* Function types for the supported port functions.  */
typedef int (*port_getc_t) (zzz_scm_t port);
typedef void (*port_ungetc_t) (int c, zzz_scm_t port);
typedef void (*port_putc_t) (int c, zzz_scm_t port);
typedef void (*port_puts_t) (zzz_scm_t port, char * buf, unsigned len);
typedef void (*port_flush_t) (zzz_scm_t port);
typedef void (*port_close_t) (zzz_scm_t port);
typedef long (*port_seek_t) (zzz_scm_t port, long offset, int whence);
typedef long (*port_tell_t) (zzz_scm_t port);
typedef int (*port_char_ready_p_t) (zzz_scm_t port);
typedef int (*port_free_t) (zzz_scm_t port);
typedef int (*port_mark_t) (zzz_scm_t port);

/* Defined port types are stored in a table consisting of these port
   type descriptors.  */
typedef struct port_type * port_type_t;
struct port_type
{
  port_getc_t port_getc;	/* May be NULL.  */
  port_ungetc_t port_ungetc;	/* May be NULL.  */
  port_putc_t port_putc;	/* May be NULL.  */
  port_puts_t port_puts;	/* May be NULL.  */
  port_flush_t port_flush;	/* May be NULL.  */
  port_close_t port_close;	/* May be NULL.  */
  port_seek_t port_seek;	/* May be NULL.  */
  port_tell_t port_tell;	/* May be NULL.  */
  port_char_ready_p_t port_char_ready_p; /* May be NULL.  */
  port_free_t port_free;	/* May be NULL.  */
  port_mark_t port_mark;	/* May be NULL.  */
};

/* Port objects contain this data structure.  The port functions are
   accessed by indexing the port type table with @var{port_type}, and
   the other fields hold the port object's state.  @var{info} is a
   pointer to port-type specific data.  */
typedef struct port_descriptor * port_desc_t;
struct port_descriptor
{
  unsigned port_type;		/* Index into the port type table.  */
  unsigned is_open:1;		/* Port is open.  */
  unsigned can_read:1;		/* Port can be read from.  */
  unsigned can_write:1;		/* Port can be written to.  */
  int flags;			/* Various flags.  */
  int line_number;		/* Current line number.  */
  int col_number;		/* Current column number.  */
  int saved_col;		/* Previous column number.  */
  zzz_scm_t filename;		/* Associated file name or '().  */
  int tty_p;			/* True if port refers to a tty.  */
  void * info;			/* Port-type specific information.  */
};

#define PORT_FLAGS_LINEBUF 0x0001

/* The default mode when creating files.  */
SIZZLE_API extern int zzz_default_file_mode;

/* These hold ports connected to the standard input/output/error file
   descriptors.  */
SIZZLE_API extern zzz_scm_t zzz_stdin_port;
SIZZLE_API extern zzz_scm_t zzz_stdout_port;
SIZZLE_API extern zzz_scm_t zzz_stderr_port;

/* These hold the current input/output/error ports during evaluation.  */
SIZZLE_API extern zzz_scm_t zzz_current_in_port;
SIZZLE_API extern zzz_scm_t zzz_current_out_port;
SIZZLE_API extern zzz_scm_t zzz_current_err_port;

/* The tagged type for port objects.  */
SIZZLE_API extern zzz_object_t zzz_tagged_type_port;

/* Function to create a new port type. */
SIZZLE_API unsigned zzz_define_port_type 
  (port_getc_t port_getc,	/* May be NULL.  */
   port_ungetc_t port_ungetc,	/* May be NULL.  */
   port_putc_t port_putc,	/* May be NULL.  */
   port_puts_t port_puts,	/* May be NULL.  */
   port_flush_t port_flush,	/* May be NULL.  */
   port_close_t port_close,	/* May be NULL.  */
   port_seek_t port_seek,	/* May be NULL.  */
   port_tell_t port_tell,	/* May be NULL.  */
   port_char_ready_p_t port_char_ready_p, /* May be NULL.  */
   port_free_t port_free,	/* May be NULL.  */
   port_mark_t port_mark);	/* May be NULL.  */

/* Initialize the port subsystem. */
SIZZLE_API result_t zzz_init_port (void);

/* Initialize the standard input/output/error ports.  This must be
   called after all port modules are initialized.  */
SIZZLE_API result_t zzz_init_standard_ports (void);

/* Basic input/output functions.  */
SIZZLE_API result_t zzz_port_puts (zzz_scm_t port, char * buf, int len,
				   zzz_scm_t * result);
SIZZLE_API result_t zzz_port_putc (int ch, zzz_scm_t port, zzz_scm_t * result);
SIZZLE_API result_t zzz_port_print (zzz_scm_t port, zzz_scm_t cell,
				    zzz_print_state_t state,
				    zzz_scm_t * result);
SIZZLE_API result_t zzz_port_getc (zzz_scm_t port, int * ch,
				   zzz_scm_t * result);
SIZZLE_API result_t zzz_port_ungetc (int ch, zzz_scm_t port,
				     zzz_scm_t * result);
SIZZLE_API result_t zzz_port_close (zzz_scm_t port, zzz_scm_t * result);
SIZZLE_API result_t zzz_port_seek (zzz_scm_t port, long ofs, int whence,
				   long * res_ofs, zzz_scm_t * result);
SIZZLE_API result_t zzz_port_tell (zzz_scm_t port, long * res_ofs,
				   zzz_scm_t * result);
SIZZLE_API result_t zzz_port_flush (zzz_scm_t port, zzz_scm_t * result);
SIZZLE_API result_t zzz_port_char_ready_p (zzz_scm_t port, int * ready,
					   zzz_scm_t *result);

/* Create a port of the specified port type and install @var{info} as
   the port's info field.  */
SIZZLE_API zzz_scm_t zzz_make_port (unsigned port_type, void * info);

#endif /* not __SIZZLE_PORT_H__ */
