1 /* 2 * Copyright 2014 Ran Benita <ran234 (at) 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 * 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 * 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 * 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 * 143 get_xcomposefile_path(void) 144 { 145 return secure_getenv("XCOMPOSEFILE"); 146 } 147 148 char * 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 * 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