head 1.35;
access;
symbols
L2_0_9_13:1.35
FSL_1_7_0:1.35
L2_0_9_12:1.35
LMTP2NNTP_1_4_1:1.35
LMTP2NNTP_1_4_0:1.35
FSL_1_6_1:1.35
L2_0_9_11:1.35
FSL_1_6_0:1.34
FSL_1_6b2:1.34
L2_0_9_10:1.34
FSL_1_6b1:1.34
L2_0_9_9:1.34
LMTP2NNTP_1_3_0:1.33
LMTP2NNTP_1_3b2:1.33
LMTP2NNTP_1_3b1:1.33
LMTP2NNTP_1_3a3:1.33
FSL_1_5_0:1.33
LMTP2NNTP_1_3a2:1.33
FSL_1_5a3:1.33
LMTP2NNTP_1_3a1:1.33
FSL_1_5a2:1.33
L2_0_9_8:1.33
FSL_1_5a1:1.33
L2_0_9_7:1.33
L2_0_9_6:1.33
FSL_1_4_0:1.33
FSL_1_4b1:1.33
L2_0_9_5:1.33
FSL_1_4a1:1.32
FSL_1_3_0:1.32
FSL_1_3b1:1.32
L2_0_9_4:1.32
FSL_1_2_1:1.32
L2_0_9_3:1.32
FSL_1_2_0:1.32
L2_0_9_2:1.32
FSL_1_1_0:1.32
FSL_1_1b1:1.32
WORKOFF:1.32.0.2
WORKOFF_BP:1.32
FSL_1_0_8:1.32
LMTP2NNTP_1_2_0:1.31
LMTP2NNTP_1_2b4:1.31
LMTP2NNTP_1_2b3:1.31
LMTP2NNTP_1_2b2:1.31
LMTP2NNTP_1_2b1:1.31
LMTP2NNTP_1_2a8:1.31
LMTP2NNTP_1_2a7:1.31
FSL_1_0_7:1.31
FSL_1_0_6:1.29
FSL_1_0_5:1.29
FSL_1_0_4:1.29
L2_0_9_1:1.29
FSL_1_0_3:1.29
LMTP2NNTP_1_2a6:1.29
FSL_1_0_2:1.29
FSL_1_0_1:1.29
FSL_1_0_0:1.29
FSL_0_9_0:1.29
L2_0_9_0:1.29
FSL_0_1_12:1.28
FSL_0_1_11:1.28
FSL_0_1_10:1.28
FSL_0_1_9:1.28
FSL_0_1_8:1.28
FSL_0_1_7:1.28
FSL_0_1_6:1.28
FSL_0_1_5:1.28
FSL_0_1_1:1.27
LMTP2NNTP_1_2a5:1.27
LMTP2NNTP_1_2a4:1.27
LMTP2NNTP_1_2a3:1.27
LMTP2NNTP_1_2a1:1.26
LMTP2NNTP_1_1_1:1.20
LMTP2NNTP_1_1_0:1.20
LMTP2NNTP_1_1b4:1.20
LMTP2NNTP_1_1b3:1.20
L2_CHANNEL_ONLY_REVAMPING_BEFORE:1.20
LMTP2NNTP_1_1b2:1.20
LMTP2NNTP_1_1b1:1.20
L2_0_1_0:1.18
L2NGATE:1.8.0.2
START_MICHAEL:1.5
L2_INITIAL:1.1.1.1
OSSP:1.1.1;
locks; strict;
comment @ * @;
1.35
date 2005.10.03.08.08.11; author rse; state Exp;
branches;
next 1.34;
1.34
date 2005.01.24.15.03.17; author rse; state Exp;
branches;
next 1.33;
1.33
date 2003.11.06.15.31.47; author thl; state Exp;
branches;
next 1.32;
1.32
date 2003.02.13.15.37.28; author rse; state Exp;
branches;
next 1.31;
1.31
date 2003.01.27.16.01.35; author thl; state Exp;
branches;
next 1.30;
1.30
date 2003.01.06.11.41.51; author rse; state Exp;
branches;
next 1.29;
1.29
date 2002.07.30.19.08.25; author rse; state Exp;
branches;
next 1.28;
1.28
date 2002.07.24.09.36.54; author rse; state Exp;
branches;
next 1.27;
1.27
date 2002.01.02.17.07.38; author rse; state Exp;
branches;
next 1.26;
1.26
date 2001.11.07.16.04.22; author rse; state Exp;
branches;
next 1.25;
1.25
date 2001.11.07.11.37.18; author rse; state Exp;
branches;
next 1.24;
1.24
date 2001.11.06.15.02.49; author rse; state Exp;
branches;
next 1.23;
1.23
date 2001.11.04.13.55.06; author rse; state Exp;
branches;
next 1.22;
1.22
date 2001.11.04.13.21.17; author rse; state Exp;
branches;
next 1.21;
1.21
date 2001.11.03.22.51.36; author rse; state Exp;
branches;
next 1.20;
1.20
date 2001.09.27.13.56.35; author rse; state Exp;
branches;
next 1.19;
1.19
date 2001.09.24.15.36.23; author rse; state Exp;
branches;
next 1.18;
1.18
date 2001.09.13.12.50.26; author thl; state Exp;
branches;
next 1.17;
1.17
date 2001.09.12.09.42.34; author ms; state Exp;
branches;
next 1.16;
1.16
date 2001.09.06.14.37.53; author rse; state Exp;
branches;
next 1.15;
1.15
date 2001.09.05.19.58.44; author rse; state Exp;
branches;
next 1.14;
1.14
date 2001.09.05.13.56.12; author rse; state Exp;
branches;
next 1.13;
1.13
date 2001.09.05.10.59.37; author ms; state Exp;
branches;
next 1.12;
1.12
date 2001.09.04.15.41.17; author rse; state Exp;
branches;
next 1.11;
1.11
date 2001.09.04.13.52.59; author rse; state Exp;
branches;
next 1.10;
1.10
date 2001.09.03.13.43.33; author rse; state Exp;
branches;
next 1.9;
1.9
date 2001.09.03.11.50.25; author rse; state Exp;
branches;
next 1.8;
1.8
date 2001.09.02.15.35.40; author ms; state Exp;
branches;
next 1.7;
1.7
date 2001.09.02.14.37.58; author ms; state Exp;
branches;
next 1.6;
1.6
date 2001.08.26.13.04.37; author ms; state Exp;
branches;
next 1.5;
1.5
date 2001.08.15.10.36.03; author rse; state Exp;
branches;
next 1.4;
1.4
date 2001.05.24.09.40.28; author rse; state Exp;
branches;
next 1.3;
1.3
date 2001.05.22.20.00.12; author rse; state Exp;
branches;
next 1.2;
1.2
date 2001.05.22.18.47.31; author rse; state Exp;
branches;
next 1.1;
1.1
date 2001.05.10.19.46.01; author rse; state Exp;
branches
1.1.1.1;
next ;
1.1.1.1
date 2001.05.10.19.46.01; author rse; state Exp;
branches;
next ;
desc
@@
1.35
log
@Adjust copyright messages for new year 2005.
@
text
@/*
** OSSP l2 - Flexible Logging
** Copyright (c) 2001-2005 Cable & Wireless
** Copyright (c) 2001-2005 The OSSP Project
** Copyright (c) 2001-2005 Ralf S. Engelschall
**
** This file is part of OSSP l2, a flexible logging library which
** can be found at http://www.ossp.org/pkg/lib/l2/.
**
** 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.
**
** l2_channel.c: channel object
**
*/
#include "l2_p.h"
/*
* A channel is the central object for a logging stream. It is
* implemented by a framework (the code implemented here) which provides
* the channel API and which is equal for all channels and a particular
* handler which implements the characteristics specific to a particular
* channel class. The lifecycle of a channel is illustrated in the
* following figure:
*
* -----BEGIN EMBEDDED OBJECT-----
* Content-editor: xfig %s
* Content-encoding: gzip:9 base64
* Content-type: application/fig
* Content-viewer: xfig %s
* Description: L2 Channel Lifecycle
* Filename: l2_ch_lifecycle.fig
* Last-modified: 2000-09-28/14:40
* Name: l2_ch_lifecycle
* Version: eo/1.0
* H4sIAGdztDsCA62WTW/bMAyGz/WvENBzM5KyPnwusGFAdtp1l8BVWgOZUyTuhv77
* kfKHnC4t5CZJ7JAO3kcUKUq5/fr9m9IrKtab9uFYb55DcR/aLhyKH6E7NHWxDh17
* ShUIsAIofjbt4y4Ud1QgASgqQGlSt3V8Fai0AoV8gTJyI76xLD6Tb35iPSpybNlS
* PsknV5po5WC0BZZRWSlL8km+tlYsa3MwJfAP6Kdokl8iltHKwjiwJ5jJL52DbIxB
* Z+aY5BvSVT7GEieSzISZfGN9Fa0cjAVj55iZz7XPxxg6mdTMNz5/Ug55ncwwyXdU
* mnyMPS148p1bUHCPAPPcJN+jLOrM3GjUOMckX2PV16ygiJDL9Zi7Qa4GR36i4kYM
* XMW6yZ1LJP160y+iofqUy4SeKW01zCtaMT2XBjSRUrdFJr1h0rmAZg3qhnV0cUAT
* KTVcfoYsjOmN1jLxbPWJdZV6T2GkTstPb2pOh3ilek+kNN3LmWO6UuflZB0/YvYk
* B+eYXpi4PM4YYs80g3XK/Gh1JHG0UC/p3OFIhRkhiuXNJ3aaDr0/tKExbraWqtFX
* g1qsiyue8qDxWq0ykdI+l5/g2eE87rCX79XGj8cK6CGgMh0gyH8qYPrPoTCeGzx0
* Jft6yUHU+3bbPL4cwi8AzFAazU+XKXlJlHL6O64uec3KQ9h0OQPK1uJRZNob9RCO
* 3WH/mjGc5kC1HXX759Bmiixas0jkZHIgBy9wrH8PTRe+bHcvx6dMrTUOPqOVYA1x
* sFhJQnf7Y8hUOVfCOZV/v3h+3N88W7tmG7rm9ztCXPGE/Gw4IuAgLUd67M4V3f8/
* nPS/M9IprN/UXfMnR2b8MA4Rl6Np3wh9EtJM6OWRlkGrfrtUa1L3T5u2DTu15qnW
* r/Wup/wDvlAM/PkMAAA=
* -----END EMBEDDED OBJECT-----
*/
/* create channel */
l2_result_t l2_channel_create(l2_channel_t **chp, l2_env_t *env, const char *name)
{
l2_channel_t *ch;
l2_handler_t *h;
int i;
/* argument sanity check */
if (env == NULL || name == NULL)
return L2_ERR_ARG;
/* lookup channel handler */
h = NULL;
for (i = 0; i < L2_MAX_HANDLERS && env->handlers[i] != NULL; i++) {
if (strcmp(env->handlers[i]->name, name) == 0) {
h = env->handlers[i];
break;
}
}
if (h == NULL)
return L2_ERR_CH;
/* allocate channel structure */
if ((ch = (l2_channel_t *)malloc(sizeof(l2_channel_t))) == NULL)
return L2_ERR_SYS;
/* initialize channel structure */
ch->env = env;
ch->state = L2_CHSTATE_CREATED;
ch->parent = NULL;
ch->sibling = NULL;
ch->child = NULL;
memset(&ch->context, 0, sizeof(l2_context_t));
memcpy(&ch->handler, h, sizeof(l2_handler_t));
ch->levelmask = env->levelmask;
ch->flushmask = env->flushmask;
/* (optionally) perform create operation in handler */
if (ch->handler.create != NULL) {
if (ch->handler.create(&ch->context, ch) != L2_OK) {
free(ch);
return L2_ERR_SYS;
}
}
/* pass object to caller */
(*chp) = ch;
return L2_OK;
}
/* link channels */
l2_result_t l2_channel_link(l2_channel_t *ch0, l2_link_t id, l2_channel_t *ch, ...)
{
l2_channel_t *chT;
l2_channel_t *chN;
va_list ap;
/* argument sanity check */
if (ch0 == NULL || ch == NULL)
return L2_ERR_ARG;
/* perform either child or sibling linking operation(s) */
if (id == L2_LINK_CHILD) {
/* make sure child parents are filters only */
if (ch0->handler.type != L2_CHANNEL_FILTER)
return L2_ERR_USE;
va_start(ap, ch);
chT = ch;
do {
chN = (l2_channel_t *)va_arg(ap, l2_channel_t *);
if (chN != NULL && chT->handler.type != L2_CHANNEL_FILTER)
return L2_ERR_USE;
} while ((chT = chN) != NULL);
va_end(ap);
/* perform link operation(s) */
va_start(ap, ch);
do {
ch->parent = ch0;
if (ch0->child == NULL)
ch0->child = ch;
else {
chT = ch0->child;
while (chT->sibling != NULL)
chT = chT->sibling;
chT->sibling = ch;
}
ch0 = ch;
ch = (l2_channel_t *)va_arg(ap, l2_channel_t *);
} while (ch != NULL);
va_end(ap);
}
else if (id == L2_LINK_SIBLING) {
/* perform link operation(s) */
va_start(ap, ch);
do {
ch0->sibling = ch;
ch->parent = ch0->parent;
ch0 = ch;
ch = (l2_channel_t *)va_arg(ap, l2_channel_t *);
} while (ch != NULL);
va_end(ap);
}
return L2_OK;
}
/* unlink channels */
l2_result_t l2_channel_unlink(l2_channel_t *ch)
{
l2_channel_t *chS;
l2_channel_t *chP;
/* argument sanity check */
if (ch == NULL)
return L2_ERR_ARG;
/* make sure channel is in state "created" */
if (ch->state != L2_CHSTATE_CREATED)
return L2_ERR_USE;
/* make sure channel has no childs */
if (ch->child != NULL)
return L2_ERR_USE;
/* unlink the channel */
chP = ch->parent;
ch->parent = NULL;
if (chP != NULL) {
if (chP->child == ch)
chP->child = ch->sibling;
else {
chS = chP->child;
while (chS->sibling != ch)
chS = chS->sibling;
chS->sibling = ch->sibling;
}
}
return L2_OK;
}
/* return upstream channel */
l2_result_t l2_channel_upstream(l2_channel_t *ch, l2_channel_t **chU)
{
/* argument sanity check */
if (ch == NULL || chU == NULL)
return L2_ERR_ARG;
/* determine parent/upstream channel */
*chU = ch->parent;
return (*chU != NULL ? L2_OK : L2_ERR_CH);
}
/* return (subsequent) downstream channel(s) */
l2_result_t l2_channel_downstream(l2_channel_t *ch, l2_channel_t **chD)
{
/* argument sanity check */
if (ch == NULL || chD == NULL)
return L2_ERR_ARG;
/* determine (next) downstream/child channel */
if (*chD == NULL)
*chD = ch->child;
else
*chD = (*chD)->sibling;
return (*chD != NULL ? L2_OK : L2_ERR_CH);
}
/* return channel type */
l2_result_t l2_channel_type(l2_channel_t *ch, l2_chtype_t *type)
{
/* argument sanity check */
if (ch == NULL || type == NULL)
return L2_ERR_ARG;
/* return type */
(*type) = ch->handler.type;
return L2_OK;
}
/* set channel level masks */
l2_result_t l2_channel_levels(l2_channel_t *ch, unsigned int levelmask, unsigned int flushmask)
{
/* argument sanity check */
if (ch == NULL)
return L2_ERR_ARG;
/* override global level mask */
ch->levelmask = levelmask;
ch->flushmask = flushmask;
return L2_OK;
}
/* configure channel */
l2_result_t l2_channel_configure(l2_channel_t *ch, const char *fmt, ...)
{
l2_result_t rv;
va_list ap;
/* argument sanity check */
if (ch == NULL || fmt == NULL)
return L2_ERR_ARG;
/* make sure the channel is in state "created" */
if (ch->state != L2_CHSTATE_CREATED)
return L2_ERR_USE;
/* pass operation to handler */
rv = L2_OK;
va_start(ap, fmt);
if (ch->handler.configure != NULL)
rv = ch->handler.configure(&ch->context, ch, fmt, ap);
va_end(ap);
return rv;
}
/* open channel */
l2_result_t l2_channel_open(l2_channel_t *ch)
{
l2_result_t rv;
l2_result_t rvD;
l2_channel_t *chD;
/* argument sanity check */
if (ch == NULL)
return L2_ERR_ARG;
/* make sure channel is in state "created" */
if (ch->state != L2_CHSTATE_CREATED)
return L2_ERR_USE;
/* perform operation */
if (ch->handler.open != NULL)
rv = ch->handler.open(&ch->context, ch);
else
rv = L2_OK_PASS;
/* optionally pass operation downstream */
if (rv == L2_OK_PASS) {
rv = L2_OK;
chD = NULL;
while (l2_channel_downstream(ch, &chD) == L2_OK)
if ((rvD = l2_channel_open(chD)) != L2_OK)
rv = rvD;
if (rv != L2_OK) {
chD = NULL;
while (l2_channel_downstream(ch, &chD) == L2_OK)
l2_channel_close(chD);
}
}
/* mark channel as opened */
if (rv == L2_OK)
ch->state = L2_CHSTATE_OPENED;
return rv;
}
/* write to channel */
l2_result_t l2_channel_write(l2_channel_t *ch, l2_level_t level, const char *buf, size_t bufsize)
{
int l, j;
l2_result_t rv;
l2_result_t rvD;
l2_channel_t *chD;
/* argument sanity check */
if (ch == NULL || level == 0 || buf == NULL)
return L2_ERR_ARG;
/* make sure channel is in state "opened" */
if (ch->state != L2_CHSTATE_OPENED)
return L2_ERR_USE;
/* make sure only a single level is specified */
for (l = level, j = 0; l != 0; l = (l >> 1))
if (l & 0x1)
j++;
if (j != 1)
return L2_ERR_ARG;
/* check whether level mask already stops processing */
if (!(ch->levelmask & level))
return L2_OK;
/* short circuiting */
if (bufsize == 0)
return L2_OK;
/* perform operation */
if (ch->handler.write != NULL)
rv = ch->handler.write(&ch->context, ch, level, buf, bufsize);
else
rv = L2_OK_PASS;
/* optionally pass operation downstream */
if (rv == L2_OK_PASS) {
rv = L2_OK;
chD = NULL;
while (l2_channel_downstream(ch, &chD) == L2_OK)
if ((rvD = l2_channel_write(chD, level, buf, bufsize)) != L2_OK)
rv = rvD;
}
return rv;
}
/* flush channel (stack) */
l2_result_t l2_channel_flush(l2_channel_t *ch)
{
l2_result_t rv;
l2_result_t rvD;
l2_channel_t *chD;
/* argument sanity check */
if (ch == NULL)
return L2_ERR_ARG;
/* make sure channel is in state "opened" */
if (ch->state != L2_CHSTATE_OPENED)
return L2_ERR_USE;
/* perform operation */
if (ch->handler.flush != NULL)
rv = ch->handler.flush(&ch->context, ch);
else
rv = L2_OK_PASS;
/* optionally pass operation downstream */
if (rv == L2_OK_PASS) {
rv = L2_OK;
chD = NULL;
while (l2_channel_downstream(ch, &chD) == L2_OK)
if ((rvD = l2_channel_flush(chD)) != L2_OK)
rv = rvD;
}
return rv;
}
/* close channel (stack) */
l2_result_t l2_channel_close(l2_channel_t *ch)
{
l2_result_t rv;
l2_result_t rvD;
l2_channel_t *chD;
/* argument sanity check */
if (ch == NULL)
return L2_ERR_ARG;
/* make sure channel is in state "opened" */
if (ch->state != L2_CHSTATE_OPENED)
return L2_ERR_USE;
/* perform operation */
if (ch->handler.close != NULL)
rv = ch->handler.close(&ch->context, ch);
else
rv = L2_OK_PASS;
/* optionally pass operation downstream */
if (rv == L2_OK_PASS) {
rv = L2_OK;
chD = NULL;
while (l2_channel_downstream(ch, &chD) == L2_OK)
if ((rvD = l2_channel_close(chD)) != L2_OK)
rv = rvD;
}
/* mark channel as closed */
if (rv == L2_OK)
ch->state = L2_CHSTATE_CREATED;
return rv;
}
/* destroy channel */
l2_result_t l2_channel_destroy(l2_channel_t *ch)
{
l2_result_t rv;
l2_result_t rvD; /* downstream */
l2_channel_t *chD;
l2_result_t rvL; /* lookahead */
l2_channel_t *chL;
/* argument sanity check */
if (ch == NULL)
return L2_ERR_ARG;
/* make sure channel is in state "opened" */
if (ch->state == L2_CHSTATE_OPENED)
if ((rv = l2_channel_close(ch)) != L2_OK)
return rv;
/* perform operation */
if (ch->handler.destroy != NULL)
rv = ch->handler.destroy(&ch->context, ch);
else
rv = L2_OK_PASS;
/* optionally pass operation downstream */
if (rv == L2_OK_PASS) {
rv = L2_OK;
chD = NULL;
if (l2_channel_downstream(ch, &chD) == L2_OK) {
chL = chD;
do {
rvL = l2_channel_downstream(ch, &chL);
if ((rvD = l2_channel_destroy(chD)) != L2_OK)
rv = rvD;
if (rvL == L2_OK)
chD = chL;
} while ((rv == L2_OK) && (rvL == L2_OK));
}
}
/* free channel structure */
if (rv == L2_OK)
free(ch);
return rv;
}
/* log a message to channel */
l2_result_t l2_channel_log(l2_channel_t *ch, l2_level_t level, const char *fmt, ...)
{
va_list ap;
l2_result_t rv;
/* pass-through to va_list-based variant */
va_start(ap, fmt);
rv = l2_channel_vlog(ch, level, fmt, ap);
va_end(ap);
return rv;
}
/* indirect callback function from l2_channel_vlog for flushing */
static int l2_channel_vlog_flush(l2_util_format_t *vfmt)
{
/* we do no format buffer flushing */
return -1;
}
/* indirect callback function from l2_channel_vlog for formatting */
static void l2_channel_vlog_format(
l2_util_format_t *vfmt,
char *cPrefix, char *cPad, char **cppOut, size_t *npOutLen,
char *cpBuf, int nBufLenMax, char *cpParam, char cId, va_list *apArgs)
{
l2_env_t *env = (l2_env_t *)(vfmt->data[0].vp);
l2_result_t rv;
int i;
/* init formatting result */
*cPrefix = '\0';
*cPad = ' ';
*cppOut = NULL;
*npOutLen = 0;
/* iterate over all configured L2 formatters */
for (i = 0; i < L2_MAX_FORMATTERS && env->formatters[i].cb != NULL; i++) {
if (env->formatters[i].id == cId) {
rv = env->formatters[i].cb(env->formatters[i].ctx, cId, cpParam,
cpBuf, nBufLenMax, npOutLen, apArgs);
vfmt->data[1].i = (int)rv;
if (rv == L2_OK) {
*cppOut = cpBuf;
break;
}
}
}
return;
}
/* log a message to channel (va_list-variant) */
l2_result_t l2_channel_vlog(l2_channel_t *ch, l2_level_t level, const char *fmt, va_list ap)
{
int l, j;
size_t len;
l2_result_t rv;
l2_util_format_t vfmt;
l2_env_t *env;
/* argument sanity check */
if (ch == NULL || level == 0 || fmt == NULL)
return L2_ERR_ARG;
/* make sure only a single level is specified */
for (l = level, j = 0; l != 0; l = (l >> 1))
if (l & 0x1)
j++;
if (j != 1)
return L2_ERR_ARG;
/* check whether level mask already stops processing */
if (!(ch->levelmask & level))
return L2_OK;
/* format message */
env = ch->env;
vfmt.curpos = env->message;
vfmt.endpos = env->message + L2_MAX_MSGSIZE;
vfmt.data[0].vp = env;
vfmt.data[1].i = L2_ERR_FMT;
vfmt.flush = l2_channel_vlog_flush;
vfmt.format = l2_channel_vlog_format;
len = l2_util_format(&vfmt, fmt, ap);
/* check for formatting error including buffer overrun */
if (len == -1)
return (l2_result_t)(vfmt.data[1].i);
/* check for formatting led to completely empty message */
if (len == 0)
return L2_ERR_FMT;
/* check for formatting led to newline-only message */
if (len == 1 && env->message[len] == '\n')
return L2_ERR_FMT;
/* make sure a trailing newline exists; L2_MSG_BUFSIZE has room for CR/LF */
if (env->message[len-1] != '\n')
env->message[len++] = '\n';
/* make sure a trailing NUL exists; L2_MSG_BUFSIZE has room for NUL */
env->message[len] = '\0';
/* write message to channel */
rv = L2_OK;
if ((rv = l2_channel_write(ch, level, env->message, len)) != L2_OK)
return rv;
if (ch->flushmask & level)
l2_channel_flush(ch);
return rv;
}
/* return environment object */
l2_result_t l2_channel_env(l2_channel_t *ch, l2_env_t **env)
{
if (ch == NULL || env == NULL)
return L2_ERR_ARG;
*env = ch->env;
return L2_OK;
}
@
1.34
log
@Adjust copyright messages for new year 2005.
@
text
@d3 3
a5 3
** Copyright (c) 2001-2004 Cable & Wireless
** Copyright (c) 2001-2004 The OSSP Project
** Copyright (c) 2001-2004 Ralf S. Engelschall
@
1.33
log
@fix PR#23: l2 does not terminate a message when it contains a newline
@
text
@d3 3
a5 3
** Copyright (c) 2001-2003 Cable & Wireless Deutschland GmbH
** Copyright (c) 2001-2003 The OSSP Project (http://www.ossp.org/)
** Copyright (c) 2001-2003 Ralf S. Engelschall
@
1.32
log
@Remove NULL checks for va_list based variables because it is not
portable to assume that va_list behaves like a pointer or other
scalar type. Indeed it is a full structure on some platforms like
FreeBSD/alpha.
@
text
@d585 4
a588 1
if ((len = l2_util_format(&vfmt, fmt, ap)) == -1)
d590 2
d595 6
a600 4
/* make sure a trailing newline exists */
if (env->message[len-1] != '\n') {
if (len == L2_MAX_MSGSIZE)
return L2_ERR_MEM;
d602 3
a604 2
env->message[len] = '\0';
}
@
1.31
log
@fix iteration through non malloc(3)ed memory in l2_channel_destroy(). Bug caught on FreeBSD5
@
text
@d563 1
a563 1
if (ch == NULL || level == 0 || fmt == NULL || ap == NULL)
@
1.30
log
@- remove trailing whitespaces
- adjust copyright messages
- consistently use "OSSP l2"
- consistently talk about "Flexible Logging"
- use standard OSSP ASCII-art
@
text
@d458 1
a458 1
l2_result_t rvD;
d460 2
d482 10
a491 3
while (l2_channel_downstream(ch, &chD) == L2_OK)
if ((rvD = l2_channel_destroy(chD)) != L2_OK)
rv = rvD;
@
1.29
log
@polish for release
@
text
@d2 4
a5 3
** OSSP l2 - Logging Library
** Copyright (c) 2001-2002 The OSSP Project (http://www.ossp.org/)
** Copyright (c) 2001-2002 Cable & Wireless Deutschland (http://www.cw.com/de/)
d7 1
a7 1
** This file is part of OSSP L2, a flexible logging library which
d34 1
a34 1
/*
d313 2
a314 2
/* optionally pass operation downstream */
d371 2
a372 2
/* optionally pass operation downstream */
d404 2
a405 2
/* optionally pass operation downstream */
d427 1
a427 1
d437 2
a438 2
/* optionally pass operation downstream */
d475 2
a476 2
/* optionally pass operation downstream */
d532 1
a532 1
rv = env->formatters[i].cb(env->formatters[i].ctx, cId, cpParam,
@
1.28
log
@make sure the channel mask on each individual channel is also active
@
text
@d2 1
a2 1
** L2 - OSSP Logging Library
d7 1
a7 1
** can be found at http://www.ossp.org/pkg/l2/.
@
1.27
log
@bump copyright year
@
text
@d337 1
d349 11
@
1.26
log
@do not re-init related links, because the parser else has no chance
@
text
@d3 2
a4 2
** Copyright (c) 2001 The OSSP Project (http://www.ossp.org/)
** Copyright (c) 2001 Cable & Wireless Deutschland (http://www.cw.com/de/)
@
1.25
log
@More preparations for forthcoming channel tree specification parser
(especially to allow the parser to determine the handler structure
from a handler name without introducing another and this way redundant
sub-API):
- add "char *name" to l2_handler_t in order to tag each
handler structure with the corresponding channel name
- add l2_env_handler() function to add handler to
l2_env_t objects. All l2_handler_xxxx are automatically
pre-configured there after l2_env_create().
- change l2_channel_create() to take a "const char *name"
(handler name) instead of the "l2_handler_t *h" (handler
pointer) to make the stuff consistent and more clear.
- adjust l2_test.c to reflect the changes.
@
text
@a148 2
ch->sibling = NULL;
ch->child = NULL;
a167 2
ch->sibling = NULL;
ch->child = NULL;
@
1.24
log
@Change semantics of sibling linkage operations in order to fulfill the
requirements in the forthcoming channel tree specification parser.
@
text
@d70 1
a70 1
l2_result_t l2_channel_create(l2_channel_t **chp, l2_env_t *env, l2_handler_t *h)
d73 2
d77 1
a77 1
if (h == NULL || env == NULL)
d79 11
@
1.23
log
@code cleanups
@
text
@d108 1
a108 1
l2_result_t l2_channel_link(l2_channel_t *chR, l2_link_t id, l2_channel_t *chC, ...)
d115 1
a115 1
if (chR == NULL || chC == NULL)
d118 10
a127 15
/* make sure root channel is in state "created" */
if (chR->state != L2_CHSTATE_CREATED)
return L2_ERR_USE;
/* make sure root channel is a filter channel */
if (chR->handler.type != L2_CHANNEL_FILTER)
return L2_ERR_USE;
/* check childs */
va_start(ap, chC);
chT = chC;
do {
chN = (l2_channel_t *)va_arg(ap, l2_channel_t *);
if (id == L2_LINK_CHILDS && chN != NULL)
if (chT->handler.type != L2_CHANNEL_FILTER)
d129 2
a130 2
} while ((chT = chN) != NULL);
va_end(ap);
d132 31
a162 17
/* perform link operation(s) */
va_start(ap, chC);
do {
chC->parent = chR;
chC->sibling = NULL;
chC->child = NULL;
if (chR->child == NULL)
chR->child = chC;
else {
chT = chR->child;
while (chT->sibling != NULL)
chT = chT->sibling;
chT->sibling = chC;
}
if (id == L2_LINK_CHILDS)
chR = chC;
chC = (l2_channel_t *)va_arg(ap, l2_channel_t *);
a163 2
while (chC != NULL);
va_end(ap);
@
1.22
log
@Channel-Only Revamping Step 2:
- moved code of l2_stream.c into (new) l2_env.c and l2_channel.c
- created new l2_env_t and l2_env_xxx()
- changed l2_xx_create() functions to also return l2_result_t
- moved error handling into l2_env_t
- replaced l2_channel_stack() with two new and more flexible
l2_channel_link() and l2_channel_unlink() functions
- rewritten test stuff in l2_test.c to use new structure
- added new l2_channel_env() function for retriving l2_env_t
Puhhh....
@
text
@d27 1
a27 1
** l2_channel.c: channel handling
a30 1
#include "l2.h"
a31 2
#include
@
1.21
log
@Channel-Only Revamping Step 1:
allow multiple downstream channels in order to
approach the later tree-like channel-only structure.
@
text
@d73 1
a73 1
l2_channel_t *l2_channel_create(l2_handler_t *h)
d78 2
a79 2
if (h == NULL)
return NULL;
d83 1
a83 1
return NULL;
d86 1
d93 2
a94 5
ch->rvErrorInfo = L2_OK;
ch->szErrorInfo[0] = '\0';
ch->szError[0] = '\0';
ch->levelmask = L2_LEVEL_ALL;
ch->flushmask = L2_LEVEL_NONE;
d100 1
a100 1
return NULL;
d104 4
a107 1
return ch;
d110 2
a111 2
/* stack channel on top of another channel */
l2_result_t l2_channel_stack(l2_channel_t *ch, l2_channel_t *chP)
d114 2
d118 1
a118 1
if (ch == NULL || chP == NULL)
d121 2
a122 3
/* make sure both channels are in state "created" */
if ( ch->state != L2_CHSTATE_CREATED
|| chP->state != L2_CHSTATE_CREATED)
d125 2
a126 2
/* make sure parent channel is a filter channel */
if (chP->handler.type != L2_CHANNEL_FILTER)
d129 47
a175 2
/* make sure child still has no parent */
if (ch->parent != NULL)
d178 16
a193 9
/* stack the two channels */
ch->parent = chP;
if (chP->child == NULL)
chP->child = ch;
else {
chT = chP->child;
while (chT->sibling != NULL)
chT = chT->sibling;
chT->sibling = ch;
d241 14
d466 2
a467 1
l2_result_t l2_channel_errorinfo(l2_channel_t *ch, l2_result_t rv, const char *fmt, ...)
d470 1
d472 1
a472 5
/* argument sanity check */
if (ch == NULL || rv == L2_OK || fmt == NULL)
return L2_ERR_ARG;
/* remember error information */
d474 1
a474 2
l2_util_vsprintf(ch->szErrorInfo, sizeof(ch->szErrorInfo), fmt, ap);
ch->rvErrorInfo = rv;
d477 39
a515 1
return L2_OK;
d518 2
a519 1
char *l2_channel_strerror(l2_channel_t *ch, l2_result_t rv)
d521 5
a525 4
char *sz;
char *cpBuf;
int nBuf;
int n;
d528 13
a540 2
if (ch == NULL)
return NULL;
d542 19
a560 23
/* start at begin of buffer */
cpBuf = ch->szError;
nBuf = sizeof(ch->szError);
/* translate result value into corresponding string */
if (rv == L2_OK) sz = "everything ok";
else if (rv == L2_ERR_ARG) sz = "invalid argument";
else if (rv == L2_ERR_USE) sz = "invalid use";
else if (rv == L2_ERR_MEM) sz = "no more memory available";
else if (rv == L2_ERR_SYS) sz = "operating system error";
else if (rv == L2_ERR_IO) sz = "input/output error";
else if (rv == L2_ERR_FMT) sz = "formatting error";
else if (rv == L2_ERR_INT) sz = "internal error";
else sz = "unknown error";
n = l2_util_sprintf(cpBuf, nBuf, "%s", sz);
cpBuf += n;
nBuf -= n;
/* optionally annotate with error information */
if (rv == ch->rvErrorInfo && ch->szErrorInfo[0] != '\0') {
n = l2_util_sprintf(cpBuf, nBuf, "; %s", ch->szErrorInfo);
cpBuf += n;
nBuf -= n;
d563 9
a571 6
/* optionally annotate with operating system error information */
if (rv == L2_ERR_SYS) {
n = l2_util_sprintf(cpBuf, nBuf, "; %s (%d)", strerror(errno), errno);
cpBuf += n;
nBuf -= n;
}
d573 7
a579 2
/* return pointer to internal buffer */
return ch->szError;
@
1.20
log
@document channel lifecycle
@
text
@d54 1
a54 1
* H4sIAIsvszsCA62WTW/bMAyGz/WvENBzM5KyPnwusGFAdtp1l8BVWgOZUyTuhv77
d87 3
a89 1
ch->downstream = NULL;
d95 2
d109 78
d211 1
a211 1
/* open channel (stack) */
d215 2
d226 18
a243 4
/* skip empty open handlers on channel stack */
while (ch != NULL && ch->handler.open == NULL) {
ch->state = L2_CHSTATE_OPENED;
ch = ch->downstream;
a244 2
if (ch == NULL)
return L2_ERR_USE;
d246 1
a246 2
/* pass operation to handler */
rv = ch->handler.open(&ch->context, ch);
d253 1
a253 1
/* write to channel (stack) */
d257 2
d261 1
a261 1
if (ch == NULL || buf == NULL)
d272 14
a285 8
/* walk to next available write handler */
while (ch != NULL && ch->handler.write == NULL)
ch = ch->downstream;
if (ch == NULL)
return L2_ERR_USE;
/* pass operation to handler */
rv = ch->handler.write(&ch->context, ch, level, buf, bufsize);
d294 2
d305 14
a318 8
/* walk to next available flush handler */
while (ch != NULL && ch->handler.flush == NULL)
ch = ch->downstream;
if (ch == NULL)
return L2_ERR_USE;
/* pass operation to handler */
rv = ch->handler.flush(&ch->context, ch);
d327 2
d338 13
a350 4
/* walk to next available close handler */
while (ch != NULL && ch->handler.close == NULL) {
ch->state = L2_CHSTATE_CREATED;
ch = ch->downstream;
a351 2
if (ch == NULL)
return L2_ERR_USE;
d353 1
a353 2
/* pass operation to handler */
rv = ch->handler.close(&ch->context, ch);
d364 2
d376 2
a377 6
/* walk to next available destroy handler */
while (ch != NULL && ch->handler.destroy == NULL)
ch = ch->downstream;
/* pass operation to handler */
if (ch != NULL)
d380 4
d385 5
d392 2
a393 1
free(ch);
a459 42
}
/* stack channel on top of another channel */
l2_result_t l2_channel_stack(l2_channel_t *ch, l2_channel_t *chTop)
{
/* argument sanity check */
if (ch == NULL || chTop == NULL)
return L2_ERR_ARG;
/* make sure both channels are in state "created" */
if ( ch->state != L2_CHSTATE_CREATED
|| chTop->state != L2_CHSTATE_CREATED)
return L2_ERR_USE;
/* make sure top channel is a filter channel */
if (chTop->handler.type != L2_CHANNEL_FILTER)
return L2_ERR_USE;
/* stack the channels */
chTop->downstream = ch;
return L2_OK;
}
/* return downstream channel */
l2_channel_t *l2_channel_downstream(l2_channel_t *ch)
{
/* argument sanity check */
if (ch == NULL)
return NULL;
return ch->downstream;
}
/* return channel type */
l2_chtype_t l2_channel_type(l2_channel_t *ch)
{
/* argument sanity check */
if (ch == NULL)
return L2_CHANNEL_FILTER; /* FIXME */
return ch->handler.type;
@
1.19
log
@Provide convinient channel error handling functions.
@
text
@d36 36
@
1.18
log
@temporary bugfix
@
text
@d54 3
d233 64
@
1.17
log
@Upgraded both stream and channel-level APIs to include new L2_LEVEL parameter design.
@
text
@d269 1
a269 1
return NULL;
@
1.16
log
@Replace generic L2_ERROR with more granular L2_ERR_XXX and
make sure that we always check with "!= L2_OK".
@
text
@d120 1
a120 1
l2_result_t l2_channel_write(l2_channel_t *ch, const char *buf, size_t bufsize)
d143 1
a143 1
rv = ch->handler.write(&ch->context, ch, buf, bufsize);
@
1.15
log
@Perform the channel state tagging immediately for a channel and not
afterwards. Functionality-wise this is the same, but semantically it is
more clean.
@
text
@d36 1
d41 1
d44 2
d48 2
d54 7
a60 3
if (ch->handler.create(&ch->context, ch) == L2_ERROR) {
free(ch);
return NULL;
d62 1
d66 1
d72 1
d74 3
a76 1
return L2_ERROR;
d78 4
a81 1
return L2_ERROR;
d83 2
a84 1
rv = ch->handler.configure(&ch->context, ch, fmt, ap);
d86 1
d90 1
d95 1
d97 3
a99 1
return L2_ERROR;
d101 3
a103 1
return L2_ERROR;
d109 3
a111 1
return L2_ERROR;
d115 1
d119 1
d124 5
a128 2
if (ch == NULL)
return L2_ERROR;
d130 3
a132 3
return L2_ERROR;
if (buf == NULL)
return L2_ERROR;
d135 2
d140 3
a142 1
return L2_ERROR;
d144 1
d148 1
d153 1
d155 3
a157 1
return L2_ERROR;
d159 3
a161 1
return L2_ERROR;
d165 3
a167 1
return L2_ERROR;
d169 1
d173 1
d178 1
d180 3
a182 1
return L2_ERROR;
d184 3
a186 1
return L2_ERROR;
d192 3
a194 1
return L2_ERROR;
d198 1
d202 1
d207 1
d209 3
a211 1
return L2_ERROR;
d215 2
d219 2
d225 2
d228 1
d232 1
d235 1
d237 3
a239 1
return L2_ERROR;
d242 3
a244 1
return L2_ERROR;
d246 3
a248 1
return L2_ERROR;
d250 1
d254 1
d257 1
d260 1
d264 1
d267 1
d270 1
@
1.14
log
@Bugfix channel API: L2_OK -> NULL, states have to be remembered for
all channels in a stack, not just the last found one.
@
text
@a72 1
l2_channel_t *chFirst;
d78 2
a79 2
chFirst = ch;
while (ch != NULL && ch->handler.open == NULL)
d81 1
d85 2
a86 7
if (rv == L2_OK) {
ch = chFirst;
do {
ch->state = L2_CHSTATE_OPENED;
ch = ch->downstream;
} while (ch != NULL);
}
a128 1
l2_channel_t *chFirst;
a131 1
chFirst = ch;
d134 2
a135 1
while (ch != NULL && ch->handler.close == NULL)
d137 1
d141 2
a142 7
if (rv == L2_OK) {
ch = chFirst;
do {
ch->state = L2_CHSTATE_CREATED;
ch = ch->downstream;
} while (ch != NULL);
}
@
1.13
log
@Bring into conformance with new l2_result_t channel handler return standard.
@
text
@d73 1
d79 2
a80 1
while (ch != NULL && ch->handler.open == L2_OK)
d85 7
a91 2
if (rv == L2_OK)
ch->state = L2_CHSTATE_OPENED;
d107 1
a107 1
while (ch != NULL && ch->handler.write == L2_OK)
d123 1
a123 1
while (ch != NULL && ch->handler.flush == L2_OK)
d134 1
d138 1
d141 1
a141 1
while (ch != NULL && ch->handler.close == L2_OK)
d146 7
a152 2
if (rv == L2_OK)
ch->state = L2_CHSTATE_CREATED;
d165 1
a165 1
while (ch != NULL && ch->handler.destroy == L2_OK)
@
1.12
log
@Revamp channel handler API:
Instead of passing the downstream channel to all channels we instead
provide a l2_channel_downstream() function and provide the current
channel. This way the handler API is prototype-wise fully orthogonal
with the channel API (which it implements) and we no longer pass
information to 2/3 of our (output) channels which is of no use there.
Additionally add a channel type field to l2_handler_t which allows a
handler to say what type of channel it implements (filter or output).
This information is now used in l2_channel_stack() to make sure that
one can only stack a filter channel on top of another channel. For
convinience reasons there is also a new l2_channel_type() function which
allows one to query the type of a particular channel.
@
text
@d78 1
a78 1
while (ch != NULL && ch->handler.open == NULL)
d100 1
a100 1
while (ch != NULL && ch->handler.write == NULL)
d116 1
a116 1
while (ch != NULL && ch->handler.flush == NULL)
d132 1
a132 1
while (ch != NULL && ch->handler.close == NULL)
d151 1
a151 1
while (ch != NULL && ch->handler.destroy == NULL)
@
1.11
log
@Wohhooooo! Here comes the underlying message formatting support:
1. renamed l2_channel_setparam() to l2_util_setparam() because it
is just a utility function and is not tied to any channel.
2. moved l2_util_setparam() to its own l2_ut_param.c source file.
3. added l2_ut_format.c which contains a slightly adjusted version
of Str's str_format() stuff under the name l2_util_format().
4. use l2_util_format() in l2_stream.c instead of vsnprintf()
and this way finally support l2_formatter_t callbacks.
5. cleanup adjustments to the l2_stream_formatter() API.
Let's rock...
@
text
@d48 1
a48 1
if (ch->handler.create(&ch->context) == L2_ERROR) {
a54 11
l2_result_t l2_channel_stack(l2_channel_t *ch, l2_channel_t *chTop)
{
if (ch == NULL || chTop == NULL)
return L2_ERROR;
if ( ch->state != L2_CHSTATE_CREATED
|| chTop->state != L2_CHSTATE_CREATED)
return L2_ERROR;
chTop->downstream = ch;
return L2_OK;
}
d65 1
a65 1
rv = ch->handler.configure(&ch->context, fmt, ap);
d82 1
a82 1
rv = ch->handler.open(&ch->context, ch->downstream);
d104 1
a104 1
rv = ch->handler.write(&ch->context, ch->downstream, buf, bufsize);
d120 1
a120 1
rv = ch->handler.flush(&ch->context, ch->downstream);
d136 1
a136 1
rv = ch->handler.close(&ch->context, ch->downstream);
d154 1
a154 1
rv = ch->handler.destroy(&ch->context);
d159 27
@
1.10
log
@- replace "int" with "l2_result_t" in L2 channel API
- use a 2^n for L2_LEVEL_XXX in order to be able to create mask
- remember loglevel for each channel
- rewrite test suite
@
text
@a171 70
l2_result_t l2_channel_setparams(l2_param_t pa[], const char *fmt, va_list ap)
{
const char *cpB, *cpE;
const char *cpC, *cpG;
int ok;
int i;
if (pa == NULL || fmt == NULL || ap == NULL)
return L2_ERROR;
cpE = fmt;
while (*cpE != '\0') {
/* determine begin of parameter name */
cpB = cpE;
while (*cpB == ',')
cpB++;
/* determine end of parameter name */
cpE = cpB;
while (*cpE != ',' && *cpE != '\0')
cpE++;
/* try to match with configured parameters */
ok = FALSE;
for (i = 0; pa[i].name != NULL; i++) {
cpC = pa[i].name;
cpG = cpB;
while (*cpC != '\0' && cpG < cpE) {
if (*cpC != *cpG)
break;
cpC++;
cpG++;
}
if (*cpC == '\0' && cpG == cpE) {
/* parameter matched, so store value */
switch (pa[i].type) {
case L2_TYPE_CHAR:
*(char *)(pa[i].store) = va_get(ap, char);
break;
case L2_TYPE_SHORT:
*(short *)(pa[i].store) = va_get(ap, short);
break;
case L2_TYPE_INT:
*(int *)(pa[i].store) = va_get(ap, int);
break;
case L2_TYPE_LONG:
*(long *)(pa[i].store) = va_get(ap, long);
break;
case L2_TYPE_FLOAT:
*(float *)(pa[i].store) = va_get(ap, float);
break;
case L2_TYPE_DOUBLE:
*(double *)(pa[i].store) = va_get(ap, double);
break;
case L2_TYPE_CHARPTR:
*(char **)(pa[i].store) = va_get(ap, charptr);
break;
case L2_TYPE_VOIDPTR:
*(void **)(pa[i].store) = va_get(ap, voidptr);
break;
}
ok = TRUE;
break;
}
}
if (!ok)
return L2_ERROR;
}
return L2_OK;
}
@
1.9
log
@remove useless assign
@
text
@d55 1
a55 1
l2_channel_t *l2_channel_stack(l2_channel_t *ch1, l2_channel_t *ch2)
d57 7
a63 7
if (ch1 == NULL || ch2 == NULL)
return NULL;
if ( ch1->state != L2_CHSTATE_CREATED
|| ch2->state != L2_CHSTATE_CREATED)
return NULL;
ch1->downstream = ch2;
return ch1;
d66 1
a66 1
int l2_channel_configure(l2_channel_t *ch, const char *fmt, ...)
d68 1
a68 1
int rv;
d81 1
a81 1
int l2_channel_open(l2_channel_t *ch)
d99 1
a99 1
int l2_channel_write(l2_channel_t *ch, const char *buf, size_t bufsize)
d119 1
a119 1
int l2_channel_flush(l2_channel_t *ch)
d135 1
a135 1
int l2_channel_close(l2_channel_t *ch)
d153 1
a153 1
int l2_channel_destroy(l2_channel_t *ch)
d172 1
a172 1
int l2_channel_setparams(l2_param_t pa[], const char *fmt, va_list ap)
@
1.8
log
@When destroying a channel, erase its pointer to avoid a double-destruction
mistake (possibly by both the channel and stream parent.)
@
text
@a168 1
ch = NULL;
@
1.7
log
@Revert to last version due to new design of l2_ch_socket_t.
@
text
@d169 1
@
1.6
log
@Added unsigned short type to PARAMETER macros for sockaddr_in struct.
@
text
@a212 3
case L2_TYPE_USHORT:
*(unsigned short *)(pa[i].store) = va_get(ap, ushort);
break;
@
1.5
log
@Fix more ossp.com references by replacing with the
correct domain name ossp.org.
@
text
@d213 3
@
1.4
log
@o rename l2_error_t to l2_result_t
o introduce internal channel state for API robustness
@
text
@d7 1
a7 1
** can be found at http://www.ossp.com/pkg/l2/.
@
1.3
log
@Implement a first cut for a buffer channel (still untested).
@
text
@d34 2
d44 4
a47 9
ch->below = NULL;
ch->context.vp = NULL;
ch->handler.create = h->create;
ch->handler.configure = h->configure;
ch->handler.open = h->open;
ch->handler.write = h->write;
ch->handler.flush = h->flush;
ch->handler.close = h->close;
ch->handler.destroy = h->destroy;
d59 5
a63 2
ch2->below = ch1;
return ch2;
d73 2
d83 2
d87 2
d90 1
a90 1
ch = ch->below;
d93 4
a96 1
return ch->handler.open(&ch->context, ch->below);
d101 3
a103 1
if (ch == NULL || buf == NULL || bufsize <= 0)
d105 1
a105 3
while (ch != NULL && ch->handler.write == NULL)
ch = ch->below;
if (ch == NULL)
d111 6
a116 1
return ch->handler.write(&ch->context, ch->below, buf, bufsize);
d121 2
d125 2
d128 1
a128 1
ch = ch->below;
d131 2
a132 1
return ch->handler.flush(&ch->context, ch->below);
d137 2
d141 2
d144 1
a144 1
ch = ch->below;
d147 4
a150 1
return ch->handler.close(&ch->context, ch->below);
d155 1
a155 1
int rv = L2_OK;
d159 3
d163 1
a163 1
ch = ch->below;
d166 2
d179 2
@
1.2
log
@Simplify things by merging the parameter stuff into l2_channel.c and the
l2_stream_t related things into l2_stream.c
@
text
@d98 4
@
1.1
log
@Initial revision
@
text
@d137 68
@
1.1.1.1
log
@L2 initial source tree
@
text
@@