xref: /aosp_15_r20/external/libxkbcommon/src/compose/paths.c (revision 2b949d0487e80d67f1fda82db69e101e761f8064)
1*2b949d04SAndroid Build Coastguard Worker /*
2*2b949d04SAndroid Build Coastguard Worker  * Copyright © 2014 Ran Benita <[email protected]>
3*2b949d04SAndroid Build Coastguard Worker  *
4*2b949d04SAndroid Build Coastguard Worker  * Permission is hereby granted, free of charge, to any person obtaining a
5*2b949d04SAndroid Build Coastguard Worker  * copy of this software and associated documentation files (the "Software"),
6*2b949d04SAndroid Build Coastguard Worker  * to deal in the Software without restriction, including without limitation
7*2b949d04SAndroid Build Coastguard Worker  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8*2b949d04SAndroid Build Coastguard Worker  * and/or sell copies of the Software, and to permit persons to whom the
9*2b949d04SAndroid Build Coastguard Worker  * Software is furnished to do so, subject to the following conditions:
10*2b949d04SAndroid Build Coastguard Worker  *
11*2b949d04SAndroid Build Coastguard Worker  * The above copyright notice and this permission notice (including the next
12*2b949d04SAndroid Build Coastguard Worker  * paragraph) shall be included in all copies or substantial portions of the
13*2b949d04SAndroid Build Coastguard Worker  * Software.
14*2b949d04SAndroid Build Coastguard Worker  *
15*2b949d04SAndroid Build Coastguard Worker  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16*2b949d04SAndroid Build Coastguard Worker  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17*2b949d04SAndroid Build Coastguard Worker  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18*2b949d04SAndroid Build Coastguard Worker  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19*2b949d04SAndroid Build Coastguard Worker  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20*2b949d04SAndroid Build Coastguard Worker  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21*2b949d04SAndroid Build Coastguard Worker  * DEALINGS IN THE SOFTWARE.
22*2b949d04SAndroid Build Coastguard Worker  */
23*2b949d04SAndroid Build Coastguard Worker 
24*2b949d04SAndroid Build Coastguard Worker #include "config.h"
25*2b949d04SAndroid Build Coastguard Worker 
26*2b949d04SAndroid Build Coastguard Worker #include "utils.h"
27*2b949d04SAndroid Build Coastguard Worker #include "paths.h"
28*2b949d04SAndroid Build Coastguard Worker #include "utils.h"
29*2b949d04SAndroid Build Coastguard Worker 
30*2b949d04SAndroid Build Coastguard Worker enum resolve_name_direction {
31*2b949d04SAndroid Build Coastguard Worker     LEFT_TO_RIGHT,
32*2b949d04SAndroid Build Coastguard Worker     RIGHT_TO_LEFT,
33*2b949d04SAndroid Build Coastguard Worker };
34*2b949d04SAndroid Build Coastguard Worker 
35*2b949d04SAndroid Build Coastguard Worker const char *
get_xlocaledir_path(void)36*2b949d04SAndroid Build Coastguard Worker get_xlocaledir_path(void)
37*2b949d04SAndroid Build Coastguard Worker {
38*2b949d04SAndroid Build Coastguard Worker     const char *dir = secure_getenv("XLOCALEDIR");
39*2b949d04SAndroid Build Coastguard Worker     if (!dir)
40*2b949d04SAndroid Build Coastguard Worker         dir = XLOCALEDIR;
41*2b949d04SAndroid Build Coastguard Worker     return dir;
42*2b949d04SAndroid Build Coastguard Worker }
43*2b949d04SAndroid Build Coastguard Worker 
44*2b949d04SAndroid Build Coastguard Worker /*
45*2b949d04SAndroid Build Coastguard Worker  * Files like compose.dir have the format LEFT: RIGHT.  Lookup @name in
46*2b949d04SAndroid Build Coastguard Worker  * such a file and return its matching value, according to @direction.
47*2b949d04SAndroid Build Coastguard Worker  * @filename is relative to the xlocaledir.
48*2b949d04SAndroid Build Coastguard Worker  */
49*2b949d04SAndroid Build Coastguard Worker static char *
resolve_name(const char * filename,enum resolve_name_direction direction,const char * name)50*2b949d04SAndroid Build Coastguard Worker resolve_name(const char *filename, enum resolve_name_direction direction,
51*2b949d04SAndroid Build Coastguard Worker              const char *name)
52*2b949d04SAndroid Build Coastguard Worker {
53*2b949d04SAndroid Build Coastguard Worker     int ret;
54*2b949d04SAndroid Build Coastguard Worker     bool ok;
55*2b949d04SAndroid Build Coastguard Worker     const char *xlocaledir;
56*2b949d04SAndroid Build Coastguard Worker     char path[512];
57*2b949d04SAndroid Build Coastguard Worker     FILE *file;
58*2b949d04SAndroid Build Coastguard Worker     char *string;
59*2b949d04SAndroid Build Coastguard Worker     size_t string_size;
60*2b949d04SAndroid Build Coastguard Worker     const char *end;
61*2b949d04SAndroid Build Coastguard Worker     const char *s, *left, *right;
62*2b949d04SAndroid Build Coastguard Worker     char *match;
63*2b949d04SAndroid Build Coastguard Worker     size_t left_len, right_len, name_len;
64*2b949d04SAndroid Build Coastguard Worker 
65*2b949d04SAndroid Build Coastguard Worker     xlocaledir = get_xlocaledir_path();
66*2b949d04SAndroid Build Coastguard Worker 
67*2b949d04SAndroid Build Coastguard Worker     ret = snprintf(path, sizeof(path), "%s/%s", xlocaledir, filename);
68*2b949d04SAndroid Build Coastguard Worker     if (ret < 0 || (size_t) ret >= sizeof(path))
69*2b949d04SAndroid Build Coastguard Worker         return false;
70*2b949d04SAndroid Build Coastguard Worker 
71*2b949d04SAndroid Build Coastguard Worker     file = fopen(path, "rb");
72*2b949d04SAndroid Build Coastguard Worker     if (!file)
73*2b949d04SAndroid Build Coastguard Worker         return false;
74*2b949d04SAndroid Build Coastguard Worker 
75*2b949d04SAndroid Build Coastguard Worker     ok = map_file(file, &string, &string_size);
76*2b949d04SAndroid Build Coastguard Worker     fclose(file);
77*2b949d04SAndroid Build Coastguard Worker     if (!ok)
78*2b949d04SAndroid Build Coastguard Worker         return false;
79*2b949d04SAndroid Build Coastguard Worker 
80*2b949d04SAndroid Build Coastguard Worker     s = string;
81*2b949d04SAndroid Build Coastguard Worker     end = string + string_size;
82*2b949d04SAndroid Build Coastguard Worker     name_len = strlen(name);
83*2b949d04SAndroid Build Coastguard Worker     match = NULL;
84*2b949d04SAndroid Build Coastguard Worker 
85*2b949d04SAndroid Build Coastguard Worker     while (s < end) {
86*2b949d04SAndroid Build Coastguard Worker         /* Skip spaces. */
87*2b949d04SAndroid Build Coastguard Worker         while (s < end && is_space(*s))
88*2b949d04SAndroid Build Coastguard Worker             s++;
89*2b949d04SAndroid Build Coastguard Worker 
90*2b949d04SAndroid Build Coastguard Worker         /* Skip comments. */
91*2b949d04SAndroid Build Coastguard Worker         if (s < end && *s == '#') {
92*2b949d04SAndroid Build Coastguard Worker             while (s < end && *s != '\n')
93*2b949d04SAndroid Build Coastguard Worker                 s++;
94*2b949d04SAndroid Build Coastguard Worker             continue;
95*2b949d04SAndroid Build Coastguard Worker         }
96*2b949d04SAndroid Build Coastguard Worker 
97*2b949d04SAndroid Build Coastguard Worker         /* Get the left value. */
98*2b949d04SAndroid Build Coastguard Worker         left = s;
99*2b949d04SAndroid Build Coastguard Worker         while (s < end && !is_space(*s) && *s != ':')
100*2b949d04SAndroid Build Coastguard Worker             s++;
101*2b949d04SAndroid Build Coastguard Worker         left_len = s - left;
102*2b949d04SAndroid Build Coastguard Worker 
103*2b949d04SAndroid Build Coastguard Worker         /* There's an optional colon between left and right. */
104*2b949d04SAndroid Build Coastguard Worker         if (s < end && *s == ':')
105*2b949d04SAndroid Build Coastguard Worker             s++;
106*2b949d04SAndroid Build Coastguard Worker 
107*2b949d04SAndroid Build Coastguard Worker         /* Skip spaces. */
108*2b949d04SAndroid Build Coastguard Worker         while (s < end && is_space(*s))
109*2b949d04SAndroid Build Coastguard Worker             s++;
110*2b949d04SAndroid Build Coastguard Worker 
111*2b949d04SAndroid Build Coastguard Worker         /* Get the right value. */
112*2b949d04SAndroid Build Coastguard Worker         right = s;
113*2b949d04SAndroid Build Coastguard Worker         while (s < end && !is_space(*s))
114*2b949d04SAndroid Build Coastguard Worker             s++;
115*2b949d04SAndroid Build Coastguard Worker         right_len = s - right;
116*2b949d04SAndroid Build Coastguard Worker 
117*2b949d04SAndroid Build Coastguard Worker         /* Discard rest of line. */
118*2b949d04SAndroid Build Coastguard Worker         while (s < end && *s != '\n')
119*2b949d04SAndroid Build Coastguard Worker             s++;
120*2b949d04SAndroid Build Coastguard Worker 
121*2b949d04SAndroid Build Coastguard Worker         if (direction == LEFT_TO_RIGHT) {
122*2b949d04SAndroid Build Coastguard Worker             if (left_len == name_len && memcmp(left, name, left_len) == 0) {
123*2b949d04SAndroid Build Coastguard Worker                 match = strndup(right, right_len);
124*2b949d04SAndroid Build Coastguard Worker                 break;
125*2b949d04SAndroid Build Coastguard Worker             }
126*2b949d04SAndroid Build Coastguard Worker         }
127*2b949d04SAndroid Build Coastguard Worker         else if (direction == RIGHT_TO_LEFT) {
128*2b949d04SAndroid Build Coastguard Worker             if (right_len == name_len && memcmp(right, name, right_len) == 0) {
129*2b949d04SAndroid Build Coastguard Worker                 match = strndup(left, left_len);
130*2b949d04SAndroid Build Coastguard Worker                 break;
131*2b949d04SAndroid Build Coastguard Worker             }
132*2b949d04SAndroid Build Coastguard Worker         }
133*2b949d04SAndroid Build Coastguard Worker     }
134*2b949d04SAndroid Build Coastguard Worker 
135*2b949d04SAndroid Build Coastguard Worker     unmap_file(string, string_size);
136*2b949d04SAndroid Build Coastguard Worker     return match;
137*2b949d04SAndroid Build Coastguard Worker }
138*2b949d04SAndroid Build Coastguard Worker 
139*2b949d04SAndroid Build Coastguard Worker char *
resolve_locale(const char * locale)140*2b949d04SAndroid Build Coastguard Worker resolve_locale(const char *locale)
141*2b949d04SAndroid Build Coastguard Worker {
142*2b949d04SAndroid Build Coastguard Worker     char *alias = resolve_name("locale.alias", LEFT_TO_RIGHT, locale);
143*2b949d04SAndroid Build Coastguard Worker     return alias ? alias : strdup(locale);
144*2b949d04SAndroid Build Coastguard Worker }
145*2b949d04SAndroid Build Coastguard Worker 
146*2b949d04SAndroid Build Coastguard Worker char *
get_xcomposefile_path(void)147*2b949d04SAndroid Build Coastguard Worker get_xcomposefile_path(void)
148*2b949d04SAndroid Build Coastguard Worker {
149*2b949d04SAndroid Build Coastguard Worker     return strdup_safe(secure_getenv("XCOMPOSEFILE"));
150*2b949d04SAndroid Build Coastguard Worker }
151*2b949d04SAndroid Build Coastguard Worker 
152*2b949d04SAndroid Build Coastguard Worker char *
get_xdg_xcompose_file_path(void)153*2b949d04SAndroid Build Coastguard Worker get_xdg_xcompose_file_path(void)
154*2b949d04SAndroid Build Coastguard Worker {
155*2b949d04SAndroid Build Coastguard Worker     const char *xdg_config_home;
156*2b949d04SAndroid Build Coastguard Worker     const char *home;
157*2b949d04SAndroid Build Coastguard Worker 
158*2b949d04SAndroid Build Coastguard Worker     xdg_config_home = secure_getenv("XDG_CONFIG_HOME");
159*2b949d04SAndroid Build Coastguard Worker     if (!xdg_config_home || xdg_config_home[0] != '/') {
160*2b949d04SAndroid Build Coastguard Worker         home = secure_getenv("HOME");
161*2b949d04SAndroid Build Coastguard Worker         if (!home)
162*2b949d04SAndroid Build Coastguard Worker             return NULL;
163*2b949d04SAndroid Build Coastguard Worker         return asprintf_safe("%s/.config/XCompose", home);
164*2b949d04SAndroid Build Coastguard Worker     }
165*2b949d04SAndroid Build Coastguard Worker 
166*2b949d04SAndroid Build Coastguard Worker     return asprintf_safe("%s/XCompose", xdg_config_home);
167*2b949d04SAndroid Build Coastguard Worker }
168*2b949d04SAndroid Build Coastguard Worker 
169*2b949d04SAndroid Build Coastguard Worker char *
get_home_xcompose_file_path(void)170*2b949d04SAndroid Build Coastguard Worker get_home_xcompose_file_path(void)
171*2b949d04SAndroid Build Coastguard Worker {
172*2b949d04SAndroid Build Coastguard Worker     const char *home;
173*2b949d04SAndroid Build Coastguard Worker 
174*2b949d04SAndroid Build Coastguard Worker     home = secure_getenv("HOME");
175*2b949d04SAndroid Build Coastguard Worker     if (!home)
176*2b949d04SAndroid Build Coastguard Worker         return NULL;
177*2b949d04SAndroid Build Coastguard Worker 
178*2b949d04SAndroid Build Coastguard Worker     return asprintf_safe("%s/.XCompose", home);
179*2b949d04SAndroid Build Coastguard Worker }
180*2b949d04SAndroid Build Coastguard Worker 
181*2b949d04SAndroid Build Coastguard Worker char *
get_locale_compose_file_path(const char * locale)182*2b949d04SAndroid Build Coastguard Worker get_locale_compose_file_path(const char *locale)
183*2b949d04SAndroid Build Coastguard Worker {
184*2b949d04SAndroid Build Coastguard Worker     char *resolved;
185*2b949d04SAndroid Build Coastguard Worker     char *path;
186*2b949d04SAndroid Build Coastguard Worker 
187*2b949d04SAndroid Build Coastguard Worker     /*
188*2b949d04SAndroid Build Coastguard Worker      * WARNING: Random workaround ahead.
189*2b949d04SAndroid Build Coastguard Worker      *
190*2b949d04SAndroid Build Coastguard Worker      * We currently do not support non-UTF-8 Compose files.  The C/POSIX
191*2b949d04SAndroid Build Coastguard Worker      * locale is specified to be the default fallback locale with an
192*2b949d04SAndroid Build Coastguard Worker      * ASCII charset.  But for some reason the compose.dir points the C
193*2b949d04SAndroid Build Coastguard Worker      * locale to the iso8859-1/Compose file, which is not ASCII but
194*2b949d04SAndroid Build Coastguard Worker      * ISO8859-1.  Since this is bound to happen a lot, and since our API
195*2b949d04SAndroid Build Coastguard Worker      * is UTF-8 based, and since 99% of the time a C locale is really just
196*2b949d04SAndroid Build Coastguard Worker      * a misconfiguration for UTF-8, let's do the most helpful thing.
197*2b949d04SAndroid Build Coastguard Worker      */
198*2b949d04SAndroid Build Coastguard Worker     if (streq(locale, "C"))
199*2b949d04SAndroid Build Coastguard Worker         locale = "en_US.UTF-8";
200*2b949d04SAndroid Build Coastguard Worker 
201*2b949d04SAndroid Build Coastguard Worker     resolved = resolve_name("compose.dir", RIGHT_TO_LEFT, locale);
202*2b949d04SAndroid Build Coastguard Worker     if (!resolved)
203*2b949d04SAndroid Build Coastguard Worker         return NULL;
204*2b949d04SAndroid Build Coastguard Worker 
205*2b949d04SAndroid Build Coastguard Worker     if (resolved[0] == '/') {
206*2b949d04SAndroid Build Coastguard Worker         path = resolved;
207*2b949d04SAndroid Build Coastguard Worker     }
208*2b949d04SAndroid Build Coastguard Worker     else {
209*2b949d04SAndroid Build Coastguard Worker         const char *xlocaledir = get_xlocaledir_path();
210*2b949d04SAndroid Build Coastguard Worker         path = asprintf_safe("%s/%s", xlocaledir, resolved);
211*2b949d04SAndroid Build Coastguard Worker         free(resolved);
212*2b949d04SAndroid Build Coastguard Worker     }
213*2b949d04SAndroid Build Coastguard Worker 
214*2b949d04SAndroid Build Coastguard Worker     return path;
215*2b949d04SAndroid Build Coastguard Worker }
216