/*
**  OSSP l2 - Flexible Logging
**  Copyright (c) 2001-2005 Cable & Wireless <http://www.cw.com/>
**  Copyright (c) 2001-2005 The OSSP Project <http://www.ossp.org/>
**  Copyright (c) 2001-2005 Ralf S. Engelschall <rse@engelschall.com>
**
**  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.h: C API
*/

#ifndef __L2_H__
#define __L2_H__

/* version information (compile-time) */
#define L2_VERSION_STR "0.9.11 (03-Oct-2005)"
#define L2_VERSION_HEX 0x00920B

/* version information (run-time) */
typedef struct {
    const int   v_hex;
    const char *v_short;
    const char *v_long;
    const char *v_tex;
    const char *v_gnu;
    const char *v_web;
    const char *v_sccs;
    const char *v_rcs;
} l2_version_t;
extern l2_version_t l2_version;

/* include standard environment we are based on */
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>

/* counterbalance poor standard environments */
#ifndef NULL
#define NULL (void *)0
#endif
#ifndef FALSE
#define FALSE (0)
#endif
#ifndef TRUE
#define TRUE (!FALSE)
#endif

/* forward declarations for opaque data structures */
union  l2_context_un;
struct l2_param_st;
struct l2_stream_st;
struct l2_channel_st;
struct l2_handler_st;
struct l2_env_st;

/* corresponding data types for data structures */
typedef union  l2_context_un l2_context_t;
typedef struct l2_param_st   l2_param_t;
typedef struct l2_handler_st l2_handler_t;
typedef struct l2_stream_st  l2_stream_t;
typedef struct l2_channel_st l2_channel_t;
typedef struct l2_env_st     l2_env_t;

/* list of logging levels (high to low priority; low to high amount of logging) */
typedef enum {
    L2_LEVEL_NONE     = 0,
    L2_LEVEL_PANIC    = (1 << 0),
    L2_LEVEL_CRITICAL = (1 << 1),
    L2_LEVEL_ERROR    = (1 << 2),
    L2_LEVEL_WARNING  = (1 << 3),
    L2_LEVEL_NOTICE   = (1 << 4),
    L2_LEVEL_INFO     = (1 << 5),
    L2_LEVEL_TRACE    = (1 << 6),
    L2_LEVEL_DEBUG    = (1 << 7)
} l2_level_t;

/* macro describing a particular custom level */
#define L2_LEVEL_CUSTOM(n) (1 << (8+(n))

/* macro describing all levels */
#define L2_LEVEL_ALL ((1 << (8+9+1))-1)

/* macro describing all levels from highest (PANIC)
   to and including a particular low level */
#define L2_LEVEL_UPTO(level) (((level)-1)|(level))

/* list of return values */
typedef enum {
    L2_OK,         /* everything ok */
    L2_OK_PASS,    /* everything ok - pass downstream */
    L2_ERR_ARG,    /* invalid argument */
    L2_ERR_USE,    /* invalid usage */
    L2_ERR_MEM,    /* no more memory available */
    L2_ERR_SYS,    /* system error (see errno) */
    L2_ERR_IO,     /* input/output error */
    L2_ERR_FMT,    /* message formating error */
    L2_ERR_INT,    /* internal error */
    L2_ERR_SYN,    /* syntax error */
    L2_ERR_CH      /* no (more) channel found */
} l2_result_t;

/* context union for storing data */
union l2_context_un {
    char    c;
    short   s;
    int     i;
    long    l;
    float   f;
    double  d;
    char   *cp;
    void   *vp;
};

/* list of types for storing data */
typedef enum {
    L2_TYPE_INT,
    L2_TYPE_FLT,
    L2_TYPE_STR
} l2_type_t;

/* parameter specification */
struct l2_param_st {
    char     *name;
    l2_type_t type;
    void     *store;
};

/* parameter constructors */
#define L2_PARAM_SET(pa,n,t,s) \
    pa.name = #n, pa.type = L2_TYPE_##t, pa.store = s
#define L2_PARAM_END(pa) \
    pa.name = NULL

/* list of handler types */
typedef enum {
    L2_CHANNEL_FILTER,
    L2_CHANNEL_OUTPUT
} l2_chtype_t;

/* list of linking modes */
typedef enum {
    L2_LINK_CHILD,
    L2_LINK_SIBLING
} l2_link_t;

/* channel handler specification structure */
struct l2_handler_st {
    const char *name;
    l2_chtype_t type;
    l2_result_t (*create)   (l2_context_t *ctx, l2_channel_t *ch);
    l2_result_t (*configure)(l2_context_t *ctx, l2_channel_t *ch, const char *fmt, va_list ap);
    l2_result_t (*open)     (l2_context_t *ctx, l2_channel_t *ch);
    l2_result_t (*write)    (l2_context_t *ctx, l2_channel_t *ch, l2_level_t level, const char *buf, size_t bufsize);
    l2_result_t (*flush)    (l2_context_t *ctx, l2_channel_t *ch);
    l2_result_t (*close)    (l2_context_t *ctx, l2_channel_t *ch);
    l2_result_t (*destroy)  (l2_context_t *ctx, l2_channel_t *ch);
};

/* type of formatter callback function */
typedef l2_result_t (*l2_formatter_t)(
    l2_context_t *ctx,      /* application context */
    const char    id,       /* input  arg: format string id ('x' of '%x') */
    const char   *param,    /* input  arg: format string parameter ('foo' of '%{foo}x') */
    char         *bufptr,   /* input  arg: pointer to output buffer */
    size_t        bufsize,  /* input  arg: maximum size of output buffer */
    size_t       *buflen,   /* ouput  arg: written characters in output buffer */
    va_list      *ap        /* in/out arg: variable argument pointer */
);

/* list of shipped (output) channel handlers (pre-configured in l2_env_t objects) */
extern l2_handler_t l2_handler_null;
extern l2_handler_t l2_handler_fd;
extern l2_handler_t l2_handler_file;
extern l2_handler_t l2_handler_pipe;
extern l2_handler_t l2_handler_socket;
extern l2_handler_t l2_handler_syslog;
extern l2_handler_t l2_handler_smtp;

/* list of shipped (filter) channel handlers (pre-configured in l2_env_t objects) */
extern l2_handler_t l2_handler_noop;
extern l2_handler_t l2_handler_filter;
extern l2_handler_t l2_handler_prefix;
extern l2_handler_t l2_handler_buffer;

/* context operations */
l2_result_t   l2_env_create         (l2_env_t **env);
l2_result_t   l2_env_destroy        (l2_env_t *env);
l2_result_t   l2_env_levels         (l2_env_t *env, unsigned int levelmask, unsigned int flushmask);
l2_result_t   l2_env_formatter      (l2_env_t *env, char id, l2_formatter_t cb, l2_context_t *ctx);
l2_result_t   l2_env_handler        (l2_env_t *env, l2_handler_t *h);
l2_result_t   l2_env_errorinfo      (l2_env_t *env, l2_result_t rv, const char *fmt, ...);
char         *l2_env_strerror       (l2_env_t *env, l2_result_t rv);
l2_result_t   l2_env_settimer       (l2_env_t *env, int iInterval);

/* channel operations */
l2_result_t   l2_channel_create     (l2_channel_t **ch, l2_env_t *env, const char *name);
l2_result_t   l2_channel_destroy    (l2_channel_t *ch);
l2_result_t   l2_channel_levels     (l2_channel_t *ch, unsigned int levelmask, unsigned int flushmask);
l2_result_t   l2_channel_configure  (l2_channel_t *ch, const char *fmt, ...);
l2_result_t   l2_channel_open       (l2_channel_t *ch);
l2_result_t   l2_channel_write      (l2_channel_t *ch, l2_level_t level, const char *buf, size_t bufsize);
l2_result_t   l2_channel_flush      (l2_channel_t *ch);
l2_result_t   l2_channel_close      (l2_channel_t *ch);
l2_result_t   l2_channel_log        (l2_channel_t *ch, l2_level_t level, const char *fmt, ...);
l2_result_t   l2_channel_vlog       (l2_channel_t *ch, l2_level_t level, const char *fmt, va_list ap);
l2_result_t   l2_channel_link       (l2_channel_t *ch, l2_link_t id, l2_channel_t *ch2, ...);
l2_result_t   l2_channel_unlink     (l2_channel_t *ch);
l2_result_t   l2_channel_upstream   (l2_channel_t *ch, l2_channel_t **chU);
l2_result_t   l2_channel_downstream (l2_channel_t *ch, l2_channel_t **chD);
l2_result_t   l2_channel_type       (l2_channel_t *ch, l2_chtype_t *type);
l2_result_t   l2_channel_env        (l2_channel_t *ch, l2_env_t **env);

/* channel tree specification operations */
l2_result_t   l2_spec               (l2_channel_t **ch, l2_env_t *env, const char *spec, ...);
l2_result_t   l2_vspec              (l2_channel_t **ch, l2_env_t *env, const char *spec, va_list ap);

/* utility operations */
l2_result_t   l2_util_setparams     (l2_env_t *env, l2_param_t p[], const char *fmt, va_list ap);
l2_result_t   l2_util_l2s           (char *string,       size_t maxlen, int sep, unsigned int  levelmask);
l2_result_t   l2_util_s2l           (const char *string, size_t maxlen, int sep, unsigned int *levelmask);
l2_result_t   l2_util_fmt_string    (l2_context_t *, const char, const char *, char *, size_t, size_t *, va_list *);
l2_result_t   l2_util_fmt_dump      (l2_context_t *, const char, const char *, char *, size_t, size_t *, va_list *);
l2_result_t   l2_util_fmt_errno     (l2_context_t *, const char, const char *, char *, size_t, size_t *, va_list *);

#endif /* __L2_H__ */

