• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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