head 1.26;
access;
symbols
SIO_0_9_3:1.26
SIO_0_9_2:1.24
SIO_0_9_1:1.24
SIO_0_9_0:1.24;
locks; strict;
comment @ * @;
1.26
date 2005.10.03.09.06.11; author rse; state Exp;
branches;
next 1.25;
1.25
date 2004.02.11.08.34.46; author rse; state Exp;
branches;
next 1.24;
1.24
date 2003.02.06.10.59.18; author mlelstv; state Exp;
branches;
next 1.23;
1.23
date 2003.01.30.14.24.53; author mlelstv; state Exp;
branches;
next 1.22;
1.22
date 2003.01.20.17.43.21; author mlelstv; state Exp;
branches;
next 1.21;
1.21
date 2003.01.20.16.16.40; author mlelstv; state Exp;
branches;
next 1.20;
1.20
date 2003.01.06.19.04.56; author rse; state Exp;
branches;
next 1.19;
1.19
date 2002.12.18.15.51.35; author mlelstv; state Exp;
branches;
next 1.18;
1.18
date 2002.11.29.15.33.20; author mlelstv; state Exp;
branches;
next 1.17;
1.17
date 2002.11.29.13.04.15; author mlelstv; state Exp;
branches;
next 1.16;
1.16
date 2002.11.29.13.00.18; author mlelstv; state Exp;
branches;
next 1.15;
1.15
date 2002.11.28.16.39.40; author mlelstv; state Exp;
branches;
next 1.14;
1.14
date 2002.11.28.16.29.37; author mlelstv; state Exp;
branches;
next 1.13;
1.13
date 2002.11.24.19.36.48; author mlelstv; state Exp;
branches;
next 1.12;
1.12
date 2002.11.14.15.56.10; author mlelstv; state Exp;
branches;
next 1.11;
1.11
date 2002.11.14.09.22.42; author rse; state Exp;
branches;
next 1.10;
1.10
date 2002.11.08.19.46.42; author mlelstv; state Exp;
branches;
next 1.9;
1.9
date 2002.11.08.10.34.24; author mlelstv; state Exp;
branches;
next 1.8;
1.8
date 2002.11.05.16.53.55; author mlelstv; state Exp;
branches;
next 1.7;
1.7
date 2002.11.05.16.12.39; author mlelstv; state Exp;
branches;
next 1.6;
1.6
date 2002.11.05.15.52.21; author mlelstv; state Exp;
branches;
next 1.5;
1.5
date 2002.11.05.15.48.57; author mlelstv; state Exp;
branches;
next 1.4;
1.4
date 2002.11.05.13.23.36; author mlelstv; state Exp;
branches;
next 1.3;
1.3
date 2002.10.24.07.46.01; author mlelstv; state Exp;
branches;
next 1.2;
1.2
date 2002.10.23.17.05.10; author mlelstv; state Exp;
branches;
next 1.1;
1.1
date 2002.10.22.12.57.20; author mlelstv; state Exp;
branches;
next ;
desc
@@
1.26
log
@adjust copyright messages
@
text
@/*
** OSSP sio - Stream I/O
** Copyright (c) 2002-2005 Cable & Wireless
** Copyright (c) 2002-2005 The OSSP Project
** Copyright (c) 2002-2005 Ralf S. Engelschall
**
** This file is part of OSSP sio, a layered stream I/O library
** which can be found at http://www.ossp.org/pkg/lib/sio/.
**
** Permission to use, copy, modify, and distribute this software for
** any purpose with or without fee is hereby granted, provided that
** the above copyright notice and this permission notice appear in all
** copies.
**
** THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR
** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
** USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
** OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
** SUCH DAMAGE.
**
** sio.c: stream I/O library implementation
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include
#include
#include
#include "al.h"
#include "sio.h"
#include "list.h"
/****************************************************************************/
/* unique library identifier */
const char sio_id[] = "OSSP sio";
/* support for OSSP ex based exception throwing */
#ifdef WITH_EX
#define __EX_NS_UCCXX__
#include "ex.h"
#define SIO_RC(rv) \
( (rv) != SIO_OK && (ex_catching && !ex_shielding) \
? (ex_throw(sio_id, NULL, (rv)), (rv)) : (rv) )
#else
#define SIO_RC(rv) (rv)
#endif /* WITH_EX */
/*
* node representing either input or output
* direction of a processing node
*/
struct sio_halfduplex_st;
typedef struct sio_halfduplex_st sio_halfduplex_t;
struct sio_halfduplex_st {
NODE(sio_halfduplex_t) hd; /* link to reader/writer chain */
sio_stage_t *stage; /* back to its stage structure */
sio_halfduplex_t *cross; /* reader <-> writer sibling */
const char *tag; /* debugging help */
sio_rc_t rc_with_data; /* default rc to avoid */
sio_rc_t rc_no_data; /* decision in strategy() */
al_t *al; /* reader/writer assembly line */
sio_rc_t (*func)(sio_t *, al_t *, void *, sio_rc_t); /* input() or output() */
};
/*
* processing node
*/
struct sio_stage_st {
sio_halfduplex_t reader; /* reader node, linked into sio_t */
sio_halfduplex_t writer; /* writer node, linked into sio_t */
void *userdata; /* module private per-instance data */
sio_module_t *module; /* link to module methods */
sio_mode_t rw; /* state of attachment */
};
/*
* represent the whole full-duplex pipe
*/
struct sio_st {
struct {
LIST(sio_halfduplex_t) hd; /* link reader halfduplex nodes */
al_t *al; /* the reader assembly line */
} readers;
struct {
LIST(sio_halfduplex_t) hd; /* link writer halfduplex nodes */
al_t *al; /* the writer assembly line */
} writers;
sio_labelnum_t label_data; /* unique al_label object */
sio_labelnum_t label_error; /* to tag data and signals */
sio_labelnum_t label_eof;
int eof_flag; /* accumulating flags */
int error_flag;
};
/*
* AL tags data with unique pointers. Each (!) sio structure has
* unique (!) labels to tag data, error information and eof
* information on the global assembly lines
*/
#define SIO_LABEL_DATA(sio) ((al_label_t)&(sio)->label_data)
#define SIO_LABEL_ERROR(sio) ((al_label_t)&(sio)->label_error)
#define SIO_LABEL_EOF(sio) ((al_label_t)&(sio)->label_eof)
/****************************************************************************/
/*
* schedule stages on chain of halfduplex nodes
*/
static
sio_rc_t sio_strategy(sio_t *sio, sio_halfduplex_t *chain)
{
sio_rc_t rc;
sio_halfduplex_t *h;
/*
* call stage and direct data upstream/downstream
* according to response code
*
* if stage directs SIO_OK, chose default direction
* depending on data in assembly line
*
* if we the stage does not return a direction,
* simply end the code
*
* if we drop off the chain, simply result SIO_OK
*
*/
rc = SIO_SCHED_UP;
h = chain;
while (h != NULL) {
rc = h->func(sio, h->al, h->stage->userdata, rc);
/* chose default direction */
if (rc == SIO_OK) {
if (al_bytes(h->al) > 0)
rc = h->rc_with_data;
else
rc = h->rc_no_data;
}
if (rc == SIO_SCHED_UP)
h = NEXT(h,hd);
else if (rc == SIO_SCHED_DOWN)
h = PREV(h,hd);
else if (rc == SIO_SCHED_CROSS)
h = h->cross;
else if (rc == SIO_SCHED_LOOP)
h = h;
else
break;
}
if (h == NULL)
rc = SIO_OK;
return rc;
}
/**************************************************************************/
/*
* allocate and intialize sio_t data structure
*
*/
sio_rc_t sio_create(sio_t **siop)
{
sio_t *sio;
/* argument sanity check(s) */
if (siop == NULL)
return SIO_RC(SIO_ERR_ARG);
sio = (sio_t *)malloc(sizeof(sio_t));
if (sio == NULL)
return SIO_RC(SIO_ERR_MEM);
LISTINIT(&sio->readers,hd);
LISTINIT(&sio->writers,hd);
/*
* we only need unique pointers for the labels, but
* we point the pointers also to symbolic constants
*/
sio->label_data = SIO_LN_DATA;
sio->label_error = SIO_LN_ERROR;
sio->label_eof = SIO_LN_EOF;
sio->eof_flag = 0;
sio->error_flag = 0;
*siop = sio;
return SIO_OK;
}
/*
* destroy sio_t data structure.
*
* no deinitialization is done.
*/
sio_rc_t sio_destroy(sio_t *sio)
{
/* argument sanity check(s) */
if (sio == NULL)
return SIO_RC(SIO_ERR_ARG);
/* see wether all stages are detached */
if (!ISEMPTY(&sio->readers,hd) ||
!ISEMPTY(&sio->writers,hd))
return SIO_RC(SIO_ERR_ARG);
free(sio);
return SIO_OK;
}
/*
* create pair of halfduplex nodes that use methods
* from module siom.
*/
sio_rc_t sio_create_stage(sio_t *sio, sio_module_t *siom, sio_stage_t **siosp)
{
sio_rc_t rc;
sio_stage_t *sios;
/* argument sanity check(s) */
if (sio == NULL || siom == NULL || siosp == NULL)
return SIO_RC(SIO_ERR_ARG);
sios = (sio_stage_t *)malloc(sizeof(sio_stage_t));
if (sios == NULL)
return SIO_RC(SIO_ERR_MEM);
NODEINIT(&sios->reader,hd);
NODEINIT(&sios->writer,hd);
sios->module = siom;
sios->userdata = NULL;
sios->rw = SIO_MODE_INVALID;
sios->reader.func = sios->module->input;
sios->reader.stage = sios;
sios->writer.func = sios->module->output;
sios->writer.stage = sios;
sios->reader.cross = NULL;
sios->writer.cross = NULL;
sios->reader.tag = "reader";
sios->writer.tag = "writer";
/* default rules */
sios->reader.rc_with_data = SIO_SCHED_DOWN;
sios->reader.rc_no_data = SIO_SCHED_UP;
sios->writer.rc_with_data = SIO_SCHED_UP;
sios->writer.rc_no_data = SIO_SCHED_DOWN;
rc = sios->module->init(sio, &sios->userdata);
if (rc != SIO_OK) {
free(sios);
return SIO_RC(rc);
}
*siosp = sios;
return SIO_RC(rc);
}
/*
* pass parameters to the configure method of a stage
*/
sio_rc_t sio_configure_stage(sio_t *sio, sio_stage_t *sios,
void *obj, void *value)
{
sio_rc_t rc;
/* argument sanity check(s) */
if (sio == NULL || sios == NULL)
return SIO_RC(SIO_ERR_ARG);
rc = sios->module->configure(sio, sios->userdata, obj, value);
return SIO_RC(rc);
}
/*
*
*/
sio_rc_t sio_destroy_stage(sio_t *sio, sio_stage_t *sios)
{
sio_rc_t rc;
/* argument sanity check(s) */
if (sio == NULL || sios == NULL)
return SIO_RC(SIO_ERR_ARG);
/* more sanity checking */
if (sios->rw != SIO_MODE_INVALID)
return SIO_RC(SIO_ERR_ARG);
rc = sios->module->cleanup(sio, sios->userdata);
free(sios);
return SIO_OK;
}
/*
* allocate global assembly lines
*
* this is called before a module gets attached
*
* the first module attached as a reader allocates
* the read assembly line
*
* the first module attached as a writer allocates
* the write assembly line
*/
static
sio_rc_t sio_create_al(sio_t *sio, sio_mode_t rw)
{
al_rc_t arc;
int freereader = 0;
if (rw == SIO_MODE_READ || rw == SIO_MODE_READWRITE) {
if (ISEMPTY(&sio->readers,hd)) {
arc = al_create(&sio->readers.al);
if (arc != AL_OK)
return SIO_ERR_INT;
freereader = 1;
}
}
if (rw == SIO_MODE_WRITE || rw == SIO_MODE_READWRITE) {
if (ISEMPTY(&sio->writers,hd)) {
arc = al_create(&sio->writers.al);
if (arc != AL_OK) {
if (freereader)
al_destroy(sio->readers.al);
return SIO_ERR_INT;
}
}
}
return SIO_OK;
}
/*
* free global assembly lines
*
* this is called after a module has been detached
*
* if the detached module was a reader and there are no more
* readers then drop read assembly line
*
* if the detached module was a writer and there are no more
* writers then drop write assembly line
*
*/
static
sio_rc_t sio_destroy_al(sio_t *sio, sio_mode_t rw)
{
if (rw == SIO_MODE_READ || rw == SIO_MODE_READWRITE) {
if (ISEMPTY(&sio->readers,hd)) {
al_destroy(sio->readers.al);
sio->readers.al = NULL;
}
}
if (rw == SIO_MODE_WRITE || rw == SIO_MODE_READWRITE) {
if (ISEMPTY(&sio->writers,hd)) {
al_destroy(sio->writers.al);
sio->writers.al = NULL;
}
}
return SIO_OK;
}
/*
* attach a stage to the read and/or write side of the pipe
*
* the stage is attached to the head of the pipe, you
* have to create your pipes "backwards".
*
* prepare assembly lines
*
* stages that are reader and writer get a pointer to the
* sibling side so that the scheduler can cross between
* reading and writing
*
* when a stage is attached to either side its openr and
* openw methods are called respectively
*
*/
sio_rc_t sio_attach(sio_t *sio, sio_stage_t *sios, sio_mode_t rw)
{
sio_rc_t rc;
int freereader = 0;
/* argument sanity check(s) */
if (sio == NULL || sios == NULL)
return SIO_RC(SIO_ERR_ARG);
switch (rw) {
case SIO_MODE_READ:
case SIO_MODE_WRITE:
case SIO_MODE_READWRITE:
break;
default:
return SIO_RC(SIO_ERR_ARG);
}
/* is module already attached ? */
if (sios->rw != SIO_MODE_INVALID)
return SIO_RC(SIO_ERR_ARG);
/* create assembly lines (if aready existing) */
rc = sio_create_al(sio, rw);
if (rc != SIO_OK)
return SIO_RC(rc);
if (rw == SIO_MODE_READ || rw == SIO_MODE_READWRITE) {
rc = sios->module->openr(sio, sio->readers.al, sios->userdata);
if (rc != SIO_OK) {
sio_destroy_al(sio, rw);
return SIO_RC(rc);
}
ADDHEAD(&sio->readers,hd,&sios->reader);
freereader = 1;
}
if (rw == SIO_MODE_WRITE || rw == SIO_MODE_READWRITE) {
rc = sios->module->openw(sio, sio->writers.al, sios->userdata);
if (rc != SIO_OK) {
if (freereader) {
REMOVE(&sio->readers,hd,&sios->reader);
sios->module->closer(sio, sio->readers.al, sios->userdata);
}
sio_destroy_al(sio, rw);
return SIO_RC(rc);
}
ADDHEAD(&sio->writers,hd,&sios->writer);
}
if (rw == SIO_MODE_READWRITE) {
sios->reader.cross = &sios->writer;
sios->writer.cross = &sios->reader;
}
sios->reader.al = sio->readers.al;
sios->writer.al = sio->writers.al;
sios->rw = rw;
return SIO_OK;
}
/*
* detach a stage to the read and/or write side of the pipe
*
* when a stage is detached from either side its closer and
* closew methods are called respectively
*
* drop assembly lines when possible
*
*/
sio_rc_t sio_detach(sio_t *sio, sio_stage_t *sios)
{
sio_rc_t rc, rc2;
/* argument sanity check(s) */
if (sio == NULL || sios == NULL)
return SIO_RC(SIO_ERR_ARG);
switch (sios->rw) {
case SIO_MODE_READ:
case SIO_MODE_WRITE:
case SIO_MODE_READWRITE:
break;
default:
return SIO_RC(SIO_ERR_ARG);
}
rc = SIO_OK;
rc2 = SIO_OK;
if (sios->module->shutdown != NULL &&
sios->module->shutdown(sio, sios->userdata) == SIO_OK) {
if (sios->rw == SIO_MODE_WRITE || sios->rw == SIO_MODE_READWRITE) {
rc = sio_strategy(sio, HEAD(&sio->writers,hd));
if (rc != SIO_OK) return SIO_RC(rc);
}
if (sios->rw == SIO_MODE_READ || sios->rw == SIO_MODE_READWRITE) {
sio_strategy(sio, HEAD(&sio->readers,hd));
if (rc != SIO_OK) return SIO_RC(rc);
}
}
if (sios->rw == SIO_MODE_WRITE || sios->rw == SIO_MODE_READWRITE) {
REMOVE(&sio->writers,hd,&sios->writer);
rc = sios->module->closew(sio, sio->writers.al, sios->userdata);
}
if (sios->rw == SIO_MODE_READ || sios->rw == SIO_MODE_READWRITE) {
REMOVE(&sio->readers,hd,&sios->reader);
rc2 = sios->module->closer(sio, sio->readers.al, sios->userdata);
}
/* XXX double error handling ? */
if (rc == SIO_OK)
rc = rc2;
if (sios->rw == SIO_MODE_READWRITE) {
sios->reader.cross = NULL;
sios->writer.cross = NULL;
}
sios->writer.al = NULL;
sios->reader.al = NULL;
sio_destroy_al(sio, sios->rw);
sios->rw = SIO_MODE_INVALID;
return SIO_RC(rc);
}
/*
* retrieve data from the input side
*
* if there is no data in the reader assembly line
* then schedule the input side of the pipe once
* if this still doesn't retrieve data then raise
* a SIO_ERR_EOF error.
*
* retrieve data from the reader assembly line up to
* the specified byte limit for the first span of
* the specified label or any data if label == NULL
*
*/
sio_rc_t sio_input(sio_t *sio, al_t *al, size_t limit, al_label_t label)
{
sio_rc_t rc;
sio_halfduplex_t *h;
al_t *src;
size_t n;
size_t datastart, datasize;
/* argument sanity check(s) */
if (sio == NULL || al == NULL)
return SIO_RC(SIO_ERR_ARG);
h = HEAD(&sio->readers,hd);
if (h == NULL)
return SIO_RC(SIO_ERR_ARG);
src = h->al;
n = al_bytes(src);
if (n == 0) {
rc = sio_strategy(sio, h);
if (rc != SIO_OK)
return SIO_RC(rc);
n = al_bytes(src);
if (n == 0)
return SIO_RC(SIO_ERR_EOF);
}
/*
* clamp to requested size
*/
if (n > limit)
n = limit;
while (n > 0) {
if (label == NULL) {
datastart = 0;
datasize = n;
} else if (al_spanlabel(src, 0, n, label, &datastart, &datasize) != AL_OK)
break;
/*
* clamp to requested size
*/
if (datasize > n)
datasize = n;
/* XXX - error handling ? */
(void) al_splice(src, datastart, datasize, NULL, al);
n -= datasize;
}
return SIO_OK;
}
/*
* pass data to the output side
*
* append data to the writer assembly line
*
* schedule the output side of the pipe
*
*/
sio_rc_t sio_output(sio_t *sio, al_t *al)
{
sio_rc_t rc;
al_rc_t arc;
sio_halfduplex_t *h;
al_t *dst;
size_t n;
/* argument sanity check(s) */
if (sio == NULL || al == NULL)
return SIO_RC(SIO_ERR_ARG);
h = HEAD(&sio->writers,hd);
if (h == NULL)
return SIO_RC(SIO_ERR_ARG);
dst = h->al;
n = al_bytes(dst);
arc = al_splice(dst, n, 0, al, NULL);
if (arc != AL_OK)
return SIO_RC(SIO_ERR_INT);
rc = sio_strategy(sio, h);
return SIO_RC(rc);
}
/*
* schedule the output side of the pipe and
* signal to flush data buffers
*
* current the signalling is done by sending
* an EOF data chunk. Convention for all
* buffering modules is to flush data buffers
* on label boundaries.
*
*/
sio_rc_t sio_push(sio_t *sio)
{
sio_rc_t rc;
al_rc_t arc;
sio_halfduplex_t *h;
al_t *dst;
char eof = '\0';
/* argument sanity check(s) */
if (sio == NULL)
return SIO_RC(SIO_ERR_ARG);
h = HEAD(&sio->writers,hd);
if (h == NULL)
return SIO_RC(SIO_ERR_ARG);
dst = h->al;
arc = al_append_bytes(dst, &eof, 1, SIO_LABEL_EOF(sio));
if (arc != AL_OK)
return SIO_RC(SIO_ERR_INT);
rc = sio_strategy(sio, h);
return SIO_RC(rc);
}
/*
* retrieve data from the pipe into a buffer much like read()
*
* handles error and eof signals
*
*/
sio_rc_t sio_read(sio_t *sio, char *dst, size_t n, size_t *actualp)
{
al_rc_t arc;
sio_rc_t rc;
al_t *al;
*actualp = 0;
if (n == 0)
return SIO_OK;
arc = al_create(&al);
if (arc != AL_OK) return SIO_RC(SIO_ERR_INT);
rc = sio_input(sio, al, n, SIO_LABEL_DATA(sio));
if (rc == SIO_OK) {
if (al_bytes(al) > 0)
al_flatten(al, 0, n, AL_FORWARD, NULL, dst, actualp);
else {
rc = sio_input(sio, al, n, SIO_LABEL_ERROR(sio));
if (rc == SIO_OK) {
if (al_bytes(al) > 0)
sio->error_flag = 1;
else {
rc = sio_input(sio, al, n, SIO_LABEL_EOF(sio));
if (rc == SIO_OK) {
if (al_bytes(al) > 0)
sio->eof_flag = 1;
}
}
}
}
}
arc = al_destroy(al);
if (arc != AL_OK) return SIO_RC(SIO_ERR_INT);
return SIO_RC(rc);
}
/*
* send data to the pipe from a buffer much like write()
*/
sio_rc_t sio_write(sio_t *sio, char *src, size_t n, size_t *actualp)
{
al_rc_t arc;
sio_rc_t rc;
al_t *al;
if (n == 0)
return SIO_OK;
arc = al_create(&al);
if (arc != AL_OK) return SIO_RC(SIO_ERR_INT);
arc = al_append_bytes(al, src, n, SIO_LABEL_DATA(sio));
if (arc != AL_OK)
rc = SIO_ERR_INT;
else
rc = sio_output(sio, al);
*actualp = n - al_bytes(al);
arc = al_destroy(al);
if (arc != AL_OK) return SIO_RC(SIO_ERR_INT);
return SIO_RC(rc);
}
/*
* query a SIO flag
*
* currently this is SIO_FLAG_ERROR and SIO_FLAG_EOF
* which are set by sio_read()
*
*/
sio_rc_t sio_flag(sio_t *sio, sio_flag_t fl)
{
int rc;
switch (fl) {
case SIO_FLAG_ERROR:
rc = sio->error_flag;
break;
case SIO_FLAG_EOF:
rc = sio->eof_flag;
break;
default:
rc = 0;
break;
}
return rc ? SIO_TRUE : SIO_FALSE;
}
/*
* query and clear a SIO flag
*/
sio_rc_t sio_clearflag(sio_t *sio, sio_flag_t fl)
{
int rc;
switch (fl) {
case SIO_FLAG_ERROR:
rc = sio->error_flag;
sio->error_flag = 0;
break;
case SIO_FLAG_EOF:
rc = sio->eof_flag;
sio->eof_flag = 0;
break;
default:
rc = 0;
break;
}
return rc ? SIO_TRUE : SIO_FALSE;
}
const char *sio_error(sio_rc_t rc)
{
const char *mess;
switch (rc) {
case SIO_OK: mess = "Everything Ok"; break;
case SIO_ERR_ARG: mess = "Invalid Argument"; break;
case SIO_ERR_MEM: mess = "Not Enough Memory"; break;
case SIO_ERR_EOF: mess = "End Of Data"; break;
case SIO_ERR_SYS: mess = "Operating System Error"; break;
case SIO_ERR_INT: mess = "Internal Error"; break;
case SIO_SCHED_UP: mess = "Invoke Upstream Stage"; break;
case SIO_SCHED_DOWN: mess = "Invoke Downstream Stage"; break;
case SIO_SCHED_CROSS: mess = "Invoke Crossstream Stage"; break;
case SIO_SCHED_LOOP: mess = "Loop through current Stage"; break;
default: mess = "Invalid Result Code"; break;
}
return mess;
}
/*
* stages need to share the labels that distinguish between
* data and signals on the pipe
*
* this function returns OSSP al labels for SIO specific
* label numbers defined in sio.h
*
*/
sio_rc_t sio_label(sio_t *sio, sio_labelnum_t ln, al_label_t *p)
{
void *label;
switch (ln) {
case SIO_LN_DATA:
label = SIO_LABEL_DATA(sio);
break;
case SIO_LN_ERROR:
label = SIO_LABEL_ERROR(sio);
break;
case SIO_LN_EOF:
label = SIO_LABEL_EOF(sio);
break;
default:
return SIO_ERR_ARG;
}
*p = label;
return SIO_OK;
}
@
1.25
log
@Fixed OSSP ex support by internally using a non-conflicting
namespace for the OSSP ex API.
Submitted by: Kimura Fuyuki
@
text
@d3 3
a5 3
** Copyright (c) 2002-2003 Cable & Wireless Deutschland
** Copyright (c) 2002-2003 The OSSP Project
** Copyright (c) 2002-2003 Ralf S. Engelschall
@
1.24
log
@clear actual result
@
text
@d50 1
@
1.23
log
@clear eof/error flags on creation
@
text
@d688 2
@
1.22
log
@correctly limit sio_input data transfer
@
text
@d198 3
@
1.21
log
@sio_write now returns number of bytes sent upstream
@
text
@d574 6
@
1.20
log
@- consistently use standard OSSP copyright message everywhere
- strip trailing whitespaces
@
text
@d732 2
@
1.19
log
@add autoconf support
PR:
Submitted by:
Reviewed by:
Approved by:
Obtained from:
@
text
@d2 4
a5 5
** OSSP sio -- stream I/O
** Copyright (c) 2002 The OSSP Project
** Copyright (c) 2002 Cable & Wireless Deutschland
** Copyright (c) 2002 Ralf S. Engelschall
** Copyright (c) 2002 Michael van Elst
d7 2
a8 1
** This file is part of OSSP sio, a library implementing layered I/O
@
1.18
log
@batch all data in sio_input
don't retry sio_input for different labels in sio_read if there was
an error.
PR:
Submitted by:
Reviewed by:
Approved by:
Obtained from:
@
text
@d31 4
@
1.17
log
@fix old prototype
PR:
Submitted by:
Reviewed by:
Approved by:
Obtained from:
@
text
@d561 2
a562 1
if (rc != SIO_OK) return SIO_RC(rc);
d570 12
a581 7
if (label == NULL) {
datastart = 0;
datasize = n;
} else if (al_spanlabel(src, 0, n, label, &datastart, &datasize) != AL_OK) {
datastart = 0;
datasize = 0;
}
d583 2
a584 5
/*
* clamp to requested size
*/
if (datasize > n)
datasize = n;
d586 2
a587 2
/* XXX - error handling ? */
(void) al_splice(src, datastart, datasize, NULL, al);
d682 3
a684 6
if (rc == SIO_OK && al_bytes(al) > 0)
al_flatten(al, 0, n, AL_FORWARD, NULL, dst, actualp);
else {
rc = sio_input(sio, al, n, SIO_LABEL_ERROR(sio));
if (rc == SIO_OK && al_bytes(al) > 0)
sio->error_flag = 1;
d686 12
a697 3
rc = sio_input(sio, al, n, SIO_LABEL_EOF(sio));
if (rc == SIO_OK && al_bytes(al) > 0)
sio->eof_flag = 1;
@
1.16
log
@input/output now gets another parameter where scheduler tells
them from where they methods called by passing the return value
of the previously called stage.
PR:
Submitted by:
Reviewed by:
Approved by:
Obtained from:
@
text
@d68 1
a68 1
sio_rc_t (*func)(sio_t *, al_t *, void *); /* input() or output() */
@
1.15
log
@use new sio_input facility in sio_read
PR:
Submitted by:
Reviewed by:
Approved by:
Obtained from:
@
text
@d137 1
a137 1
rc = h->func(sio, h->al, h->stage->userdata);
@
1.14
log
@changed sio_input API to support label filtering
PR:
Submitted by:
Reviewed by:
Approved by:
Obtained from:
@
text
@a98 1
char *dst; /* write pointer for sio_read */
a660 26
* callback used by sio_read to scan through
* reader assembly line
*
* data chunks are copied to the destination buffer
* error chunks set the error flag
* eof chunks set the eof flag
*/
static al_rc_t sio_readchunk(al_chunk_t *alc, void *u)
{
sio_t *sio = (sio_t *)u;
size_t len;
if (al_same_label(alc, SIO_LABEL_DATA(sio))) {
len = al_chunk_len(alc);
memcpy(sio->dst, al_chunk_ptr(alc,0), len);
sio->dst += len;
} else if (al_same_label(alc, SIO_LABEL_ERROR(sio))) {
sio->error_flag = 1;
} else if (al_same_label(alc, SIO_LABEL_EOF(sio))) {
sio->eof_flag = 1;
}
return AL_OK;
}
/*
d678 12
a689 5
rc = sio_input(sio, al, n, NULL);
if (rc == SIO_OK) {
sio->dst = dst;
al_traverse_cb(al, 0, n, AL_FORWARD, NULL, sio_readchunk, (void*)sio);
*actualp = sio->dst - dst;
@
1.13
log
@add optional shutdown function to modules. On detach, it is called
and if returning SIO_OK another round through output and input
is done.
modules are now pushed at pipe head instead of appended so that
a module can do upstream I/O while being wound up.
PR:
Submitted by:
Reviewed by:
Approved by:
Obtained from:
@
text
@a489 1
printf("final output\n");
a493 1
printf("final input\n");
d533 2
d537 2
a538 1
* the specified byte limit
d541 1
a541 1
sio_rc_t sio_input(sio_t *sio, al_t *al, size_t limit)
d547 1
d570 13
a582 2
if (n > limit)
n = limit;
d584 2
a585 1
(void) al_splice(src, 0, n, NULL, al); /* XXX - error handling ? */
d705 1
a705 1
rc = sio_input(sio, al, n);
@
1.12
log
@merged sio_module.h into sio.h
renamed scheduler codes to SIO_SCHED_*
added comments to sio.c
PR:
Submitted by:
Reviewed by:
Approved by:
Obtained from:
@
text
@d384 3
d429 1
a429 1
ADDTAIL(&sio->readers,hd,&sios->reader);
d442 1
a442 1
ADDTAIL(&sio->writers,hd,&sios->writer);
d468 1
a468 1
sio_rc_t rc;
d483 19
a501 1
rc = SIO_OK;
d508 1
a508 5
if (rc == SIO_OK)
rc = sios->module->closer(sio, sio->readers.al, sios->userdata);
else
/* XXX - double error handling ? */
sios->module->closer(sio, sio->readers.al, sios->userdata);
d510 4
@
1.11
log
@remove remaining GCC warnings
@
text
@a36 1
#include "sio_module.h"
d54 4
a57 1
d61 19
a79 7
NODE(sio_halfduplex_t) hd;
sio_stage_t *stage;
sio_halfduplex_t *cross;
const char *tag;
sio_rc_t rc_with_data, rc_no_data;
al_t *al;
sio_rc_t (*func)(sio_t *, al_t *, void *);
d82 3
d87 2
a88 2
LIST(sio_halfduplex_t) hd;
al_t *al;
d91 2
a92 2
LIST(sio_halfduplex_t) hd;
al_t *al;
d94 2
a95 2
sio_labelnum_t label_data;
sio_labelnum_t label_error;
d97 1
a97 1
int eof_flag;
d99 1
a99 1
char *dst;
d101 6
a110 8
struct sio_stage_st {
sio_halfduplex_t reader;
sio_halfduplex_t writer;
void *userdata;
sio_module_t *module;
sio_mode_t rw;
};
d113 3
d135 1
a135 1
rc = SIO_UPSTREAM;
d148 1
a148 1
if (rc == SIO_UPSTREAM)
d150 1
a150 1
else if (rc == SIO_DOWNSTREAM)
d152 1
a152 1
else if (rc == SIO_XSTREAM)
d154 1
a154 1
else if (rc == SIO_LOOP)
d168 4
d187 4
d200 5
d211 5
d221 4
d257 4
a260 4
sios->reader.rc_with_data = SIO_DOWNSTREAM;
sios->reader.rc_no_data = SIO_UPSTREAM;
sios->writer.rc_with_data = SIO_UPSTREAM;
sios->writer.rc_no_data = SIO_DOWNSTREAM;
d273 3
d290 3
d301 4
d311 11
d350 12
d381 13
d454 9
d509 10
d555 8
d590 10
d626 8
d652 6
d683 3
d710 8
a717 1
int sio_flag(sio_t *sio, sio_flag_t fl)
d733 1
a733 1
return rc;
d736 4
a739 1
int sio_clearflag(sio_t *sio, sio_flag_t fl)
d757 1
a757 1
return rc;
d765 11
a775 11
case SIO_OK: mess = "Everything Ok"; break;
case SIO_ERR_ARG: mess = "Invalid Argument"; break;
case SIO_ERR_MEM: mess = "Not Enough Memory"; break;
case SIO_ERR_EOF: mess = "End Of Data"; break;
case SIO_ERR_SYS: mess = "Operating System Error"; break;
case SIO_ERR_INT: mess = "Internal Error"; break;
case SIO_UPSTREAM: mess = "Invoke Upstream Stage"; break;
case SIO_DOWNSTREAM: mess = "Invoke Downstream Stage"; break;
case SIO_XSTREAM: mess = "Invoke Crossstream Stage"; break;
case SIO_LOOP: mess = "Loop through current Stage"; break;
default: mess = "Invalid Result Code"; break;
d781 8
@
1.10
log
@initialize SIO_XSTREAM pointers only when stage is attached
read-write.
PR:
Submitted by:
Reviewed by:
Approved by:
Obtained from:
@
text
@d503 1
a503 1
al_rc_t sio_readchunk(al_chunk_t *alc, void *u)
@
1.9
log
@add SIO_LOOP status to simplify protocol state machine
PR:
Submitted by:
Reviewed by:
Approved by:
Obtained from:
@
text
@d210 2
a211 2
sios->reader.cross = &sios->writer;
sios->writer.cross = &sios->reader;
d356 5
d397 5
@
1.8
log
@add special state flags (error, eof)
sio_read now parses assembly line for data and signalling chunks
and sets flags accordingly.
PR:
Submitted by:
Reviewed by:
Approved by:
Obtained from:
@
text
@d136 2
d614 1
@
1.7
log
@pass through error code from open routines
PR:
Submitted by:
Reviewed by:
Approved by:
Obtained from:
@
text
@d33 1
d77 6
a82 3
sio_labelnum_t label_data;
sio_labelnum_t label_error;
sio_labelnum_t label_eof;
d491 18
d522 5
a526 3
if (rc == SIO_OK)
arc = al_flatten(al, 0, n, AL_FORWARD_SPAN, SIO_LABEL_DATA(sio),
dst, actualp);
d556 40
@
1.6
log
@code cleanup
PR:
Submitted by:
Reviewed by:
Approved by:
Obtained from:
@
text
@d332 1
a332 1
return SIO_ERR_INT;
d345 1
a345 1
return SIO_ERR_INT;
@
1.5
log
@code cleanup
PR:
Submitted by:
Reviewed by:
Approved by:
Obtained from:
@
text
@d80 3
a82 3
#define SIO_LABEL_DATA(sio) ((al_label_t *)&(sio)->label_data)
#define SIO_LABEL_ERROR(sio) ((al_label_t *)&(sio)->label_error)
#define SIO_LABEL_EOF(sio) ((al_label_t *)&(sio)->label_eof)
d554 1
a554 1
sio_rc_t sio_label(sio_t *sio, sio_labelnum_t ln, void **p)
@
1.4
log
@snapshot
- sio_strategy now has a default direction triggered by SIO_OK result
- added structure tag to aid debugging
- sio_hole eats all data and returns downstream (correct ?)
- sio_null now uses default directio
- sio_sa puts wrapper on sa objects
- sio_hello.c implements a trivial protocol handler
PR:
Submitted by:
Reviewed by:
Approved by:
Obtained from:
@
text
@d80 3
a82 3
#define SIO_LABEL_DATA(sio) ((void*)&(sio)->label_data)
#define SIO_LABEL_ERROR(sio) ((void*)&(sio)->label_error)
#define SIO_LABEL_EOF(sio) ((void*)&(sio)->label_eof)
d500 1
a500 1
if (rc == AL_OK) {
a502 3
if (arc != AL_OK)
rc = SIO_ERR_INT;
}
@
1.3
log
@initialize cross pointers
PR:
Submitted by:
Reviewed by:
Approved by:
Obtained from:
@
text
@d61 2
d104 3
d113 2
a114 1
h = chain;
d117 9
d194 1
d196 1
d199 1
a199 1
sios->reader.func = siom->input;
d201 1
a201 1
sios->writer.func = siom->output;
d206 9
@
1.2
log
@snapshot
PR:
Submitted by:
Reviewed by:
Approved by:
Obtained from:
@
text
@d187 3
@
1.1
log
@initial commit
PR:
Submitted by:
Reviewed by:
Approved by:
Obtained from:
@
text
@d60 2
d67 1
a67 1
LIST(sio_halfduplex_t) hd;
d71 1
a71 1
LIST(sio_halfduplex_t) hd;
d74 3
d78 3
d93 1
a93 1
sio_rc_t sio_strategy(sio_t *sio, sio_halfduplex_t *chain, al_t *al)
d98 10
d110 1
a110 1
rc = h->func(sio, al, h->stage->userdata);
d114 3
a116 1
h = NEXT(h,hd);
d121 4
a124 1
return SIO_OK;
d144 4
a167 1
void *u;
d180 1
a180 1
sios->userdata = u;
d187 7
a193 1
rc = sios->module->init(sio, sios->userdata);
d198 2
a199 1
sio_rc_t sio_cofigure_stage(sio_t *sio, sio_stage_t *sios, void *obj, void *value)
d226 47
d276 1
d281 8
d294 11
a304 6
/* prepare module for being attached */
rc = sios->module->open(sio, sios->userdata);
if (rc != SIO_OK) return SIO_RC(rc);
switch (rw) {
case SIO_MODE_READ:
d306 12
a317 2
break;
case SIO_MODE_WRITE:
a318 7
break;
case SIO_MODE_READWRITE:
ADDTAIL(&sio->readers,hd,&sios->reader);
ADDTAIL(&sio->writers,hd,&sios->writer);
break;
default:
return SIO_RC(SIO_ERR_ARG);
d321 3
a323 2
/* Remember the lists that sios has been attached to */
sios->rw = rw;
a337 2
REMOVE(&sio->readers,hd,&sios->reader);
break;
a338 2
REMOVE(&sio->writers,hd,&sios->writer);
break;
a339 2
REMOVE(&sio->readers,hd,&sios->reader);
REMOVE(&sio->writers,hd,&sios->writer);
a342 1
break;
d345 20
a364 1
rc = sios->module->close(sio, sios->userdata);
d372 2
a373 1
al_t *src = sio->readers.al;
d380 5
d388 1
a388 1
rc = sio_strategy(sio, HEAD(&sio->readers,hd), src);
d405 1
a405 1
sio_rc_t sio_discard(sio_t *sio)
d408 3
a410 1
al_t *src = sio->readers.al;
d414 1
a414 1
if (sio == NULL)
d417 2
a418 20
while ((n = al_bytes(src)) > 0) {
rc = sio_strategy(sio, HEAD(&sio->readers,hd), src);
if (rc != SIO_OK)
break;
}
if (rc == SIO_ERR_EOF)
return SIO_OK;
return SIO_RC(rc);
}
sio_rc_t sio_output(sio_t *sio, al_t *al)
{
sio_rc_t rc;
al_t *dst = sio->writers.al;
size_t n;
/* argument sanity check(s) */
if (sio == NULL || al == NULL)
d420 1
d423 3
a425 1
al_splice(dst, n, 0, al, NULL);
d427 1
a427 1
rc = sio_strategy(sio, HEAD(&sio->writers,hd), dst);
d432 1
a432 1
sio_rc_t sio_flush(sio_t *sio)
d435 4
a438 2
al_t *dst = sio->writers.al;
size_t n;
d444 10
a453 5
while ((n = al_bytes(dst)) > 0) {
rc = sio_strategy(sio, HEAD(&sio->writers,hd), sio->writers.al);
if (rc != SIO_OK)
break;
}
d464 3
d472 2
a473 1
arc = al_flatten(al, 0, n, dst, actualp);
d490 3
d496 1
a496 1
arc = al_append_bytes(al, src, n);
d521 1
d526 22
@