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 @