src/state.c \
src/text.c \
src/text.h \
- src/utils.c \
src/utils.h \
src/xkb-priv.h
#include <sys/types.h>
#include <sys/stat.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdarg.h>
#include <stdio.h>
#include <unistd.h>
+#include <syslog.h>
#include "xkb-priv.h"
#include "atom.h"
struct xkb_context {
int refcnt;
+ ATTR_PRINTF(3, 0) void (*log_fn)(struct xkb_context *ctx, int priority,
+ const char *fmt, va_list args);
+ int log_priority;
+ int log_verbosity;
+ void *user_data;
+
darray(char *) includes;
/* xkbcomp needs to assign sequential IDs to XkbFile's it creates. */
free(ctx);
}
+static const char *
+priority_to_prefix(int priority)
+{
+ switch (priority) {
+ case LOG_DEBUG:
+ return "Debug:";
+ case LOG_INFO:
+ return "Info:";
+ case LOG_WARNING:
+ return "Warning:";
+ case LOG_ERR:
+ return "Error:";
+ case LOG_CRIT:
+ case LOG_ALERT:
+ case LOG_EMERG:
+ return "Internal error:";
+ default:
+ return "";
+ }
+}
+
+ATTR_PRINTF(3, 0) static void
+default_log_fn(struct xkb_context *ctx, int priority,
+ const char *fmt, va_list args)
+{
+ const char *prefix = priority_to_prefix(priority);
+
+ if (prefix)
+ fprintf(stderr, "%-15s", prefix);
+ vfprintf(stderr, fmt, args);
+}
+
+static int
+log_priority(const char *priority) {
+ char *endptr;
+ int prio;
+
+ errno = 0;
+ prio = strtol(priority, &endptr, 10);
+ if (errno == 0 && (endptr[0] == '\0' || isspace(endptr[0])))
+ return prio;
+ if (strncasecmp(priority, "err", 3) == 0)
+ return LOG_ERR;
+ if (strncasecmp(priority, "warn", 4) == 0)
+ return LOG_WARNING;
+ if (strncasecmp(priority, "info", 4) == 0)
+ return LOG_INFO;
+ if (strncasecmp(priority, "debug", 5) == 0)
+ return LOG_DEBUG;
+
+ return LOG_ERR;
+}
+
+static int
+log_verbosity(const char *verbosity) {
+ char *endptr;
+ int v;
+
+ errno = 0;
+ v = strtol(verbosity, &endptr, 10);
+ if (errno == 0)
+ return v;
+
+ return 0;
+}
+
/**
* Create a new context.
*/
XKB_EXPORT struct xkb_context *
xkb_context_new(enum xkb_context_flags flags)
{
+ const char *env;
struct xkb_context *ctx = calloc(1, sizeof(*ctx));
if (!ctx)
return NULL;
ctx->refcnt = 1;
+ ctx->log_fn = default_log_fn;
+ ctx->log_priority = LOG_ERR;
+ ctx->log_verbosity = 0;
+
+ /* Environment overwrites defaults. */
+ env = getenv("XKB_LOG");
+ if (env)
+ xkb_set_log_priority(ctx, log_priority(env));
+
+ env = getenv("XKB_VERBOSITY");
+ if (env)
+ xkb_set_log_verbosity(ctx, log_verbosity(env));
if (!(flags & XKB_CONTEXT_NO_DEFAULT_INCLUDES) &&
!xkb_context_include_path_append_default(ctx)) {
{
return atom_text(ctx->atom_table, atom);
}
+
+void
+xkb_log(struct xkb_context *ctx, int priority, const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ /* NOTE: This test will be removed in a few commits. */
+ if (ctx)
+ ctx->log_fn(ctx, priority, fmt, args);
+ else
+ default_log_fn(ctx, priority, fmt, args);
+ va_end(args);
+}
+
+XKB_EXPORT void
+xkb_set_log_fn(struct xkb_context *ctx,
+ void (*log_fn)(struct xkb_context *ctx, int priority,
+ const char *fmt, va_list args))
+{
+ ctx->log_fn = log_fn;
+}
+
+XKB_EXPORT int
+xkb_get_log_priority(struct xkb_context *ctx)
+{
+ return ctx->log_priority;
+}
+
+XKB_EXPORT void
+xkb_set_log_priority(struct xkb_context *ctx, int priority)
+{
+ ctx->log_priority = priority;
+}
+
+XKB_EXPORT int
+xkb_get_log_verbosity(struct xkb_context *ctx)
+{
+ return ctx->log_verbosity;
+}
+
+XKB_EXPORT void
+xkb_set_log_verbosity(struct xkb_context *ctx, int verbosity)
+{
+ ctx->log_verbosity = verbosity;
+}
+
+XKB_EXPORT void *
+xkb_get_user_data(struct xkb_context *ctx)
+{
+ if (ctx)
+ return ctx->user_data;
+ return NULL;
+}
+
+XKB_EXPORT void
+xkb_set_user_data(struct xkb_context *ctx, void *user_data)
+{
+ ctx->user_data = user_data;
+}
+++ /dev/null
-/*\
- *
- * COPYRIGHT 1990
- * DIGITAL EQUIPMENT CORPORATION
- * MAYNARD, MASSACHUSETTS
- * ALL RIGHTS RESERVED.
- *
- * THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT NOTICE AND
- * SHOULD NOT BE CONSTRUED AS A COMMITMENT BY DIGITAL EQUIPMENT CORPORATION.
- * DIGITAL MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THIS SOFTWARE
- * FOR ANY PURPOSE. IT IS SUPPLIED "AS IS" WITHOUT EXPRESS OR IMPLIED
- * WARRANTY.
- *
- * IF THE SOFTWARE IS MODIFIED IN A MANNER CREATING DERIVATIVE COPYRIGHT
- * RIGHTS, APPROPRIATE LEGENDS MAY BE PLACED ON THE DERIVATIVE WORK IN
- * ADDITION TO THAT SET FORTH ABOVE.
- *
- * Permission to use, copy, modify, and distribute this software and its
- * documentation for any purpose and without fee is hereby granted, provided
- * that the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation, and that the name of Digital Equipment Corporation not be
- * used in advertising or publicity pertaining to distribution of the
- * software without specific, written prior permission.
- \*/
-
-#include <ctype.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <string.h>
-
-#include "utils.h"
-
-static FILE *errorFile = NULL;
-static int outCount = 0;
-static char *preMsg = NULL;
-static char *prefix = NULL;
-
-bool
-uSetErrorFile(char *name)
-{
- if ((errorFile != NULL) && (errorFile != stderr)) {
- fprintf(errorFile, "switching to %s\n", name ? name : "stderr");
- fclose(errorFile);
- }
- if (name != NULL)
- errorFile = fopen(name, "w");
- else
- errorFile = stderr;
- if (errorFile == NULL) {
- errorFile = stderr;
- return false;
- }
- return true;
-}
-
-void
-uInformation(const char *s, ...)
-{
- va_list args;
-
- if (!errorFile)
- errorFile = stderr;
-
- va_start(args, s);
- vfprintf(errorFile, s, args);
- va_end(args);
- fflush(errorFile);
-}
-
-/***====================================================================***/
-
-void
-uAction(const char *s, ...)
-{
- va_list args;
-
- if (!errorFile)
- errorFile = stderr;
-
- if (prefix != NULL)
- fprintf(errorFile, "%s", prefix);
- fprintf(errorFile, " ");
- va_start(args, s);
- vfprintf(errorFile, s, args);
- va_end(args);
- fflush(errorFile);
-}
-
-/***====================================================================***/
-
-void
-uWarning(const char *s, ...)
-{
- va_list args;
-
- if (!errorFile)
- errorFile = stderr;
-
- if ((outCount == 0) && (preMsg != NULL))
- fprintf(errorFile, "%s\n", preMsg);
- if (prefix != NULL)
- fprintf(errorFile, "%s", prefix);
- fprintf(errorFile, "Warning: ");
- va_start(args, s);
- vfprintf(errorFile, s, args);
- va_end(args);
- fflush(errorFile);
- outCount++;
-}
-
-/***====================================================================***/
-
-void
-uError(const char *s, ...)
-{
- va_list args;
-
- if (!errorFile)
- errorFile = stderr;
-
- if ((outCount == 0) && (preMsg != NULL))
- fprintf(errorFile, "%s\n", preMsg);
- if (prefix != NULL)
- fprintf(errorFile, "%s", prefix);
- fprintf(errorFile, "Error: ");
- va_start(args, s);
- vfprintf(errorFile, s, args);
- va_end(args);
- fflush(errorFile);
- outCount++;
-}
-
-/***====================================================================***/
-
-void
-uInternalError(const char *s, ...)
-{
- va_list args;
-
- if (!errorFile)
- errorFile = stderr;
-
- if ((outCount == 0) && (preMsg != NULL))
- fprintf(errorFile, "%s\n", preMsg);
- if (prefix != NULL)
- fprintf(errorFile, "%s", prefix);
- fprintf(errorFile, "Internal error: ");
- va_start(args, s);
- vfprintf(errorFile, s, args);
- va_end(args);
- fflush(errorFile);
- outCount++;
-}
/***====================================================================***/
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-
/*
* We sometimes malloc strings and then expose them as const char*'s. This
* macro is used when we free these strings in order to avoid -Wcast-qual
#define ATTR_MALLOC
#endif
-extern bool
-uSetErrorFile(char *name);
-
-#define INFO uInformation
-
-ATTR_PRINTF(1, 2) void
-uInformation(const char *s, ...);
-
-#define ACTION uAction
-
-ATTR_PRINTF(1, 2) void
-uAction(const char *s, ...);
-
-#define WARN uWarning
-
-ATTR_PRINTF(1, 2) void
-uWarning(const char *s, ...);
-
-#define ERROR uError
-
-ATTR_PRINTF(1, 2) void
-uError(const char *s, ...);
-
-/* WSGO stands for "Weird Stuff Going On" (wtf???) */
-#define WSGO uInternalError
-
-ATTR_PRINTF(1, 2) void
-uInternalError(const char *s, ...);
+#define INFO(...) xkb_log(NULL, LOG_INFO, __VA_ARGS__)
+#define WARN(...) xkb_log(NULL, LOG_WARNING, __VA_ARGS__)
+#define ERROR(...) xkb_log(NULL, LOG_ERR, __VA_ARGS__)
+#define WSGO(...) xkb_log(NULL, LOG_CRIT, __VA_ARGS__)
+#define ACTION(...) xkb_log(NULL, -1, __VA_ARGS__)
#endif /* UTILS_H */
#include <stdbool.h>
#include <string.h>
#include <strings.h>
+#include <syslog.h>
#include <X11/extensions/XKB.h>
#include <X11/X.h>
bool
xkb_keysym_is_keypad(xkb_keysym_t keysym);
+ATTR_PRINTF(3, 4) void
+xkb_log(struct xkb_context *ctx, int priority, const char *fmt, ...);
+
+#define xkb_log_cond(ctx, prio, ...) \
+ do { \
+ if (xkb_get_log_priority(ctx) >= (prio)) \
+ xkb_log((ctx), (prio), __VA_ARGS__); \
+ } while (0)
+
+#define xkb_log_cond_lvl(ctx, prio, lvl, ...) \
+ do { \
+ if (xkb_get_log_verbosity(ctx) >= (lvl)) \
+ xkb_log_cond((ctx), (prio), __VA_ARGS__); \
+ } while (0)
+
+/*
+ * The format is not part of the argument list in order to avoid the
+ * "ISO C99 requires rest arguments to be used" warning when only the
+ * format is supplied without arguments. Not supplying it would still
+ * result in an error, though.
+ */
+#define log_dbg(ctx, ...) xkb_log_cond((ctx), LOG_DEBUG, __VA_ARGS__)
+#define log_info(ctx, ...) xkb_log_cond((ctx), LOG_INFO, __VA_ARGS__)
+#define log_warn(ctx, ...) xkb_log_cond((ctx), LOG_WARNING, __VA_ARGS__)
+#define log_err(ctx, ...) xkb_log_cond((ctx), LOG_ERR, __VA_ARGS__)
+#define log_wsgo(ctx, ...) xkb_log_cond((ctx), LOG_CRIT, __VA_ARGS__)
+#define log_lvl(ctx, lvl, ...) \
+ xkb_log_cond_lvl((ctx), LOG_WARNING, (lvl), __VA_ARGS__)
+
#endif /* XKB_PRIV_H */
/** @} */
/**
+ * @defgroup logging Logging handling
+ * These functions allow you to manipulate how logging from this library
+ * will be handled.
+ *
+ * @{
+ */
+
+/**
+ * Sets the function to be called for logging messages, instead of the
+ * default logger which writes to stderr.
+ **/
+void
+xkb_set_log_fn(struct xkb_context *context,
+ void (*log_fn)(struct xkb_context *context, int priority,
+ const char *format, va_list args));
+/**
+ * Sets the current logging priority. The value controls which messages
+ * are logged.
+ *
+ * The value should be one of LOG_ERR, LOG_WARNING, LOG_DEBUG, etc., see
+ * syslog(3) or syslog.h. The default priority is LOG_ERR.
+ * The environment variable XKB_LOG, if set, overrides the default value
+ * and may be specified as a priority number or name.
+ */
+void
+xkb_set_log_priority(struct xkb_context *context, int priority);
+
+/**
+ * Returns the current logging priority.
+ */
+int
+xkb_get_log_priority(struct xkb_context *context);
+
+/**
+ * Sets the current logging verbosity, a value from 0 to 10.
+ *
+ * The library can generate a number of warnings which are not helpful to
+ * ordinary users of the library. The verbosity may be increased if more
+ * information is desired (e.g. when developing a keymap). Defaults to 0.
+ * The environment variable XKB_VERBOSITY, if set, overrdies the default
+ * value.
+ *
+ * Note that most verbose messages are of priority LOG_WARNING or lower.
+ */
+void
+xkb_set_log_verbosity(struct xkb_context *ctx, int verbosity);
+
+/**
+ * Returns the current logging verbosity.
+ */
+int
+xkb_get_log_verbosity(struct xkb_context *ctx);
+
+/**
+ * Retrieves stored data pointer from the context. This might be useful
+ * to access from callbacks like a custom logging function.
+ *
+ * If context is NULL, returns NULL.
+ **/
+void *
+xkb_get_user_data(struct xkb_context *context);
+
+/**
+ * Store custom user data in the context.
+ */
+void
+xkb_set_user_data(struct xkb_context *context, void *user_data);
+
+/** @} */
+
+/**
* @defgroup map Keymap management
* These utility functions allow you to create and deallocate XKB keymaps.
*