/*
** Copyright (C) 2006-2011 by Carnegie Mellon University.
**
** @OPENSOURCE_HEADER_START@
**
** Use of the SILK system and related source code is subject to the terms
** of the following licenses:
**
** GNU Public License (GPL) Rights pursuant to Version 2, June 1991
** Government Purpose License Rights (GPLR) pursuant to DFARS 252.227.7013
**
** NO WARRANTY
**
** ANY INFORMATION, MATERIALS, SERVICES, INTELLECTUAL PROPERTY OR OTHER
** PROPERTY OR RIGHTS GRANTED OR PROVIDED BY CARNEGIE MELLON UNIVERSITY
** PURSUANT TO THIS LICENSE (HEREINAFTER THE "DELIVERABLES") ARE ON AN
** "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY
** KIND, EITHER EXPRESS OR IMPLIED AS TO ANY MATTER INCLUDING, BUT NOT
** LIMITED TO, WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE,
** MERCHANTABILITY, INFORMATIONAL CONTENT, NONINFRINGEMENT, OR ERROR-FREE
** OPERATION. CARNEGIE MELLON UNIVERSITY SHALL NOT BE LIABLE FOR INDIRECT,
** SPECIAL OR CONSEQUENTIAL DAMAGES, SUCH AS LOSS OF PROFITS OR INABILITY
** TO USE SAID INTELLECTUAL PROPERTY, UNDER THIS LICENSE, REGARDLESS OF
** WHETHER SUCH PARTY WAS AWARE OF THE POSSIBILITY OF SUCH DAMAGES.
** LICENSEE AGREES THAT IT WILL NOT MAKE ANY WARRANTY ON BEHALF OF
** CARNEGIE MELLON UNIVERSITY, EXPRESS OR IMPLIED, TO ANY PERSON
** CONCERNING THE APPLICATION OF OR THE RESULTS TO BE OBTAINED WITH THE
** DELIVERABLES UNDER THIS LICENSE.
**
** Licensee hereby agrees to defend, indemnify, and hold harmless Carnegie
** Mellon University, its trustees, officers, employees, and agents from
** all claims or demands made against them (and any related losses,
** expenses, or attorney's fees) arising out of, or relating to Licensee's
** and/or its sub licensees' negligent use or willful misuse of or
** negligent conduct or willful misconduct regarding the Software,
** facilities, or other rights or assistance granted by Carnegie Mellon
** University under this License, including, but not limited to, any
** claims of product liability, personal injury, death, damage to
** property, or violation of any laws or regulations.
**
** Carnegie Mellon University Software Engineering Institute authored
** documents are sponsored by the U.S. Department of Defense under
** Contract FA8721-05-C-0003. Carnegie Mellon University retains
** copyrights in all material produced under this contract. The U.S.
** Government retains a non-exclusive, royalty-free license to publish or
** reproduce these documents, or allow others to do so, for U.S.
** Government purposes only pursuant to the copyright license under the
** contract clause at 252.227.7013.
**
** @OPENSOURCE_HEADER_END@
*/
#ifndef _SKSTREAM_H
#define _SKSTREAM_H

#include <silk/silk.h>

RCSIDENTVAR(rcsID_SKSTREAM_H, "$SiLK: skstream.h 16752 2011-02-24 17:41:51Z mthomas $");

/*
**  skstream.h
**
**    An interface around file descriptors, which allows for buffered
**    reading and writing, as well as compression.
**
*/


/* The stream object itself */
struct skstream_st;
typedef struct skstream_st skstream_t;


#include <silk/skipaddr.h>
#include <silk/rwrec.h>
#include <silk/skheader.h>
#include <silk/skiobuf.h>


/* What we are attempting to do with the stream */
typedef enum {
    SK_IO_READ = 1,
    SK_IO_WRITE = 2,
    SK_IO_APPEND = 4
} skstream_mode_t;


/* What type of content the stream contains */
typedef enum {
    /* stream contains line-oriented text */
    SK_CONTENT_TEXT = (1 << 0),
    /* stream contains a SiLK file header and SiLK Flow data */
    SK_CONTENT_SILK_FLOW = (1 << 1),
    /* stream contains a SiLK file header and data (non-Flow data) */
    SK_CONTENT_SILK = (1 << 2),
    /* stream contains binary data other than SiLK */
    SK_CONTENT_OTHERBINARY = (1 << 3)
} skcontent_t;


/* Return values that most skStream*() functions return */
typedef enum {
    SKSTREAM_OK = 0,
    RWIO_OK = 0,
    /* The last command was completed successfully. */

    /* The following often represent programmer errors */

    SKSTREAM_ERR_ALLOC = -64,
    /* Memory could not be allocated. */

    SKSTREAM_ERR_CLOSED = -65,
    /* Attempt to operate on a file that is already closed.  Once
     * closed, a stream can only be destroyed; re-opening is not (yet)
     * supported. */

    SKSTREAM_ERR_INVALID_INPUT = -66,
    /* An argument to a function is invalid: passing skStreamFDOpen()
     * a value of -1, passing too long a pathname ti skStreamBind(),
     * using an supported SiLK file format. */

    SKSTREAM_ERR_NOT_BOUND = -67,
    /* Attempt to open a stream that is not bound to a pathname. */

    SKSTREAM_ERR_NOT_OPEN = -68,
    /* Attempt to read or write from a stream that has not yet been
     * opened. */

    SKSTREAM_ERR_NULL_ARGUMENT = -69,
    /* An argument to the function is NULL or empty */

    SKSTREAM_ERR_PREV_BOUND = -70,
    /* The stream is already bound to a pathname. */

    SKSTREAM_ERR_PREV_DATA = -71,
    /* Attempt to operate on a stream in a way that is not support
     * since data has already been written-to/read-from the stream. */

    SKSTREAM_ERR_PREV_OPEN = -72,
    /* The stream is already open. */

    SKSTREAM_ERR_UNSUPPORT_CONTENT = -73,
    /* The file's content type does not support the action: attempt to
     * skStreamRead() on a SK_CONTENT_TEXT stream, attempt to
     * skStreamPrint() to a binary or SiLK stream, etc. */

    SKSTREAM_ERR_PREV_COPYINPUT = -74,
    /* The skStreamSetCopyInput() function has already been called on
     * this stream. */


    /* Errors due to missing or outdated libraries */

    SKSTREAM_ERR_COMPRESS_INVALID = -80,
    /* The stream is compressed with a compression method that SiLK
     * does not recognize. */

    SKSTREAM_ERR_COMPRESS_UNAVAILABLE = -81,
    /* The stream is compressed with a unavailable compression mode;
     * for example, you're operating on a gzipped file but SiLK was
     * not linked with gzip. */


    /* User errors when creating a new stream */

    SKSTREAM_ERR_BAD_MAGIC = -16,
    /* The file's header does not contain the SiLK magic number---for
     * files that contain SK_CONTENT_SILK. */

    SKSTREAM_ERR_FILE_EXISTS = -17,
    /* Attempt to open a stream for writing that is bound to a file
     * name that already exists. */

    SKSTREAM_ERR_ISTERMINAL = -18,
    /* Attempt to read or write binary data on a terminal (tty) */

    SKSTREAM_ERR_NOPAGER = -19,
    /* Attempt to invoke the paging program failed. */

    SKSTREAM_ERR_RLOCK = -20,
    /* Could not get a read lock on the stream. */

    SKSTREAM_ERR_SYS_FDOPEN = -21,
    /* The call to fdopen() failed. */

    SKSTREAM_ERR_SYS_LSEEK = -22,
    /* The call to lseek() failed. */

    SKSTREAM_ERR_SYS_OPEN = -23,
    /* The call to open() failed. */

    SKSTREAM_ERR_SYS_MKSTEMP = -24,
    /* The call to mkstemp() failed. */

    SKSTREAM_ERR_UNSUPPORT_IOMODE = -25,
    /* The file's read/write status does not support the action: an
     * attempt to write to "stdin", an attempt to append to a FIFO or
     * a gzipped file. */

    SKSTREAM_ERR_WLOCK = -26,
    /* Could not get a read lock on the stream. */

    SKSTREAM_ERR_SYS_FORK = -27,
    /* The call to fork() failed. */

    SKSTREAM_ERR_SYS_PIPE = -28,
    /* The call to pipe() failed. */

    SKSTREAM_ERR_SYS_MKDIR = -29,
    /* The call to mkdir() failed. */


    /* Errors that may occur while processing the stream that
     * typically indicate a fatal condition. */

    SKSTREAM_ERR_IO = -1,
    /* Value returned skStreamRead() and skStreamWrite() when an error
     * has occured. */

    SKSTREAM_ERR_IOBUF = -2,
    /* Error with internal buffering. */

    SKSTREAM_ERR_WRITE = -3,
    /* There was an error writing to the stream. */

    SKSTREAM_ERR_READ = -4,
    /* There was an error reading from the stream. */

    SKSTREAM_ERR_EOF = -5,
    RWIO_ERR_READ_EOF = -5,
    /* Value returned when the input is exhausted.  Note that reaching
     * the end of a file is not really an "error". */

    SKSTREAM_ERR_ZLIB = -6,
    /* Error occurred in a gz* function */

    SKSTREAM_ERR_READ_SHORT = -7,
    RWIO_ERR_READ_SHORT = -7,
    /* The read returned fewer bytes than required for a complete
     * record. */

    SKSTREAM_ERR_NOT_SEEKABLE = -8,
    /* The operation requires the stream to be bound to a seekable
     * file, and the stream is not. */

    SKSTREAM_ERR_SYS_FTRUNCATE = -9,
    /* The call to ftruncate() failed. */


    /* The following set of errors are general errors that occur when
     * opening a SiLK file for read, write, or append. */

    SKSTREAM_ERR_UNSUPPORT_FORMAT = 32,
    /* The file has a format that does not support this operation.
     * See also the next error code. */

    SKSTREAM_ERR_REQUIRE_SILK_FLOW = 33,
    /* An operation that requires SiLK Flow data is attempting to open
     * a SiLK file that does not contain flows. */

    SKSTREAM_ERR_UNSUPPORT_VERSION = 34,
    /* The file or record has a version that this version of libsilk
     * does not know how to handle */


    /* The following set of errors affect only the current record;
     * they occur when trying to write a record to a stream.  These
     * are considered non-fatal.  Use the SKSTREAM_ERROR_IS_FATAL()
     * macro below. */

    SKSTREAM_ERR_STIME_UNDRFLO = 64,
    /* The record's start time is less than the file's start time */

    SKSTREAM_ERR_STIME_OVRFLO = 65,
    /* The record's start time at least an hour greater than the
     * file's start time */

    SKSTREAM_ERR_ELPSD_OVRFLO = 66,
    /* The record's elapsed time is greater than space allocated for
     * duration in this file format */

    SKSTREAM_ERR_PKTS_OVRFLO = 67,
    /* The record contains more than the number of packets allowed in
     * this file format */

    SKSTREAM_ERR_PKTS_ZERO = 68,
    /* The record contains a 0 value in the packets field. */

    SKSTREAM_ERR_BPP_OVRFLO = 69,
    /* The byte-per-packet value is too large to fit into the space
     * provided by this file format. */

    SKSTREAM_ERR_SNMP_OVRFLO = 70,
    /* The records contains an SNMP value too large to fit into the
     * space allocated in this file format. */

    SKSTREAM_ERR_SENSORID_OVRFLO = 71,
    /* The records contains a SensorID too large to fit into the space
     * allocated in this file format. */

    SKSTREAM_ERR_PROTO_MISMATCH = 72,
    /* The record's IP protocol is not supported by the file's format;
     * for example, trying to store a non-TCP record in a FT_RWWWW
     * file. */

    SKSTREAM_ERR_PKTS_GT_BYTES = 73,
    /* The record's "packets" value is greater than the "bytes" value. */

    SKSTREAM_ERR_UNSUPPORT_IPV6 = 74,
    /* The record is an IPv6 record which is not supported. */


    /* Errors that may occur which indicate an error with one
     * line/record, but which are normally not fatal */

    SKSTREAM_ERR_LONG_LINE = 96
    /* Returned by skStreamGetLine() when an input line is longer than
     * the specified buffer size. */

} skstream_err_t;


/*
 *  SKSTREAM_ERROR_IS_FATAL(err);
 *
 *    Evaluates to a true value if error is a fatal error, false otherwise.
 */
#define SKSTREAM_ERROR_IS_FATAL(err) ((err) != SKSTREAM_OK && (err) < 64)


int skStreamBind(
    skstream_t         *stream,
    const char         *pathname);
/*
 *    Set 'stream' to operate on the file specified in 'pathname';
 *    'pathname' may also be one of "stdin", "stdout", or "stderr".
 *    Return SKSTREAM_OK on success, or one of these error codes:
 *
 *    SKSTREAM_ERR_NULL_ARGUMENT
 *    SKSTREAM_ERR_PREV_BOUND
 *    SKSTREAM_ERR_INVALID_INPUT
 *    SKSTREAM_ERR_ISTERMINAL
 *    SKSTREAM_ERR_UNSUPPORT_IOMODE
 */




int skStreamCheckCompmethod(
    skstream_t         *stream,
    sk_msg_fn_t         err_fn);
/*
 *    Check that the compression method used by 'stream' is known and
 *    is available.  Return SKSTREAM_OK if it is; otherwise return an
 *    error code as described below and print an error message using
 *    the 'err_fn' when it is provided.
 *
 *    If the stream uses an unknown compression method, return
 *    SKSTREAM_ERR_COMPRESS_INVALID.  If the compression method is
 *    recognized but not available in this compilation of SiLK, return
 *    SKSTREAM_ERR_COMPRESS_UNAVAILABLE.
 */


int skStreamCheckSilkHeader(
    skstream_t             *stream,
    fileFormat_t            file_format,
    fileVersion_t           min_rec_version,
    fileVersion_t           max_rec_version,
    sk_msg_fn_t             err_fn);
/*
 *    Check several attributes of the SiLK header on the file
 *    associated with 'stream'.  If the header passes all tests,
 *    return SKSTREAM_OK.  If the header fails a test an error code is
 *    returned; in addtion, if 'err_fn' is provided, that function
 *    will be called to print an error message.
 *
 *    If the stream's format is not 'file_format', return
 *    SKSTREAM_ERR_UNSUPPORT_FORMAT.
 *
 *    If the version of the records in the stream is below
 *    'min_rec_version' or above 'max_rec_version', return
 *    SKSTREAM_ERR_UNSUPPORT_VERSION.
 *
 *    The skStreamCheckCompmethod() function is also called.
 */


int skStreamClose(
    skstream_t         *stream);
/*
 *    Flush any data on the 'stream' and closes the underlying file
 *    descriptor.  Return SKSTREAM_OK on success, or one of these
 *    error codes:
 *
 *    SKSTREAM_ERR_NULL_ARGUMENT
 *    SKSTREAM_ERR_CLOSED
 *    SKSTREAM_ERR_NOT_OPEN
 *    SKSTREAM_ERR_WRITE
 *    SKSTREAM_ERR_IOBUF
 */


int skStreamCreate(
    skstream_t        **new_stream,
    skstream_mode_t     read_write_append,
    skcontent_t         content_type);
/*
 *    Create a new stream at the location pointed to by 'new_stream';
 *    the action to perform on 'new_stream' is determined by
 *    'read_write_append', and 'content_type' specified the content of
 *    'new_stream'.  Return SKSTREAM_OK on success, or one of these
 *    error codes:
 *
 *    SKSTREAM_ERR_NULL_ARGUMENT
 *    SKSTREAM_ERR_ALLOC
 */


int skStreamDestroy(
    skstream_t        **stream);
/*
 *    Closes the stream at '*stream', if open, destroys the stream
 *    pointed at by 'stream' and sets '*stream' to NULL.  If 'stream'
 *    is NULL or its value is NULL, no action is taken and the
 *    function returns.  Return SKSTREAM_OK on success, or any of the
 *    error codes listed by skStreamClose().
 */


int skStreamFDOpen(
    skstream_t         *stream,
    int                 file_desc);
/*
 *    Associate 'stream' with the previously opened file descriptor
 *    'file_desc'.  The 'stream' must have been previously bound to a
 *    filename.  Return SKSTREAM_OK on success, or one of these error
 *    codes:
 *
 *    SKSTREAM_ERR_NULL_ARGUMENT
 *    SKSTREAM_ERR_NOT_BOUND
 *    SKSTREAM_ERR_PREV_OPEN
 *    SKSTREAM_ERR_CLOSED
 *    SKSTREAM_ERR_INVALID_INPUT
 *    SKSTREAM_ERR_UNSUPPORT_COMPRESS
 *    SKSTREAM_ERR_ALLOC
 */


int skStreamFlush(
    skstream_t         *stream);
/*
 *    Flush any data in the stream's buffers to disk; has no effect on
 *    a stream open for reading.  Return SKSTREAM_OK on success, or
 *    one of these error codes:
 *
 *    SKSTREAM_ERR_NULL_ARGUMENT
 *    SKSTREAM_ERR_NOT_OPEN
 */


skcontent_t skStreamGetContentType(
    const skstream_t   *stream);
/*
 *    Return the type of content associated with the stream.
 */


int skStreamGetDescriptor(
    const skstream_t   *stream);
/*
 *    Return the file descriptor associated with 'stream'.
 */


int skStreamGetLastErrno(
    const skstream_t   *stream);
/*
 *    Return the value of errno that is cached on 'stream'.
 *
 *    The skstream_t normally only caches errno for failed commands,
 *    so the returned value may not reflect the errno from the most
 *    recent command.
 */


int skStreamGetLine(
    skstream_t         *stream,
    char               *out_buffer,
    size_t              buf_size,
    int                *line_count);
/*
 *    Read a line of text from 'stream' and store it in 'out_buffer',
 *    a character array of buf_size characters.  If 'line_count' is
 *    non-NULL, it's value will be INCREMENTED by the number of lines
 *    read, typically 1.  The line will be truncated at the newline
 *    character---the newline will not be returned.  Return
 *    SKSTREAM_OK on success, or SKSTREAM_ERR_EOF at the end of file.
 *
 *    Lines containing only whitespace are ignored.  If the stream's
 *    comment character has been set, comments are stripped from the
 *    input as well, and lines containing only comments are ignored.
 *
 *    If a line is longer than 'buf_size', the line is ignored and
 *    SKSTREAM_ERR_LONG_LINE is returned.  The value in 'out_buffer'
 *    will be random.
 *
 *    This function requires that 'stream' be an SK_IO_READ stream
 *    that has a content type of SK_CONTENT_TEXT.
 *
 *    In addition to the above return values, the function may also
 *    return:
 *
 *    SKSTREAM_ERR_NULL_ARGUMENT
 *    SKSTREAM_ERR_NOT_OPEN
 *    SKSTREAM_ERR_CLOSED
 *    SKSTREAM_ERR_UNSUPPORT_CONTENT
 *    SKSTREAM_ERR_UNSUPPORT_IOMODE
 *    SKSTREAM_ERR_SYS_FDOPEN
 */


skstream_mode_t skStreamGetMode(
    const skstream_t   *stream);
/*
 *    Return a value indicating whether the stream is being used for
 *    reading, writing, or appending.
 */


const char *skStreamGetPager(
    const skstream_t   *stream);
/*
 *    For an open stream, returns the name of the paging program if it
 *    is being used, or NULL if a pager is not in use.  For a stream
 *    that is not yet open, returns the name of the paging program
 *    which MAY be used, or NULL if paging has not been requested.
 */


const char *skStreamGetPathname(
    const skstream_t   *stream);
/*
 *    Return the pathname to which 'stream' has been bound, or NULL if
 *    the stream is unbound.
 */


uint64_t skStreamGetRecordCount(
    const skstream_t   *stream);
/*
 *    Return the number of SiLK Flow records that have been processed
 *    by 'stream' since is was opened.  This will be the number of
 *    records in the file, unless the file was opened for append, in
 *    which case it is the number of records appeneded.
 *
 *    A return value of ((uint64_t)(-1)) indicates that 'stream' does
 *    not contain SiLK Flow records.
 */


sk_file_header_t *skStreamGetSilkHeader(
    const skstream_t   *stream);
/*
 *    Return the SiLK file header for the stream.  Returns NULL if the
 *    stream is not a SiLK stream.
 */


int skStreamGetSupportsIPv6(
    const skstream_t   *stream);
/*
 *    Return 1 if 'stream' supports IPv6 addresses, 0 otherwise.
 */


off_t skStreamGetUpperBound(
    skstream_t         *stream);
/*
 *    Return the maximum possible file size that would be created if
 *    the file were to be flushed.
 */


int skStreamIsSeekable(
    const skstream_t   *stream);
/*
 *    Return a non-zero value if 'stream' is a seekable stream; return
 *    0 otherwise.
 */


int skStreamIsStdout(
    const skstream_t   *stream);
/*
 *    Return a non-zero value if 'stream' is bound to the standard
 *    output.
 */


int skStreamLockFile(
    skstream_t         *stream);
/*
 *    Block until the stream has a lock on the file associated with
 *    'stream'.  Return SKSTREAM_OK on success or if the stream is
 *    not-seekable, or one of the following error codes:
 *
 *    SKSTREAM_ERR_NULL_ARGUMENT
 *    SKSTREAM_ERR_NOT_OPEN
 *    SKSTREAM_ERR_CLOSED
 *    SKSTREAM_ERR_RLOCK
 *    SKSTREAM_ERR_WLOCK
 */


int skStreamMakeDirectory(
    skstream_t          *stream);
/*
 *    Create any directories that would be required before opening the
 *    file bound to 'stream'.
 */


int skStreamMakeTemp(
    skstream_t         *stream);
/*
 *    Pass the pathname associated with 'stream' to the mkstemp()
 *    system call to create a temporary file.  Return SKSTREAM_OK on
 *    success, or one of the following error codes:
 *
 *    SKSTREAM_ERR_NULL_ARGUMENT
 *    SKSTREAM_ERR_NOT_BOUND
 *    SKSTREAM_ERR_PREV_OPEN
 *    SKSTREAM_ERR_CLOSED
 *    SKSTREAM_ERR_ALLOC
 *    SKSTREAM_ERR_UNSUPPORT_IOMODE
 *    SKSTREAM_ERR_SYS_MKSTEMP
 */


int skStreamOpen(
    skstream_t         *stream);
/*
 *    Open the file associated with 'stream'.  Note that
 *    skStreamOpen() must be called even when the stream has been
 *    bound to a standard stream, i.e., "stdin", "stdout", or
 *    "stderr".  For an output stream, the target file must not
 *    previously exist, unless it is a FIFO or a character special
 *    file, i.e., "/dev/null".
 *
 *    Return SKSTREAM_OK on success, or one of the following error
 *    codes:
 *
 *    SKSTREAM_ERR_NULL_ARGUMENT
 *    SKSTREAM_ERR_NOT_BOUND
 *    SKSTREAM_ERR_PREV_OPEN
 *    SKSTREAM_ERR_CLOSED
 *    SKSTREAM_ERR_ALLOC
 *    SKSTREAM_ERR_SYS_OPEN
 *    SKSTREAM_ERR_FILE_EXISTS
 *    SKSTREAM_ERR_UNSUPPORT_IOMODE
 *    SKSTREAM_ERR_UNSUPPORT_COMPRESS
 */


int skStreamOpenSilkFlow(
    skstream_t        **stream,
    const char         *pathname,
    skstream_mode_t     read_write_append);
/*
 *    A convenience function for creating a stream that processes SiLK
 *    flow records.  This function will create a stream at the
 *    location specified by 'stream', set its mode to
 *    'read_write_append', bind it to 'pathname', and open it.  If the
 *    'read_write_append' mode is SK_IO_READ or SK_IO_APPEND, this
 *    function will also read the file's header.
 *
 *    Returns SKSTREAM_OK on success.
 *
 *    If there is an error opening the stream, 'stream' will be left
 *    in a partially allocated/opened state.  The caller should invoke
 *    skStreamDestroy() to destroy the stream.
 */


int skStreamPageOutput(
    skstream_t         *stream,
    const char         *pager);
/*
 *    Allow 'stream' to display its output a screenful at a time by
 *    invoking the program named by 'pager' and pass the output of
 *    'stream' through it.  This function requires that 'stream' be an
 *    SK_IO_WRITE stream that has a content type of SK_CONTENT_TEXT.
 *
 *    'stream' may be open or not-yet-open; if open, no data can have
 *    been written to 'stream' yet.  If 'stream' is already open, this
 *    function will invoke the pager; otherwise, the pager will be
 *    invoked on the first attempt to skStreamPrint() to 'stream'.
 *
 *    Return SKSTREAM_OK on success, or one of the following error
 *    codes:
 *
 *    SKSTREAM_ERR_NULL_ARGUMENT
 *    SKSTREAM_ERR_CLOSED
 *    SKSTREAM_ERR_ATTRIBUTE_FIXED
 *    SKSTREAM_ERR_ALLOC
 *    SKSTREAM_ERR_SYS_FDOPEN
 *    SKSTREAM_ERR_UNSUPPORT_IOMODE
 *    SKSTREAM_ERR_UNSUPPORT_CONTENT
 */


#ifdef TEST_PRINTF_FORMATS
#define skStreamPrint(stream, ...) printf(__VA_ARGS__)
#else
int skStreamPrint(
    skstream_t         *stream,
    const char         *format,
                        ...)
    SK_CHECK_PRINTF(2, 3);
#endif
/*
 *    Perform printf()-style formatting and write the result to
 *    'stream'.  On the first call to this funtion for 'stream', the
 *    pager for 'stream' will be invoked if the paging program was set
 *    and output would be to a terminal.  This function requires that
 *    'stream' be an SK_IO_WRITE stream that has a content type of
 *    SK_CONTENT_TEXT.
 *
 *    Return SKSTREAM_OK on success, or one of the following error
 *    codes:
 *
 *    SKSTREAM_ERR_NULL_ARGUMENT
 *    SKSTREAM_ERR_CLOSED
 *    SKSTREAM_ERR_NOT_OPEN
 *    SKSTREAM_ERR_WRITE
 *    SKSTREAM_ERR_UNSUPPORT_IOMODE
 *    SKSTREAM_ERR_UNSUPPORT_CONTENT
 */


void skStreamPrintLastErr(
    const skstream_t   *stream,
    int                 err_code,
    sk_msg_fn_t         err_fn);
/*
 *    Print, using the function pointed to by err_fn, a description of
 *    the last error that occured on 'stream', where 'err_code' is the
 *    return code that a function returned.  'stream' may be NULL.
 */


ssize_t skStreamRead(
    skstream_t         *stream,
    void               *buf,
    size_t              count);
/*
 *    Attempt to read 'count' bytes from 'stream', putting the data
 *    into 'buf'.  Return the number of bytes actually read, 0 for end
 *    of file, and -1 on error.
 *
 *    When 'buf' is NULL, 'count' bytes are "read" but the data is
 *    dropped.  The function returns the number of bytes "read", or -1
 *    for error.
 *
 *    The function will use a buffered reader, gzread(), or raw read()
 *    as appropriate.  For a raw read(), the function continues to call
 *    read() until it has read 'count' bytes or read() returns 0 or
 *    -1.
 *
 *    When the function returns -1, there is no way to determine how
 *    many bytes were read prior to the error.
 */


int skStreamReadRecord(
    skstream_t         *stream,
    rwRec              *rec);
/*
 *    Read a single SiLK Flow record from 'stream'.
 */


int skStreamReadSilkHeader(
    skstream_t         *stream,
    sk_file_header_t  **hdr);
/*
 *    Attempt to read the SiLK file header from 'stream', putting the
 *    data into 'hdr'.  This function requires that 'stream' contain
 *    SK_CONTENT_SILK or SK_CONTENT_SILK_FLOW and that it's mode be
 *    either SK_IO_READ or SK_IO_APPEND.
 *
 *    An attempt to read the header multiple times will result in
 *    SKSTREAM_ERR_PREV_DATA.
 *
 *    Return SKSTREAM_OK on success, or one of the following error
 *    codes:
 *
 *    SKSTREAM_ERR_NULL_ARGUMENT
 *    SKSTREAM_ERR_CLOSED
 *    SKSTREAM_ERR_NOT_OPEN
 *    SKSTREAM_ERR_READ
 *    SKSTREAM_ERR_ALLOC
 *    SKSTREAM_ERR_PREV_DATA
 *    SKSTREAM_ERR_BAD_MAGIC
 *    SKSTREAM_ERR_UNSUPPORT_IOMODE
 *    SKSTREAM_ERR_UNSUPPORT_CONTENT
 */


int skStreamReadSilkHeaderStart(
    skstream_t         *stream);


void *skStreamReadToEndOfFile(
    skstream_t         *stream,
    ssize_t            *length);
/*
 *    Attempt to read all (remaining) data in 'stream', and return
 *    that content.  Set 'length' to the number of bytes of data from
 *    from the stream.
 *
 *    An extra NUL byte is added to the data read from the stream, but
 *    that byte is not included in 'length'.  (This guarantees that
 *    textual files are NUL terminated.)
 *
 *    On error, NULL is returned. length is indeterminate, and any
 *    data read from the stream is lost.  You may call
 *    skStreamPrintLastErr() with an 'err_code' of -1 to find the
 *    exact error.
 */


int skStreamSetCommentStart(
    skstream_t         *stream,
    const char         *comment_start);
/*
 *    Set the comment string for a textual input file to
 *    'comment_start'.  This function requires that 'stream' be an
 *    SK_IO_READ stream that contains SK_CONTENT_TEXT.  Return
 *    SKSTREAM_OK on success, or one of the following error codes:
 *
 *    SKSTREAM_ERR_NULL_ARGUMENT
 *    SKSTREAM_ERR_ALLOC
 *    SKSTREAM_ERR_UNSUPPORT_CONTENT
 *    SKSTREAM_ERR_UNSUPPORT_IOMODE
 */


#define skStreamSetCompressionMethod(stream, comp_method)               \
    (skHeaderSetCompressionMethod(skStreamGetSilkHeader(stream),        \
                                  (comp_method)))
/*
 *    Set the compression method on 'stream' to 'comp_method'.
 */


int skStreamSetCopyInput(
    skstream_t         *read_stream,
    skstream_t         *write_stream);
/*
 *    Inform 'read_stream' that all records it reads must be written
 *    to 'write_stream'.  'read_stream' and 'write_stream' must both
 *    contain SiLK Flow records.  This function must be called before
 *    data is read from the 'read_stream'.
 */


int skStreamSetIPv6Policy(
    skstream_t         *stream,
    sk_ipv6policy_t     policy);
/*
 *    Determine how to handle IPv6 records, or IPv4 records in a mixed
 *    IPv4/IPv6 environment.  The 'stream' must represent a SiLK
 *    stream.
 */


int skStreamSetUnbuffered(
    skstream_t         *stream);
/*
 *    Do not use buffering on this stream.  This must be called prior
 *    to opening the stream.
 */


int skStreamSkipRecords(
    skstream_t         *stream,
    size_t              skip_count,
    size_t             *records_skipped);


off_t skStreamTell(
    skstream_t         *stream);
/*
 *    Return the current byte offset into the underlying stream.
 *    Return -1 if the stream is unopend, is unseekable, or if another
 *    error occurs.
 */


int skStreamTruncate(
    skstream_t         *stream,
    off_t               length);
/*
 *    Set the length of the file bound to 'stream' to 'length'.
 *
 *    This function will call skStreamFlush() on the stream prior to
 *    setting its length.
 *
 *    The value of 'length' should be a value determined before any
 *    new data has been written to the file, or after a call to
 *    skStreamFlush() to ensure there is no unsaved data.
 *
 *    Return SKSTREAM_OK on success.  If 'stream' is not open for
 *    writing or appending, return SKSTREAM_ERR_UNSUPPORT_IOMODE.  If
 *    stream's content is SK_CONTENT_TEXT, return
 *    SKSTREAM_ERR_UNSUPPORT_CONTENT.  If 'stream' is not seekable,
 *    return SKSTREAM_ERR_NOT_SEEKABLE.  Return
 *    SKSTREAM_ERR_SYS_FTRUNCATE if the call to ftruncate() fails.
 *
 *    If the call to skStreamFlush() returns an error value, the
 *    ftruncate() call is still attempted, and the function will
 *    return SKSTREAM_ERR_SYS_FTRUNCATE if the ftruncate() call
 *    failed, or the error status from the skStreamFlush() call.  If
 *    skStreamFlush() fails, there may be unflushed buffers that the
 *    system will attempt to flush when the stream is destroyed,
 *    making the file's length different than 'length'.
 *
 *    In addition, the function may return:
 *
 *    SKSTREAM_ERR_NULL_ARGUMENT
 *    SKSTREAM_ERR_NOT_OPEN
 *    SKSTREAM_ERR_CLOSED
 */


int skStreamUnbind(
    skstream_t         *stream);
/*
 *    Closes the stream at 'stream', if open, and unbinds the stream
 *    from the filename.  If 'stream' is NULL, no action is taken and
 *    the function returns.  Return SKSTREAM_OK on success, or any of
 *    the error codes listed by skStreamClose().
 *
 *    Currently, a stream cannot be re-bound, so this function is of
 *    limited utility.
 */


ssize_t skStreamWrite(
    skstream_t         *stream,
    const void         *buf,
    size_t              count);
/*
 *    Attempt to write 'count' bytes from 'buf' to 'stream'.  Return
 *    the number of bytes actually written or -1 on error.
 *
 *    The function will use a buffered writer, gzwrite(), or raw
 *    write() as appropriate.  For a raw write(), the function
 *    continue to call write() until it has written 'count' bytes or
 *    write() returns -1.
 */



int skStreamWriteRecord(
    skstream_t         *stream,
    const rwRec        *rec);


int skStreamWriteSilkHeader(
    skstream_t         *stream);
/*
 *    Attempt to write 'hdr_size' bytes from 'buf' to 'stream', with
 *    the following caveat: the first eight bytes of 'hdr' will be
 *    modified to contain the SiLK magic file number, and the values
 *    that were specified in the calls to skStreamSetByteOrder(),
 *    skStreamSetSilkFormat(), skStreamSetSilkVersion(), and
 *    skStreamSetCompressionMethod().
 *
 *    If 'hdr' is shorter than eight bytes, return
 *    SKSTREAM_ERR_INVALID_INPUT.  If fewer than 'hdr_size' bytes were
 *    written, return SKSTREAM_ERR_WRITE.  This function requires that
 *    'stream' be an SK_IO_WRITE stream containing SK_CONTENT_SILK or
 *    SK_CONTENT_SILK_FLOW.
 *
 *    An attempt to write the header multiple times will result in
 *    SKSTREAM_ERR_PREV_DATA.
 *
 *    Return SKSTREAM_OK on success, or one of the following error
 *    codes:
 *
 *    SKSTREAM_ERR_NULL_ARGUMENT
 *    SKSTREAM_ERR_CLOSED
 *    SKSTREAM_ERR_NOT_OPEN
 *    SKSTREAM_ERR_INVALID_INPUT
 *    SKSTREAM_ERR_WRITE
 *    SKSTREAM_ERR_ALLOC
 *    SKSTREAM_ERR_PREV_DATA
 *    SKSTREAM_ERR_UNSUPPORT_IOMODE
 *    SKSTREAM_ERR_UNSUPPORT_CONTENT
 */


#endif /* _SKSTREAM_H */


/*
** Local Variables:
** mode:c
** indent-tabs-mode:nil
** c-basic-offset:4
** End:
*/
