Home | History | Annotate | Download | only in compose
      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