Blame src/emoji-parser.c

Packit Service 1d8f1c
/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
Packit Service 1d8f1c
/* vim:set et sts=4: */
Packit Service 1d8f1c
/* ibus - The Input Bus
Packit Service 1d8f1c
 * Copyright (C) 2016-2018 Takao Fujiwara <takao.fujiwara1@gmail.com>
Packit Service 1d8f1c
 * Copyright (C) 2016 Red Hat, Inc.
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
/* Convert /usr/share/unicode/cldr/common/annotations/\*.xml and
Packit Service 1d8f1c
 * /usr/share/unicode/emoji/emoji-test.txt
Packit Service 1d8f1c
 * to the dictionary file which look up the Emoji from the annotation.
Packit Service 1d8f1c
 * Get *.xml from https://github.com/fujiwarat/cldr-emoji-annotation
Packit Service 1d8f1c
 * or http://www.unicode.org/repos/cldr/trunk/common/annotations .
Packit Service 1d8f1c
 * Get emoji-test.txt from http://unicode.org/Public/emoji/4.0/ .
Packit Service 1d8f1c
 * en.xml is used for the Unicode annotations and emoji-test.txt is used
Packit Service 1d8f1c
 * for the category, e.g. "Smileys & People".
Packit Service 1d8f1c
 * ASCII emoji annotations are saved in ../data/annotations/en_ascii.xml
Packit Service 1d8f1c
 */
Packit Service 1d8f1c
Packit Service 1d8f1c
#ifdef HAVE_CONFIG_H
Packit Service 1d8f1c
#include <config.h>
Packit Service 1d8f1c
#endif
Packit Service 1d8f1c
Packit Service 1d8f1c
#include <glib.h>
Packit Service 1d8f1c
Packit Service 1d8f1c
#ifdef HAVE_JSON_GLIB1
Packit Service 1d8f1c
#include <json-glib/json-glib.h>
Packit Service 1d8f1c
#endif
Packit Service 1d8f1c
Packit Service 1d8f1c
#ifdef HAVE_LOCALE_H
Packit Service 1d8f1c
#include <locale.h>
Packit Service 1d8f1c
#endif
Packit Service 1d8f1c
Packit Service 1d8f1c
#include <string.h>
Packit Service 1d8f1c
Packit Service 1d8f1c
#include "ibusemoji.h"
Packit Service 1d8f1c
Packit Service 1d8f1c
/* This file has 21 lines about the license at the top of the file. */
Packit Service 1d8f1c
#define LICENSE_LINES 21
Packit Service 1d8f1c
Packit Service 1d8f1c
typedef enum {
Packit Service 1d8f1c
  EMOJI_STRICT,
Packit Service 1d8f1c
  EMOJI_VARIANT,
Packit Service 1d8f1c
  EMOJI_NOVARIANT
Packit Service 1d8f1c
} EmojiDataSearchType;
Packit Service 1d8f1c
Packit Service 1d8f1c
typedef struct _EmojiData EmojiData;
Packit Service 1d8f1c
struct _EmojiData {
Packit Service 1d8f1c
    gchar              *emoji;
Packit Service 1d8f1c
    gchar              *emoji_alternates;
Packit Service 1d8f1c
    GSList             *annotations;
Packit Service 1d8f1c
    gboolean            is_annotation;
Packit Service 1d8f1c
    gchar              *description;
Packit Service 1d8f1c
    gboolean            is_tts;
Packit Service 1d8f1c
    gchar              *category;
Packit Service 1d8f1c
    gchar              *subcategory;
Packit Service 1d8f1c
    gboolean            is_derived;
Packit Service 1d8f1c
    GSList             *list;
Packit Service 1d8f1c
    EmojiDataSearchType search_type;
Packit Service 1d8f1c
};
Packit Service 1d8f1c
Packit Service 1d8f1c
typedef struct _NoTransData NoTransData;
Packit Service 1d8f1c
struct _NoTransData {
Packit Service 1d8f1c
    const gchar *xml_file;
Packit Service 1d8f1c
    const gchar *xml_derived_file;
Packit Service 1d8f1c
    GSList      *emoji_list;
Packit Service 1d8f1c
};
Packit Service 1d8f1c
Packit Service 1d8f1c
static gchar *unicode_emoji_version;
Packit Service 1d8f1c
Packit Service 1d8f1c
Packit Service 1d8f1c
static void
Packit Service 1d8f1c
init_annotations (IBusEmojiData *emoji,
Packit Service 1d8f1c
                  gpointer       user_data)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    g_return_if_fail (IBUS_IS_EMOJI_DATA (emoji));
Packit Service 1d8f1c
    ibus_emoji_data_set_annotations (emoji, NULL);
Packit Service 1d8f1c
    ibus_emoji_data_set_description (emoji, "");
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
static void
Packit Service 1d8f1c
check_no_trans (IBusEmojiData *emoji,
Packit Service 1d8f1c
                NoTransData   *no_trans_data)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    const gchar *str = NULL;
Packit Service 1d8f1c
    g_return_if_fail (IBUS_IS_EMOJI_DATA (emoji));
Packit Service 1d8f1c
    if (ibus_emoji_data_get_annotations (emoji) != NULL)
Packit Service 1d8f1c
        return;
Packit Service 1d8f1c
    str = ibus_emoji_data_get_emoji (emoji);
Packit Service 1d8f1c
    if (g_getenv ("IBUS_EMOJI_PARSER_DEBUG") != NULL) {
Packit Service 1d8f1c
        gchar *basename = NULL;
Packit Service 1d8f1c
        if (no_trans_data->xml_file)
Packit Service 1d8f1c
            basename = g_path_get_basename (no_trans_data->xml_file);
Packit Service 1d8f1c
        else if (no_trans_data->xml_derived_file)
Packit Service 1d8f1c
            basename = g_path_get_basename (no_trans_data->xml_derived_file);
Packit Service 1d8f1c
        else
Packit Service 1d8f1c
            basename = g_strdup ("WRONG FILE");
Packit Service 1d8f1c
        g_warning ("Not found emoji %s in the file %s", str, basename);
Packit Service 1d8f1c
        g_free (basename);
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
    no_trans_data->emoji_list =
Packit Service 1d8f1c
            g_slist_append (no_trans_data->emoji_list, g_strdup (str));
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
int
Packit Service 1d8f1c
strcmp_ibus_emoji_data_str (IBusEmojiData *emoji,
Packit Service 1d8f1c
                            const gchar   *str)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    g_return_val_if_fail (IBUS_IS_EMOJI_DATA (emoji), -1);
Packit Service 1d8f1c
    return g_strcmp0 (ibus_emoji_data_get_emoji (emoji), str);
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
static void
Packit Service 1d8f1c
delete_emoji_from_list (const gchar  *str,
Packit Service 1d8f1c
                        GSList      **list)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    IBusEmojiData *emoji;
Packit Service 1d8f1c
Packit Service 1d8f1c
    g_return_if_fail (list != NULL);
Packit Service 1d8f1c
    GSList *p = g_slist_find_custom (*list,
Packit Service 1d8f1c
                                     str,
Packit Service 1d8f1c
                                     (GCompareFunc)strcmp_ibus_emoji_data_str);
Packit Service 1d8f1c
    g_return_if_fail (p != NULL);
Packit Service 1d8f1c
    emoji = p->data;
Packit Service 1d8f1c
    *list = g_slist_remove (*list, emoji);
Packit Service 1d8f1c
    g_object_unref (emoji);
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
static void
Packit Service 1d8f1c
reset_emoji_element (EmojiData *data)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    g_assert (data != NULL);
Packit Service 1d8f1c
Packit Service 1d8f1c
    g_clear_pointer (&data->emoji, g_free);
Packit Service 1d8f1c
    g_clear_pointer (&data->emoji_alternates, g_free);
Packit Service 1d8f1c
    g_slist_free_full (data->annotations, g_free);
Packit Service 1d8f1c
    data->annotations = NULL;
Packit Service 1d8f1c
    g_clear_pointer (&data->description, g_free);
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
/**
Packit Service 1d8f1c
 * strcmp_novariant:
Packit Service 1d8f1c
 *
Packit Service 1d8f1c
 * Return 0 between non-fully-qualified and fully-qualified emojis.
Packit Service 1d8f1c
 * E.g. U+1F3CC-200D-2642 and U+1F3CC-FE0F-200D-2642-FE0F
Packit Service 1d8f1c
 * in case @a_variant or @b_variant == U+FE0F
Packit Service 1d8f1c
 */
Packit Service 1d8f1c
gint
Packit Service 1d8f1c
strcmp_novariant (const gchar *a,
Packit Service 1d8f1c
                  const gchar *b,
Packit Service 1d8f1c
                  gunichar     a_variant,
Packit Service 1d8f1c
                  gunichar     b_variant)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    gint retval;
Packit Service 1d8f1c
    GString *buff = NULL;;
Packit Service 1d8f1c
    gchar *head = NULL;
Packit Service 1d8f1c
    gchar *p;
Packit Service 1d8f1c
    gchar *variant = NULL;
Packit Service 1d8f1c
    gchar *substr = NULL;
Packit Service 1d8f1c
Packit Service 1d8f1c
    if (a_variant > 0) {
Packit Service 1d8f1c
        if (g_utf8_strchr (a, -1, a_variant) != NULL) {
Packit Service 1d8f1c
            buff = g_string_new (NULL);
Packit Service 1d8f1c
            p = head = g_strdup (a);
Packit Service 1d8f1c
            while (*p != '\0') {
Packit Service 1d8f1c
                if ((variant = g_utf8_strchr (p, -1, a_variant)) == NULL) {
Packit Service 1d8f1c
                    g_string_append (buff, p);
Packit Service 1d8f1c
                    break;
Packit Service 1d8f1c
                }
Packit Service 1d8f1c
                if (p != variant) {
Packit Service 1d8f1c
                    substr = g_strndup (p, variant - p);
Packit Service 1d8f1c
                    g_string_append (buff, substr);
Packit Service 1d8f1c
                    g_free (substr);
Packit Service 1d8f1c
                }
Packit Service 1d8f1c
                p = g_utf8_next_char (variant);
Packit Service 1d8f1c
            }
Packit Service 1d8f1c
            retval = g_strcmp0 (buff->str, b);
Packit Service 1d8f1c
            g_string_free (buff, TRUE);
Packit Service 1d8f1c
            g_free (head);
Packit Service 1d8f1c
            return retval;
Packit Service 1d8f1c
        } else {
Packit Service 1d8f1c
            return -1;
Packit Service 1d8f1c
        }
Packit Service 1d8f1c
    } else if (b_variant > 0) {
Packit Service 1d8f1c
        if (g_utf8_strchr (b, -1, b_variant) != NULL) {
Packit Service 1d8f1c
            buff = g_string_new (NULL);
Packit Service 1d8f1c
            p = head = g_strdup (b);
Packit Service 1d8f1c
            while (*p != '\0') {
Packit Service 1d8f1c
                if ((variant = g_utf8_strchr (p, -1, b_variant)) == NULL) {
Packit Service 1d8f1c
                    g_string_append (buff, p);
Packit Service 1d8f1c
                    break;
Packit Service 1d8f1c
                }
Packit Service 1d8f1c
                if (p != variant) {
Packit Service 1d8f1c
                    substr = g_strndup (p, variant - p);
Packit Service 1d8f1c
                    g_string_append (buff, substr);
Packit Service 1d8f1c
                    g_free (substr);
Packit Service 1d8f1c
                }
Packit Service 1d8f1c
                p = g_utf8_next_char (variant);
Packit Service 1d8f1c
            }
Packit Service 1d8f1c
            retval = g_strcmp0 (a, buff->str);
Packit Service 1d8f1c
            g_string_free (buff, TRUE);
Packit Service 1d8f1c
            g_free (head);
Packit Service 1d8f1c
            return retval;
Packit Service 1d8f1c
        } else {
Packit Service 1d8f1c
            return -1;
Packit Service 1d8f1c
        }
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
    return g_strcmp0 (a, b);
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
gint
Packit Service 1d8f1c
find_emoji_data_list (IBusEmojiData *a,
Packit Service 1d8f1c
                      EmojiData     *b)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    const gchar *a_str;
Packit Service 1d8f1c
Packit Service 1d8f1c
    g_return_val_if_fail (IBUS_IS_EMOJI_DATA (a), 0);
Packit Service 1d8f1c
Packit Service 1d8f1c
    a_str = ibus_emoji_data_get_emoji (a);
Packit Service 1d8f1c
    switch (b->search_type) {
Packit Service 1d8f1c
    case EMOJI_VARIANT:
Packit Service 1d8f1c
        if (strcmp_novariant (a_str, b->emoji, 0xfe0e, 0) == 0)
Packit Service 1d8f1c
            return 0;
Packit Service 1d8f1c
        else if (strcmp_novariant (a_str, b->emoji, 0xfe0f, 0) == 0)
Packit Service 1d8f1c
            return 0;
Packit Service 1d8f1c
        else
Packit Service 1d8f1c
            return g_strcmp0 (a_str, b->emoji);
Packit Service 1d8f1c
        break;
Packit Service 1d8f1c
    case EMOJI_NOVARIANT:
Packit Service 1d8f1c
        if (strcmp_novariant (a_str, b->emoji, 0, 0xfe0e) == 0)
Packit Service 1d8f1c
            return 0;
Packit Service 1d8f1c
        else if (strcmp_novariant (a_str, b->emoji, 0, 0xfe0f) == 0)
Packit Service 1d8f1c
            return 0;
Packit Service 1d8f1c
        else
Packit Service 1d8f1c
            return g_strcmp0 (a_str, b->emoji);
Packit Service 1d8f1c
        break;
Packit Service 1d8f1c
    default:;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
    return g_strcmp0 (a_str, b->emoji);
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
static void
Packit Service 1d8f1c
emoji_data_update_object (EmojiData     *data,
Packit Service 1d8f1c
                          IBusEmojiData *emoji)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    GSList *src_annotations = data->annotations;
Packit Service 1d8f1c
    GSList *dest_annotations = ibus_emoji_data_get_annotations (emoji);
Packit Service 1d8f1c
    GSList *l;
Packit Service 1d8f1c
    gboolean updated_annotations = FALSE;
Packit Service 1d8f1c
    for (l = src_annotations; l; l = l->next) {
Packit Service 1d8f1c
        GSList *duplicated = g_slist_find_custom (dest_annotations,
Packit Service 1d8f1c
                                                  l->data,
Packit Service 1d8f1c
                                                  (GCompareFunc) g_strcmp0);
Packit Service 1d8f1c
        if (duplicated == NULL) {
Packit Service 1d8f1c
            dest_annotations = g_slist_append (dest_annotations,
Packit Service 1d8f1c
                                               g_strdup (l->data));
Packit Service 1d8f1c
            updated_annotations = TRUE;
Packit Service 1d8f1c
        }
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
    if (updated_annotations) {
Packit Service 1d8f1c
        ibus_emoji_data_set_annotations (
Packit Service 1d8f1c
                    emoji,
Packit Service 1d8f1c
                    g_slist_copy_deep (dest_annotations,
Packit Service 1d8f1c
                                       (GCopyFunc) g_strdup,
Packit Service 1d8f1c
                                       NULL));
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
    if (data->description)
Packit Service 1d8f1c
        ibus_emoji_data_set_description (emoji, data->description);
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
static void
Packit Service 1d8f1c
emoji_data_new_object (EmojiData *data)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    IBusEmojiData *emoji =
Packit Service 1d8f1c
            ibus_emoji_data_new ("emoji",
Packit Service 1d8f1c
                                 data->emoji,
Packit Service 1d8f1c
                                 "annotations",
Packit Service 1d8f1c
                                 data->annotations,
Packit Service 1d8f1c
                                 "description",
Packit Service 1d8f1c
                                 data->description ? data->description
Packit Service 1d8f1c
                                         : g_strdup (""),
Packit Service 1d8f1c
                                 "category",
Packit Service 1d8f1c
                                 data->category ? data->category
Packit Service 1d8f1c
                                         : g_strdup (""),
Packit Service 1d8f1c
                                 NULL);
Packit Service 1d8f1c
    data->list = g_slist_append (data->list, emoji);
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
static void
Packit Service 1d8f1c
update_emoji_list (EmojiData *data,
Packit Service 1d8f1c
                   gboolean   base_update)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    GSList *list;
Packit Service 1d8f1c
    data->search_type = EMOJI_STRICT;
Packit Service 1d8f1c
    list = g_slist_find_custom (
Packit Service 1d8f1c
            data->list,
Packit Service 1d8f1c
            data,
Packit Service 1d8f1c
            (GCompareFunc) find_emoji_data_list);
Packit Service 1d8f1c
    if (list) {
Packit Service 1d8f1c
        emoji_data_update_object (data, list->data);
Packit Service 1d8f1c
        return;
Packit Service 1d8f1c
    } else if (base_update) {
Packit Service 1d8f1c
        emoji_data_new_object (data);
Packit Service 1d8f1c
        return;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
    if (g_utf8_strchr (data->emoji, -1, 0xfe0e) == NULL &&
Packit Service 1d8f1c
        g_utf8_strchr (data->emoji, -1, 0xfe0f) == NULL) {
Packit Service 1d8f1c
        data->search_type = EMOJI_VARIANT;
Packit Service 1d8f1c
        list = g_slist_find_custom (
Packit Service 1d8f1c
                data->list,
Packit Service 1d8f1c
                data,
Packit Service 1d8f1c
                (GCompareFunc) find_emoji_data_list);
Packit Service 1d8f1c
        if (list) {
Packit Service 1d8f1c
            emoji_data_update_object (data, list->data);
Packit Service 1d8f1c
            return;
Packit Service 1d8f1c
        }
Packit Service 1d8f1c
    } else {
Packit Service 1d8f1c
        data->search_type = EMOJI_NOVARIANT;
Packit Service 1d8f1c
        list = g_slist_find_custom (
Packit Service 1d8f1c
                data->list,
Packit Service 1d8f1c
                data,
Packit Service 1d8f1c
                (GCompareFunc) find_emoji_data_list);
Packit Service 1d8f1c
        if (list) {
Packit Service 1d8f1c
            emoji_data_update_object (data, list->data);
Packit Service 1d8f1c
            return;
Packit Service 1d8f1c
        }
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
    emoji_data_new_object (data);
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
static void
Packit Service 1d8f1c
unicode_annotations_start_element_cb (GMarkupParseContext *context,
Packit Service 1d8f1c
                                      const gchar         *element_name,
Packit Service 1d8f1c
                                      const gchar        **attribute_names,
Packit Service 1d8f1c
                                      const gchar        **attribute_values,
Packit Service 1d8f1c
                                      gpointer             user_data,
Packit Service 1d8f1c
                                      GError             **error)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    EmojiData *data = (EmojiData *) user_data;
Packit Service 1d8f1c
    int i;
Packit Service 1d8f1c
    const gchar *attribute;
Packit Service 1d8f1c
    const gchar *value;
Packit Service 1d8f1c
Packit Service 1d8f1c
    g_assert (data != NULL);
Packit Service 1d8f1c
Packit Service 1d8f1c
    if (g_strcmp0 (element_name, "annotation") != 0)
Packit Service 1d8f1c
        return;
Packit Service 1d8f1c
Packit Service 1d8f1c
    reset_emoji_element (data);
Packit Service 1d8f1c
Packit Service 1d8f1c
    for (i = 0; (attribute = attribute_names[i]) != NULL; i++) {
Packit Service 1d8f1c
        value = attribute_values[i];
Packit Service 1d8f1c
Packit Service 1d8f1c
        if (g_strcmp0 (attribute, "cp") == 0) {
Packit Service 1d8f1c
            if (value == NULL || *value == '\0') {
Packit Service 1d8f1c
                g_warning ("cp='' in unicode.org annotations file");
Packit Service 1d8f1c
                return;
Packit Service 1d8f1c
            } else if (value[0] == '[' && value[strlen(value) - 1] == ']') {
Packit Service 1d8f1c
                g_warning ("cp!='[emoji]' is an old format in unicode.org"
Packit Service 1d8f1c
                           " annotations file");
Packit Service 1d8f1c
                data->emoji = g_strndup (value + 1, strlen(value) - 2);
Packit Service 1d8f1c
            } else {
Packit Service 1d8f1c
                data->emoji = g_strdup (value);
Packit Service 1d8f1c
            }
Packit Service 1d8f1c
        }
Packit Service 1d8f1c
        /* tts seems 'text to speach' and it would be a description
Packit Service 1d8f1c
         * instead of annotation.
Packit Service 1d8f1c
         */
Packit Service 1d8f1c
        else if (g_strcmp0 (attribute, "type") == 0) {
Packit Service 1d8f1c
            if (g_strcmp0 (value, "tts") == 0) {
Packit Service 1d8f1c
                data->is_tts = TRUE;
Packit Service 1d8f1c
            }
Packit Service 1d8f1c
        }
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    data->is_annotation = TRUE;
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
static void
Packit Service 1d8f1c
unicode_annotations_end_element_cb (GMarkupParseContext *context,
Packit Service 1d8f1c
                                    const gchar         *element_name,
Packit Service 1d8f1c
                                    gpointer             user_data,
Packit Service 1d8f1c
                                    GError             **error)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    EmojiData *data = (EmojiData *) user_data;
Packit Service 1d8f1c
Packit Service 1d8f1c
    g_assert (data != NULL);
Packit Service 1d8f1c
    if (!data->is_annotation)
Packit Service 1d8f1c
        return;
Packit Service 1d8f1c
Packit Service 1d8f1c
    update_emoji_list (data, FALSE);
Packit Service 1d8f1c
    data->is_annotation = FALSE;
Packit Service 1d8f1c
    data->is_tts = FALSE;
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
void
Packit Service 1d8f1c
unicode_annotations_text_cb (GMarkupParseContext *context,
Packit Service 1d8f1c
                             const gchar         *text,
Packit Service 1d8f1c
                             gsize                text_len,
Packit Service 1d8f1c
                             gpointer             user_data,
Packit Service 1d8f1c
                             GError             **error)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    EmojiData *data = (EmojiData *) user_data;
Packit Service 1d8f1c
    gchar **annotations = NULL;
Packit Service 1d8f1c
    const gchar *annotation;
Packit Service 1d8f1c
    int i;
Packit Service 1d8f1c
Packit Service 1d8f1c
    g_assert (data != NULL);
Packit Service 1d8f1c
    if (!data->is_annotation)
Packit Service 1d8f1c
        return;
Packit Service 1d8f1c
    if (data->is_tts) {
Packit Service 1d8f1c
        if (data->description) {
Packit Service 1d8f1c
            g_warning ("Duplicated 'tts' is found: %s: %s",
Packit Service 1d8f1c
                       data->description, text);
Packit Service 1d8f1c
            g_clear_pointer (&data->description, g_free);
Packit Service 1d8f1c
        }
Packit Service 1d8f1c
        data->description = g_strdup (text);
Packit Service 1d8f1c
        return;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
    annotations = g_strsplit (text, " | ", -1);
Packit Service 1d8f1c
    for (i = 0; (annotation = annotations[i]) != NULL; i++) {
Packit Service 1d8f1c
        GSList *duplicated = g_slist_find_custom (data->annotations,
Packit Service 1d8f1c
                                                  annotation,
Packit Service 1d8f1c
                                                  (GCompareFunc) g_strcmp0);
Packit Service 1d8f1c
        if (duplicated == NULL) {
Packit Service 1d8f1c
            data->annotations = g_slist_prepend (data->annotations,
Packit Service 1d8f1c
                                                 g_strdup (annotation));
Packit Service 1d8f1c
        }
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
    g_strfreev (annotations);
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
static gboolean
Packit Service 1d8f1c
unicode_annotations_parse_xml_file (const gchar  *filename,
Packit Service 1d8f1c
                                    GSList      **list,
Packit Service 1d8f1c
                                    gboolean      is_derived)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    gchar *content = NULL;
Packit Service 1d8f1c
    gsize length = 0;
Packit Service 1d8f1c
    GError *error = NULL;
Packit Service 1d8f1c
    const static GMarkupParser parser = {
Packit Service 1d8f1c
        unicode_annotations_start_element_cb,
Packit Service 1d8f1c
        unicode_annotations_end_element_cb,
Packit Service 1d8f1c
        unicode_annotations_text_cb,
Packit Service 1d8f1c
        NULL,
Packit Service 1d8f1c
        NULL
Packit Service 1d8f1c
    };
Packit Service 1d8f1c
    GMarkupParseContext *context = NULL;
Packit Service 1d8f1c
    EmojiData data = { 0, };
Packit Service 1d8f1c
Packit Service 1d8f1c
    g_return_val_if_fail (filename != NULL, FALSE);
Packit Service 1d8f1c
    g_return_val_if_fail (list != NULL, FALSE);
Packit Service 1d8f1c
Packit Service 1d8f1c
    if (!g_file_get_contents (filename, &content, &length, &error)) {
Packit Service 1d8f1c
        g_warning ("Failed to load %s: %s", filename,
Packit Service 1d8f1c
                   error ? error->message : "");
Packit Service 1d8f1c
        goto failed_to_parse_unicode_annotations;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    data.list = *list;
Packit Service 1d8f1c
    data.is_derived = is_derived;
Packit Service 1d8f1c
Packit Service 1d8f1c
    context = g_markup_parse_context_new (&parser, 0, &data, NULL);
Packit Service 1d8f1c
    if (!g_markup_parse_context_parse (context, content, length, &error)) {
Packit Service 1d8f1c
        g_warning ("Failed to parse %s: %s", filename, error->message);
Packit Service 1d8f1c
        goto failed_to_parse_unicode_annotations;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    reset_emoji_element (&data);
Packit Service 1d8f1c
    g_markup_parse_context_free (context);
Packit Service 1d8f1c
    g_free (content);
Packit Service 1d8f1c
    *list = data.list;
Packit Service 1d8f1c
    return TRUE;
Packit Service 1d8f1c
Packit Service 1d8f1c
failed_to_parse_unicode_annotations:
Packit Service 1d8f1c
    if (error)
Packit Service 1d8f1c
        g_error_free (error);
Packit Service 1d8f1c
    if (data.list)
Packit Service 1d8f1c
        g_slist_free (data.list);
Packit Service 1d8f1c
    if (context)
Packit Service 1d8f1c
        g_markup_parse_context_free (context);
Packit Service 1d8f1c
    g_free (content);
Packit Service 1d8f1c
    return FALSE;
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
static gboolean
Packit Service 1d8f1c
unicode_emoji_test_parse_unicode (const gchar *line,
Packit Service 1d8f1c
                                  EmojiData   *data)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    GString *emoji = NULL;
Packit Service 1d8f1c
    gchar *endptr = NULL;
Packit Service 1d8f1c
    guint32 uch;
Packit Service 1d8f1c
    static gchar outbuf[8] = { 0, };
Packit Service 1d8f1c
Packit Service 1d8f1c
    g_return_val_if_fail (line != NULL, FALSE);
Packit Service 1d8f1c
Packit Service 1d8f1c
    emoji = g_string_new (NULL);
Packit Service 1d8f1c
    while (line && *line) {
Packit Service 1d8f1c
        uch = g_ascii_strtoull (line, &endptr, 16);
Packit Service 1d8f1c
        outbuf[g_unichar_to_utf8 (uch, outbuf)] = '\0';
Packit Service 1d8f1c
        g_string_append (emoji, outbuf);
Packit Service 1d8f1c
        if (*endptr == '\0') {
Packit Service 1d8f1c
            break;
Packit Service 1d8f1c
        }
Packit Service 1d8f1c
        line = endptr + 1;
Packit Service 1d8f1c
        while (*line == ' ')
Packit Service 1d8f1c
            line++;
Packit Service 1d8f1c
        endptr = NULL;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    data->emoji = g_string_free (emoji, FALSE);
Packit Service 1d8f1c
    return TRUE;
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
static gboolean
Packit Service 1d8f1c
unicode_emoji_test_parse_description (const gchar *line,
Packit Service 1d8f1c
                                      EmojiData   *data)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    g_return_val_if_fail (line != NULL, FALSE);
Packit Service 1d8f1c
Packit Service 1d8f1c
    /* skip spaces */
Packit Service 1d8f1c
    while (*line == ' ')
Packit Service 1d8f1c
        line++;
Packit Service 1d8f1c
    /* skip emoji */
Packit Service 1d8f1c
    while (*line != ' ')
Packit Service 1d8f1c
        line++;
Packit Service 1d8f1c
    /* skip spaces */
Packit Service 1d8f1c
    while (*line == ' ')
Packit Service 1d8f1c
        line++;
Packit Service 1d8f1c
    if (*line == '\0')
Packit Service 1d8f1c
        return FALSE;
Packit Service 1d8f1c
    data->description = g_strdup (line);
Packit Service 1d8f1c
    return TRUE;
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
#define EMOJI_VERSION_TAG "# Version: "
Packit Service 1d8f1c
#define EMOJI_GROUP_TAG "# group: "
Packit Service 1d8f1c
#define EMOJI_SUBGROUP_TAG "# subgroup: "
Packit Service 1d8f1c
#define EMOJI_NON_FULLY_QUALIFIED_TAG "non-fully-qualified"
Packit Service 1d8f1c
Packit Service 1d8f1c
static gboolean
Packit Service 1d8f1c
unicode_emoji_test_parse_line (const gchar *line,
Packit Service 1d8f1c
                               EmojiData   *data)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    int tag_length;
Packit Service 1d8f1c
    gchar **segments = NULL;
Packit Service 1d8f1c
Packit Service 1d8f1c
    g_return_val_if_fail (line != NULL, FALSE);
Packit Service 1d8f1c
Packit Service 1d8f1c
    tag_length = strlen (EMOJI_VERSION_TAG);
Packit Service 1d8f1c
    if (strlen (line) > tag_length &&
Packit Service 1d8f1c
        g_ascii_strncasecmp (line, EMOJI_VERSION_TAG, tag_length) == 0) {
Packit Service 1d8f1c
        unicode_emoji_version = g_strdup (line + tag_length);
Packit Service 1d8f1c
        return TRUE;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
    tag_length = strlen (EMOJI_GROUP_TAG);
Packit Service 1d8f1c
    if (strlen (line) > tag_length &&
Packit Service 1d8f1c
        g_ascii_strncasecmp (line, EMOJI_GROUP_TAG, tag_length) == 0) {
Packit Service 1d8f1c
        g_free (data->category);
Packit Service 1d8f1c
        g_clear_pointer (&data->subcategory, g_free);
Packit Service 1d8f1c
        data->category = g_strdup (line + tag_length);
Packit Service 1d8f1c
        return TRUE;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
    tag_length = strlen (EMOJI_SUBGROUP_TAG);
Packit Service 1d8f1c
    if (strlen (line) > tag_length &&
Packit Service 1d8f1c
        g_ascii_strncasecmp (line, EMOJI_SUBGROUP_TAG, tag_length) == 0) {
Packit Service 1d8f1c
        g_free (data->subcategory);
Packit Service 1d8f1c
        data->subcategory = g_strdup (line + tag_length);
Packit Service 1d8f1c
        return TRUE;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
    if (*line == '#')
Packit Service 1d8f1c
        return TRUE;
Packit Service 1d8f1c
    segments = g_strsplit (line, "; ", 2);
Packit Service 1d8f1c
    if (segments[1] == NULL) {
Packit Service 1d8f1c
        g_warning ("No qualified line\n");
Packit Service 1d8f1c
        goto failed_to_parse_unicode_emoji_test_line;
Packit Service 1d8f1c
        return FALSE;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
    tag_length = strlen (EMOJI_NON_FULLY_QUALIFIED_TAG);
Packit Service 1d8f1c
    /* Ignore the non-fully-qualified emoji */
Packit Service 1d8f1c
    if (g_ascii_strncasecmp (segments[1], EMOJI_NON_FULLY_QUALIFIED_TAG,
Packit Service 1d8f1c
                             tag_length) == 0) {
Packit Service 1d8f1c
        g_strfreev (segments);
Packit Service 1d8f1c
        return TRUE;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
    unicode_emoji_test_parse_unicode (segments[0], data);
Packit Service 1d8f1c
    g_strfreev (segments);
Packit Service 1d8f1c
    segments = g_strsplit (line, "# ", 2);
Packit Service 1d8f1c
    if (segments[1] == NULL) {
Packit Service 1d8f1c
        g_warning ("No description line\n");
Packit Service 1d8f1c
        goto failed_to_parse_unicode_emoji_test_line;
Packit Service 1d8f1c
        return FALSE;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
    unicode_emoji_test_parse_description (segments[1], data);
Packit Service 1d8f1c
    g_strfreev (segments);
Packit Service 1d8f1c
    if (data->annotations == NULL) {
Packit Service 1d8f1c
        if (data->subcategory) {
Packit Service 1d8f1c
            int i;
Packit Service 1d8f1c
            gchar *amp;
Packit Service 1d8f1c
            segments = g_strsplit(data->subcategory, "-", -1);
Packit Service 1d8f1c
            for (i = 0; segments && segments[i]; i++) {
Packit Service 1d8f1c
                if ((amp = strchr (segments[i], '&')) != NULL) {
Packit Service 1d8f1c
                    if (amp - segments[i] <= 1) {
Packit Service 1d8f1c
                        g_warning ("Wrong ampersand");
Packit Service 1d8f1c
                        goto failed_to_parse_unicode_emoji_test_line;
Packit Service 1d8f1c
                    }
Packit Service 1d8f1c
                    data->annotations = g_slist_append (
Packit Service 1d8f1c
                            data->annotations,
Packit Service 1d8f1c
                            g_strndup (segments[i], amp - segments[i] - 1));
Packit Service 1d8f1c
                    data->annotations = g_slist_append (
Packit Service 1d8f1c
                            data->annotations,
Packit Service 1d8f1c
                            g_strdup (amp + 1));
Packit Service 1d8f1c
                    continue;
Packit Service 1d8f1c
                }
Packit Service 1d8f1c
                data->annotations = g_slist_append (data->annotations,
Packit Service 1d8f1c
                                                    g_strdup (segments[i]));
Packit Service 1d8f1c
            }
Packit Service 1d8f1c
            g_strfreev (segments);
Packit Service 1d8f1c
        } else {
Packit Service 1d8f1c
            g_warning ("No subcategory line\n");
Packit Service 1d8f1c
            goto failed_to_parse_unicode_emoji_test_line;
Packit Service 1d8f1c
        }
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
    update_emoji_list (data, TRUE);
Packit Service 1d8f1c
    reset_emoji_element (data);
Packit Service 1d8f1c
    return TRUE;
Packit Service 1d8f1c
Packit Service 1d8f1c
failed_to_parse_unicode_emoji_test_line:
Packit Service 1d8f1c
    if (segments)
Packit Service 1d8f1c
        g_strfreev (segments);
Packit Service 1d8f1c
    reset_emoji_element (data);
Packit Service 1d8f1c
    return FALSE;
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
#undef EMOJI_VERSION_TAG
Packit Service 1d8f1c
#undef EMOJI_GROUP_TAG
Packit Service 1d8f1c
#undef EMOJI_SUBGROUP_TAG
Packit Service 1d8f1c
#undef EMOJI_NON_FULLY_QUALIFIED_TAG
Packit Service 1d8f1c
Packit Service 1d8f1c
static gboolean
Packit Service 1d8f1c
unicode_emoji_test_parse_file (const gchar *filename,
Packit Service 1d8f1c
                               GSList      **list)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    gchar *content = NULL;
Packit Service 1d8f1c
    gsize length = 0;
Packit Service 1d8f1c
    GError *error = NULL;
Packit Service 1d8f1c
    gchar *head, *end, *line;
Packit Service 1d8f1c
    int n = 1;
Packit Service 1d8f1c
    EmojiData data = { 0, };
Packit Service 1d8f1c
Packit Service 1d8f1c
    g_return_val_if_fail (filename != NULL, FALSE);
Packit Service 1d8f1c
    g_return_val_if_fail (list != NULL, FALSE);
Packit Service 1d8f1c
Packit Service 1d8f1c
    if (!g_file_get_contents (filename, &content, &length, &error)) {
Packit Service 1d8f1c
        g_warning ("Failed to load %s: %s",
Packit Service 1d8f1c
                   filename, error ? error->message : "");
Packit Service 1d8f1c
        goto failed_to_parse_unicode_emoji_test;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
    head = end = content;
Packit Service 1d8f1c
    while (*end == '\n' && end - content < length) {
Packit Service 1d8f1c
        end++;
Packit Service 1d8f1c
        n++;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
    head = end;
Packit Service 1d8f1c
    data.list = *list;
Packit Service 1d8f1c
    while (end - content < length) {
Packit Service 1d8f1c
        while (*end != '\n' && end - content < length)
Packit Service 1d8f1c
            end++;
Packit Service 1d8f1c
        if (end - content >= length)
Packit Service 1d8f1c
            break;
Packit Service 1d8f1c
        line = g_strndup (head, end - head);
Packit Service 1d8f1c
        if (!unicode_emoji_test_parse_line (line, &data))
Packit Service 1d8f1c
            g_warning ("parse error #%d in %s version %s: %s",
Packit Service 1d8f1c
                       n, filename,
Packit Service 1d8f1c
                       unicode_emoji_version ? unicode_emoji_version : "(null)",
Packit Service 1d8f1c
                       line);
Packit Service 1d8f1c
        while (*end == '\n' && end - content < length) {
Packit Service 1d8f1c
            end++;
Packit Service 1d8f1c
            n++;
Packit Service 1d8f1c
        }
Packit Service 1d8f1c
        g_free (line);
Packit Service 1d8f1c
        head = end;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
    g_free (content);
Packit Service 1d8f1c
    g_free (unicode_emoji_version);
Packit Service 1d8f1c
    *list = data.list;
Packit Service 1d8f1c
    return TRUE;
Packit Service 1d8f1c
Packit Service 1d8f1c
failed_to_parse_unicode_emoji_test:
Packit Service 1d8f1c
    if (error)
Packit Service 1d8f1c
        g_error_free (error);
Packit Service 1d8f1c
    g_clear_pointer (&content, g_free);
Packit Service 1d8f1c
    return FALSE;
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
static gboolean 
Packit Service 1d8f1c
unicode_emoji_parse_dir (const gchar *dirname,
Packit Service 1d8f1c
                         GSList      **list)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    gchar *filename = NULL;
Packit Service 1d8f1c
    g_return_val_if_fail (dirname != NULL, FALSE);
Packit Service 1d8f1c
    g_return_val_if_fail (list != NULL, FALSE);
Packit Service 1d8f1c
Packit Service 1d8f1c
    filename = g_build_path ("/", dirname, "emoji-test.txt", NULL);
Packit Service 1d8f1c
    if (!unicode_emoji_test_parse_file (filename, list)) {
Packit Service 1d8f1c
        g_free (filename);
Packit Service 1d8f1c
        return FALSE;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
    g_free (filename);
Packit Service 1d8f1c
    return TRUE;
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
#ifdef HAVE_JSON_GLIB1
Packit Service 1d8f1c
static gboolean
Packit Service 1d8f1c
parse_emojione_unicode (JsonNode  *node,
Packit Service 1d8f1c
                        EmojiData *data,
Packit Service 1d8f1c
                        gboolean   is_alternates)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    const gchar *str, *unicode;
Packit Service 1d8f1c
    gchar *endptr = NULL;
Packit Service 1d8f1c
    guint32 uch;
Packit Service 1d8f1c
    static gchar outbuf[8] = { 0, };
Packit Service 1d8f1c
    GString *emoji;
Packit Service 1d8f1c
Packit Service 1d8f1c
    if (json_node_get_node_type (node) != JSON_NODE_VALUE) {
Packit Service 1d8f1c
        g_warning ("'unicode' element is not string");
Packit Service 1d8f1c
        return FALSE;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    emoji = g_string_new (NULL);
Packit Service 1d8f1c
    str = unicode = json_node_get_string (node);
Packit Service 1d8f1c
    while (str && *str) {
Packit Service 1d8f1c
        uch = g_ascii_strtoull (str, &endptr, 16);
Packit Service 1d8f1c
        outbuf[g_unichar_to_utf8 (uch, outbuf)] = '\0';
Packit Service 1d8f1c
        g_string_append (emoji, outbuf);
Packit Service 1d8f1c
        if (*endptr == '\0') {
Packit Service 1d8f1c
            break;
Packit Service 1d8f1c
        } else {
Packit Service 1d8f1c
            switch (*endptr) {
Packit Service 1d8f1c
            case '-':
Packit Service 1d8f1c
                endptr++;
Packit Service 1d8f1c
                break;
Packit Service 1d8f1c
            default:
Packit Service 1d8f1c
                g_warning ("Failed to parse unicode %s", unicode);
Packit Service 1d8f1c
            }
Packit Service 1d8f1c
        }
Packit Service 1d8f1c
        str = endptr;
Packit Service 1d8f1c
        endptr = NULL;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    if (is_alternates)
Packit Service 1d8f1c
        data->emoji_alternates = g_string_free (emoji, FALSE);
Packit Service 1d8f1c
    else
Packit Service 1d8f1c
        data->emoji = g_string_free (emoji, FALSE);
Packit Service 1d8f1c
Packit Service 1d8f1c
    return TRUE;
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
static gboolean
Packit Service 1d8f1c
parse_emojione_shortname (JsonNode  *node,
Packit Service 1d8f1c
                          EmojiData *data)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
#if 0
Packit Service 1d8f1c
    const gchar *shortname;
Packit Service 1d8f1c
    gchar *head, *s;
Packit Service 1d8f1c
    int length;
Packit Service 1d8f1c
    GSList *duplicated;
Packit Service 1d8f1c
Packit Service 1d8f1c
    if (json_node_get_node_type (node) != JSON_NODE_VALUE) {
Packit Service 1d8f1c
        g_warning ("'shortname' element is not string");
Packit Service 1d8f1c
        return FALSE;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    /* The format is ':short_name:' */
Packit Service 1d8f1c
    shortname = json_node_get_string (node);
Packit Service 1d8f1c
    if (shortname == 0 || *shortname == '\0')
Packit Service 1d8f1c
        return TRUE;
Packit Service 1d8f1c
    if (*shortname != ':') {
Packit Service 1d8f1c
        g_warning ("'shortname' format is different: %s", shortname);
Packit Service 1d8f1c
        return FALSE;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    length = strlen (shortname);
Packit Service 1d8f1c
    head  = g_new0 (gchar, length);
Packit Service 1d8f1c
    strcpy (head, shortname + 1);
Packit Service 1d8f1c
    for (s = head; *s; s++) {
Packit Service 1d8f1c
        if (*s == ':') {
Packit Service 1d8f1c
            *s = '\0';
Packit Service 1d8f1c
            break;
Packit Service 1d8f1c
        } else if (*s == '_') {
Packit Service 1d8f1c
            *s = ' ';
Packit Service 1d8f1c
        }
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    if (head == NULL || *head == '\0') {
Packit Service 1d8f1c
        g_warning ("'shortname' format is different: %s", shortname);
Packit Service 1d8f1c
        g_free (head);
Packit Service 1d8f1c
        return FALSE;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    duplicated = g_slist_find_custom (data->annotations,
Packit Service 1d8f1c
                                      head,
Packit Service 1d8f1c
                                      (GCompareFunc) g_strcmp0);
Packit Service 1d8f1c
    if (duplicated == NULL) {
Packit Service 1d8f1c
        data->annotations = g_slist_prepend (data->annotations,
Packit Service 1d8f1c
                                             head);
Packit Service 1d8f1c
    } else {
Packit Service 1d8f1c
       g_free (head);
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
#endif
Packit Service 1d8f1c
    return TRUE;
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
static gboolean
Packit Service 1d8f1c
parse_emojione_name (JsonNode  *node,
Packit Service 1d8f1c
                     EmojiData *data)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    const gchar *name;
Packit Service 1d8f1c
Packit Service 1d8f1c
    if (json_node_get_node_type (node) != JSON_NODE_VALUE) {
Packit Service 1d8f1c
        g_warning ("'name' element is not string");
Packit Service 1d8f1c
        return FALSE;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    name = json_node_get_string (node);
Packit Service 1d8f1c
Packit Service 1d8f1c
    if (name == NULL || *name == '\0')
Packit Service 1d8f1c
        return TRUE;
Packit Service 1d8f1c
Packit Service 1d8f1c
    data->description = g_strdup (name);
Packit Service 1d8f1c
Packit Service 1d8f1c
    return TRUE;
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
static gboolean
Packit Service 1d8f1c
parse_emojione_category (JsonNode  *node,
Packit Service 1d8f1c
                         EmojiData *data)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    const gchar *category;
Packit Service 1d8f1c
    GSList *duplicated;
Packit Service 1d8f1c
Packit Service 1d8f1c
    if (json_node_get_node_type (node) != JSON_NODE_VALUE) {
Packit Service 1d8f1c
        g_warning ("'category' element is not string");
Packit Service 1d8f1c
        return FALSE;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    category = json_node_get_string (node);
Packit Service 1d8f1c
Packit Service 1d8f1c
    if (category == NULL || *category == '\0')
Packit Service 1d8f1c
        return TRUE;
Packit Service 1d8f1c
Packit Service 1d8f1c
    data->category = g_strdup (category);
Packit Service 1d8f1c
    duplicated = g_slist_find_custom (data->annotations,
Packit Service 1d8f1c
                                      category,
Packit Service 1d8f1c
                                      (GCompareFunc) g_strcmp0);
Packit Service 1d8f1c
    if (duplicated == NULL) {
Packit Service 1d8f1c
        data->annotations = g_slist_prepend (data->annotations,
Packit Service 1d8f1c
                                             g_strdup (category));
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    return TRUE;
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
#ifdef EMOJIONE_ALIASES_ASCII_PRINT
Packit Service 1d8f1c
static gchar *
Packit Service 1d8f1c
text_to_entity (const gchar *text)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    gchar *p;
Packit Service 1d8f1c
    GString *buff = g_string_new (NULL);
Packit Service 1d8f1c
    for (p = text; *p; p++) {
Packit Service 1d8f1c
        switch (*p) {
Packit Service 1d8f1c
        case '<':
Packit Service 1d8f1c
            g_string_append (buff, "<");
Packit Service 1d8f1c
            break;
Packit Service 1d8f1c
        case '>':
Packit Service 1d8f1c
            g_string_append (buff, ">");
Packit Service 1d8f1c
            break;
Packit Service 1d8f1c
        case '&':
Packit Service 1d8f1c
            g_string_append (buff, "&");
Packit Service 1d8f1c
            break;
Packit Service 1d8f1c
        default:
Packit Service 1d8f1c
            g_string_append_c (buff, *p);
Packit Service 1d8f1c
        }
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
    g_string_free (buff, FALSE);
Packit Service 1d8f1c
}
Packit Service 1d8f1c
#endif
Packit Service 1d8f1c
Packit Service 1d8f1c
static gboolean
Packit Service 1d8f1c
parse_emojione_aliases_ascii (JsonNode  *node,
Packit Service 1d8f1c
                              EmojiData *data)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    JsonArray *aliases_ascii;
Packit Service 1d8f1c
    guint i, length;
Packit Service 1d8f1c
Packit Service 1d8f1c
    if (json_node_get_node_type (node) != JSON_NODE_ARRAY) {
Packit Service 1d8f1c
        g_warning ("'aliases_ascii' element is not array");
Packit Service 1d8f1c
        return FALSE;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    aliases_ascii = json_node_get_array (node);
Packit Service 1d8f1c
    length = json_array_get_length (aliases_ascii);
Packit Service 1d8f1c
    for (i = 0; i < length; i++) {
Packit Service 1d8f1c
#ifdef EMOJIONE_ALIASES_ASCII_PRINT
Packit Service 1d8f1c
        if (i == 0)
Packit Service 1d8f1c
            printf ("        <annotation cp=\"%s\">", data->emoji);
Packit Service 1d8f1c
#endif
Packit Service 1d8f1c
        const gchar *alias = json_array_get_string_element (aliases_ascii, i);
Packit Service 1d8f1c
        GSList *duplicated = g_slist_find_custom (data->annotations,
Packit Service 1d8f1c
                                                  alias,
Packit Service 1d8f1c
                                                  (GCompareFunc) g_strcmp0);
Packit Service 1d8f1c
        if (duplicated == NULL) {
Packit Service 1d8f1c
#ifdef EMOJIONE_ALIASES_ASCII_PRINT
Packit Service 1d8f1c
            gchar *entity = text_to_entity (alias);
Packit Service 1d8f1c
            if (i != length - 1)
Packit Service 1d8f1c
                printf ("%s | ", entity);
Packit Service 1d8f1c
            else
Packit Service 1d8f1c
                printf ("%s</annotation>\n", entity);
Packit Service 1d8f1c
            g_free (entity);
Packit Service 1d8f1c
#endif
Packit Service 1d8f1c
            data->annotations = g_slist_prepend (data->annotations,
Packit Service 1d8f1c
                                                 g_strdup (alias));
Packit Service 1d8f1c
        }
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_emojione_keywords (JsonNode  *node,
Packit Service 1d8f1c
                         EmojiData *data)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
#if 0
Packit Service 1d8f1c
    JsonArray *keywords;
Packit Service 1d8f1c
    guint i, length;
Packit Service 1d8f1c
Packit Service 1d8f1c
    if (json_node_get_node_type (node) != JSON_NODE_ARRAY) {
Packit Service 1d8f1c
        g_warning ("'keywords' element is not array");
Packit Service 1d8f1c
        return FALSE;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    keywords = json_node_get_array (node);
Packit Service 1d8f1c
    length = json_array_get_length (keywords);
Packit Service 1d8f1c
    for (i = 0; i < length; i++) {
Packit Service 1d8f1c
        const gchar *keyword = json_array_get_string_element (keywords, i);
Packit Service 1d8f1c
        GSList *duplicated = g_slist_find_custom (data->annotations,
Packit Service 1d8f1c
                                                  keyword,
Packit Service 1d8f1c
                                                  (GCompareFunc) g_strcmp0);
Packit Service 1d8f1c
        if (duplicated == NULL) {
Packit Service 1d8f1c
            data->annotations = g_slist_prepend (data->annotations,
Packit Service 1d8f1c
                                                 g_strdup (keyword));
Packit Service 1d8f1c
        }
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
#endif
Packit Service 1d8f1c
    return TRUE;
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
static gboolean
Packit Service 1d8f1c
parse_emojione_emoji_data (JsonNode    *node,
Packit Service 1d8f1c
                           const gchar *member,
Packit Service 1d8f1c
                           EmojiData   *data)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    if (g_strcmp0 (member, "unicode") == 0)
Packit Service 1d8f1c
        return parse_emojione_unicode (node, data, FALSE);
Packit Service 1d8f1c
    else if (g_strcmp0 (member, "unicode_alt") == 0)
Packit Service 1d8f1c
        return parse_emojione_unicode (node, data, TRUE);
Packit Service 1d8f1c
    else if (g_strcmp0 (member, "unicode_alternates") == 0)
Packit Service 1d8f1c
        return parse_emojione_unicode (node, data, TRUE);
Packit Service 1d8f1c
    else if (g_strcmp0 (member, "shortname") == 0)
Packit Service 1d8f1c
        return parse_emojione_shortname (node, data);
Packit Service 1d8f1c
    else if (g_strcmp0 (member, "name") == 0)
Packit Service 1d8f1c
        return parse_emojione_name (node, data);
Packit Service 1d8f1c
    else if (g_strcmp0 (member, "category") == 0)
Packit Service 1d8f1c
        return parse_emojione_category (node, data);
Packit Service 1d8f1c
    else if (g_strcmp0 (member, "aliases_ascii") == 0)
Packit Service 1d8f1c
        return parse_emojione_aliases_ascii (node, data);
Packit Service 1d8f1c
    else if (g_strcmp0 (member, "keywords") == 0)
Packit Service 1d8f1c
        return parse_emojione_keywords (node, data);
Packit Service 1d8f1c
    return TRUE;
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
static gboolean
Packit Service 1d8f1c
parse_emojione_element (JsonNode  *node,
Packit Service 1d8f1c
                        EmojiData *data)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    JsonObject *object;
Packit Service 1d8f1c
    GList *members, *m;
Packit Service 1d8f1c
Packit Service 1d8f1c
    if (json_node_get_node_type (node) != JSON_NODE_OBJECT) {
Packit Service 1d8f1c
            return FALSE;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    reset_emoji_element (data);
Packit Service 1d8f1c
Packit Service 1d8f1c
    object = json_node_get_object (node);
Packit Service 1d8f1c
    m = members = json_object_get_members (object);
Packit Service 1d8f1c
    while (m) {
Packit Service 1d8f1c
       const gchar *member = (const gchar *) m->data;
Packit Service 1d8f1c
       if (!parse_emojione_emoji_data (json_object_get_member (object, member),
Packit Service 1d8f1c
                                       member,
Packit Service 1d8f1c
                                       data)) {
Packit Service 1d8f1c
           g_list_free (members);
Packit Service 1d8f1c
           return FALSE;
Packit Service 1d8f1c
       }
Packit Service 1d8f1c
       m = m->next;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
    g_list_free (members);
Packit Service 1d8f1c
Packit Service 1d8f1c
    update_emoji_list (data, TRUE);
Packit Service 1d8f1c
Packit Service 1d8f1c
    return TRUE;
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
static gboolean
Packit Service 1d8f1c
emojione_parse_json_file (const gchar  *filename,
Packit Service 1d8f1c
                          GSList      **list)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    JsonParser *parser = json_parser_new ();
Packit Service 1d8f1c
    JsonNode *node;
Packit Service 1d8f1c
    JsonObject *object;
Packit Service 1d8f1c
    GList *members, *m;
Packit Service 1d8f1c
    GError *error = NULL;
Packit Service 1d8f1c
    EmojiData data = { 0, };
Packit Service 1d8f1c
Packit Service 1d8f1c
    g_return_val_if_fail (filename != NULL, FALSE);
Packit Service 1d8f1c
    g_return_val_if_fail (list != NULL, FALSE);
Packit Service 1d8f1c
Packit Service 1d8f1c
    if (!json_parser_load_from_file (parser, filename, &error)) {
Packit Service 1d8f1c
        g_error ("%s", error->message);
Packit Service 1d8f1c
        g_error_free (error);
Packit Service 1d8f1c
        goto fail_to_json_file;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    node = json_parser_get_root (parser);
Packit Service 1d8f1c
    if (json_node_get_node_type (node) != JSON_NODE_OBJECT) {
Packit Service 1d8f1c
        g_warning ("Json file does not have Json object %s", filename);
Packit Service 1d8f1c
        goto fail_to_json_file;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    object = json_node_get_object (node);
Packit Service 1d8f1c
    members = json_object_get_members (object);
Packit Service 1d8f1c
    data.list = *list;
Packit Service 1d8f1c
Packit Service 1d8f1c
    m = members;
Packit Service 1d8f1c
    while (m) {
Packit Service 1d8f1c
       const gchar *member = (const gchar *) m->data;
Packit Service 1d8f1c
       if (!parse_emojione_element (json_object_get_member (object, member),
Packit Service 1d8f1c
                                    &data)) {
Packit Service 1d8f1c
           g_warning ("Failed to parse member '%s' in %s", member, filename);
Packit Service 1d8f1c
       }
Packit Service 1d8f1c
       m = m->next;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    g_list_free (members);
Packit Service 1d8f1c
    reset_emoji_element (&data);
Packit Service 1d8f1c
    g_object_unref (parser);
Packit Service 1d8f1c
    *list = data.list;
Packit Service 1d8f1c
Packit Service 1d8f1c
    return TRUE;
Packit Service 1d8f1c
Packit Service 1d8f1c
fail_to_json_file:
Packit Service 1d8f1c
    g_object_unref (parser);
Packit Service 1d8f1c
    return FALSE;
Packit Service 1d8f1c
}
Packit Service 1d8f1c
#endif /* HAVE_JSON_GLIB1 */
Packit Service 1d8f1c
Packit Service 1d8f1c
static void
Packit Service 1d8f1c
emoji_data_list_unify_categories (IBusEmojiData  *data,
Packit Service 1d8f1c
                                  GSList        **list)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    g_return_if_fail (IBUS_IS_EMOJI_DATA (data));
Packit Service 1d8f1c
    g_return_if_fail (list != NULL);
Packit Service 1d8f1c
Packit Service 1d8f1c
    const gchar *category = ibus_emoji_data_get_category (data);
Packit Service 1d8f1c
    if (*category == '\0')
Packit Service 1d8f1c
        return;
Packit Service 1d8f1c
    if (g_slist_find_custom (*list, category, (GCompareFunc)g_strcmp0) == NULL)
Packit Service 1d8f1c
        *list = g_slist_append (*list, g_strdup (category));
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
static void
Packit Service 1d8f1c
category_list_dump (const gchar *category,
Packit Service 1d8f1c
                    GString     *buff)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    g_return_if_fail (buff != NULL);
Packit Service 1d8f1c
Packit Service 1d8f1c
    const gchar *line = g_strdup_printf ("    N_(\"%s\"),\n", category);
Packit Service 1d8f1c
    g_string_append (buff, line);
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
static void
Packit Service 1d8f1c
category_file_save (const gchar *filename,
Packit Service 1d8f1c
                    GSList      *list)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    gchar *content = NULL;
Packit Service 1d8f1c
    gsize length = 0;
Packit Service 1d8f1c
    GError *error = NULL;
Packit Service 1d8f1c
    gchar *p;
Packit Service 1d8f1c
    GString *buff = NULL;
Packit Service 1d8f1c
    int i;
Packit Service 1d8f1c
    GSList *list_categories = NULL;
Packit Service 1d8f1c
Packit Service 1d8f1c
    g_return_if_fail (filename != NULL);
Packit Service 1d8f1c
    g_return_if_fail (list != NULL);
Packit Service 1d8f1c
Packit Service 1d8f1c
    g_slist_foreach (list, (GFunc)emoji_data_list_unify_categories, &list_categories);
Packit Service 1d8f1c
    if (list_categories == NULL) {
Packit Service 1d8f1c
        g_warning ("Not found categories in IBusEmojiData list");
Packit Service 1d8f1c
        return;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    if (!g_file_get_contents (__FILE__, &content, &length, &error)) {
Packit Service 1d8f1c
        g_warning ("Failed to load %s: %s", __FILE__, error->message);
Packit Service 1d8f1c
        g_clear_pointer (&error, g_error_free);
Packit Service 1d8f1c
        return;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
    buff = g_string_new (NULL);
Packit Service 1d8f1c
    p = content;
Packit Service 1d8f1c
    for (i = 0; i < LICENSE_LINES; i++, p++) {
Packit Service 1d8f1c
        if ((p = strchr (p, '\n')) == NULL)
Packit Service 1d8f1c
            break;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
    if (p != NULL) {
Packit Service 1d8f1c
        g_string_append (buff, g_strndup (content, p - content));
Packit Service 1d8f1c
        g_string_append_c (buff, '\n');
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
    g_clear_pointer (&content, g_free);
Packit Service 1d8f1c
Packit Service 1d8f1c
    g_string_append (buff, g_strdup ("\n"));
Packit Service 1d8f1c
    g_string_append (buff, g_strdup_printf ("/* This file is generated by %s. */", __FILE__));
Packit Service 1d8f1c
    g_string_append (buff, g_strdup ("\n"));
Packit Service 1d8f1c
    g_string_append (buff, g_strdup ("include <glib/gi18n.h>\n"));
Packit Service 1d8f1c
    g_string_append (buff, g_strdup ("\n"));
Packit Service 1d8f1c
    g_string_append (buff, g_strdup ("#ifndef __IBUS_EMOJI_GEN_H_\n"));
Packit Service 1d8f1c
    g_string_append (buff, g_strdup ("#define __IBUS_EMOJI_GEN_H_\n"));
Packit Service 1d8f1c
    g_string_append (buff, g_strdup ("const static char *unicode_emoji_categories[] = {\n"));
Packit Service 1d8f1c
    list_categories = g_slist_sort (list_categories, (GCompareFunc)g_strcmp0);
Packit Service 1d8f1c
    g_slist_foreach (list_categories, (GFunc)category_list_dump, buff);
Packit Service 1d8f1c
    g_slist_free (list_categories);
Packit Service 1d8f1c
    g_string_append (buff, g_strdup ("};\n"));
Packit Service 1d8f1c
    g_string_append (buff, g_strdup ("#endif\n"));
Packit Service 1d8f1c
Packit Service 1d8f1c
    if (!g_file_set_contents (filename, buff->str, -1, &error)) {
Packit Service 1d8f1c
        g_warning ("Failed to save emoji category file %s: %s", filename, error->message);
Packit Service 1d8f1c
        g_error_free (error);
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    g_string_free (buff, TRUE);
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
int
Packit Service 1d8f1c
main (int argc, char *argv[])
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    gchar *prgname;
Packit Service 1d8f1c
#ifdef HAVE_JSON_GLIB1
Packit Service 1d8f1c
    gchar *json_file = NULL;
Packit Service 1d8f1c
#endif
Packit Service 1d8f1c
    gchar *emoji_dir = NULL;
Packit Service 1d8f1c
    gchar *xml_file = NULL;
Packit Service 1d8f1c
    gchar *xml_derived_file = NULL;
Packit Service 1d8f1c
    gchar *xml_ascii_file = NULL;
Packit Service 1d8f1c
    gchar *output = NULL;
Packit Service 1d8f1c
    gchar *output_category = NULL;
Packit Service 1d8f1c
    GOptionEntry     entries[] = {
Packit Service 1d8f1c
#ifdef HAVE_JSON_GLIB1
Packit Service 1d8f1c
        { "json", 'j', 0, G_OPTION_ARG_STRING, &json_file,
Packit Service 1d8f1c
          "Parse Emoji One JSON file",
Packit Service 1d8f1c
          "JSON"
Packit Service 1d8f1c
        },
Packit Service 1d8f1c
#endif
Packit Service 1d8f1c
        { "unicode-emoji-dir", 'd', 0, G_OPTION_ARG_STRING, &emoji_dir,
Packit Service 1d8f1c
          "Parse Emoji files in DIRECTORY which includes emoji-test.txt " \
Packit Service 1d8f1c
          "emoji-sequences.txt emoji-zwj-sequences.txt in unicode.org",
Packit Service 1d8f1c
          "DIRECTORY"
Packit Service 1d8f1c
        },
Packit Service 1d8f1c
        { "out", 'o', 0, G_OPTION_ARG_STRING, &output,
Packit Service 1d8f1c
          "Save the emoji data as FILE",
Packit Service 1d8f1c
          "FILE"
Packit Service 1d8f1c
        },
Packit Service 1d8f1c
        { "out-category", 'C', 0, G_OPTION_ARG_STRING, &output_category,
Packit Service 1d8f1c
          "Save the translatable categories as FILE",
Packit Service 1d8f1c
          "FILE"
Packit Service 1d8f1c
        },
Packit Service 1d8f1c
        { "xml", 'x', 0, G_OPTION_ARG_STRING, &xml_file,
Packit Service 1d8f1c
          "Parse Unocode.org ANNOTATIONS file",
Packit Service 1d8f1c
          "ANNOTATIONS"
Packit Service 1d8f1c
        },
Packit Service 1d8f1c
        { "xml-derived", 'X', 0, G_OPTION_ARG_STRING, &xml_derived_file,
Packit Service 1d8f1c
          "Parse Unocode.org derived ANNOTATIONS file",
Packit Service 1d8f1c
          "ANNOTATIONS"
Packit Service 1d8f1c
        },
Packit Service 1d8f1c
        { "xml-ascii", 'A', 0, G_OPTION_ARG_STRING, &xml_ascii_file,
Packit Service 1d8f1c
          "Parse ASCII ANNOTATIONS file",
Packit Service 1d8f1c
          "ANNOTATIONS"
Packit Service 1d8f1c
        },
Packit Service 1d8f1c
        { NULL }
Packit Service 1d8f1c
    };
Packit Service 1d8f1c
    GOptionContext *context;
Packit Service 1d8f1c
    GError *error = NULL;
Packit Service 1d8f1c
    GSList *list = NULL;
Packit Service 1d8f1c
    gboolean is_en = TRUE;
Packit Service 1d8f1c
Packit Service 1d8f1c
#ifdef HAVE_LOCALE_H
Packit Service 1d8f1c
    /* To output emoji warnings. */
Packit Service 1d8f1c
    setlocale (LC_ALL, "");
Packit Service 1d8f1c
#endif
Packit Service 1d8f1c
Packit Service 1d8f1c
    prgname = g_path_get_basename (argv[0]);
Packit Service 1d8f1c
    g_set_prgname (prgname);
Packit Service 1d8f1c
    g_free (prgname);
Packit Service 1d8f1c
Packit Service 1d8f1c
    context = g_option_context_new (NULL);
Packit Service 1d8f1c
    g_option_context_add_main_entries (context, entries, NULL);
Packit Service 1d8f1c
Packit Service 1d8f1c
    if (argc < 3) {
Packit Service 1d8f1c
        g_print ("%s", g_option_context_get_help (context, TRUE, NULL));
Packit Service 1d8f1c
        g_option_context_free (context);
Packit Service 1d8f1c
        return -1;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    if (!g_option_context_parse (context, &argc, &argv, &error)) {
Packit Service 1d8f1c
        g_warning ("Failed options: %s", error->message);
Packit Service 1d8f1c
        g_error_free (error);
Packit Service 1d8f1c
        return -1;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
    g_option_context_free (context);
Packit Service 1d8f1c
Packit Service 1d8f1c
#ifdef HAVE_JSON_GLIB1
Packit Service 1d8f1c
    if (json_file)
Packit Service 1d8f1c
        emojione_parse_json_file (json_file, &list);
Packit Service 1d8f1c
#endif
Packit Service 1d8f1c
    if (emoji_dir)
Packit Service 1d8f1c
        unicode_emoji_parse_dir (emoji_dir, &list);
Packit Service 1d8f1c
    if (list) {
Packit Service 1d8f1c
#define CHECK_IS_EN(file) if ((file)) {                                     \
Packit Service 1d8f1c
    gchar *basename = g_path_get_basename ((file));                         \
Packit Service 1d8f1c
    is_en = (g_ascii_strncasecmp (basename, "en.", 3) == 0) ?               \
Packit Service 1d8f1c
            TRUE : FALSE;                                                   \
Packit Service 1d8f1c
    g_free (basename);                                                      \
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
        CHECK_IS_EN(xml_derived_file);
Packit Service 1d8f1c
        CHECK_IS_EN(xml_file);
Packit Service 1d8f1c
#undef CHECK_IS_EN
Packit Service 1d8f1c
Packit Service 1d8f1c
        /* Use English emoji-test.txt to get fully-qualified. */
Packit Service 1d8f1c
        if (!is_en)
Packit Service 1d8f1c
            g_slist_foreach (list, (GFunc)init_annotations, NULL);
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
    if (xml_file)
Packit Service 1d8f1c
        unicode_annotations_parse_xml_file (xml_file, &list, FALSE);
Packit Service 1d8f1c
    if (xml_derived_file)
Packit Service 1d8f1c
        unicode_annotations_parse_xml_file (xml_derived_file, &list, TRUE);
Packit Service 1d8f1c
    if (xml_ascii_file)
Packit Service 1d8f1c
        unicode_annotations_parse_xml_file (xml_ascii_file, &list, FALSE);
Packit Service 1d8f1c
    if (list != NULL && !is_en) {
Packit Service 1d8f1c
        /* If emoji-test.txt has an emoji but $lang.xml does not, clear it
Packit Service 1d8f1c
         * since the language dicts do not want English annotations.
Packit Service 1d8f1c
         */
Packit Service 1d8f1c
        NoTransData no_trans_data = {
Packit Service 1d8f1c
            xml_file,
Packit Service 1d8f1c
            xml_derived_file,
Packit Service 1d8f1c
            NULL
Packit Service 1d8f1c
        };
Packit Service 1d8f1c
        g_slist_foreach (list, (GFunc)check_no_trans, &no_trans_data);
Packit Service 1d8f1c
        if (no_trans_data.emoji_list) {
Packit Service 1d8f1c
            g_slist_foreach (no_trans_data.emoji_list,
Packit Service 1d8f1c
                             (GFunc)delete_emoji_from_list,
Packit Service 1d8f1c
                             &list);
Packit Service 1d8f1c
            g_slist_free_full (no_trans_data.emoji_list, g_free);
Packit Service 1d8f1c
        }
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
    if (list != NULL && output)
Packit Service 1d8f1c
        ibus_emoji_data_save (output, list);
Packit Service 1d8f1c
    if (list != NULL && output_category)
Packit Service 1d8f1c
        category_file_save (output_category, list);
Packit Service 1d8f1c
    if (list)
Packit Service 1d8f1c
        g_slist_free (list);
Packit Service 1d8f1c
Packit Service 1d8f1c
    return 0;
Packit Service 1d8f1c
}