X-Git-Url: http://git.draconx.ca/gitweb/upkg.git/blobdiff_plain/a0efa108741b6cb53ddc3b1228a91b2e0c75a56a..e3726c0480d74840dd9104850cba0f3e5f93beed:/src/uobject/uobject.c 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); +}