1 /*
2 * Copyright © 2014 Ran Benita <ran234@gmail.com>
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
24 #include "utils.h"
25 #include "paths.h"
26
27 enum resolve_name_direction {
28 LEFT_TO_RIGHT,
29 RIGHT_TO_LEFT,
30 };
31
32 const char *
get_xlocaledir_path(void)33 get_xlocaledir_path(void)
34 {
35 const char *dir = secure_getenv("XLOCALEDIR");
36 if (!dir)
37 dir = XLOCALEDIR;
38 return dir;
39 }
40
41 /*
42 * Files like compose.dir have the format LEFT: RIGHT. Lookup @name in
43 * such a file and return its matching value, according to @direction.
44 * @filename is relative to the xlocaledir.
45 */
46 static char *
resolve_name(const char * filename,enum resolve_name_direction direction,const char * name)47 resolve_name(const char *filename, enum resolve_name_direction direction,
48 const char *name)
49 {
50 int ret;
51 bool ok;
52 const char *xlocaledir;
53 char path[512];
54 FILE *file;
55 const char *string, *end;
56 size_t string_size;
57 const char *s, *left, *right;
58 char *match;
59 size_t left_len, right_len, name_len;
60
61 xlocaledir = get_xlocaledir_path();
62
63 ret = snprintf(path, sizeof(path), "%s/%s", xlocaledir, filename);
64 if (ret < 0 || (size_t) ret >= sizeof(path))
65 return false;
66
67 file = fopen(path, "r");
68 if (!file)
69 return false;
70
71 ok = map_file(file, &string, &string_size);
72 fclose(file);
73 if (!ok)
74 return false;
75
76 s = string;
77 end = string + string_size;
78 name_len = strlen(name);
79 match = NULL;
80
81 while (s < end) {
82 /* Skip spaces. */
83 while (s < end && is_space(*s))
84 s++;
85
86 /* Skip comments. */
87 if (s < end && *s == '#') {
88 while (s < end && *s != '\n')
89 s++;
90 continue;
91 }
92
93 /* Get the left value. */
94 left = s;
95 while (s < end && !is_space(*s) && *s != ':')
96 s++;
97 left_len = s - left;
98
99 /* There's an optional colon between left and right. */
100 if (s < end && *s == ':')
101 s++;
102
103 /* Skip spaces. */
104 while (s < end && is_space(*s))
105 s++;
106
107 /* Get the right value. */
108 right = s;
109 while (s < end && !is_space(*s))
110 s++;
111 right_len = s - right;
112
113 /* Discard rest of line. */
114 while (s < end && *s != '\n')
115 s++;
116
117 if (direction == LEFT_TO_RIGHT) {
118 if (left_len == name_len && memcmp(left, name, left_len) == 0) {
119 match = strndup(right, right_len);
120 break;
121 }
122 }
123 else if (direction == RIGHT_TO_LEFT) {
124 if (right_len == name_len && memcmp(right, name, right_len) == 0) {
125 match = strndup(left, left_len);
126 break;
127 }
128 }
129 }
130
131 unmap_file(string, string_size);
132 return match;
133 }
134
135 char *
resolve_locale(const char * locale)136 resolve_locale(const char *locale)
137 {
138 char *alias = resolve_name("locale.alias", LEFT_TO_RIGHT, locale);
139 return alias ? alias : strdup(locale);
140 }
141
142 const char *
get_xcomposefile_path(void)143 get_xcomposefile_path(void)
144 {
145 return secure_getenv("XCOMPOSEFILE");
146 }
147
148 char *
get_home_xcompose_file_path(void)149 get_home_xcompose_file_path(void)
150 {
151 int ret;
152 const char *home;
153 char *path;
154
155 home = secure_getenv("HOME");
156 if (!home)
157 return NULL;
158
159 ret = asprintf(&path, "%s/.XCompose", home);
160 if (ret <0)
161 return NULL;
162
163 return path;
164 }
165
166 char *
get_locale_compose_file_path(const char * locale)167 get_locale_compose_file_path(const char *locale)
168 {
169 int ret;
170 const char *xlocaledir;
171 char *resolved;
172 char *path;
173
174 /*
175 * WARNING: Random workaround ahead.
176 *
177 * We currently do not support non-UTF-8 Compose files. The C/POSIX
178 * locale is specified to be the default fallback locale with an
179 * ASCII charset. But for some reason the compose.dir points the C
180 * locale to the iso8859-1/Compose file, which is not ASCII but
181 * ISO8859-1. Since this is bound to happen a lot, and since our API
182 * is UTF-8 based, and since 99% of the time a C locale is really just
183 * a misconfiguration for UTF-8, let's do the most helpful thing.
184 */
185 if (streq(locale, "C"))
186 locale = "en_US.UTF-8";
187
188 resolved = resolve_name("compose.dir", RIGHT_TO_LEFT, locale);
189 if (!resolved)
190 return NULL;
191
192 if (resolved[0] == '/') {
193 path = resolved;
194 }
195 else {
196 xlocaledir = get_xlocaledir_path();
197 ret = asprintf(&path, "%s/%s", xlocaledir, resolved);
198 free(resolved);
199 if (ret < 0)
200 return NULL;
201 }
202
203 return path;
204 }
205