--- l2_channel.c 2001/11/03 22:51:36 1.21
+++ l2_channel.c 2001/11/04 13:21:17 1.22
@@ -70,73 +70,127 @@
*/
/* create channel */
-l2_channel_t *l2_channel_create(l2_handler_t *h)
+l2_result_t l2_channel_create(l2_channel_t **chp, l2_env_t *env, l2_handler_t *h)
{
l2_channel_t *ch;
/* argument sanity check */
- if (h == NULL)
- return NULL;
+ if (h == NULL || env == NULL)
+ return L2_ERR_ARG;
/* allocate channel structure */
if ((ch = (l2_channel_t *)malloc(sizeof(l2_channel_t))) == NULL)
- return 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->rvErrorInfo = L2_OK;
- ch->szErrorInfo[0] = '\0';
- ch->szError[0] = '\0';
- ch->levelmask = L2_LEVEL_ALL;
- ch->flushmask = L2_LEVEL_NONE;
+ 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 NULL;
+ return L2_ERR_SYS;
}
}
- return ch;
+ /* pass object to caller */
+ (*chp) = ch;
+
+ return L2_OK;
}
-/* stack channel on top of another channel */
-l2_result_t l2_channel_stack(l2_channel_t *ch, l2_channel_t *chP)
+/* link channels */
+l2_result_t l2_channel_link(l2_channel_t *chR, l2_link_t id, l2_channel_t *chC, ...)
{
l2_channel_t *chT;
+ l2_channel_t *chN;
+ va_list ap;
/* argument sanity check */
- if (ch == NULL || chP == NULL)
+ if (chR == NULL || chC == NULL)
return L2_ERR_ARG;
- /* make sure both channels are in state "created" */
- if ( ch->state != L2_CHSTATE_CREATED
- || chP->state != L2_CHSTATE_CREATED)
+ /* make sure root channel is in state "created" */
+ if (chR->state != L2_CHSTATE_CREATED)
return L2_ERR_USE;
- /* make sure parent channel is a filter channel */
- if (chP->handler.type != L2_CHANNEL_FILTER)
+ /* make sure root channel is a filter channel */
+ if (chR->handler.type != L2_CHANNEL_FILTER)
return L2_ERR_USE;
- /* make sure child still has no parent */
- if (ch->parent != NULL)
+ /* 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)
+ return L2_ERR_USE;
+ } while ((chT = chN) != NULL);
+ va_end(ap);
+
+ /* 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 *);
+ }
+ while (chC != 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;
- /* 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;
+ /* 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;
@@ -184,6 +238,20 @@
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, ...)
{
@@ -395,67 +463,119 @@
return rv;
}
-l2_result_t l2_channel_errorinfo(l2_channel_t *ch, l2_result_t rv, const char *fmt, ...)
+/* 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;
- /* argument sanity check */
- if (ch == NULL || rv == L2_OK || fmt == NULL)
- return L2_ERR_ARG;
-
- /* remember error information */
+ /* pass-through to va_list-based variant */
va_start(ap, fmt);
- l2_util_vsprintf(ch->szErrorInfo, sizeof(ch->szErrorInfo), fmt, ap);
- ch->rvErrorInfo = rv;
+ rv = l2_channel_vlog(ch, level, fmt, ap);
va_end(ap);
- return L2_OK;
+ return rv;
}
-char *l2_channel_strerror(l2_channel_t *ch, l2_result_t rv)
+/* indirect callback function from l2_channel_vlog for flushing */
+static int l2_channel_vlog_flush(l2_util_format_t *vfmt)
{
- char *sz;
- char *cpBuf;
- int nBuf;
- int n;
+ /* we do no format buffer flushing */
+ return -1;
+}
- /* argument sanity check */
- if (ch == NULL)
- return NULL;
+/* 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;
- /* 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;
+ /* 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 || ap == 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;
- /* 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;
+ /* 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;
+ if ((len = l2_util_format(&vfmt, fmt, ap)) == -1)
+ return (l2_result_t)(vfmt.data[1].i);
+ if (len == 0)
+ return L2_ERR_FMT;
+
+ /* make sure a trailing newline exists */
+ if (env->message[len-1] != '\n') {
+ if (len == L2_MAX_MSGSIZE)
+ return L2_ERR_MEM;
+ env->message[len++] = '\n';
+ env->message[len] = '\0';
}
- /* return pointer to internal buffer */
- return ch->szError;
+ /* 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;
}
|