Files
libstrophe-gh/src/ctx.c
Jack Moffitt c52d0aaa28 Add new snprintf/vsnprintf implementation. This should fix the compability
problems between Win32 (with its broken implementation) and the standard
stdio API.  Also fixed a bug in debug output where long messages got
truncated to 1023 chars, and in xmpp_stanza_to_text where long stanzas
got truncated by one character.
2006-01-21 00:26:40 +00:00

250 lines
5.8 KiB
C

/* ctx.c
** libstrophe XMPP client library -- run-time context implementation
**
** Copyright (C) 2005 OGG, LCC. All rights reserved.
**
** This software is provided AS-IS with no warranty, either express
** or implied.
**
** This software is distributed under license and may not be copied,
** modified or distributed except as expressly authorized under the
** terms of the license contained in the file LICENSE.txt in this
** distribution.
*/
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include "strophe.h"
#include "common.h"
#include "util.h"
/* initialization and shutdown */
void xmpp_initialize(void)
{
sock_initialize();
}
void xmpp_shutdown(void)
{
sock_shutdown();
}
/** version **/
/* TODO: update from the build system? */
#ifndef LIBXMPP_VERSION_MAJOR
#define LIBXMPP_VERSION_MAJOR (0)
#endif
#ifndef LIBXMPP_VERSION_MINOR
#define LIBXMPP_VERSION_MINOR (0)
#endif
int xmpp_version_check(int major, int minor)
{
return (major == LIBXMPP_VERSION_MAJOR) &&
(minor >= LIBXMPP_VERSION_MINOR);
}
/** run-time contexts **/
/* define the global default allocator, logger and context here */
/* wrap stdlib routines to deal with userdata pointer */
static void *_malloc(const size_t size, void * const userdata)
{
return malloc(size);
}
static void _free(void *p, void * const userdata)
{
free(p);
}
static void *_realloc(void *p, const size_t size, void * const userdata)
{
return realloc(p, size);
}
static xmpp_mem_t xmpp_default_mem = {
_malloc, /* use the thinly wrapped stdlib routines by default */
_free,
_realloc,
NULL
};
static const char * const _xmpp_log_level_name[4] = {"DEBUG", "INFO", "WARN", "ERROR"};
static const xmpp_log_level_t _xmpp_default_logger_levels[] = {XMPP_LEVEL_DEBUG,
XMPP_LEVEL_INFO,
XMPP_LEVEL_WARN,
XMPP_LEVEL_ERROR};
void xmpp_default_logger(void * const userdata,
const xmpp_log_level_t level,
const char * const area,
const char * const msg)
{
xmpp_log_level_t filter_level = * (xmpp_log_level_t*)userdata;
if (level >= filter_level)
fprintf(stderr, "%s %s %s\n", area, _xmpp_log_level_name[level], msg);
}
static const xmpp_log_t _xmpp_default_loggers[] = {
{&xmpp_default_logger, (void*)&_xmpp_default_logger_levels[XMPP_LEVEL_DEBUG]},
{&xmpp_default_logger, (void*)&_xmpp_default_logger_levels[XMPP_LEVEL_INFO]},
{&xmpp_default_logger, (void*)&_xmpp_default_logger_levels[XMPP_LEVEL_WARN]},
{&xmpp_default_logger, (void*)&_xmpp_default_logger_levels[XMPP_LEVEL_ERROR]}
};
xmpp_log_t *xmpp_get_default_logger(xmpp_log_level_t level)
{
/* clamp to the known range */
if (level > XMPP_LEVEL_ERROR) level = XMPP_LEVEL_ERROR;
if (level < XMPP_LEVEL_DEBUG) level = XMPP_LEVEL_DEBUG;
return (xmpp_log_t*)&_xmpp_default_loggers[level];
}
static xmpp_log_t xmpp_default_log = { NULL, NULL };
/** convenience functions for accessing the context **/
/* allocator */
void *xmpp_alloc(const xmpp_ctx_t * const ctx, const size_t size)
{
return ctx->mem->alloc(size, ctx->mem->userdata);
}
void xmpp_free(const xmpp_ctx_t * const ctx, void *p)
{
ctx->mem->free(p, ctx->mem->userdata);
}
void *xmpp_realloc(const xmpp_ctx_t * const ctx, void *p,
const size_t size)
{
return ctx->mem->realloc(p, size, ctx->mem->userdata);
}
/* logger */
void xmpp_log(const xmpp_ctx_t * const ctx,
const xmpp_log_level_t level,
const char * const area,
const char * const fmt,
va_list ap)
{
int oldret, ret;
char smbuf[1024];
char *buf;
buf = smbuf;
ret = xmpp_vsnprintf(buf, 1023, fmt, ap);
if (ret > 1023) {
buf = (char *)xmpp_alloc(ctx, ret + 1);
if (!buf) {
buf = NULL;
xmpp_error(ctx, "log", "Failed allocating memory for log message.");
return;
}
oldret = ret;
ret = xmpp_vsnprintf(buf, ret, fmt, ap);
if (ret > oldret) {
xmpp_error(ctx, "log", "Unexpected error");
return;
}
}
if (ctx->log->handler)
ctx->log->handler(ctx->log->userdata, level, area, buf);
}
void xmpp_error(const xmpp_ctx_t * const ctx,
const char * const area,
const char * const fmt,
...)
{
va_list ap;
va_start(ap, fmt);
xmpp_log(ctx, XMPP_LEVEL_ERROR, area, fmt, ap);
va_end(ap);
}
void xmpp_warn(const xmpp_ctx_t * const ctx,
const char * const area,
const char * const fmt,
...)
{
va_list ap;
va_start(ap, fmt);
xmpp_log(ctx, XMPP_LEVEL_WARN, area, fmt, ap);
va_end(ap);
}
void xmpp_info(const xmpp_ctx_t * const ctx,
const char * const area,
const char * const fmt,
...)
{
va_list ap;
va_start(ap, fmt);
xmpp_log(ctx, XMPP_LEVEL_INFO, area, fmt, ap);
va_end(ap);
}
void xmpp_debug(const xmpp_ctx_t * const ctx,
const char * const area,
const char * const fmt,
...)
{
va_list ap;
va_start(ap, fmt);
xmpp_log(ctx, XMPP_LEVEL_DEBUG, area, fmt, ap);
va_end(ap);
}
/** allocate and initialize a new ctx object */
xmpp_ctx_t *xmpp_ctx_new(const xmpp_mem_t * const mem,
const xmpp_log_t * const log)
{
xmpp_ctx_t *ctx = NULL;
if (mem == NULL)
ctx = xmpp_default_mem.alloc(sizeof(xmpp_ctx_t), NULL);
else
ctx = mem->alloc(sizeof(xmpp_ctx_t), mem->userdata);
if (ctx != NULL) {
if (mem != NULL)
ctx->mem = mem;
else
ctx->mem = &xmpp_default_mem;
if (log == NULL)
ctx->log = &xmpp_default_log;
else
ctx->log = log;
ctx->connlist = NULL;
ctx->loop_status = XMPP_LOOP_NOTSTARTED;
}
return ctx;
}
/** free a ctx object no longer in use */
void xmpp_ctx_free(xmpp_ctx_t * const ctx)
{
/* mem and log are owned by their suppliers */
xmpp_free(ctx, ctx); /* pull the hole in after us */
}