X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fcontext.c;h=b8b214bcda86d75d1c72b1b1c38d5da44e9b2261;hb=cf228acd26b8798e077ae83b5a1351af0b78a287;hp=12aeed4e8ac57c0e664f538f4e920e6f0af5144f;hpb=5eb0a70e61528adba4f14fe1c7e058cc01378c4c;p=platform%2Fupstream%2Flibxkbcommon.git diff --git a/src/context.c b/src/context.c index 12aeed4..b8b214b 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,175 +24,346 @@ * Author: Daniel Stone */ +#include "config.h" + #include #include -#include -#include +#include #include "xkbcommon/xkbcommon.h" -#include "XKBcommonint.h" #include "utils.h" +#include "context.h" -struct xkb_context { - int refcnt; - char **include_paths; - int num_include_paths; - int size_include_paths; -}; /** * Append one directory to the context's include path. */ -_X_EXPORT int -xkb_context_include_path_append(struct xkb_context *context, 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 (context->size_include_paths <= context->num_include_paths) { - int new_size; - char **new_paths; - new_size = context->size_include_paths + 2; - new_paths = uTypedRecalloc(context->include_paths, - context->size_include_paths, - new_size, - char *); - if (!new_paths) - return 0; - context->include_paths = new_paths; - context->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; - - context->include_paths[context->num_include_paths] = strdup(path); - if (!context->include_paths[context->num_include_paths]) - return 0; - context->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, "Include path added: %s\n", tmp); return 1; + +err: + darray_append(ctx->failed_includes, tmp); + log_dbg(ctx, "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_context_include_path_append_default(struct xkb_context *context) +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; - (void) xkb_context_include_path_append(context, DFLT_XKB_CONFIG_ROOT); + home = xkb_context_getenv(ctx, "HOME"); - home = getenv("HOME"); - if (!home) - return 1; - err = asprintf(&user_path, "%s/.xkb", home); - if (err <= 0) - return 1; - (void) xkb_context_include_path_append(context, user_path); - free(user_path); + 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); + } + } - return 1; + 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); + } + } + + 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 ret; } /** * Remove all entries in the context's include path. */ -_X_EXPORT void -xkb_context_include_path_clear(struct xkb_context *context) +XKB_EXPORT void +xkb_context_include_path_clear(struct xkb_context *ctx) { - int i; + char **path; - for (i = 0; i < context->num_include_paths; i++) { - free(context->include_paths[i]); - context->include_paths[i] = NULL; - } - free(context->include_paths); - context->include_paths = NULL; - context->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_context_include_path_clear() + xkb_context_include_path_append_default() */ -_X_EXPORT int -xkb_context_include_path_reset_defaults(struct xkb_context *context) +XKB_EXPORT int +xkb_context_include_path_reset_defaults(struct xkb_context *ctx) { - xkb_context_include_path_clear(context); - return xkb_context_include_path_append_default(context); + 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_context_num_include_paths(struct xkb_context *context) +XKB_EXPORT unsigned int +xkb_context_num_include_paths(struct xkb_context *ctx) { - return context->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_context_include_path_get(struct xkb_context *context, unsigned int idx) +XKB_EXPORT const char * +xkb_context_include_path_get(struct xkb_context *ctx, unsigned int idx) { - if (idx >= xkb_context_num_include_paths(context)) + if (idx >= xkb_context_num_include_paths(ctx)) return NULL; - return context->include_paths[idx]; + return darray_item(ctx->includes, idx); } /** * Take a new reference on the context. */ -_X_EXPORT struct xkb_context * -xkb_context_ref(struct xkb_context *context) +XKB_EXPORT struct xkb_context * +xkb_context_ref(struct xkb_context *ctx) { - context->refcnt++; - return context; + ctx->refcnt++; + return ctx; } /** * Drop an existing reference on the context, and free it if the refcnt is * now 0. */ -_X_EXPORT void -xkb_context_unref(struct xkb_context *context) +XKB_EXPORT void +xkb_context_unref(struct xkb_context *ctx) { - if (--context->refcnt > 0) + if (!ctx || --ctx->refcnt > 0) return; - xkb_context_include_path_clear(context); - free(context); + 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_context * -xkb_context_new(void) +XKB_EXPORT struct xkb_context * +xkb_context_new(enum xkb_context_flags flags) { - struct xkb_context *context = calloc(1, sizeof(*context)); + const char *env; + struct xkb_context *ctx = calloc(1, sizeof(*ctx)); - if (!context) + if (!ctx) return NULL; - context->refcnt = 1; + 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)); - if (!xkb_context_include_path_append_default(context)) { - xkb_context_unref(context); + 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_context_include_path_append_default(ctx)) { + log_err(ctx, "failed to add default include path %s\n", + DFLT_XKB_CONFIG_ROOT); + xkb_context_unref(ctx); return NULL; } - return context; + ctx->atom_table = atom_table_new(); + if (!ctx->atom_table) { + xkb_context_unref(ctx); + return NULL; + } + + ctx->x11_atom_cache = NULL; + + return ctx; +} + +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)) +{ + ctx->log_fn = (log_fn ? log_fn : default_log_fn); +} + +XKB_EXPORT enum xkb_log_level +xkb_context_get_log_level(struct xkb_context *ctx) +{ + return ctx->log_level; +} + +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) +{ + ctx->user_data = user_data; }