From: Nick Bowler Date: Wed, 9 May 2012 04:06:19 +0000 (-0400) Subject: uobject: First stab at a generic logging mechanism. X-Git-Url: https://git.draconx.ca/gitweb/upkg.git/commitdiff_plain/e3726c0480d74840dd9104850cba0f3e5f93beed?ds=sidebyside uobject: First stab at a generic logging mechanism. Let's build something on top of Glib's logging facilities which probably work well enough for what we want to do. Add a couple calls to the texture class for starters. --- diff --git a/src/engine/texture.gob b/src/engine/texture.gob index 3db176e..8059c3a 100644 --- a/src/engine/texture.gob +++ b/src/engine/texture.gob @@ -84,8 +84,10 @@ struct engine_texture_data *decode_mipmap(UObject *uo) /* At this point, the current file offset should match the one recorded * above. */ - if (uo->pkg->version >= 63 && end_offset != (f->base + f->offset)) + if (uo->pkg->version >= 63 && end_offset != (f->base + f->offset)) { + u_err(uo, "mipmap end offset does not match data size"); goto err_free; + } /* Read in the remaining fields */ buflen = upkg_export_read(f, buf, 10); @@ -136,6 +138,8 @@ class Engine:Texture from U:Object (dynamic) for (int i = 0; i < self->_priv->mipmap_count; i++) { data[i] = decode_mipmap(uo); if (!data[i]) { + u_err(uo, "error decoding mipmap level %d", i); + /* Unwind the allocations. */ for (; i >= 0; i--) free(data[i]); diff --git a/src/uobject/uobject.c b/src/uobject/uobject.c index 9174005..1a3d740 100644 --- a/src/uobject/uobject.c +++ b/src/uobject/uobject.c @@ -19,7 +19,9 @@ #include #include #include +#include #include +#include #include #include @@ -375,3 +377,74 @@ static void u_object_class_init(UObjectClass *class) class->deserialize = deserialize; go->finalize = u_object_finalize; } + +/* + * Prepend a prefix to a printf-style format string. Unfortunately, there's + * no way to construct va_list values on the fly in C, so we cannot simply + * prepend %s and pass the prefix as an argument. Any % characters in the + * prefix will be escaped. + * + * Returns a pointer to a newly allocated string, which should be freed by the + * caller, or NULL otherwise. + */ +static char *prepend_fmt(const char *prefix, const char *fmt) +{ + size_t prefix_len = strlen(prefix), fmt_len = strlen(fmt); + char *new_fmt; + + if (prefix_len > SIZE_MAX/2 - sizeof ": ") + return NULL; + if (2*prefix_len > SIZE_MAX - fmt_len) + return NULL; + + new_fmt = malloc(2*prefix_len + fmt_len + 1); + if (new_fmt) { + size_t offset = 0; + + for (size_t i = 0; i < prefix_len; i++) { + if (prefix[i] == '%') + new_fmt[offset++] = '%'; + new_fmt[offset++] = prefix[i]; + } + + new_fmt[offset++] = ':'; + new_fmt[offset++] = ' '; + strcpy(new_fmt+offset, fmt); + } + + return new_fmt; +} + +/* Logging helpers that automatically prepend the UObject class information. */ +void u_vlog_full(GObject *o, GLogLevelFlags level, const char *fmt, va_list ap) +{ + g_return_if_fail(IS_U_OBJECT(o)); + UObject *uo = U_OBJECT(o); + char *new_fmt = NULL; + + if (uo->pkg_file) { + /* XXX: Currently, there's no way to get the full object name + * here because the object path information is discarded + * after opening it. In principle, there's no reason why + * we couldn't keep it around to improve log messages. */ + new_fmt = prepend_fmt(uo->pkg_file->name, fmt); + if (!new_fmt) { + g_log(G_OBJECT_TYPE_NAME(o), level, "%s", + uo->pkg_file->name); + } else { + fmt = new_fmt; + } + } + + g_logv(G_OBJECT_TYPE_NAME(o), level, fmt, ap); + free(new_fmt); +} + +void u_log_full(GObject *o, GLogLevelFlags level, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + u_vlog_full(o, level, fmt, ap); + va_end(ap); +} diff --git a/src/uobject/uobject.h b/src/uobject/uobject.h index 2f70940..e91bf5b 100644 --- a/src/uobject/uobject.h +++ b/src/uobject/uobject.h @@ -20,6 +20,7 @@ #define U_OBJECT_H_ #include +#include #include "upkg.h" #define U_TYPE_OBJECT u_object_get_type() @@ -56,4 +57,12 @@ int u_object_deserialize(GObject *obj, struct upkg *pkg, unsigned long idx); GObject *u_object_new_from_package(struct upkg *pkg, unsigned long idx); +/* Logging helpers for UObject class implementations. */ +void u_vlog_full(GObject *o, GLogLevelFlags level, const char *fmt, va_list ap); +void u_log_full(GObject *o, GLogLevelFlags level, const char *fmt, ...); + +#define u_log(uo, ...) u_log_full(G_OBJECT(uo), G_LOG_LEVEL_MESSAGE, __VA_ARGS__) +#define u_warn(uo, ...) u_log_full(G_OBJECT(uo), G_LOG_LEVEL_WARNING, __VA_ARGS__) +#define u_err(uo, ...) u_log_full(G_OBJECT(uo), G_LOG_LEVEL_CRITICAL, __VA_ARGS__) + #endif