/*
    GSK - a library to write servers
    Copyright (C) 1999-2000 Dave Benson

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser 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
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser 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

    Contact:
        daveb@ffem.org <Dave Benson>
*/

#ifndef __GSK_BUFFER_H_
#define __GSK_BUFFER_H_

#include "gskbasic.h"
#include "gsksocket.h"
#include "gskstreamsocket.h"

typedef struct _GskBuffer GskBuffer;
typedef struct _GskBufferFragment GskBufferFragment;
typedef struct _GskBufferWalker GskBufferWalker;

#define GSK_BUFFER_SIZEOF_INT		4

struct _GskBuffer
{
  GskBufferFragment*	first_frag;
  GskBufferFragment*	last_frag;
  int			total_size;

  /* If num_newlines < 0, newlines won't be counted, which
   * is slightly faster. */
  int			num_newlines;

  /* This function, if non-NULL, is called whenever
   * the buffer goes from empty to nonempty.
   */
  GHookFunc             fill_func;
  gpointer              fill_data;
};


void     gsk_buffer_construct           (GskBuffer    *buffer,
                                         gboolean      count_newlines);
int      gsk_buffer_write_out           (GskBuffer       *read_from,
                                         GskStreamSocket *write_to);
int      gsk_buffer_writev              (GskBuffer    *read_from,
                                         int           fd);
int      gsk_buffer_read_in             (GskBuffer       *write_to,
                                         GskStreamSocket *read_from);


/*
 * Removing from the buffer.
 */
int      gsk_buffer_read                (GskBuffer    *buffer,
                                         void         *data,
                                         int           max_length);
int      gsk_buffer_peek_read           (const GskBuffer* buffer,
                                         void         *data,
                                         int           max_length);
int      gsk_buffer_discard             (GskBuffer    *buffer,
                                         int           max_discard);
char    *gsk_buffer_read_line           (GskBuffer    *buffer);

gboolean gsk_buffer_parse_int           (GskBuffer    *buffer,
                                         int          *rv);
gboolean gsk_buffer_peek_int            (GskBuffer    *buffer,
                                         int          *rv);
char    *gsk_buffer_parse_string0       (GskBuffer    *buffer);
                        /* Returns first char of buffer, or -1. */
int      gsk_buffer_peek                (GskBuffer    *buffer);

/* 
 * Appending to the buffer.
 */
void     gsk_buffer_append              (GskBuffer    *buffer, 
                                         const void   *data,
                                         int           length);
void     gsk_buffer_append_string       (GskBuffer    *buffer, 
                                         const char   *string);
void     gsk_buffer_append_char         (GskBuffer    *buffer, 
                                         char          character);
void     gsk_buffer_append_int          (GskBuffer    *buffer,
                                         int           i);
void     gsk_buffer_append_string0      (GskBuffer    *buffer,
                                         const char   *string);

void     gsk_buffer_append_foreign      (GskBuffer    *buffer,
                                         gconstpointer slat,
					 int           length,
					 GDestroyNotify destroy,
					 gpointer      destroy_data);

/* Take all the contents from src and append
 * them to dst, leaving src empty.
 */
void     gsk_buffer_drain               (GskBuffer    *dst,
                                         GskBuffer    *src);

/* Like `drain', but only transfers some of the data. */
void     gsk_buffer_transfer            (GskBuffer    *dst,
                                         GskBuffer    *src,
					 int           max_transfer);

/*
 * Scanning the buffer.
 */
int      gsk_buffer_index_of            (GskBuffer    *buffer,
                                         int           char_to_find);
int      gsk_buffer_polystr_index_of    (GskBuffer    *buffer,
                                         char        **strings);

/* This deallocates memory used by the buffer-- you are responsible
 * for the allocation and deallocation of the GskBuffer itself. */
void     gsk_buffer_destruct            (GskBuffer    *to_destroy);

/* Free all unused buffer fragments. */
void     gsk_buffer_cleanup_recycling_bin ();


/* Traversing the buffer: you must not change the
 *                        buffer while iterating.
 */
GskBufferWalker   *gsk_buffer_make_walker (GskBuffer          *buffer);
void               gsk_buffer_walker_cur  (GskBufferWalker    *walker,
					   gpointer           *data_out,
					   guint              *length_out);
GskBufferWalker   *gsk_buffer_walker_next (GskBufferWalker    *walker);

#ifndef GSK_DEBUG
#define gsk_buffer_make_walker(b) ((GskBufferWalker *) ((b)->first_frag))
#endif

#endif
