Home | History | Annotate | Download | only in src
      1 /*
      2  * Copyright  2012 Intel Corporation
      3  * Copyright  2012 Ran Benita
      4  *
      5  * Permission is hereby granted, free of charge, to any person obtaining a
      6  * copy of this software and associated documentation files (the "Software"),
      7  * to deal in the Software without restriction, including without limitation
      8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      9  * and/or sell copies of the Software, and to permit persons to whom the
     10  * Software is furnished to do so, subject to the following conditions:
     11  *
     12  * The above copyright notice and this permission notice (including the next
     13  * paragraph) shall be included in all copies or substantial portions of the
     14  * Software.
     15  *
     16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
     22  * DEALINGS IN THE SOFTWARE.
     23  *
     24  * Author: Daniel Stone <daniel (at) fooishbar.org>
     25  */
     26 
     27 #include <sys/types.h>
     28 #include <sys/stat.h>
     29 #include <errno.h>
     30 #include <unistd.h>
     31 
     32 #include "xkbcommon/xkbcommon.h"
     33 #include "utils.h"
     34 #include "context.h"
     35 
     36 /**
     37  * Append one directory to the context's include path.
     38  */
     39 XKB_EXPORT int
     40 xkb_context_include_path_append(struct xkb_context *ctx, const char *path)
     41 {
     42     struct stat stat_buf;
     43     int err;
     44     char *tmp;
     45 
     46     tmp = strdup(path);
     47     if (!tmp)
     48         goto err;
     49 
     50     err = stat(path, &stat_buf);
     51     if (err != 0)
     52         goto err;
     53     if (!S_ISDIR(stat_buf.st_mode))
     54         goto err;
     55 
     56 #if defined(HAVE_EACCESS)
     57     if (eaccess(path, R_OK | X_OK) != 0)
     58         goto err;
     59 #elif defined(HAVE_EUIDACCESS)
     60     if (euidaccess(path, R_OK | X_OK) != 0)
     61         goto err;
     62 #endif
     63 
     64     darray_append(ctx->includes, tmp);
     65     return 1;
     66 
     67 err:
     68     darray_append(ctx->failed_includes, tmp);
     69     return 0;
     70 }
     71 
     72 /**
     73  * Append the default include directories to the context.
     74  */
     75 XKB_EXPORT int
     76 xkb_context_include_path_append_default(struct xkb_context *ctx)
     77 {
     78     const char *home;
     79     char *user_path;
     80     int err;
     81     int ret = 0;
     82 
     83     ret |= xkb_context_include_path_append(ctx, DFLT_XKB_CONFIG_ROOT);
     84 
     85     home = secure_getenv("HOME");
     86     if (!home)
     87         return ret;
     88     err = asprintf(&user_path, "%s/.xkb", home);
     89     if (err <= 0)
     90         return ret;
     91     ret |= xkb_context_include_path_append(ctx, user_path);
     92     free(user_path);
     93 
     94     return ret;
     95 }
     96 
     97 /**
     98  * Remove all entries in the context's include path.
     99  */
    100 XKB_EXPORT void
    101 xkb_context_include_path_clear(struct xkb_context *ctx)
    102 {
    103     char **path;
    104 
    105     darray_foreach(path, ctx->includes)
    106         free(*path);
    107     darray_free(ctx->includes);
    108 
    109     darray_foreach(path, ctx->failed_includes)
    110         free(*path);
    111     darray_free(ctx->failed_includes);
    112 }
    113 
    114 /**
    115  * xkb_context_include_path_clear() + xkb_context_include_path_append_default()
    116  */
    117 XKB_EXPORT int
    118 xkb_context_include_path_reset_defaults(struct xkb_context *ctx)
    119 {
    120     xkb_context_include_path_clear(ctx);
    121     return xkb_context_include_path_append_default(ctx);
    122 }
    123 
    124 /**
    125  * Returns the number of entries in the context's include path.
    126  */
    127 XKB_EXPORT unsigned int
    128 xkb_context_num_include_paths(struct xkb_context *ctx)
    129 {
    130     return darray_size(ctx->includes);
    131 }
    132 
    133 /**
    134  * Returns the given entry in the context's include path, or NULL if an
    135  * invalid index is passed.
    136  */
    137 XKB_EXPORT const char *
    138 xkb_context_include_path_get(struct xkb_context *ctx, unsigned int idx)
    139 {
    140     if (idx >= xkb_context_num_include_paths(ctx))
    141         return NULL;
    142 
    143     return darray_item(ctx->includes, idx);
    144 }
    145 
    146 /**
    147  * Take a new reference on the context.
    148  */
    149 XKB_EXPORT struct xkb_context *
    150 xkb_context_ref(struct xkb_context *ctx)
    151 {
    152     ctx->refcnt++;
    153     return ctx;
    154 }
    155 
    156 /**
    157  * Drop an existing reference on the context, and free it if the refcnt is
    158  * now 0.
    159  */
    160 XKB_EXPORT void
    161 xkb_context_unref(struct xkb_context *ctx)
    162 {
    163     if (!ctx || --ctx->refcnt > 0)
    164         return;
    165 
    166     xkb_context_include_path_clear(ctx);
    167     atom_table_free(ctx->atom_table);
    168     free(ctx);
    169 }
    170 
    171 static const char *
    172 log_level_to_prefix(enum xkb_log_level level)
    173 {
    174     switch (level) {
    175     case XKB_LOG_LEVEL_DEBUG:
    176         return "xkbcommon: DEBUG: ";
    177     case XKB_LOG_LEVEL_INFO:
    178         return "xkbcommon: INFO: ";
    179     case XKB_LOG_LEVEL_WARNING:
    180         return "xkbcommon: WARNING: ";
    181     case XKB_LOG_LEVEL_ERROR:
    182         return "xkbcommon: ERROR: ";
    183     case XKB_LOG_LEVEL_CRITICAL:
    184         return "xkbcommon: CRITICAL: ";
    185     default:
    186         return NULL;
    187     }
    188 }
    189 
    190 ATTR_PRINTF(3, 0) static void
    191 default_log_fn(struct xkb_context *ctx, enum xkb_log_level level,
    192                const char *fmt, va_list args)
    193 {
    194     const char *prefix = log_level_to_prefix(level);
    195 
    196     if (prefix)
    197         fprintf(stderr, "%s", prefix);
    198     vfprintf(stderr, fmt, args);
    199 }
    200 
    201 static enum xkb_log_level
    202 log_level(const char *level) {
    203     char *endptr;
    204     enum xkb_log_level lvl;
    205 
    206     errno = 0;
    207     lvl = strtol(level, &endptr, 10);
    208     if (errno == 0 && (endptr[0] == '\0' || is_space(endptr[0])))
    209         return lvl;
    210     if (istreq_prefix("crit", level))
    211         return XKB_LOG_LEVEL_CRITICAL;
    212     if (istreq_prefix("err", level))
    213         return XKB_LOG_LEVEL_ERROR;
    214     if (istreq_prefix("warn", level))
    215         return XKB_LOG_LEVEL_WARNING;
    216     if (istreq_prefix("info", level))
    217         return XKB_LOG_LEVEL_INFO;
    218     if (istreq_prefix("debug", level) || istreq_prefix("dbg", level))
    219         return XKB_LOG_LEVEL_DEBUG;
    220 
    221     return XKB_LOG_LEVEL_ERROR;
    222 }
    223 
    224 static int
    225 log_verbosity(const char *verbosity) {
    226     char *endptr;
    227     int v;
    228 
    229     errno = 0;
    230     v = strtol(verbosity, &endptr, 10);
    231     if (errno == 0)
    232         return v;
    233 
    234     return 0;
    235 }
    236 
    237 /**
    238  * Create a new context.
    239  */
    240 XKB_EXPORT struct xkb_context *
    241 xkb_context_new(enum xkb_context_flags flags)
    242 {
    243     const char *env;
    244     struct xkb_context *ctx = calloc(1, sizeof(*ctx));
    245 
    246     if (!ctx)
    247         return NULL;
    248 
    249     ctx->refcnt = 1;
    250     ctx->log_fn = default_log_fn;
    251     ctx->log_level = XKB_LOG_LEVEL_ERROR;
    252     ctx->log_verbosity = 0;
    253 
    254     /* Environment overwrites defaults. */
    255     env = secure_getenv("XKB_LOG_LEVEL");
    256     if (env)
    257         xkb_context_set_log_level(ctx, log_level(env));
    258 
    259     env = secure_getenv("XKB_LOG_VERBOSITY");
    260     if (env)
    261         xkb_context_set_log_verbosity(ctx, log_verbosity(env));
    262 
    263     if (!(flags & XKB_CONTEXT_NO_DEFAULT_INCLUDES) &&
    264         !xkb_context_include_path_append_default(ctx)) {
    265         log_err(ctx, "failed to add default include path %s\n",
    266                 DFLT_XKB_CONFIG_ROOT);
    267         xkb_context_unref(ctx);
    268         return NULL;
    269     }
    270 
    271     ctx->use_environment_names = !(flags & XKB_CONTEXT_NO_ENVIRONMENT_NAMES);
    272 
    273     ctx->atom_table = atom_table_new();
    274     if (!ctx->atom_table) {
    275         xkb_context_unref(ctx);
    276         return NULL;
    277     }
    278 
    279     return ctx;
    280 }
    281 
    282 XKB_EXPORT void
    283 xkb_context_set_log_fn(struct xkb_context *ctx,
    284                        void (*log_fn)(struct xkb_context *ctx,
    285                                       enum xkb_log_level level,
    286                                       const char *fmt, va_list args))
    287 {
    288     ctx->log_fn = (log_fn ? log_fn : default_log_fn);
    289 }
    290 
    291 XKB_EXPORT enum xkb_log_level
    292 xkb_context_get_log_level(struct xkb_context *ctx)
    293 {
    294     return ctx->log_level;
    295 }
    296 
    297 XKB_EXPORT void
    298 xkb_context_set_log_level(struct xkb_context *ctx, enum xkb_log_level level)
    299 {
    300     ctx->log_level = level;
    301 }
    302 
    303 XKB_EXPORT int
    304 xkb_context_get_log_verbosity(struct xkb_context *ctx)
    305 {
    306     return ctx->log_verbosity;
    307 }
    308 
    309 XKB_EXPORT void
    310 xkb_context_set_log_verbosity(struct xkb_context *ctx, int verbosity)
    311 {
    312     ctx->log_verbosity = verbosity;
    313 }
    314 
    315 XKB_EXPORT void *
    316 xkb_context_get_user_data(struct xkb_context *ctx)
    317 {
    318     if (ctx)
    319         return ctx->user_data;
    320     return NULL;
    321 }
    322 
    323 XKB_EXPORT void
    324 xkb_context_set_user_data(struct xkb_context *ctx, void *user_data)
    325 {
    326     ctx->user_data = user_data;
    327 }
    328