Blame src/terminal-encoding.c

Packit d370c2
/*
Packit d370c2
 * Copyright © 2002 Red Hat, Inc.
Packit d370c2
 * Copyright © 2008, 2017 Christian Persch
Packit d370c2
 *
Packit d370c2
 * This program is free software: you can redistribute it and/or modify
Packit d370c2
 * it under the terms of the GNU General Public License as published by
Packit d370c2
 * the Free Software Foundation, either version 3 of the License, or
Packit d370c2
 * (at your option) any later version.
Packit d370c2
 *
Packit d370c2
 * This program is distributed in the hope that it will be useful,
Packit d370c2
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit d370c2
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit d370c2
 * GNU General Public License for more details.
Packit d370c2
 *
Packit d370c2
 * You should have received a copy of the GNU General Public License
Packit d370c2
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
Packit d370c2
 */
Packit d370c2
Packit d370c2
#include "config.h"
Packit d370c2
Packit d370c2
#include <string.h>
Packit d370c2
#include <search.h>
Packit d370c2
#include <stdlib.h>
Packit d370c2
Packit d370c2
#include <glib.h>
Packit d370c2
#include <glib/gi18n.h>
Packit d370c2
#include <gtk/gtk.h>
Packit d370c2
Packit d370c2
#include "terminal-app.h"
Packit d370c2
#include "terminal-debug.h"
Packit d370c2
#include "terminal-encoding.h"
Packit d370c2
#include "terminal-schemas.h"
Packit d370c2
#include "terminal-util.h"
Packit d370c2
#include "terminal-libgsystem.h"
Packit d370c2
Packit d370c2
/* Overview
Packit d370c2
 *
Packit d370c2
 * There's a list of character sets stored in gsettings, indicating
Packit d370c2
 * which encodings to display in the encoding menu.
Packit d370c2
 * 
Packit d370c2
 * We have a pre-canned list of available encodings
Packit d370c2
 * (hardcoded in the table below) that can be added to
Packit d370c2
 * the encoding menu, and to give a human-readable name
Packit d370c2
 * to certain encodings.
Packit d370c2
 *
Packit d370c2
 * If the setting list contains an encoding not in the
Packit d370c2
 * predetermined table, then that encoding is
Packit d370c2
 * labeled "user defined" but still appears in the menu.
Packit d370c2
 */
Packit d370c2
Packit d370c2
typedef enum {
Packit d370c2
  GROUP_UNICODE,
Packit d370c2
  GROUP_CJKV,
Packit d370c2
  GROUP_OBSOLETE,
Packit d370c2
  LAST_GROUP
Packit d370c2
} EncodingGroup;
Packit d370c2
Packit d370c2
typedef struct {
Packit d370c2
  const char *charset;
Packit d370c2
  const char *name;
Packit d370c2
  EncodingGroup group;
Packit d370c2
} EncodingEntry;
Packit d370c2
Packit d370c2
/* These MUST be sorted by charset so that bsearch can work! */
Packit d370c2
static const EncodingEntry const encodings[] = {
Packit d370c2
  { "ARMSCII-8",      N_("Armenian"),            GROUP_OBSOLETE },
Packit d370c2
  { "BIG5",           N_("Chinese Traditional"), GROUP_CJKV },
Packit d370c2
  { "BIG5-HKSCS",     N_("Chinese Traditional"), GROUP_CJKV },
Packit d370c2
  { "CP866",          N_("Cyrillic/Russian"),    GROUP_OBSOLETE },
Packit d370c2
  { "EUC-JP",         N_("Japanese"),            GROUP_CJKV },
Packit d370c2
  { "EUC-KR",         N_("Korean"),              GROUP_CJKV },
Packit d370c2
  { "EUC-TW",         N_("Chinese Traditional"), GROUP_CJKV },
Packit d370c2
  { "GB18030",        N_("Chinese Simplified"),  GROUP_CJKV },
Packit d370c2
  { "GB2312",         N_("Chinese Simplified"),  GROUP_CJKV },
Packit d370c2
  { "GBK",            N_("Chinese Simplified"),  GROUP_CJKV },
Packit d370c2
  { "GEORGIAN-PS",    N_("Georgian"),            GROUP_OBSOLETE },
Packit d370c2
  { "IBM850",         N_("Western"),             GROUP_OBSOLETE },
Packit d370c2
  { "IBM852",         N_("Central European"),    GROUP_OBSOLETE },
Packit d370c2
  { "IBM855",         N_("Cyrillic"),            GROUP_OBSOLETE },
Packit d370c2
  { "IBM857",         N_("Turkish"),             GROUP_OBSOLETE },
Packit d370c2
  { "IBM862",         N_("Hebrew"),              GROUP_OBSOLETE },
Packit d370c2
  { "IBM864",         N_("Arabic"),              GROUP_OBSOLETE },
Packit d370c2
  { "ISO-2022-JP",    N_("Japanese"),            GROUP_CJKV },
Packit d370c2
  { "ISO-2022-KR",    N_("Korean"),              GROUP_CJKV },
Packit d370c2
  { "ISO-8859-1",     N_("Western"),             GROUP_OBSOLETE },
Packit d370c2
  { "ISO-8859-10",    N_("Nordic"),              GROUP_OBSOLETE },
Packit d370c2
  { "ISO-8859-13",    N_("Baltic"),              GROUP_OBSOLETE },
Packit d370c2
  { "ISO-8859-14",    N_("Celtic"),              GROUP_OBSOLETE },
Packit d370c2
  { "ISO-8859-15",    N_("Western"),             GROUP_OBSOLETE },
Packit d370c2
  { "ISO-8859-16",    N_("Romanian"),            GROUP_OBSOLETE },
Packit d370c2
  { "ISO-8859-2",     N_("Central European"),    GROUP_OBSOLETE },
Packit d370c2
  { "ISO-8859-3",     N_("South European"),      GROUP_OBSOLETE },
Packit d370c2
  { "ISO-8859-4",     N_("Baltic"),              GROUP_OBSOLETE },
Packit d370c2
  { "ISO-8859-5",     N_("Cyrillic"),            GROUP_OBSOLETE },
Packit d370c2
  { "ISO-8859-6",     N_("Arabic"),              GROUP_OBSOLETE },
Packit d370c2
  { "ISO-8859-7",     N_("Greek"),               GROUP_OBSOLETE },
Packit d370c2
  { "ISO-8859-8",     N_("Hebrew Visual"),       GROUP_OBSOLETE },
Packit d370c2
  { "ISO-8859-8-I",   N_("Hebrew"),              GROUP_OBSOLETE },
Packit d370c2
  { "ISO-8859-9",     N_("Turkish"),             GROUP_OBSOLETE },
Packit d370c2
  { "ISO-IR-111",     N_("Cyrillic"),            GROUP_OBSOLETE },
Packit d370c2
   /* { "JOHAB",      N_("Korean"),              GROUP_CJKV }, */
Packit d370c2
  { "KOI8-R",         N_("Cyrillic"),            GROUP_OBSOLETE },
Packit d370c2
  { "KOI8-U",         N_("Cyrillic/Ukrainian"),  GROUP_OBSOLETE },
Packit d370c2
  { "MAC-CYRILLIC",   N_("Cyrillic"),            GROUP_OBSOLETE },
Packit d370c2
  { "MAC_ARABIC",     N_("Arabic"),              GROUP_OBSOLETE },
Packit d370c2
  { "MAC_CE",         N_("Central European"),    GROUP_OBSOLETE },
Packit d370c2
  { "MAC_CROATIAN",   N_("Croatian"),            GROUP_OBSOLETE },
Packit d370c2
  { "MAC_DEVANAGARI", N_("Hindi"),               GROUP_OBSOLETE },
Packit d370c2
  { "MAC_FARSI",      N_("Persian"),             GROUP_OBSOLETE },
Packit d370c2
  { "MAC_GREEK",      N_("Greek"),               GROUP_OBSOLETE },
Packit d370c2
  { "MAC_GUJARATI",   N_("Gujarati"),            GROUP_OBSOLETE },
Packit d370c2
  { "MAC_GURMUKHI",   N_("Gurmukhi"),            GROUP_OBSOLETE },
Packit d370c2
  { "MAC_HEBREW",     N_("Hebrew"),              GROUP_OBSOLETE },
Packit d370c2
  { "MAC_ICELANDIC",  N_("Icelandic"),           GROUP_OBSOLETE },
Packit d370c2
  { "MAC_ROMAN",      N_("Western"),             GROUP_OBSOLETE },
Packit d370c2
  { "MAC_ROMANIAN",   N_("Romanian"),            GROUP_OBSOLETE },
Packit d370c2
  { "MAC_TURKISH",    N_("Turkish"),             GROUP_OBSOLETE },
Packit d370c2
  { "MAC_UKRAINIAN",  N_("Cyrillic/Ukrainian"),  GROUP_OBSOLETE },
Packit d370c2
  { "SHIFT_JIS",      N_("Japanese"),            GROUP_CJKV },
Packit d370c2
  /* This is TCVN-5712-1, not TCVN-5773:1993 which would be CJKV */
Packit d370c2
  { "TCVN",           N_("Vietnamese"),          GROUP_OBSOLETE },
Packit d370c2
  { "TIS-620",        N_("Thai"),                GROUP_OBSOLETE },
Packit d370c2
  /* { "UCS-4",       N_("Unicode"),             GROUP_UNICODE }, */
Packit d370c2
  { "UHC",            N_("Korean"),              GROUP_CJKV },
Packit d370c2
  /* { "UTF-16",      N_("Unicode"),             GROUP_UNICODE }, */
Packit d370c2
  /* { "UTF-32",      N_("Unicode"),             GROUP_UNICODE }, */
Packit d370c2
  /* { "UTF-7",       N_("Unicode"),             GROUP_UNICODE }, */
Packit d370c2
  { "UTF-8",          N_("Unicode"),             GROUP_UNICODE },
Packit d370c2
  { "VISCII",         N_("Vietnamese"),          GROUP_OBSOLETE },
Packit d370c2
  { "WINDOWS-1250",   N_("Central European"),    GROUP_OBSOLETE },
Packit d370c2
  { "WINDOWS-1251",   N_("Cyrillic"),            GROUP_OBSOLETE },
Packit d370c2
  { "WINDOWS-1252",   N_("Western"),             GROUP_OBSOLETE },
Packit d370c2
  { "WINDOWS-1253",   N_("Greek"),               GROUP_OBSOLETE },
Packit d370c2
  { "WINDOWS-1254",   N_("Turkish"),             GROUP_OBSOLETE },
Packit d370c2
  { "WINDOWS-1255",   N_("Hebrew"),              GROUP_OBSOLETE},
Packit d370c2
  { "WINDOWS-1256",   N_("Arabic"),              GROUP_OBSOLETE },
Packit d370c2
  { "WINDOWS-1257",   N_("Baltic"),              GROUP_OBSOLETE },
Packit d370c2
  { "WINDOWS-1258",   N_("Vietnamese"),          GROUP_OBSOLETE },
Packit d370c2
};
Packit d370c2
Packit d370c2
static const struct {
Packit d370c2
  EncodingGroup group;
Packit d370c2
  const char *name;
Packit d370c2
} group_names[] = {
Packit d370c2
  { GROUP_UNICODE,  N_("Unicode") },
Packit d370c2
  { GROUP_CJKV,     N_("Legacy CJK Encodings") },
Packit d370c2
  { GROUP_OBSOLETE, N_("Obsolete Encodings") },
Packit d370c2
};
Packit d370c2
Packit d370c2
#define EM_DASH "—"
Packit d370c2
Packit d370c2
static int
Packit d370c2
compare_encoding_entry_cb (const void *ap,
Packit d370c2
                           const void *bp)
Packit d370c2
{
Packit d370c2
  const EncodingEntry *a = ap;
Packit d370c2
  const EncodingEntry *b = bp;
Packit d370c2
Packit d370c2
  int r = a->group - b->group;
Packit d370c2
  if (r != 0)
Packit d370c2
    return r;
Packit d370c2
Packit d370c2
  r = g_utf8_collate (a->name, b->name);
Packit d370c2
  if (r != 0)
Packit d370c2
    return r;
Packit d370c2
Packit d370c2
  return strcmp (a->charset, b->charset);
Packit d370c2
}
Packit d370c2
Packit d370c2
/**
Packit d370c2
 * terminal_encodings_append_menu:
Packit d370c2
 *
Packit d370c2
 * Appends to known encodings to a #GMenu, sorted in groups and
Packit d370c2
 * alphabetically by name inside the groups. The action name
Packit d370c2
 * used when activating the menu items is "win.encoding".
Packit d370c2
 */
Packit d370c2
void
Packit d370c2
terminal_encodings_append_menu (GMenu *menu)
Packit d370c2
{
Packit d370c2
  /* First, sort the encodings */
Packit d370c2
  gs_free EncodingEntry *array = g_memdup (encodings, sizeof encodings);
Packit d370c2
  for (guint i = 0; i < G_N_ELEMENTS (encodings); i++)
Packit d370c2
    array[i].name = _(array[i].name); /* translate */
Packit d370c2
Packit d370c2
  qsort (array, G_N_ELEMENTS (encodings), sizeof array[0],
Packit d370c2
         compare_encoding_entry_cb);
Packit d370c2
Packit d370c2
  for (guint group = 0 ; group < LAST_GROUP; group++) {
Packit d370c2
    gs_unref_object GMenu *section = g_menu_new ();
Packit d370c2
Packit d370c2
    for (guint i = 0; i < G_N_ELEMENTS (encodings); i++) {
Packit d370c2
      if (array[i].group != group)
Packit d370c2
        continue;
Packit d370c2
Packit d370c2
      gs_free_gstring GString *str = g_string_sized_new (128);
Packit d370c2
      g_string_append (str, array[i].name);
Packit d370c2
      g_string_append (str, " " EM_DASH " ");
Packit d370c2
      for (const char *p = array[i].charset; *p; p++) {
Packit d370c2
        if (*p == '_')
Packit d370c2
          g_string_append (str, "__");
Packit d370c2
        else
Packit d370c2
          g_string_append_c (str, *p);
Packit d370c2
      }
Packit d370c2
Packit d370c2
      gs_unref_object GMenuItem *item = g_menu_item_new (str->str, NULL);
Packit d370c2
      g_menu_item_set_action_and_target (item, "win.encoding", "s", array[i].charset);
Packit d370c2
Packit d370c2
      g_menu_append_item (section, item);
Packit d370c2
    }
Packit d370c2
Packit d370c2
    g_menu_append_section (menu, _(group_names[group].name), G_MENU_MODEL (section));
Packit d370c2
  }
Packit d370c2
}
Packit d370c2
Packit d370c2
/**
Packit d370c2
 * terminal_encodings_list_store_new:
Packit d370c2
 *
Packit d370c2
 * Creates a #GtkListStore containing the known encodings.
Packit d370c2
 * The model containing 2 columns, the 0th one with the
Packit d370c2
 * charset name, and the 1st one with the label.
Packit d370c2
 * The model is unsorted.
Packit d370c2
 *
Packit d370c2
 * Returns: (transfer full): a new #GtkTreeModel
Packit d370c2
 */
Packit d370c2
GtkListStore *
Packit d370c2
terminal_encodings_list_store_new (int column_id,
Packit d370c2
                                   int column_text)
Packit d370c2
{
Packit d370c2
  GtkListStore *store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING);
Packit d370c2
Packit d370c2
  for (guint i = 0; i < G_N_ELEMENTS (encodings); i++) {
Packit d370c2
    gs_free char *name = g_strdup_printf ("%s " EM_DASH " %s",
Packit d370c2
                                          _(encodings[i].name), encodings[i].charset);
Packit d370c2
Packit d370c2
    GtkTreeIter iter;
Packit d370c2
    gtk_list_store_insert_with_values (store, &iter, -1,
Packit d370c2
                                       column_id, encodings[i].charset,
Packit d370c2
                                       column_text, name,
Packit d370c2
                                       -1);
Packit d370c2
  }
Packit d370c2
Packit d370c2
  return store;
Packit d370c2
}
Packit d370c2
Packit d370c2
static int
Packit d370c2
compare_charset_cb (const void *ap,
Packit d370c2
                    const void *bp)
Packit d370c2
{
Packit d370c2
  const EncodingEntry *a = ap;
Packit d370c2
  const EncodingEntry *b = bp;
Packit d370c2
Packit d370c2
  return strcmp (a->charset, b->charset);
Packit d370c2
}
Packit d370c2
Packit d370c2
gboolean
Packit d370c2
terminal_encodings_is_known_charset (const char *charset)
Packit d370c2
{
Packit d370c2
  EncodingEntry key = { charset, NULL, 0 };
Packit d370c2
  return bsearch (&key,
Packit d370c2
                  encodings, G_N_ELEMENTS (encodings),
Packit d370c2
                  sizeof (encodings[0]),
Packit d370c2
                  compare_charset_cb) != NULL;
Packit d370c2
}