atom: drop {xkb_,}atom_strdup
[platform/upstream/libxkbcommon.git] / src / context.c
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@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 struct xkb_context {
37     int refcnt;
38
39     ATTR_PRINTF(3, 0) void (*log_fn)(struct xkb_context *ctx,
40                                      enum xkb_log_level level,
41                                      const char *fmt, va_list args);
42     enum xkb_log_level log_level;
43     int log_verbosity;
44     void *user_data;
45
46     struct xkb_rule_names names_dflt;
47
48     darray(char *) includes;
49     darray(char *) failed_includes;
50
51     struct atom_table *atom_table;
52
53     /* Buffer for the *Text() functions. */
54     char text_buffer[2048];
55     size_t text_next;
56
57     unsigned int use_environment_names : 1;
58 };
59
60 /**
61  * Append one directory to the context's include path.
62  */
63 XKB_EXPORT int
64 xkb_context_include_path_append(struct xkb_context *ctx, const char *path)
65 {
66     struct stat stat_buf;
67     int err;
68     char *tmp;
69
70     tmp = strdup(path);
71     if (!tmp)
72         goto err;
73
74     err = stat(path, &stat_buf);
75     if (err != 0)
76         goto err;
77     if (!S_ISDIR(stat_buf.st_mode))
78         goto err;
79
80 #if defined(HAVE_EACCESS)
81     if (eaccess(path, R_OK | X_OK) != 0)
82         goto err;
83 #elif defined(HAVE_EUIDACCESS)
84     if (euidaccess(path, R_OK | X_OK) != 0)
85         goto err;
86 #endif
87
88     darray_append(ctx->includes, tmp);
89     return 1;
90
91 err:
92     darray_append(ctx->failed_includes, tmp);
93     return 0;
94 }
95
96 /**
97  * Append the default include directories to the context.
98  */
99 XKB_EXPORT int
100 xkb_context_include_path_append_default(struct xkb_context *ctx)
101 {
102     const char *home;
103     char *user_path;
104     int err;
105     int ret = 0;
106
107     ret |= xkb_context_include_path_append(ctx, DFLT_XKB_CONFIG_ROOT);
108
109     home = getenv("HOME");
110     if (!home)
111         return ret;
112     err = asprintf(&user_path, "%s/.xkb", home);
113     if (err <= 0)
114         return ret;
115     ret |= xkb_context_include_path_append(ctx, user_path);
116     free(user_path);
117
118     return ret;
119 }
120
121 /**
122  * Remove all entries in the context's include path.
123  */
124 XKB_EXPORT void
125 xkb_context_include_path_clear(struct xkb_context *ctx)
126 {
127     char **path;
128
129     darray_foreach(path, ctx->includes)
130         free(*path);
131     darray_free(ctx->includes);
132
133     darray_foreach(path, ctx->failed_includes)
134         free(*path);
135     darray_free(ctx->failed_includes);
136 }
137
138 /**
139  * xkb_context_include_path_clear() + xkb_context_include_path_append_default()
140  */
141 XKB_EXPORT int
142 xkb_context_include_path_reset_defaults(struct xkb_context *ctx)
143 {
144     xkb_context_include_path_clear(ctx);
145     return xkb_context_include_path_append_default(ctx);
146 }
147
148 /**
149  * Returns the number of entries in the context's include path.
150  */
151 XKB_EXPORT unsigned int
152 xkb_context_num_include_paths(struct xkb_context *ctx)
153 {
154     return darray_size(ctx->includes);
155 }
156
157 unsigned int
158 xkb_context_num_failed_include_paths(struct xkb_context *ctx)
159 {
160     return darray_size(ctx->failed_includes);
161 }
162
163 /**
164  * Returns the given entry in the context's include path, or NULL if an
165  * invalid index is passed.
166  */
167 XKB_EXPORT const char *
168 xkb_context_include_path_get(struct xkb_context *ctx, unsigned int idx)
169 {
170     if (idx >= xkb_context_num_include_paths(ctx))
171         return NULL;
172
173     return darray_item(ctx->includes, idx);
174 }
175
176 const char *
177 xkb_context_failed_include_path_get(struct xkb_context *ctx,
178                                     unsigned int idx)
179 {
180     if (idx >= xkb_context_num_failed_include_paths(ctx))
181         return NULL;
182
183     return darray_item(ctx->failed_includes, idx);
184 }
185
186 /**
187  * Take a new reference on the context.
188  */
189 XKB_EXPORT struct xkb_context *
190 xkb_context_ref(struct xkb_context *ctx)
191 {
192     ctx->refcnt++;
193     return ctx;
194 }
195
196 /**
197  * Drop an existing reference on the context, and free it if the refcnt is
198  * now 0.
199  */
200 XKB_EXPORT void
201 xkb_context_unref(struct xkb_context *ctx)
202 {
203     if (!ctx || --ctx->refcnt > 0)
204         return;
205
206     xkb_context_include_path_clear(ctx);
207     atom_table_free(ctx->atom_table);
208     free(ctx);
209 }
210
211 static const char *
212 log_level_to_prefix(enum xkb_log_level level)
213 {
214     switch (level) {
215     case XKB_LOG_LEVEL_DEBUG:
216         return "xkbcommon: DEBUG: ";
217     case XKB_LOG_LEVEL_INFO:
218         return "xkbcommon: INFO: ";
219     case XKB_LOG_LEVEL_WARNING:
220         return "xkbcommon: WARNING: ";
221     case XKB_LOG_LEVEL_ERROR:
222         return "xkbcommon: ERROR: ";
223     case XKB_LOG_LEVEL_CRITICAL:
224         return "xkbcommon: CRITICAL: ";
225     default:
226         return NULL;
227     }
228 }
229
230 ATTR_PRINTF(3, 0) static void
231 default_log_fn(struct xkb_context *ctx, enum xkb_log_level level,
232                const char *fmt, va_list args)
233 {
234     const char *prefix = log_level_to_prefix(level);
235
236     if (prefix)
237         fprintf(stderr, "%s", prefix);
238     vfprintf(stderr, fmt, args);
239 }
240
241 static enum xkb_log_level
242 log_level(const char *level) {
243     char *endptr;
244     enum xkb_log_level lvl;
245
246     errno = 0;
247     lvl = strtol(level, &endptr, 10);
248     if (errno == 0 && (endptr[0] == '\0' || is_space(endptr[0])))
249         return lvl;
250     if (istreq_prefix("crit", level))
251         return XKB_LOG_LEVEL_CRITICAL;
252     if (istreq_prefix("err", level))
253         return XKB_LOG_LEVEL_ERROR;
254     if (istreq_prefix("warn", level))
255         return XKB_LOG_LEVEL_WARNING;
256     if (istreq_prefix("info", level))
257         return XKB_LOG_LEVEL_INFO;
258     if (istreq_prefix("debug", level) || istreq_prefix("dbg", level))
259         return XKB_LOG_LEVEL_DEBUG;
260
261     return XKB_LOG_LEVEL_ERROR;
262 }
263
264 static int
265 log_verbosity(const char *verbosity) {
266     char *endptr;
267     int v;
268
269     errno = 0;
270     v = strtol(verbosity, &endptr, 10);
271     if (errno == 0)
272         return v;
273
274     return 0;
275 }
276
277 #ifndef DEFAULT_XKB_VARIANT
278 #define DEFAULT_XKB_VARIANT NULL
279 #endif
280
281 #ifndef DEFAULT_XKB_OPTIONS
282 #define DEFAULT_XKB_OPTIONS NULL
283 #endif
284
285 /**
286  * Create a new context.
287  */
288 XKB_EXPORT struct xkb_context *
289 xkb_context_new(enum xkb_context_flags flags)
290 {
291     const char *env;
292     struct xkb_context *ctx = calloc(1, sizeof(*ctx));
293
294     if (!ctx)
295         return NULL;
296
297     ctx->refcnt = 1;
298     ctx->log_fn = default_log_fn;
299     ctx->log_level = XKB_LOG_LEVEL_ERROR;
300     ctx->log_verbosity = 0;
301
302     /* Environment overwrites defaults. */
303     env = getenv("XKB_LOG_LEVEL");
304     if (env)
305         xkb_context_set_log_level(ctx, log_level(env));
306
307     env = getenv("XKB_LOG_VERBOSITY");
308     if (env)
309         xkb_context_set_log_verbosity(ctx, log_verbosity(env));
310
311     if (!(flags & XKB_CONTEXT_NO_DEFAULT_INCLUDES) &&
312         !xkb_context_include_path_append_default(ctx)) {
313         log_err(ctx, "failed to add default include path %s\n",
314                 DFLT_XKB_CONFIG_ROOT);
315         xkb_context_unref(ctx);
316         return NULL;
317     }
318
319     ctx->use_environment_names = !(flags & XKB_CONTEXT_NO_ENVIRONMENT_NAMES);
320
321     ctx->atom_table = atom_table_new();
322     if (!ctx->atom_table) {
323         xkb_context_unref(ctx);
324         return NULL;
325     }
326
327     return ctx;
328 }
329
330 xkb_atom_t
331 xkb_atom_lookup(struct xkb_context *ctx, const char *string)
332 {
333     return atom_lookup(ctx->atom_table, string, strlen(string));
334 }
335
336 xkb_atom_t
337 xkb_atom_intern(struct xkb_context *ctx, const char *string, size_t len)
338 {
339     return atom_intern(ctx->atom_table, string, len, false);
340 }
341
342 xkb_atom_t
343 xkb_atom_steal(struct xkb_context *ctx, char *string)
344 {
345     return atom_intern(ctx->atom_table, string, strlen(string), true);
346 }
347
348 const char *
349 xkb_atom_text(struct xkb_context *ctx, xkb_atom_t atom)
350 {
351     return atom_text(ctx->atom_table, atom);
352 }
353
354 void
355 xkb_log(struct xkb_context *ctx, enum xkb_log_level level,
356         const char *fmt, ...)
357 {
358     va_list args;
359
360     va_start(args, fmt);
361     ctx->log_fn(ctx, level, fmt, args);
362     va_end(args);
363 }
364
365 XKB_EXPORT void
366 xkb_context_set_log_fn(struct xkb_context *ctx,
367                        void (*log_fn)(struct xkb_context *ctx,
368                                       enum xkb_log_level level,
369                                       const char *fmt, va_list args))
370 {
371     ctx->log_fn = (log_fn ? log_fn : default_log_fn);
372 }
373
374 XKB_EXPORT enum xkb_log_level
375 xkb_context_get_log_level(struct xkb_context *ctx)
376 {
377     return ctx->log_level;
378 }
379
380 XKB_EXPORT void
381 xkb_context_set_log_level(struct xkb_context *ctx, enum xkb_log_level level)
382 {
383     ctx->log_level = level;
384 }
385
386 XKB_EXPORT int
387 xkb_context_get_log_verbosity(struct xkb_context *ctx)
388 {
389     return ctx->log_verbosity;
390 }
391
392 XKB_EXPORT void
393 xkb_context_set_log_verbosity(struct xkb_context *ctx, int verbosity)
394 {
395     ctx->log_verbosity = verbosity;
396 }
397
398 XKB_EXPORT void *
399 xkb_context_get_user_data(struct xkb_context *ctx)
400 {
401     if (ctx)
402         return ctx->user_data;
403     return NULL;
404 }
405
406 XKB_EXPORT void
407 xkb_context_set_user_data(struct xkb_context *ctx, void *user_data)
408 {
409     ctx->user_data = user_data;
410 }
411
412 char *
413 xkb_context_get_buffer(struct xkb_context *ctx, size_t size)
414 {
415     char *rtrn;
416
417     if (size >= sizeof(ctx->text_buffer))
418         return NULL;
419
420     if (sizeof(ctx->text_buffer) - ctx->text_next <= size)
421         ctx->text_next = 0;
422
423     rtrn = &ctx->text_buffer[ctx->text_next];
424     ctx->text_next += size;
425
426     return rtrn;
427 }
428
429 const char *
430 xkb_context_get_default_rules(struct xkb_context *ctx)
431 {
432     const char *env = NULL;
433
434     if (ctx->use_environment_names)
435         env = getenv("XKB_DEFAULT_RULES");
436
437     return env ? env : DEFAULT_XKB_RULES;
438 }
439
440 const char *
441 xkb_context_get_default_model(struct xkb_context *ctx)
442 {
443     const char *env = NULL;
444
445     if (ctx->use_environment_names)
446         env = getenv("XKB_DEFAULT_MODEL");
447
448     return env ? env : DEFAULT_XKB_MODEL;
449 }
450
451 const char *
452 xkb_context_get_default_layout(struct xkb_context *ctx)
453 {
454     const char *env = NULL;
455
456     if (ctx->use_environment_names)
457         env = getenv("XKB_DEFAULT_LAYOUT");
458
459     return env ? env : DEFAULT_XKB_LAYOUT;
460 }
461
462 const char *
463 xkb_context_get_default_variant(struct xkb_context *ctx)
464 {
465     const char *env = NULL;
466     const char *layout = getenv("XKB_DEFAULT_VARIANT");
467
468     /* We don't want to inherit the variant if they haven't also set a
469      * layout, since they're so closely paired. */
470     if (layout && ctx->use_environment_names)
471         env = getenv("XKB_DEFAULT_VARIANT");
472
473     return env ? env : DEFAULT_XKB_VARIANT;
474 }
475
476 const char *
477 xkb_context_get_default_options(struct xkb_context *ctx)
478 {
479     const char *env = NULL;
480
481     if (ctx->use_environment_names)
482         env = getenv("XKB_DEFAULT_OPTIONS");
483
484     return env ? env : DEFAULT_XKB_OPTIONS;
485 }