2 * Copyright © 2014 Ran Benita <ran234@gmail.com>
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:
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
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.
26 #include "xkbcommon/xkbcommon.h"
31 enum resolve_name_direction {
37 get_xlocaledir_path(struct xkb_context *ctx)
39 const char *dir = xkb_context_getenv(ctx, "XLOCALEDIR");
46 * Files like compose.dir have the format LEFT: RIGHT. Lookup @name in
47 * such a file and return its matching value, according to @direction.
48 * @filename is relative to the xlocaledir.
51 resolve_name(struct xkb_context *ctx, const char *filename,
52 enum resolve_name_direction direction, const char *name)
56 const char *xlocaledir;
62 const char *s, *left, *right;
64 size_t left_len, right_len, name_len;
66 xlocaledir = get_xlocaledir_path(ctx);
68 ret = snprintf(path, sizeof(path), "%s/%s", xlocaledir, filename);
69 if (ret < 0 || (size_t) ret >= sizeof(path))
72 file = fopen(path, "rb");
76 ok = map_file(file, &string, &string_size);
82 end = string + string_size;
83 name_len = strlen(name);
88 while (s < end && is_space(*s))
92 if (s < end && *s == '#') {
93 while (s < end && *s != '\n')
98 /* Get the left value. */
100 while (s < end && !is_space(*s) && *s != ':')
104 /* There's an optional colon between left and right. */
105 if (s < end && *s == ':')
109 while (s < end && is_space(*s))
112 /* Get the right value. */
114 while (s < end && !is_space(*s))
116 right_len = s - right;
118 /* Discard rest of line. */
119 while (s < end && *s != '\n')
122 if (direction == LEFT_TO_RIGHT) {
123 if (left_len == name_len && memcmp(left, name, left_len) == 0) {
124 match = strndup(right, right_len);
128 else if (direction == RIGHT_TO_LEFT) {
129 if (right_len == name_len && memcmp(right, name, right_len) == 0) {
130 match = strndup(left, left_len);
136 unmap_file(string, string_size);
141 resolve_locale(struct xkb_context *ctx, const char *locale)
143 char *alias = resolve_name(ctx, "locale.alias", LEFT_TO_RIGHT, locale);
144 return alias ? alias : strdup(locale);
148 get_xcomposefile_path(struct xkb_context *ctx)
150 return strdup_safe(xkb_context_getenv(ctx, "XCOMPOSEFILE"));
154 get_xdg_xcompose_file_path(struct xkb_context *ctx)
156 const char *xdg_config_home;
159 xdg_config_home = xkb_context_getenv(ctx, "XDG_CONFIG_HOME");
160 if (!xdg_config_home || xdg_config_home[0] != '/') {
161 home = xkb_context_getenv(ctx, "HOME");
164 return asprintf_safe("%s/.config/XCompose", home);
167 return asprintf_safe("%s/XCompose", xdg_config_home);
171 get_home_xcompose_file_path(struct xkb_context *ctx)
175 home = xkb_context_getenv(ctx, "HOME");
179 return asprintf_safe("%s/.XCompose", home);
183 get_locale_compose_file_path(struct xkb_context *ctx, const char *locale)
189 * WARNING: Random workaround ahead.
191 * We currently do not support non-UTF-8 Compose files. The C/POSIX
192 * locale is specified to be the default fallback locale with an
193 * ASCII charset. But for some reason the compose.dir points the C
194 * locale to the iso8859-1/Compose file, which is not ASCII but
195 * ISO8859-1. Since this is bound to happen a lot, and since our API
196 * is UTF-8 based, and since 99% of the time a C locale is really just
197 * a misconfiguration for UTF-8, let's do the most helpful thing.
199 if (streq(locale, "C"))
200 locale = "en_US.UTF-8";
202 resolved = resolve_name(ctx, "compose.dir", RIGHT_TO_LEFT, locale);
206 if (resolved[0] == '/') {
210 const char *xlocaledir = get_xlocaledir_path(ctx);
211 path = asprintf_safe("%s/%s", xlocaledir, resolved);