log: allow to resore default log function
[platform/upstream/libxkbcommon.git] / src / context.c
1 /*
2  * Copyright © 2012 Intel Corporation
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  *
23  * Author: Daniel Stone <daniel@fooishbar.org>
24  */
25
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <ctype.h>
29 #include <errno.h>
30 #include <stdarg.h>
31 #include <stdio.h>
32 #include <unistd.h>
33 #include <syslog.h>
34
35 #include "xkb-priv.h"
36 #include "atom.h"
37
38 struct xkb_context {
39     int refcnt;
40
41     ATTR_PRINTF(3, 0) void (*log_fn)(struct xkb_context *ctx, int priority,
42                                      const char *fmt, va_list args);
43     int log_priority;
44     int log_verbosity;
45     void *user_data;
46
47     darray(char *) includes;
48
49     /* xkbcomp needs to assign sequential IDs to XkbFile's it creates. */
50     unsigned file_id;
51
52     struct atom_table *atom_table;
53 };
54
55 /**
56  * Append one directory to the context's include path.
57  */
58 XKB_EXPORT int
59 xkb_context_include_path_append(struct xkb_context *ctx, const char *path)
60 {
61     struct stat stat_buf;
62     int err;
63     char *tmp;
64
65     err = stat(path, &stat_buf);
66     if (err != 0)
67         return 0;
68     if (!S_ISDIR(stat_buf.st_mode))
69         return 0;
70
71 #if defined(HAVE_EACCESS)
72     if (eaccess(path, R_OK | X_OK) != 0)
73         return 0;
74 #elif defined(HAVE_EUIDACCESS)
75     if (euidaccess(path, R_OK | X_OK) != 0)
76         return 0;
77 #endif
78
79     tmp = strdup(path);
80     if (!tmp)
81         return 0;
82
83     darray_append(ctx->includes, tmp);
84     return 1;
85 }
86
87 /**
88  * Append the default include directories to the context.
89  */
90 XKB_EXPORT int
91 xkb_context_include_path_append_default(struct xkb_context *ctx)
92 {
93     const char *home;
94     char *user_path;
95     int err;
96     int ret = 0;
97
98     ret |= xkb_context_include_path_append(ctx, DFLT_XKB_CONFIG_ROOT);
99
100     home = getenv("HOME");
101     if (!home)
102         return ret;
103     err = asprintf(&user_path, "%s/.xkb", home);
104     if (err <= 0)
105         return ret;
106     ret |= xkb_context_include_path_append(ctx, user_path);
107     free(user_path);
108
109     return ret;
110 }
111
112 /**
113  * Remove all entries in the context's include path.
114  */
115 XKB_EXPORT void
116 xkb_context_include_path_clear(struct xkb_context *ctx)
117 {
118     char **path;
119
120     darray_foreach(path, ctx->includes)
121     free(*path);
122
123     darray_free(ctx->includes);
124 }
125
126 /**
127  * xkb_context_include_path_clear() + xkb_context_include_path_append_default()
128  */
129 XKB_EXPORT int
130 xkb_context_include_path_reset_defaults(struct xkb_context *ctx)
131 {
132     xkb_context_include_path_clear(ctx);
133     return xkb_context_include_path_append_default(ctx);
134 }
135
136 /**
137  * Returns the number of entries in the context's include path.
138  */
139 XKB_EXPORT unsigned int
140 xkb_context_num_include_paths(struct xkb_context *ctx)
141 {
142     return darray_size(ctx->includes);
143 }
144
145 /**
146  * Returns the given entry in the context's include path, or NULL if an
147  * invalid index is passed.
148  */
149 XKB_EXPORT const char *
150 xkb_context_include_path_get(struct xkb_context *ctx, unsigned int idx)
151 {
152     if (idx >= xkb_context_num_include_paths(ctx))
153         return NULL;
154
155     return darray_item(ctx->includes, idx);
156 }
157
158 unsigned
159 xkb_context_take_file_id(struct xkb_context *ctx)
160 {
161     return ctx->file_id++;
162 }
163
164 /**
165  * Take a new reference on the context.
166  */
167 XKB_EXPORT struct xkb_context *
168 xkb_context_ref(struct xkb_context *ctx)
169 {
170     ctx->refcnt++;
171     return ctx;
172 }
173
174 /**
175  * Drop an existing reference on the context, and free it if the refcnt is
176  * now 0.
177  */
178 XKB_EXPORT void
179 xkb_context_unref(struct xkb_context *ctx)
180 {
181     if (--ctx->refcnt > 0)
182         return;
183
184     xkb_context_include_path_clear(ctx);
185     atom_table_free(ctx->atom_table);
186     free(ctx);
187 }
188
189 static const char *
190 priority_to_prefix(int priority)
191 {
192     switch (priority) {
193     case LOG_DEBUG:
194         return "Debug:";
195     case LOG_INFO:
196         return "Info:";
197     case LOG_WARNING:
198         return "Warning:";
199     case LOG_ERR:
200         return "Error:";
201     case LOG_CRIT:
202     case LOG_ALERT:
203     case LOG_EMERG:
204         return "Internal error:";
205     default:
206         return NULL;
207     }
208 }
209
210 ATTR_PRINTF(3, 0) static void
211 default_log_fn(struct xkb_context *ctx, int priority,
212                const char *fmt, va_list args)
213 {
214     const char *prefix = priority_to_prefix(priority);
215
216     if (prefix)
217         fprintf(stderr, "%-15s", prefix);
218     vfprintf(stderr, fmt, args);
219 }
220
221 static int
222 log_priority(const char *priority) {
223     char *endptr;
224     int prio;
225
226     errno = 0;
227     prio = strtol(priority, &endptr, 10);
228     if (errno == 0 && (endptr[0] == '\0' || isspace(endptr[0])))
229         return prio;
230     if (strncasecmp(priority, "err", 3) == 0)
231         return LOG_ERR;
232     if (strncasecmp(priority, "warn", 4) == 0)
233         return LOG_WARNING;
234     if (strncasecmp(priority, "info", 4) == 0)
235         return LOG_INFO;
236     if (strncasecmp(priority, "debug", 5) == 0)
237         return LOG_DEBUG;
238
239     return LOG_ERR;
240 }
241
242 static int
243 log_verbosity(const char *verbosity) {
244     char *endptr;
245     int v;
246
247     errno = 0;
248     v = strtol(verbosity, &endptr, 10);
249     if (errno == 0)
250         return v;
251
252     return 0;
253 }
254
255 /**
256  * Create a new context.
257  */
258 XKB_EXPORT struct xkb_context *
259 xkb_context_new(enum xkb_context_flags flags)
260 {
261     const char *env;
262     struct xkb_context *ctx = calloc(1, sizeof(*ctx));
263
264     if (!ctx)
265         return NULL;
266
267     ctx->refcnt = 1;
268     ctx->log_fn = default_log_fn;
269     ctx->log_priority = LOG_ERR;
270     ctx->log_verbosity = 0;
271
272     /* Environment overwrites defaults. */
273     env = getenv("XKB_LOG");
274     if (env)
275         xkb_set_log_priority(ctx, log_priority(env));
276
277     env = getenv("XKB_VERBOSITY");
278     if (env)
279         xkb_set_log_verbosity(ctx, log_verbosity(env));
280
281     if (!(flags & XKB_CONTEXT_NO_DEFAULT_INCLUDES) &&
282         !xkb_context_include_path_append_default(ctx)) {
283         log_err(ctx, "failed to add default include path %s\n",
284                 DFLT_XKB_CONFIG_ROOT);
285         xkb_context_unref(ctx);
286         return NULL;
287     }
288
289     ctx->atom_table = atom_table_new();
290     if (!ctx->atom_table) {
291         xkb_context_unref(ctx);
292         return NULL;
293     }
294
295     return ctx;
296 }
297
298 xkb_atom_t
299 xkb_atom_intern(struct xkb_context *ctx, const char *string)
300 {
301     return atom_intern(ctx->atom_table, string, false);
302 }
303
304 xkb_atom_t
305 xkb_atom_steal(struct xkb_context *ctx, char *string)
306 {
307     return atom_intern(ctx->atom_table, string, true);
308 }
309
310 char *
311 xkb_atom_strdup(struct xkb_context *ctx, xkb_atom_t atom)
312 {
313     return atom_strdup(ctx->atom_table, atom);
314 }
315
316 const char *
317 xkb_atom_text(struct xkb_context *ctx, xkb_atom_t atom)
318 {
319     return atom_text(ctx->atom_table, atom);
320 }
321
322 void
323 xkb_log(struct xkb_context *ctx, int priority, const char *fmt, ...)
324 {
325     va_list args;
326
327     va_start(args, fmt);
328     ctx->log_fn(ctx, priority, fmt, args);
329     va_end(args);
330 }
331
332 XKB_EXPORT void
333 xkb_set_log_fn(struct xkb_context *ctx,
334                void (*log_fn)(struct xkb_context *ctx, int priority,
335                               const char *fmt, va_list args))
336 {
337     ctx->log_fn = (log_fn ? log_fn : default_log_fn);
338 }
339
340 XKB_EXPORT int
341 xkb_get_log_priority(struct xkb_context *ctx)
342 {
343     return ctx->log_priority;
344 }
345
346 XKB_EXPORT void
347 xkb_set_log_priority(struct xkb_context *ctx, int priority)
348 {
349     ctx->log_priority = priority;
350 }
351
352 XKB_EXPORT int
353 xkb_get_log_verbosity(struct xkb_context *ctx)
354 {
355     return ctx->log_verbosity;
356 }
357
358 XKB_EXPORT void
359 xkb_set_log_verbosity(struct xkb_context *ctx, int verbosity)
360 {
361     ctx->log_verbosity = verbosity;
362 }
363
364 XKB_EXPORT void *
365 xkb_get_user_data(struct xkb_context *ctx)
366 {
367     if (ctx)
368         return ctx->user_data;
369     return NULL;
370 }
371
372 XKB_EXPORT void
373 xkb_set_user_data(struct xkb_context *ctx, void *user_data)
374 {
375     ctx->user_data = user_data;
376 }