Blame src/ibuscomposetable.c

Packit Service 1d8f1c
/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
Packit Service 1d8f1c
/* ibus - The Input Bus
Packit Service 1d8f1c
 * Copyright (C) 2013-2014 Peng Huang <shawn.p.huang@gmail.com>
rpm-build ad9c00
 * Copyright (C) 2013-2019 Takao Fujiwara <takao.fujiwara1@gmail.com>
Packit Service 1d8f1c
 *
Packit Service 1d8f1c
 * This library is free software; you can redistribute it and/or
Packit Service 1d8f1c
 * modify it under the terms of the GNU Lesser General Public
Packit Service 1d8f1c
 * License as published by the Free Software Foundation; either
Packit Service 1d8f1c
 * version 2.1 of the License, or (at your option) any later version.
Packit Service 1d8f1c
 *
Packit Service 1d8f1c
 * This library is distributed in the hope that it will be useful,
Packit Service 1d8f1c
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 1d8f1c
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 1d8f1c
 * Lesser General Public License for more details.
Packit Service 1d8f1c
 *
Packit Service 1d8f1c
 * You should have received a copy of the GNU Lesser General Public
Packit Service 1d8f1c
 * License along with this library; if not, write to the Free Software
Packit Service 1d8f1c
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
Packit Service 1d8f1c
 * USA
Packit Service 1d8f1c
 */
Packit Service 1d8f1c
Packit Service 1d8f1c
#include <glib.h>
Packit Service 1d8f1c
#include <glib/gstdio.h>
Packit Service 1d8f1c
#include <locale.h>
Packit Service 1d8f1c
#include <stdlib.h>
Packit Service 1d8f1c
#include <string.h>
Packit Service 1d8f1c
Packit Service 1d8f1c
#include "ibuscomposetable.h"
Packit Service 1d8f1c
#include "ibuserror.h"
Packit Service 1d8f1c
#include "ibusenginesimple.h"
Packit Service 1d8f1c
#include "ibuskeys.h"
Packit Service 1d8f1c
#include "ibuskeysyms.h"
Packit Service 1d8f1c
#include "ibustypes.h"
Packit Service 1d8f1c
Packit Service 1d8f1c
#include "ibusenginesimpleprivate.h"
Packit Service 1d8f1c
Packit Service 1d8f1c
#define IBUS_COMPOSE_TABLE_MAGIC "IBusComposeTable"
Packit Service 1d8f1c
#define IBUS_COMPOSE_TABLE_VERSION (2)
Packit Service 1d8f1c
Packit Service 1d8f1c
typedef struct {
Packit Service 1d8f1c
  gunichar     *sequence;
Packit Service 1d8f1c
  gunichar      value[2];
Packit Service 1d8f1c
  gchar        *comment;
Packit Service 1d8f1c
} IBusComposeData;
Packit Service 1d8f1c
Packit Service 1d8f1c
static void
Packit Service 1d8f1c
ibus_compose_data_free (IBusComposeData *compose_data)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    g_free (compose_data->sequence);
Packit Service 1d8f1c
    g_free (compose_data->comment);
Packit Service 1d8f1c
    g_slice_free (IBusComposeData, compose_data);
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
static void
Packit Service 1d8f1c
ibus_compose_list_element_free (IBusComposeData *compose_data,
Packit Service 1d8f1c
                                gpointer         data)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    ibus_compose_data_free (compose_data);
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
static gboolean
Packit Service 1d8f1c
is_codepoint (const gchar *str)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    int i;
Packit Service 1d8f1c
Packit Service 1d8f1c
    /* 'U' is not code point but 'U00C0' is code point */
Packit Service 1d8f1c
    if (str[0] == '\0' || str[0] != 'U' || str[1] == '\0')
Packit Service 1d8f1c
        return FALSE;
Packit Service 1d8f1c
Packit Service 1d8f1c
    for (i = 1; str[i] != '\0'; i++) {
Packit Service 1d8f1c
        if (!g_ascii_isxdigit (str[i]))
Packit Service 1d8f1c
            return FALSE;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    return TRUE;
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
static gboolean
Packit Service 1d8f1c
parse_compose_value (IBusComposeData  *compose_data,
Packit Service 1d8f1c
                     const gchar      *val,
Packit Service 1d8f1c
                     const gchar      *line)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    gchar **words = g_strsplit (val, "\"", 3);
Packit Service 1d8f1c
    gunichar uch;
Packit Service 1d8f1c
Packit Service 1d8f1c
    if (g_strv_length (words) < 3) {
Packit Service 1d8f1c
        g_warning ("Need to double-quote the value: %s: %s", val, line);
Packit Service 1d8f1c
        goto fail;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    uch = g_utf8_get_char (words[1]);
Packit Service 1d8f1c
Packit Service 1d8f1c
    if (uch == 0) {
Packit Service 1d8f1c
        g_warning ("Invalid value: %s: %s", val, line);
Packit Service 1d8f1c
        goto fail;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
    else if (uch == '\\') {
Packit Service 1d8f1c
        uch = words[1][1];
Packit Service 1d8f1c
Packit Service 1d8f1c
        /* The escaped string "\"" is separated with '\\' and '"'. */
rpm-build ad9c00
        if (uch == '\0' && words[2][0] == '"') {
Packit Service 1d8f1c
            uch = '"';
Packit Service 1d8f1c
        /* The escaped octal */
rpm-build ad9c00
        } else if (uch >= '0' && uch <= '8') {
Packit Service 1d8f1c
            uch = g_ascii_strtoll(words[1] + 1, NULL, 8);
Packit Service 1d8f1c
        /* If we need to handle other escape sequences. */
rpm-build ad9c00
        } else if (uch != '\\') {
rpm-build ad9c00
            g_warning ("Invalid backslash: %s: %s", val, line);
rpm-build ad9c00
            goto fail;
rpm-build ad9c00
        }
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    if (g_utf8_get_char (g_utf8_next_char (words[1])) > 0) {
Packit Service 1d8f1c
        g_warning ("GTK+ supports to output one char only: %s: %s", val, line);
Packit Service 1d8f1c
        goto fail;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    compose_data->value[1] = uch;
Packit Service 1d8f1c
Packit Service 1d8f1c
    if (uch == '"')
Packit Service 1d8f1c
        compose_data->comment = g_strdup (g_strstrip (words[2] + 1));
Packit Service 1d8f1c
    else
Packit Service 1d8f1c
        compose_data->comment = g_strdup (g_strstrip (words[2]));
Packit Service 1d8f1c
Packit Service 1d8f1c
    g_strfreev (words);
Packit Service 1d8f1c
Packit Service 1d8f1c
    return TRUE;
Packit Service 1d8f1c
Packit Service 1d8f1c
fail:
Packit Service 1d8f1c
    g_strfreev (words);
Packit Service 1d8f1c
    return FALSE;
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
static gboolean
Packit Service 1d8f1c
parse_compose_sequence (IBusComposeData *compose_data,
Packit Service 1d8f1c
                        const gchar     *seq,
Packit Service 1d8f1c
                        const gchar     *line)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    gchar **words = g_strsplit (seq, "<", -1);
Packit Service 1d8f1c
    int i;
Packit Service 1d8f1c
    int n = 0;
Packit Service 1d8f1c
Packit Service 1d8f1c
    if (g_strv_length (words) < 2) {
Packit Service 1d8f1c
        g_warning ("key sequence format is  ...: %s", line);
Packit Service 1d8f1c
        goto fail;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    for (i = 1; words[i] != NULL; i++) {
Packit Service 1d8f1c
        gchar *start = words[i];
Packit Service 1d8f1c
        gchar *end = index (words[i], '>');
Packit Service 1d8f1c
        gchar *match;
Packit Service 1d8f1c
        gunichar codepoint;
Packit Service 1d8f1c
Packit Service 1d8f1c
        if (words[i][0] == '\0')
Packit Service 1d8f1c
             continue;
Packit Service 1d8f1c
Packit Service 1d8f1c
        if (start == NULL || end == NULL || end <= start) {
Packit Service 1d8f1c
            g_warning ("key sequence format is  ...: %s", line);
Packit Service 1d8f1c
            goto fail;
Packit Service 1d8f1c
        }
Packit Service 1d8f1c
Packit Service 1d8f1c
        match = g_strndup (start, end - start);
Packit Service 1d8f1c
Packit Service 1d8f1c
        if (compose_data->sequence == NULL)
Packit Service 1d8f1c
            compose_data->sequence = g_malloc (sizeof (gunichar) * 2);
Packit Service 1d8f1c
        else
Packit Service 1d8f1c
            compose_data->sequence = g_realloc (compose_data->sequence,
Packit Service 1d8f1c
                                                sizeof (gunichar) * (n + 2));
Packit Service 1d8f1c
Packit Service 1d8f1c
        if (is_codepoint (match)) {
Packit Service 1d8f1c
            codepoint = (gunichar) g_ascii_strtoll (match + 1, NULL, 16);
Packit Service 1d8f1c
            compose_data->sequence[n] = codepoint;
Packit Service 1d8f1c
            compose_data->sequence[n + 1] = 0;
Packit Service 1d8f1c
        } else {
Packit Service 1d8f1c
            codepoint = (gunichar) ibus_keyval_from_name (match);
Packit Service 1d8f1c
            compose_data->sequence[n] = codepoint;
Packit Service 1d8f1c
            compose_data->sequence[n + 1] = 0;
Packit Service 1d8f1c
        }
Packit Service 1d8f1c
Packit Service 1d8f1c
        if (codepoint == IBUS_KEY_VoidSymbol)
Packit Service 1d8f1c
            g_warning ("Could not get code point of keysym %s", match);
Packit Service 1d8f1c
        g_free (match);
Packit Service 1d8f1c
        n++;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    g_strfreev (words);
Packit Service 1d8f1c
    if (0 == n || n >= IBUS_MAX_COMPOSE_LEN) {
Packit Service 1d8f1c
        g_warning ("The max number of sequences is %d: %s",
Packit Service 1d8f1c
                   IBUS_MAX_COMPOSE_LEN, line);
Packit Service 1d8f1c
        return FALSE;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    return TRUE;
Packit Service 1d8f1c
Packit Service 1d8f1c
fail:
Packit Service 1d8f1c
    g_strfreev (words);
Packit Service 1d8f1c
    return FALSE;
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
static void
Packit Service 1d8f1c
parse_compose_line (GList       **compose_list,
Packit Service 1d8f1c
                    const gchar  *line)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    gchar **components = NULL;
Packit Service 1d8f1c
    IBusComposeData *compose_data = NULL;
Packit Service 1d8f1c
Packit Service 1d8f1c
    if (line[0] == '\0' || line[0] == '#')
Packit Service 1d8f1c
        return;
Packit Service 1d8f1c
Packit Service 1d8f1c
    if (g_str_has_prefix (line, "include "))
Packit Service 1d8f1c
        return;
Packit Service 1d8f1c
Packit Service 1d8f1c
    components = g_strsplit (line, ":", 2);
Packit Service 1d8f1c
Packit Service 1d8f1c
    if (components[1] == NULL) {
Packit Service 1d8f1c
        g_warning ("No delimiter ':': %s", line);
Packit Service 1d8f1c
        goto fail;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    compose_data = g_slice_new0 (IBusComposeData);
Packit Service 1d8f1c
Packit Service 1d8f1c
    if (!parse_compose_sequence (compose_data,
Packit Service 1d8f1c
                                 g_strstrip (components[0]),
Packit Service 1d8f1c
                                 line)) {
Packit Service 1d8f1c
        goto fail;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    if (!parse_compose_value (compose_data, g_strstrip (components[1]), line))
Packit Service 1d8f1c
        goto fail;
Packit Service 1d8f1c
Packit Service 1d8f1c
    g_strfreev (components);
Packit Service 1d8f1c
Packit Service 1d8f1c
    *compose_list = g_list_append (*compose_list, compose_data);
Packit Service 1d8f1c
Packit Service 1d8f1c
    return;
Packit Service 1d8f1c
Packit Service 1d8f1c
fail:
Packit Service 1d8f1c
    g_strfreev (components);
Packit Service 1d8f1c
    if (compose_data)
Packit Service 1d8f1c
        ibus_compose_data_free (compose_data);
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
static GList *
Packit Service 1d8f1c
ibus_compose_list_parse_file (const gchar *compose_file)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    gchar *contents = NULL;
Packit Service 1d8f1c
    gchar **lines = NULL;
Packit Service 1d8f1c
    gsize length = 0;
Packit Service 1d8f1c
    GError *error = NULL;
Packit Service 1d8f1c
    GList *compose_list = NULL;
Packit Service 1d8f1c
    int i;
Packit Service 1d8f1c
Packit Service 1d8f1c
    if (!g_file_get_contents (compose_file, &contents, &length, &error)) {
Packit Service 1d8f1c
        g_error ("%s", error->message);
Packit Service 1d8f1c
        g_error_free (error);
Packit Service 1d8f1c
        return NULL;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    lines = g_strsplit (contents, "\n", -1);
Packit Service 1d8f1c
    g_free (contents);
Packit Service 1d8f1c
    for (i = 0; lines[i] != NULL; i++)
Packit Service 1d8f1c
        parse_compose_line (&compose_list, lines[i]);
Packit Service 1d8f1c
    g_strfreev (lines);
Packit Service 1d8f1c
Packit Service 1d8f1c
    return compose_list;
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
static GList *
Packit Service 1d8f1c
ibus_compose_list_check_duplicated (GList *compose_list)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    GList *list;
Packit Service 1d8f1c
    GList *removed_list = NULL;
Packit Service 1d8f1c
    IBusComposeData *compose_data;
Packit Service 1d8f1c
Packit Service 1d8f1c
    for (list = compose_list; list != NULL; list = list->next) {
Packit Service 1d8f1c
        static guint16 keysyms[IBUS_MAX_COMPOSE_LEN + 1];
Packit Service 1d8f1c
        int i;
Packit Service 1d8f1c
        int n_compose = 0;
Packit Service 1d8f1c
        gboolean compose_finish;
Packit Service 1d8f1c
        gunichar output_char;
Packit Service 1d8f1c
Packit Service 1d8f1c
        compose_data = list->data;
Packit Service 1d8f1c
Packit Service 1d8f1c
        for (i = 0; i < IBUS_MAX_COMPOSE_LEN + 1; i++)
Packit Service 1d8f1c
            keysyms[i] = 0;
Packit Service 1d8f1c
Packit Service 1d8f1c
        for (i = 0; i < IBUS_MAX_COMPOSE_LEN + 1; i++) {
Packit Service 1d8f1c
            gunichar codepoint = compose_data->sequence[i];
Packit Service 1d8f1c
            keysyms[i] = (guint16) codepoint;
Packit Service 1d8f1c
Packit Service 1d8f1c
            if (codepoint == 0)
Packit Service 1d8f1c
                break;
Packit Service 1d8f1c
Packit Service 1d8f1c
            n_compose++;
Packit Service 1d8f1c
        }
Packit Service 1d8f1c
Packit Service 1d8f1c
        if (ibus_check_compact_table (&ibus_compose_table_compact,
Packit Service 1d8f1c
                                      keysyms,
Packit Service 1d8f1c
                                      n_compose,
Packit Service 1d8f1c
                                      &compose_finish,
Packit Service 1d8f1c
                                      &output_char) && compose_finish) {
Packit Service 1d8f1c
            if (compose_data->value[1] == output_char)
Packit Service 1d8f1c
                removed_list = g_list_append (removed_list, compose_data);
Packit Service 1d8f1c
Packit Service 1d8f1c
        } else if (ibus_check_algorithmically (keysyms,
Packit Service 1d8f1c
                                               n_compose,
Packit Service 1d8f1c
                                               &output_char)) {
Packit Service 1d8f1c
            if (compose_data->value[1] == output_char)
Packit Service 1d8f1c
                removed_list = g_list_append (removed_list, compose_data);
Packit Service 1d8f1c
        }
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    for (list = removed_list; list != NULL; list = list->next) {
Packit Service 1d8f1c
        compose_data = list->data;
Packit Service 1d8f1c
        compose_list = g_list_remove (compose_list, compose_data);
Packit Service 1d8f1c
        ibus_compose_data_free (compose_data);
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    g_list_free (removed_list);
Packit Service 1d8f1c
Packit Service 1d8f1c
    return compose_list;
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
static GList *
Packit Service 1d8f1c
ibus_compose_list_check_uint16 (GList *compose_list)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    GList *list;
Packit Service 1d8f1c
    GList *removed_list = NULL;
Packit Service 1d8f1c
    IBusComposeData *compose_data;
Packit Service 1d8f1c
Packit Service 1d8f1c
    for (list = compose_list; list != NULL; list = list->next) {
Packit Service 1d8f1c
        int i;
Packit Service 1d8f1c
Packit Service 1d8f1c
        compose_data = list->data;
Packit Service 1d8f1c
        for (i = 0; i < IBUS_MAX_COMPOSE_LEN; i++) {
Packit Service 1d8f1c
            gunichar codepoint = compose_data->sequence[i];
Packit Service 1d8f1c
Packit Service 1d8f1c
            if (codepoint == 0)
Packit Service 1d8f1c
                break;
Packit Service 1d8f1c
Packit Service 1d8f1c
            if (codepoint > 0xffff) {
Packit Service 1d8f1c
                removed_list = g_list_append (removed_list, compose_data);
Packit Service 1d8f1c
                break;
Packit Service 1d8f1c
            }
Packit Service 1d8f1c
        }
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    for (list = removed_list; list != NULL; list = list->next) {
Packit Service 1d8f1c
        compose_data = list->data;
Packit Service 1d8f1c
        compose_list = g_list_remove (compose_list, compose_data);
Packit Service 1d8f1c
        ibus_compose_data_free (compose_data);
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    g_list_free (removed_list);
Packit Service 1d8f1c
Packit Service 1d8f1c
    return compose_list;
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
static GList *
Packit Service 1d8f1c
ibus_compose_list_format_for_gtk (GList *compose_list,
Packit Service 1d8f1c
                                  int   *p_max_compose_len,
Packit Service 1d8f1c
                                  int   *p_n_index_stride)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    GList *list;
Packit Service 1d8f1c
    IBusComposeData *compose_data;
Packit Service 1d8f1c
    int max_compose_len = 0;
Packit Service 1d8f1c
    int i;
Packit Service 1d8f1c
    gunichar codepoint;
Packit Service 1d8f1c
Packit Service 1d8f1c
    for (list = compose_list; list != NULL; list = list->next) {
Packit Service 1d8f1c
        compose_data = list->data;
Packit Service 1d8f1c
Packit Service 1d8f1c
        for (i = 0; i < IBUS_MAX_COMPOSE_LEN + 1; i++) {
Packit Service 1d8f1c
            codepoint = compose_data->sequence[i];
Packit Service 1d8f1c
            if (codepoint == 0) {
Packit Service 1d8f1c
                if (max_compose_len < i)
Packit Service 1d8f1c
                    max_compose_len = i;
Packit Service 1d8f1c
                break;
Packit Service 1d8f1c
            }
Packit Service 1d8f1c
        }
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    if (p_max_compose_len)
Packit Service 1d8f1c
        *p_max_compose_len = max_compose_len;
Packit Service 1d8f1c
    if (p_n_index_stride)
Packit Service 1d8f1c
        *p_n_index_stride = max_compose_len + 2;
Packit Service 1d8f1c
Packit Service 1d8f1c
    for (list = compose_list; list != NULL; list = list->next) {
Packit Service 1d8f1c
        compose_data = list->data;
Packit Service 1d8f1c
        codepoint = compose_data->value[1];
Packit Service 1d8f1c
        if (codepoint > 0xffff) {
Packit Service 1d8f1c
            compose_data->value[0] = codepoint / 0x10000;
Packit Service 1d8f1c
            compose_data->value[1] = codepoint - codepoint / 0x10000 * 0x10000;
Packit Service 1d8f1c
        }
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    return compose_list;
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
static gint
Packit Service 1d8f1c
ibus_compose_data_compare (gpointer a,
Packit Service 1d8f1c
                           gpointer b,
Packit Service 1d8f1c
                           gpointer data)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    IBusComposeData *compose_data_a = a;
Packit Service 1d8f1c
    IBusComposeData *compose_data_b = b;
Packit Service 1d8f1c
    int max_compose_len = GPOINTER_TO_INT (data);
Packit Service 1d8f1c
    int i;
Packit Service 1d8f1c
    for (i = 0; i < max_compose_len; i++) {
Packit Service 1d8f1c
        gunichar code_a = compose_data_a->sequence[i];
Packit Service 1d8f1c
        gunichar code_b = compose_data_b->sequence[i];
Packit Service 1d8f1c
Packit Service 1d8f1c
        if (code_a != code_b)
Packit Service 1d8f1c
            return code_a - code_b;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
    return 0;
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
static void
Packit Service 1d8f1c
ibus_compose_list_print (GList *compose_list,
Packit Service 1d8f1c
                         int    max_compose_len,
Packit Service 1d8f1c
                         int    n_index_stride)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    GList *list;
Packit Service 1d8f1c
    int i, j;
Packit Service 1d8f1c
    IBusComposeData *compose_data;
Packit Service 1d8f1c
    int total_size = 0;
Packit Service 1d8f1c
    gunichar upper;
Packit Service 1d8f1c
    gunichar lower;
Packit Service 1d8f1c
    const gchar *comment;
Packit Service 1d8f1c
    const gchar *keyval;
Packit Service 1d8f1c
Packit Service 1d8f1c
    for (list = compose_list; list != NULL; list = list->next) {
Packit Service 1d8f1c
        compose_data = list->data;
Packit Service 1d8f1c
        g_printf ("  ");
Packit Service 1d8f1c
Packit Service 1d8f1c
        for (i = 0; i < max_compose_len; i++) {
Packit Service 1d8f1c
Packit Service 1d8f1c
            if (compose_data->sequence[i] == 0) {
Packit Service 1d8f1c
                for (j = i; j < max_compose_len; j++) {
Packit Service 1d8f1c
                    if (i == max_compose_len -1)
Packit Service 1d8f1c
                        g_printf ("0,\n");
Packit Service 1d8f1c
                    else
Packit Service 1d8f1c
                        g_printf ("0, ");
Packit Service 1d8f1c
                }
Packit Service 1d8f1c
                break;
Packit Service 1d8f1c
            }
Packit Service 1d8f1c
Packit Service 1d8f1c
            keyval = ibus_keyval_name (compose_data->sequence[i]);
Packit Service 1d8f1c
            if (i == max_compose_len -1)
Packit Service 1d8f1c
                g_printf ("%s,\n", keyval ? keyval : "(null)");
Packit Service 1d8f1c
            else
Packit Service 1d8f1c
                g_printf ("%s, ", keyval ? keyval : "(null)");
Packit Service 1d8f1c
        }
Packit Service 1d8f1c
        upper = compose_data->value[0];
Packit Service 1d8f1c
        lower = compose_data->value[1];
Packit Service 1d8f1c
        comment = compose_data->comment;
Packit Service 1d8f1c
Packit Service 1d8f1c
        if (list == g_list_last (compose_list))
Packit Service 1d8f1c
            g_printf ("    %#06X, %#06X  /* %s */\n", upper, lower, comment);
Packit Service 1d8f1c
        else
Packit Service 1d8f1c
            g_printf ("    %#06X, %#06X, /* %s */\n", upper, lower, comment);
Packit Service 1d8f1c
Packit Service 1d8f1c
        total_size += n_index_stride;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    g_printerr ("TOTAL_SIZE: %d\nMAX_COMPOSE_LEN: %d\nN_INDEX_STRIDE: %d\n",
Packit Service 1d8f1c
                total_size, max_compose_len, n_index_stride);
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
/* Implemented from g_str_hash() */
Packit Service 1d8f1c
static guint32
Packit Service 1d8f1c
ibus_compose_table_data_hash (gconstpointer v,
Packit Service 1d8f1c
                              int           length)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    const guint16 *p, *head;
Packit Service 1d8f1c
    unsigned char c;
Packit Service 1d8f1c
    guint32 h = 5381;
Packit Service 1d8f1c
Packit Service 1d8f1c
    for (p = v, head = v; (p - head) < length; p++) {
Packit Service 1d8f1c
        c = 0x00ff & (*p >> 8);
Packit Service 1d8f1c
        h = (h << 5) + h + c;
Packit Service 1d8f1c
        c = 0x00ff & *p;
Packit Service 1d8f1c
        h = (h << 5) + h + c;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    return h;
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
static gchar *
Packit Service 1d8f1c
ibus_compose_hash_get_cache_path (guint32 hash)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    gchar *basename = NULL;
rpm-build dbbf76
    const gchar *cache_dir;
Packit Service 1d8f1c
    gchar *dir = NULL;
Packit Service 1d8f1c
    gchar *path = NULL;
Packit Service 1d8f1c
Packit Service 1d8f1c
    basename = g_strdup_printf ("%08x.cache", hash);
Packit Service 1d8f1c
rpm-build dbbf76
    if ((cache_dir = g_getenv ("IBUS_COMPOSE_CACHE_DIR"))) {
rpm-build dbbf76
        dir = g_strdup (cache_dir);
rpm-build dbbf76
    } else {
rpm-build dbbf76
        dir = g_build_filename (g_get_user_cache_dir (),
rpm-build dbbf76
                                "ibus", "compose", NULL);
rpm-build dbbf76
    }
Packit Service 1d8f1c
    path = g_build_filename (dir, basename, NULL);
Packit Service 1d8f1c
    if (g_mkdir_with_parents (dir, 0755) != 0) {
Packit Service 1d8f1c
        g_warning ("Failed to mkdir %s", dir);
Packit Service 1d8f1c
        g_free (path);
Packit Service 1d8f1c
        path = NULL;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    g_free (dir);
Packit Service 1d8f1c
    g_free (basename);
Packit Service 1d8f1c
Packit Service 1d8f1c
    return path;
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
static GVariant *
Packit Service 1d8f1c
ibus_compose_table_serialize (IBusComposeTable *compose_table)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    const gchar *header = IBUS_COMPOSE_TABLE_MAGIC;
Packit Service 1d8f1c
    const guint16 version = IBUS_COMPOSE_TABLE_VERSION;
Packit Service 1d8f1c
    guint16 max_seq_len;
Packit Service 1d8f1c
    guint16 index_stride;
Packit Service 1d8f1c
    guint16 n_seqs;
Packit Service 1d8f1c
    GVariant *variant_data;
Packit Service 1d8f1c
    GVariant *variant_table;
Packit Service 1d8f1c
Packit Service 1d8f1c
    g_return_val_if_fail (compose_table != NULL, NULL);
Packit Service 1d8f1c
    g_return_val_if_fail (compose_table->data != NULL, NULL);
Packit Service 1d8f1c
Packit Service 1d8f1c
    max_seq_len = compose_table->max_seq_len;
Packit Service 1d8f1c
    index_stride = max_seq_len + 2;
Packit Service 1d8f1c
    n_seqs = compose_table->n_seqs;
Packit Service 1d8f1c
Packit Service 1d8f1c
    g_return_val_if_fail (max_seq_len > 0, NULL);
Packit Service 1d8f1c
    g_return_val_if_fail (n_seqs > 0, NULL);
Packit Service 1d8f1c
Packit Service 1d8f1c
    variant_data = g_variant_new_fixed_array (G_VARIANT_TYPE_UINT16,
Packit Service 1d8f1c
                                              compose_table->data,
Packit Service 1d8f1c
                                              (gsize)index_stride * n_seqs,
Packit Service 1d8f1c
                                              sizeof (guint16));
Packit Service 1d8f1c
    if (variant_data == NULL) {
Packit Service 1d8f1c
        g_warning ("Could not change compose data to GVariant.");
Packit Service 1d8f1c
        return NULL;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
    variant_table = g_variant_new ("(sqqqv)",
Packit Service 1d8f1c
                                   header,
Packit Service 1d8f1c
                                   version,
Packit Service 1d8f1c
                                   max_seq_len,
Packit Service 1d8f1c
                                   n_seqs,
Packit Service 1d8f1c
                                   variant_data);
Packit Service 1d8f1c
    return g_variant_ref_sink (variant_table);
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
static gint
Packit Service 1d8f1c
ibus_compose_table_find (gconstpointer data1,
Packit Service 1d8f1c
                         gconstpointer data2)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    const IBusComposeTable *compose_table = (const IBusComposeTable *) data1;
Packit Service 1d8f1c
    guint32 hash = (guint32) GPOINTER_TO_INT (data2);
Packit Service 1d8f1c
    return compose_table->id != hash;
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
static IBusComposeTable *
Packit Service 1d8f1c
ibus_compose_table_deserialize (const gchar *contents,
Packit Service 1d8f1c
                                gsize        length)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    IBusComposeTable *retval = NULL;
Packit Service 1d8f1c
    GVariantType *type;
Packit Service 1d8f1c
    GVariant *variant_data = NULL;
Packit Service 1d8f1c
    GVariant *variant_table = NULL;
Packit Service 1d8f1c
    const gchar *header = NULL;
Packit Service 1d8f1c
    guint16 version = 0;
Packit Service 1d8f1c
    guint16 max_seq_len = 0;
Packit Service 1d8f1c
    guint16 n_seqs = 0;
Packit Service 1d8f1c
    guint16 index_stride;
Packit Service 1d8f1c
    gconstpointer data = NULL;
Packit Service 1d8f1c
    gsize data_length = 0;
Packit Service 1d8f1c
Packit Service 1d8f1c
    g_return_val_if_fail (contents != NULL, NULL);
Packit Service 1d8f1c
    g_return_val_if_fail (length > 0, NULL);
Packit Service 1d8f1c
Packit Service 1d8f1c
    /* Check the cache version at first before load whole the file content. */
Packit Service 1d8f1c
    type = g_variant_type_new ("(sq)");
Packit Service 1d8f1c
    variant_table = g_variant_new_from_data (type,
Packit Service 1d8f1c
                                             contents,
Packit Service 1d8f1c
                                             length,
Packit Service 1d8f1c
                                             FALSE,
Packit Service 1d8f1c
                                             NULL,
Packit Service 1d8f1c
                                             NULL);
Packit Service 1d8f1c
    g_variant_type_free (type);
Packit Service 1d8f1c
Packit Service 1d8f1c
    if (variant_table == NULL) {
Packit Service 1d8f1c
        g_warning ("cache is broken.");
Packit Service 1d8f1c
        goto out_load_cache;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    g_variant_ref_sink (variant_table);
Packit Service 1d8f1c
    g_variant_get (variant_table, "(&sq)", &header, &version);
Packit Service 1d8f1c
Packit Service 1d8f1c
    if (g_strcmp0 (header, IBUS_COMPOSE_TABLE_MAGIC) != 0) {
Packit Service 1d8f1c
        g_warning ("cache is not IBusComposeTable.");
Packit Service 1d8f1c
        goto out_load_cache;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    if (version != IBUS_COMPOSE_TABLE_VERSION) {
Packit Service 1d8f1c
        g_warning ("cache version is different: %u != %u",
Packit Service 1d8f1c
                   version, IBUS_COMPOSE_TABLE_VERSION);
Packit Service 1d8f1c
        goto out_load_cache;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    version = 0;
Packit Service 1d8f1c
    header = NULL;
Packit Service 1d8f1c
    g_variant_unref (variant_table);
Packit Service 1d8f1c
    variant_table = NULL;
Packit Service 1d8f1c
Packit Service 1d8f1c
    type = g_variant_type_new ("(sqqqv)");
Packit Service 1d8f1c
    variant_table = g_variant_new_from_data (type,
Packit Service 1d8f1c
                                             contents,
Packit Service 1d8f1c
                                             length,
Packit Service 1d8f1c
                                             FALSE,
Packit Service 1d8f1c
                                             NULL,
Packit Service 1d8f1c
                                             NULL);
Packit Service 1d8f1c
    g_variant_type_free (type);
Packit Service 1d8f1c
Packit Service 1d8f1c
    if (variant_table == NULL) {
Packit Service 1d8f1c
        g_warning ("cache is broken.");
Packit Service 1d8f1c
        goto out_load_cache;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    g_variant_ref_sink (variant_table);
Packit Service 1d8f1c
    g_variant_get (variant_table, "(&sqqqv)",
Packit Service 1d8f1c
                   NULL,
Packit Service 1d8f1c
                   NULL,
Packit Service 1d8f1c
                   &max_seq_len,
Packit Service 1d8f1c
                   &n_seqs,
Packit Service 1d8f1c
                   &variant_data);
Packit Service 1d8f1c
Packit Service 1d8f1c
    if (max_seq_len == 0 || n_seqs == 0) {
Packit Service 1d8f1c
        g_warning ("cache size is not correct %d %d", max_seq_len, n_seqs);
Packit Service 1d8f1c
        goto out_load_cache;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    data = g_variant_get_fixed_array (variant_data,
Packit Service 1d8f1c
                                      &data_length,
Packit Service 1d8f1c
                                      sizeof (guint16));
Packit Service 1d8f1c
    index_stride = max_seq_len + 2;
Packit Service 1d8f1c
Packit Service 1d8f1c
    if (data == NULL) {
Packit Service 1d8f1c
        g_warning ("cache data is null.");
Packit Service 1d8f1c
        goto out_load_cache;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
    if (data_length != (gsize) index_stride * n_seqs) {
Packit Service 1d8f1c
        g_warning ("cache size is not correct %d %d %lu",
Packit Service 1d8f1c
                   max_seq_len, n_seqs, data_length);
Packit Service 1d8f1c
        goto out_load_cache;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    retval = g_new0 (IBusComposeTable, 1);
Packit Service 1d8f1c
    retval->data = g_new (guint16, data_length);
Packit Service 1d8f1c
    memcpy (retval->data, data, data_length * sizeof (guint16));
Packit Service 1d8f1c
    retval->max_seq_len = max_seq_len;
Packit Service 1d8f1c
    retval->n_seqs = n_seqs;
Packit Service 1d8f1c
Packit Service 1d8f1c
Packit Service 1d8f1c
out_load_cache:
Packit Service 1d8f1c
    if (variant_data)
Packit Service 1d8f1c
        g_variant_unref (variant_data);
Packit Service 1d8f1c
    if (variant_table)
Packit Service 1d8f1c
        g_variant_unref (variant_table);
Packit Service 1d8f1c
    return retval;
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
static IBusComposeTable *
Packit Service 1d8f1c
ibus_compose_table_load_cache (const gchar *compose_file)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    IBusComposeTable *retval = NULL;
Packit Service 1d8f1c
    guint32 hash;
Packit Service 1d8f1c
    gchar *path = NULL;
Packit Service 1d8f1c
    gchar *contents = NULL;
Packit Service 1d8f1c
    GStatBuf original_buf;
Packit Service 1d8f1c
    GStatBuf cache_buf;
Packit Service 1d8f1c
    gsize length = 0;
Packit Service 1d8f1c
    GError *error = NULL;
Packit Service 1d8f1c
Packit Service 1d8f1c
    do {
Packit Service 1d8f1c
        hash = g_str_hash (compose_file);
Packit Service 1d8f1c
        if ((path = ibus_compose_hash_get_cache_path (hash)) == NULL)
Packit Service 1d8f1c
            return NULL;
Packit Service 1d8f1c
        if (!g_file_test (path, G_FILE_TEST_EXISTS))
Packit Service 1d8f1c
            break;
Packit Service 1d8f1c
Packit Service 1d8f1c
        if (g_stat (compose_file, &original_buf))
Packit Service 1d8f1c
            break;
Packit Service 1d8f1c
        if (g_stat (path, &cache_buf))
Packit Service 1d8f1c
            break;
Packit Service 1d8f1c
        if (original_buf.st_mtime > cache_buf.st_mtime)
Packit Service 1d8f1c
            break;
Packit Service 1d8f1c
        if (!g_file_get_contents (path, &contents, &length, &error)) {
Packit Service 1d8f1c
            g_warning ("Failed to get cache content %s: %s",
Packit Service 1d8f1c
                       path, error->message);
Packit Service 1d8f1c
            g_error_free (error);
Packit Service 1d8f1c
            break;
Packit Service 1d8f1c
        }
Packit Service 1d8f1c
Packit Service 1d8f1c
        retval = ibus_compose_table_deserialize (contents, length);
Packit Service 1d8f1c
        if (retval == NULL)
Packit Service 1d8f1c
            g_warning ("Failed to load the cache file: %s", path);
Packit Service 1d8f1c
        else
Packit Service 1d8f1c
            retval->id = hash;
Packit Service 1d8f1c
    } while (0);
Packit Service 1d8f1c
Packit Service 1d8f1c
    g_free (contents);
Packit Service 1d8f1c
    g_free (path);
Packit Service 1d8f1c
    return retval;
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
static void
Packit Service 1d8f1c
ibus_compose_table_save_cache (IBusComposeTable *compose_table)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    gchar *path = NULL;
Packit Service 1d8f1c
    GVariant *variant_table = NULL;
Packit Service 1d8f1c
    const gchar *contents = NULL;
Packit Service 1d8f1c
    GError *error = NULL;
Packit Service 1d8f1c
    gsize length = 0;
Packit Service 1d8f1c
Packit Service 1d8f1c
    if ((path = ibus_compose_hash_get_cache_path (compose_table->id)) == NULL)
Packit Service 1d8f1c
      return;
Packit Service 1d8f1c
Packit Service 1d8f1c
    variant_table = ibus_compose_table_serialize (compose_table);
Packit Service 1d8f1c
    if (variant_table == NULL) {
Packit Service 1d8f1c
        g_warning ("Failed to serialize compose table %s", path);
Packit Service 1d8f1c
        goto out_save_cache;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
    contents = g_variant_get_data (variant_table);
Packit Service 1d8f1c
    length = g_variant_get_size (variant_table);
Packit Service 1d8f1c
    if (!g_file_set_contents (path, contents, length, &error)) {
Packit Service 1d8f1c
        g_warning ("Failed to save compose table %s: %s", path, error->message);
Packit Service 1d8f1c
        g_error_free (error);
Packit Service 1d8f1c
        goto out_save_cache;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
out_save_cache:
Packit Service 1d8f1c
    g_variant_unref (variant_table);
Packit Service 1d8f1c
    g_free (path);
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
static IBusComposeTable *
Packit Service 1d8f1c
ibus_compose_table_new_with_list (GList   *compose_list,
Packit Service 1d8f1c
                                  int      max_compose_len,
Packit Service 1d8f1c
                                  int      n_index_stride,
Packit Service 1d8f1c
                                  guint32  hash)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    guint length;
Packit Service 1d8f1c
    guint n = 0;
Packit Service 1d8f1c
    int i, j;
Packit Service 1d8f1c
    guint16 *ibus_compose_seqs = NULL;
Packit Service 1d8f1c
    GList *list;
Packit Service 1d8f1c
    IBusComposeData *compose_data;
Packit Service 1d8f1c
    IBusComposeTable *retval = NULL;
Packit Service 1d8f1c
Packit Service 1d8f1c
    g_return_val_if_fail (compose_list != NULL, NULL);
Packit Service 1d8f1c
Packit Service 1d8f1c
    length = g_list_length (compose_list);
Packit Service 1d8f1c
Packit Service 1d8f1c
    ibus_compose_seqs = g_new0 (guint16, length * n_index_stride);
Packit Service 1d8f1c
Packit Service 1d8f1c
    for (list = compose_list; list != NULL; list = list->next) {
Packit Service 1d8f1c
        compose_data = list->data;
Packit Service 1d8f1c
        for (i = 0; i < max_compose_len; i++) {
Packit Service 1d8f1c
            if (compose_data->sequence[i] == 0) {
Packit Service 1d8f1c
                for (j = i; j < max_compose_len; j++)
Packit Service 1d8f1c
                    ibus_compose_seqs[n++] = 0;
Packit Service 1d8f1c
                break;
Packit Service 1d8f1c
            }
Packit Service 1d8f1c
            ibus_compose_seqs[n++] = (guint16) compose_data->sequence[i];
Packit Service 1d8f1c
        }
Packit Service 1d8f1c
        ibus_compose_seqs[n++] = (guint16) compose_data->value[0];
Packit Service 1d8f1c
        ibus_compose_seqs[n++] = (guint16) compose_data->value[1];
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    retval = g_new0 (IBusComposeTable, 1);
Packit Service 1d8f1c
    retval->data = ibus_compose_seqs;
Packit Service 1d8f1c
    retval->max_seq_len = max_compose_len;
Packit Service 1d8f1c
    retval->n_seqs = length;
Packit Service 1d8f1c
    retval->id = hash;
Packit Service 1d8f1c
Packit Service 1d8f1c
    return retval;
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
IBusComposeTable *
Packit Service 1d8f1c
ibus_compose_table_new_with_file (const gchar *compose_file)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    GList *compose_list = NULL;
Packit Service 1d8f1c
    IBusComposeTable *compose_table;
Packit Service 1d8f1c
    int max_compose_len = 0;
Packit Service 1d8f1c
    int n_index_stride = 0;
Packit Service 1d8f1c
Packit Service 1d8f1c
    g_assert (compose_file != NULL);
Packit Service 1d8f1c
Packit Service 1d8f1c
    compose_list = ibus_compose_list_parse_file (compose_file);
Packit Service 1d8f1c
    if (compose_list == NULL)
Packit Service 1d8f1c
        return NULL;
Packit Service 1d8f1c
    compose_list = ibus_compose_list_check_duplicated (compose_list);
Packit Service 1d8f1c
    compose_list = ibus_compose_list_check_uint16 (compose_list);
Packit Service 1d8f1c
    compose_list = ibus_compose_list_format_for_gtk (compose_list,
Packit Service 1d8f1c
                                                     &max_compose_len,
Packit Service 1d8f1c
                                                     &n_index_stride);
Packit Service 1d8f1c
    compose_list = g_list_sort_with_data (
Packit Service 1d8f1c
            compose_list,
Packit Service 1d8f1c
            (GCompareDataFunc) ibus_compose_data_compare,
Packit Service 1d8f1c
            GINT_TO_POINTER (max_compose_len));
Packit Service 1d8f1c
Packit Service 1d8f1c
    if (compose_list == NULL) {
Packit Service 1d8f1c
        g_warning ("compose file %s does not include any keys besides keys "
Packit Service 1d8f1c
                   "in en-us compose file", compose_file);
Packit Service 1d8f1c
        return NULL;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    if (g_getenv ("IBUS_COMPOSE_TABLE_PRINT") != NULL) {
Packit Service 1d8f1c
        ibus_compose_list_print (compose_list, max_compose_len, n_index_stride);
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    compose_table = ibus_compose_table_new_with_list (
Packit Service 1d8f1c
            compose_list,
Packit Service 1d8f1c
            max_compose_len,
Packit Service 1d8f1c
            n_index_stride,
Packit Service 1d8f1c
            g_str_hash (compose_file));
Packit Service 1d8f1c
Packit Service 1d8f1c
    g_list_free_full (compose_list,
Packit Service 1d8f1c
                      (GDestroyNotify) ibus_compose_list_element_free);
Packit Service 1d8f1c
Packit Service 1d8f1c
    return compose_table;
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
/* if ibus_compose_seqs[N - 1] is an outputed compose character,
Packit Service 1d8f1c
 * ibus_compose_seqs[N * 2 - 1] is also an outputed compose character.
Packit Service 1d8f1c
 * and ibus_compose_seqs[0] to ibus_compose_seqs[0 + N - 3] are the
Packit Service 1d8f1c
 * sequences and call ibus_engine_simple_add_table:
Packit Service 1d8f1c
 * ibus_engine_simple_add_table(engine, ibus_compose_seqs,
Packit Service 1d8f1c
 *                              N - 2, G_N_ELEMENTS(ibus_compose_seqs) / N)
Packit Service 1d8f1c
 * The compose sequences are allowed within G_MAXUINT16
Packit Service 1d8f1c
 */
Packit Service 1d8f1c
GSList *
Packit Service 1d8f1c
ibus_compose_table_list_add_array (GSList        *compose_tables,
Packit Service 1d8f1c
                                   const guint16 *data,
Packit Service 1d8f1c
                                   gint           max_seq_len,
Packit Service 1d8f1c
                                   gint           n_seqs)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    guint32 hash;
Packit Service 1d8f1c
    IBusComposeTable *compose_table;
Packit Service 1d8f1c
    int n_index_stride = max_seq_len + 2;
Packit Service 1d8f1c
    int length = n_index_stride * n_seqs;
Packit Service 1d8f1c
    int i;
Packit Service 1d8f1c
    guint16 *ibus_compose_seqs = NULL;
Packit Service 1d8f1c
Packit Service 1d8f1c
    g_return_val_if_fail (data != NULL, compose_tables);
Packit Service 1d8f1c
    g_return_val_if_fail (max_seq_len <= IBUS_MAX_COMPOSE_LEN, compose_tables);
Packit Service 1d8f1c
Packit Service 1d8f1c
    hash = ibus_compose_table_data_hash (data, length);
Packit Service 1d8f1c
Packit Service 1d8f1c
    if (g_slist_find_custom (compose_tables,
Packit Service 1d8f1c
                             GINT_TO_POINTER (hash),
Packit Service 1d8f1c
                             ibus_compose_table_find) != NULL) {
Packit Service 1d8f1c
        return compose_tables;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    ibus_compose_seqs = g_new0 (guint16, length);
Packit Service 1d8f1c
    for (i = 0; i < length; i++)
Packit Service 1d8f1c
        ibus_compose_seqs[i] = data[i];
Packit Service 1d8f1c
rpm-build dbbf76
    compose_table = g_new0 (IBusComposeTable, 1);
Packit Service 1d8f1c
    compose_table->data = ibus_compose_seqs;
Packit Service 1d8f1c
    compose_table->max_seq_len = max_seq_len;
Packit Service 1d8f1c
    compose_table->n_seqs = n_seqs;
Packit Service 1d8f1c
    compose_table->id = hash;
Packit Service 1d8f1c
Packit Service 1d8f1c
    return g_slist_prepend (compose_tables, compose_table);
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
GSList *
Packit Service 1d8f1c
ibus_compose_table_list_add_file (GSList      *compose_tables,
Packit Service 1d8f1c
                                  const gchar *compose_file)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    guint32 hash;
Packit Service 1d8f1c
    IBusComposeTable *compose_table;
Packit Service 1d8f1c
Packit Service 1d8f1c
    g_return_val_if_fail (compose_file != NULL, compose_tables);
Packit Service 1d8f1c
Packit Service 1d8f1c
    hash = g_str_hash (compose_file);
Packit Service 1d8f1c
    if (g_slist_find_custom (compose_tables,
Packit Service 1d8f1c
                             GINT_TO_POINTER (hash),
Packit Service 1d8f1c
                             ibus_compose_table_find) != NULL) {
Packit Service 1d8f1c
        return compose_tables;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    compose_table = ibus_compose_table_load_cache (compose_file);
Packit Service 1d8f1c
    if (compose_table != NULL)
Packit Service 1d8f1c
        return g_slist_prepend (compose_tables, compose_table);
Packit Service 1d8f1c
Packit Service 1d8f1c
   if ((compose_table = ibus_compose_table_new_with_file (compose_file))
Packit Service 1d8f1c
           == NULL) {
Packit Service 1d8f1c
       return compose_tables;
Packit Service 1d8f1c
   }
Packit Service 1d8f1c
Packit Service 1d8f1c
    ibus_compose_table_save_cache (compose_table);
Packit Service 1d8f1c
    return g_slist_prepend (compose_tables, compose_table);
Packit Service 1d8f1c
}