X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fcontext.c;h=bcec16c43c437adc5c58812b16d83447dfc9f6f4;hb=5b3774ace991a396752ff0a846fdfb5c38424551;hp=0d0e900f25926869b1a8469a6724202db84a80d3;hpb=6433d72e7c13b7be5ed7bf227441b68b909ef46d;p=platform%2Fupstream%2Flibxkbcommon.git diff --git a/src/context.c b/src/context.c index 0d0e900..bcec16c 100644 --- a/src/context.c +++ b/src/context.c @@ -1,5 +1,6 @@ /* * Copyright © 2012 Intel Corporation + * Copyright © 2012 Ran Benita * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -23,150 +24,170 @@ * Author: Daniel Stone */ +#include "config.h" + #include #include -#include -#include - -#include "xkb-priv.h" -#include "atom.h" - -struct xkb_ctx { - int refcnt; - - char **include_paths; - int num_include_paths; - int size_include_paths; +#include - /* xkbcomp needs to assign sequential IDs to XkbFile's it creates. */ - int file_id; +#include "xkbcommon/xkbcommon.h" +#include "utils.h" +#include "context.h" - struct atom_table *atom_table; -}; /** * Append one directory to the context's include path. */ -_X_EXPORT int -xkb_ctx_include_path_append(struct xkb_ctx *ctx, const char *path) +XKB_EXPORT int +xkb_context_include_path_append(struct xkb_context *ctx, const char *path) { struct stat stat_buf; - int err; - - if (ctx->size_include_paths <= ctx->num_include_paths) { - int new_size; - char **new_paths; - new_size = ctx->size_include_paths + 2; - new_paths = uTypedRecalloc(ctx->include_paths, - ctx->size_include_paths, - new_size, - char *); - if (!new_paths) - return 0; - ctx->include_paths = new_paths; - ctx->size_include_paths = new_size; - } + int err = ENOMEM; + char *tmp; + + tmp = strdup(path); + if (!tmp) + goto err; err = stat(path, &stat_buf); - if (err != 0) - return 0; - if (!S_ISDIR(stat_buf.st_mode)) - return 0; - if (eaccess(path, R_OK | X_OK) != 0) - return 0; - - ctx->include_paths[ctx->num_include_paths] = strdup(path); - if (!ctx->include_paths[ctx->num_include_paths]) - return 0; - ctx->num_include_paths++; + if (err != 0) { + err = errno; + goto err; + } + if (!S_ISDIR(stat_buf.st_mode)) { + err = ENOTDIR; + goto err; + } + + if (!check_eaccess(path, R_OK | X_OK)) { + err = EACCES; + goto err; + } + + darray_append(ctx->includes, tmp); + log_dbg(ctx, XKB_LOG_MESSAGE_NO_ID, "Include path added: %s\n", tmp); return 1; + +err: + darray_append(ctx->failed_includes, tmp); + log_dbg(ctx, XKB_LOG_MESSAGE_NO_ID, + "Include path failed: %s (%s)\n", tmp, strerror(err)); + return 0; +} + +const char * +xkb_context_include_path_get_extra_path(struct xkb_context *ctx) +{ + const char *extra = xkb_context_getenv(ctx, "XKB_CONFIG_EXTRA_PATH"); + return extra ? extra : DFLT_XKB_CONFIG_EXTRA_PATH; +} + +const char * +xkb_context_include_path_get_system_path(struct xkb_context *ctx) +{ + const char *root = xkb_context_getenv(ctx, "XKB_CONFIG_ROOT"); + return root ? root : DFLT_XKB_CONFIG_ROOT; } /** * Append the default include directories to the context. */ -_X_EXPORT int -xkb_ctx_include_path_append_default(struct xkb_ctx *ctx) +XKB_EXPORT int +xkb_context_include_path_append_default(struct xkb_context *ctx) { - const char *home = getenv("HOME"); + const char *home, *xdg, *root, *extra; char *user_path; - int err; + int ret = 0; + + home = xkb_context_getenv(ctx, "HOME"); + + xdg = xkb_context_getenv(ctx, "XDG_CONFIG_HOME"); + if (xdg != NULL) { + user_path = asprintf_safe("%s/xkb", xdg); + if (user_path) { + ret |= xkb_context_include_path_append(ctx, user_path); + free(user_path); + } + } else if (home != NULL) { + /* XDG_CONFIG_HOME fallback is $HOME/.config/ */ + user_path = asprintf_safe("%s/.config/xkb", home); + if (user_path) { + ret |= xkb_context_include_path_append(ctx, user_path); + free(user_path); + } + } - (void) xkb_ctx_include_path_append(ctx, DFLT_XKB_CONFIG_ROOT); + if (home != NULL) { + user_path = asprintf_safe("%s/.xkb", home); + if (user_path) { + ret |= xkb_context_include_path_append(ctx, user_path); + free(user_path); + } + } - home = getenv("HOME"); - if (!home) - return 1; - err = asprintf(&user_path, "%s/.xkb", home); - if (err <= 0) - return 1; - (void) xkb_ctx_include_path_append(ctx, user_path); - free(user_path); + extra = xkb_context_include_path_get_extra_path(ctx); + ret |= xkb_context_include_path_append(ctx, extra); + root = xkb_context_include_path_get_system_path(ctx); + ret |= xkb_context_include_path_append(ctx, root); - return 1; + return ret; } /** * Remove all entries in the context's include path. */ -_X_EXPORT void -xkb_ctx_include_path_clear(struct xkb_ctx *ctx) +XKB_EXPORT void +xkb_context_include_path_clear(struct xkb_context *ctx) { - int i; + char **path; - for (i = 0; i < ctx->num_include_paths; i++) { - free(ctx->include_paths[i]); - ctx->include_paths[i] = NULL; - } - free(ctx->include_paths); - ctx->include_paths = NULL; - ctx->num_include_paths = 0; + darray_foreach(path, ctx->includes) + free(*path); + darray_free(ctx->includes); + + darray_foreach(path, ctx->failed_includes) + free(*path); + darray_free(ctx->failed_includes); } /** - * xkb_ctx_include_path_clear() + xkb_ctx_include_path_append_default() + * xkb_context_include_path_clear() + xkb_context_include_path_append_default() */ -_X_EXPORT int -xkb_ctx_include_path_reset_defaults(struct xkb_ctx *ctx) +XKB_EXPORT int +xkb_context_include_path_reset_defaults(struct xkb_context *ctx) { - xkb_ctx_include_path_clear(ctx); - return xkb_ctx_include_path_append_default(ctx); + xkb_context_include_path_clear(ctx); + return xkb_context_include_path_append_default(ctx); } /** * Returns the number of entries in the context's include path. */ -_X_EXPORT unsigned int -xkb_ctx_num_include_paths(struct xkb_ctx *ctx) +XKB_EXPORT unsigned int +xkb_context_num_include_paths(struct xkb_context *ctx) { - return ctx->num_include_paths; + return darray_size(ctx->includes); } /** * Returns the given entry in the context's include path, or NULL if an * invalid index is passed. */ -_X_EXPORT const char * -xkb_ctx_include_path_get(struct xkb_ctx *ctx, unsigned int idx) +XKB_EXPORT const char * +xkb_context_include_path_get(struct xkb_context *ctx, unsigned int idx) { - if (idx >= xkb_ctx_num_include_paths(ctx)) + if (idx >= xkb_context_num_include_paths(ctx)) return NULL; - return ctx->include_paths[idx]; -} - -int -xkb_ctx_take_file_id(struct xkb_ctx *ctx) -{ - return ctx->file_id++; + return darray_item(ctx->includes, idx); } /** * Take a new reference on the context. */ -_X_EXPORT struct xkb_ctx * -xkb_ctx_ref(struct xkb_ctx *ctx) +XKB_EXPORT struct xkb_context * +xkb_context_ref(struct xkb_context *ctx) { ctx->refcnt++; return ctx; @@ -176,59 +197,175 @@ xkb_ctx_ref(struct xkb_ctx *ctx) * Drop an existing reference on the context, and free it if the refcnt is * now 0. */ -_X_EXPORT void -xkb_ctx_unref(struct xkb_ctx *ctx) +XKB_EXPORT void +xkb_context_unref(struct xkb_context *ctx) { - if (--ctx->refcnt > 0) + if (!ctx || --ctx->refcnt > 0) return; - xkb_ctx_include_path_clear(ctx); + free(ctx->x11_atom_cache); + xkb_context_include_path_clear(ctx); atom_table_free(ctx->atom_table); free(ctx); } +static const char * +log_level_to_prefix(enum xkb_log_level level) +{ + switch (level) { + case XKB_LOG_LEVEL_DEBUG: + return "xkbcommon: DEBUG: "; + case XKB_LOG_LEVEL_INFO: + return "xkbcommon: INFO: "; + case XKB_LOG_LEVEL_WARNING: + return "xkbcommon: WARNING: "; + case XKB_LOG_LEVEL_ERROR: + return "xkbcommon: ERROR: "; + case XKB_LOG_LEVEL_CRITICAL: + return "xkbcommon: CRITICAL: "; + default: + return NULL; + } +} + +ATTR_PRINTF(3, 0) static void +default_log_fn(struct xkb_context *ctx, enum xkb_log_level level, + const char *fmt, va_list args) +{ + const char *prefix = log_level_to_prefix(level); + + if (prefix) + fprintf(stderr, "%s", prefix); + vfprintf(stderr, fmt, args); +} + +static enum xkb_log_level +log_level(const char *level) { + char *endptr; + enum xkb_log_level lvl; + + errno = 0; + lvl = strtol(level, &endptr, 10); + if (errno == 0 && (endptr[0] == '\0' || is_space(endptr[0]))) + return lvl; + if (istreq_prefix("crit", level)) + return XKB_LOG_LEVEL_CRITICAL; + if (istreq_prefix("err", level)) + return XKB_LOG_LEVEL_ERROR; + if (istreq_prefix("warn", level)) + return XKB_LOG_LEVEL_WARNING; + if (istreq_prefix("info", level)) + return XKB_LOG_LEVEL_INFO; + if (istreq_prefix("debug", level) || istreq_prefix("dbg", level)) + return XKB_LOG_LEVEL_DEBUG; + + return XKB_LOG_LEVEL_ERROR; +} + +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. */ -_X_EXPORT struct xkb_ctx * -xkb_ctx_new(enum xkb_ctx_flags flags) +XKB_EXPORT struct xkb_context * +xkb_context_new(enum xkb_context_flags flags) { - struct xkb_ctx *ctx = calloc(1, sizeof(*ctx)); + 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_level = XKB_LOG_LEVEL_ERROR; + ctx->log_verbosity = 0; + ctx->use_environment_names = !(flags & XKB_CONTEXT_NO_ENVIRONMENT_NAMES); + ctx->use_secure_getenv = !(flags & XKB_CONTEXT_NO_SECURE_GETENV); + + /* Environment overwrites defaults. */ + env = xkb_context_getenv(ctx, "XKB_LOG_LEVEL"); + if (env) + xkb_context_set_log_level(ctx, log_level(env)); + + env = xkb_context_getenv(ctx, "XKB_LOG_VERBOSITY"); + if (env) + xkb_context_set_log_verbosity(ctx, log_verbosity(env)); if (!(flags & XKB_CONTEXT_NO_DEFAULT_INCLUDES) && - !xkb_ctx_include_path_append_default(ctx)) { - xkb_ctx_unref(ctx); + !xkb_context_include_path_append_default(ctx)) { + log_err(ctx, XKB_LOG_MESSAGE_NO_ID, + "failed to add default include path %s\n", + DFLT_XKB_CONFIG_ROOT); + xkb_context_unref(ctx); return NULL; } ctx->atom_table = atom_table_new(); if (!ctx->atom_table) { - xkb_ctx_unref(ctx); + xkb_context_unref(ctx); return NULL; } + ctx->x11_atom_cache = NULL; + return ctx; } -xkb_atom_t -xkb_atom_intern(struct xkb_ctx *ctx, const char *string) +XKB_EXPORT void +xkb_context_set_log_fn(struct xkb_context *ctx, + void (*log_fn)(struct xkb_context *ctx, + enum xkb_log_level level, + const char *fmt, va_list args)) { - return atom_intern(ctx->atom_table, string); + ctx->log_fn = (log_fn ? log_fn : default_log_fn); } -char * -xkb_atom_strdup(struct xkb_ctx *ctx, xkb_atom_t atom) +XKB_EXPORT enum xkb_log_level +xkb_context_get_log_level(struct xkb_context *ctx) { - return atom_strdup(ctx->atom_table, atom); + return ctx->log_level; } -const char * -xkb_atom_text(struct xkb_ctx *ctx, xkb_atom_t atom) +XKB_EXPORT void +xkb_context_set_log_level(struct xkb_context *ctx, enum xkb_log_level level) +{ + ctx->log_level = level; +} + +XKB_EXPORT int +xkb_context_get_log_verbosity(struct xkb_context *ctx) +{ + return ctx->log_verbosity; +} + +XKB_EXPORT void +xkb_context_set_log_verbosity(struct xkb_context *ctx, int verbosity) +{ + ctx->log_verbosity = verbosity; +} + +XKB_EXPORT void * +xkb_context_get_user_data(struct xkb_context *ctx) +{ + if (ctx) + return ctx->user_data; + return NULL; +} + +XKB_EXPORT void +xkb_context_set_user_data(struct xkb_context *ctx, void *user_data) { - return atom_text(ctx->atom_table, atom); + ctx->user_data = user_data; }