--- l2_ch_file.c 2001/05/11 17:07:52 1.2
+++ l2_ch_file.c 2001/05/19 20:14:15 1.3
@@ -30,42 +30,171 @@
#include "l2.h"
#include "l2_p.h"
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+/* declare private channel configuration */
+typedef struct {
+ int fd;
+ char *path;
+ int append;
+ long perm;
+} l2_ch_file_t;
+
+/* create channel */
static int hook_create(l2_context_t *ctx)
{
+ l2_ch_file_t *cfg;
+
+ /* allocate private channel configuration */
+ if ((cfg = (l2_ch_file_t *)malloc(sizeof(l2_ch_file_t))) == NULL)
+ return L2_ERROR;
+
+ /* initialize configuration with reasonable defaults */
+ cfg->fd = -1;
+ cfg->path = NULL;
+ cfg->append = TRUE;
+ cfg->perm = (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
+
+ /* link private channel configuration into channel context */
+ ctx->vp = cfg;
+
return L2_OK;
}
+/* configure channel */
static int hook_configure(l2_context_t *ctx, const char *fmt, va_list ap)
{
- return L2_OK;
+ l2_ch_file_t *cfg;
+ l2_param_t pa[3];
+ l2_error_t rv;
+
+ /* parameter checks */
+ if (ctx == NULL)
+ return L2_ERROR;
+ if ((cfg = (l2_ch_file_t *)ctx->vp) == NULL)
+ return L2_ERROR;
+
+ /* feed and call generic parameter parsing engine */
+ L2_PARAM_SET(pa[0], path, CHARPTR, &cfg->path);
+ L2_PARAM_SET(pa[1], append, INT, &cfg->append);
+ L2_PARAM_SET(pa[1], perm, LONG, &cfg->perm);
+ L2_PARAM_END(pa[2]);
+ rv = l2_param_parse(pa, fmt, ap);
+
+ return rv;
}
-static int hook_open(l2_context_t *ctx, l2_channel_t *below)
+/* open channel */
+static int hook_open(l2_context_t *ctx, l2_channel_t *downstream)
{
+ l2_ch_file_t *cfg;
+ int mode;
+
+ /* parameter checks */
+ if (ctx == NULL)
+ return L2_ERROR;
+ if ((cfg = (l2_ch_file_t *)ctx->vp) == NULL)
+ return L2_ERROR;
+ if (cfg->path == NULL)
+ return L2_ERROR;
+
+ /* open channel file */
+ mode = O_WRONLY|O_CREAT;
+ if (cfg->append)
+ mode |= O_APPEND;
+ if ((cfg->fd = open(cfg->path, mode, cfg->perm)) == -1)
+ return L2_ERROR;
+
+ /* optionally open downstream channel, too */
+ if (downstream != NULL)
+ if (l2_channel_open(downstream) == L2_ERROR)
+ return L2_ERROR;
+
return L2_OK;
}
-static int hook_write(l2_context_t *ctx, l2_channel_t *below,
+/* write to channel */
+static int hook_write(l2_context_t *ctx, l2_channel_t *downstream,
const char *buf, size_t buf_size)
{
+ l2_ch_file_t *cfg;
+
+ /* parameter checks */
+ if (ctx == NULL)
+ return L2_ERROR;
+ if ((cfg = (l2_ch_file_t *)ctx->vp) == NULL)
+ return L2_ERROR;
+ if (cfg->fd == -1)
+ return L2_ERROR;
+
+ /* write message to channel file */
+ if (write(cfg->fd, buf, buf_size) == -1)
+ return L2_ERROR;
+
+ /* optionally write to downstream channel, too */
+ if (downstream != NULL)
+ if (l2_channel_write(downstream, buf, buf_size) == L2_ERROR)
+ return L2_ERROR;
+
return L2_OK;
}
-static int hook_flush(l2_context_t *ctx, l2_channel_t *below)
+/* flush channel */
+static int hook_flush(l2_context_t *ctx, l2_channel_t *downstream)
{
+ /* NOP for this channel, because Unix I/O files are unbuffered! */
+
+ /* optionally flush downstream channel, too */
+ if (downstream != NULL)
+ if (l2_channel_flush(downstream) == L2_ERROR)
+ return L2_ERROR;
+
return L2_OK;
}
-static int hook_close(l2_context_t *ctx, l2_channel_t *below)
+/* close channel */
+static int hook_close(l2_context_t *ctx, l2_channel_t *downstream)
{
+ l2_ch_file_t *cfg;
+
+ /* optionally close downstream channel, too */
+ if (downstream != NULL)
+ if (l2_channel_close(downstream) == L2_ERROR)
+ return L2_ERROR;
+
+ /* parameter checks */
+ if (ctx == NULL)
+ return L2_ERROR;
+ if ((cfg = (l2_ch_file_t *)ctx->vp) == NULL)
+ return L2_ERROR;
+ if (cfg->fd == -1)
+ return L2_ERROR;
+
+ /* close channel file */
+ close(cfg->fd);
+ cfg->fd = -1;
+
return L2_OK;
}
+/* destroy channel */
static int hook_destroy(l2_context_t *ctx)
{
+ /* parameter checks */
+ if (ctx == NULL)
+ return L2_ERROR;
+ if (ctx->vp == NULL)
+ return L2_ERROR;
+
+ /* destroy channel configuration */
+ free(ctx->vp);
+
return L2_OK;
}
+/* exported channel handler structure */
l2_handler_t l2_handler_file = {
hook_create,
hook_configure,
|