Complete.Org: Mailing Lists: Archives: freeciv-dev: August 2004:
[Freeciv-Dev] (PR#9722) fix charset problems in 1.14
Home

[Freeciv-Dev] (PR#9722) fix charset problems in 1.14

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
To: undisclosed-recipients: ;
Subject: [Freeciv-Dev] (PR#9722) fix charset problems in 1.14
From: "Jason Short" <jdorje@xxxxxxxxxxxxxxxxxxxxx>
Date: Tue, 17 Aug 2004 12:26:40 -0700
Reply-to: rt@xxxxxxxxxxx

<URL: http://rt.freeciv.org/Ticket/Display.html?id=9722 >

This patch is an update of the PR#1824 patch, but for the 1.14 branch.

The main purpose is to get some more people to test it out.  I believe 
it should work just like the 1824 patch, but it's possible I made an 
error in removing the "old" charset fixes.

To test: put the fciconv.[ch] files in common/, apply the patch, and 
rerun autogen.sh.

jason

? fciconv-1.14.diff
? common/fciconv.c
? common/fciconv.h
Index: client/civclient.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/civclient.c,v
retrieving revision 1.149
diff -u -r1.149 civclient.c
--- client/civclient.c  9 Oct 2002 13:39:47 -0000       1.149
+++ client/civclient.c  17 Aug 2004 19:24:23 -0000
@@ -32,6 +32,8 @@
 #endif
 
 #include "capstr.h"
+#include "dataio.h"
+#include "fciconv.h"
 #include "fcintl.h"
 #include "game.h"
 #include "idex.h"
@@ -105,6 +107,62 @@
 static void client_remove_all_cli_conn(void);
 
 /**************************************************************************
+  Convert a text string from the internal to the data encoding, when it
+  is written to the network.
+**************************************************************************/
+static unsigned char *put_conv(const char *src, size_t *length)
+{
+  char *out = internal_to_data_string_malloc(src);
+
+  if (out) {
+    *length = strlen(out);
+    return out;
+  } else {
+    *length = 0;
+    return NULL;
+  }
+}
+
+/**************************************************************************
+  Convert a text string from the data to the internal encoding when it is
+  first read from the network.  Returns FALSE if the destination isn't
+  large enough or the source was bad.
+**************************************************************************/
+static bool get_conv(char *dst, size_t ndst,
+                    const unsigned char *src, size_t nsrc)
+{
+  char *out = data_to_internal_string_malloc(src);
+  bool ret = TRUE;
+  size_t len;
+
+  if (!out) {
+    dst[0] = '\0';
+    return FALSE;
+  }
+
+  len = strlen(out);
+  if (ndst > 0 && len >= ndst) {
+    ret = FALSE;
+    len = ndst - 1;
+  }
+
+  memcpy(dst, out, len);
+  dst[len] = '\0';
+  free(out);
+
+  return ret;
+}
+
+/**************************************************************************
+  Set up charsets for the client.
+**************************************************************************/
+static void charsets_init(void)
+{
+  dio_set_put_conv_callback(put_conv);
+  dio_set_get_conv_callback(get_conv);
+}
+
+/**************************************************************************
 ...
 **************************************************************************/
 int main(int argc, char *argv[])
@@ -192,6 +250,7 @@
   /* initialization */
 
   ui_init();
+  charsets_init();
   my_init_network();
   init_messages_where();
   init_city_report_data();
Index: client/gui-gtk/gui_main.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-gtk/gui_main.c,v
retrieving revision 1.115.2.1
diff -u -r1.115.2.1 gui_main.c
--- client/gui-gtk/gui_main.c   15 Oct 2002 21:57:37 -0000      1.115.2.1
+++ client/gui-gtk/gui_main.c   17 Aug 2004 19:24:23 -0000
@@ -31,6 +31,7 @@
 #include <gtk/gtkinvisible.h>
 #include <gdk/gdkkeysyms.h>
 
+#include "fciconv.h"
 #include "fcintl.h"
 #include "game.h"
 #include "government.h"
@@ -727,6 +728,7 @@
 **************************************************************************/
 void ui_init(void)
 {
+  init_character_encodings(NULL);
 }
 
 /**************************************************************************
Index: client/gui-gtk-2.0/connectdlg.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-gtk-2.0/connectdlg.c,v
retrieving revision 1.15.2.6
diff -u -r1.15.2.6 connectdlg.c
--- client/gui-gtk-2.0/connectdlg.c     18 May 2003 16:20:41 -0000      1.15.2.6
+++ client/gui-gtk-2.0/connectdlg.c     17 Aug 2004 19:24:23 -0000
@@ -319,12 +319,12 @@
     GtkTreeIter it;
     int i;
 
-    row[0] = ntoh_str(pserver->name);
-    row[1] = ntoh_str(pserver->port);
-    row[2] = ntoh_str(pserver->version);
+    row[0] = pserver->name;
+    row[1] = pserver->port;
+    row[2] = pserver->version;
     row[3] = _(pserver->status);
-    row[4] = ntoh_str(pserver->players);
-    row[5] = ntoh_str(pserver->metastring);
+    row[4] = pserver->players;
+    row[5] = pserver->metastring;
 
     gtk_list_store_append(store, &it);
     gtk_list_store_set(store, &it,
Index: client/gui-gtk-2.0/gui_main.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-gtk-2.0/gui_main.c,v
retrieving revision 1.27.2.10
diff -u -r1.27.2.10 gui_main.c
--- client/gui-gtk-2.0/gui_main.c       26 Mar 2004 19:44:08 -0000      
1.27.2.10
+++ client/gui-gtk-2.0/gui_main.c       17 Aug 2004 19:24:24 -0000
@@ -32,6 +32,7 @@
 #include <gdk/gdkkeysyms.h>
 
 #include "dataio.h"
+#include "fciconv.h"
 #include "fcintl.h"
 #include "game.h"
 #include "government.h"
@@ -157,107 +158,13 @@
                                            gpointer data);
 static gint timer_callback(gpointer data);
 
-static char *network_charset = NULL;
-
-
-/**************************************************************************
-Network string charset conversion functions.
-**************************************************************************/
-gchar *ntoh_str(const gchar *netstr)
-{
-  return g_convert(netstr, -1, "UTF-8", network_charset, NULL, NULL, NULL);
-}
-
-/**************************************************************************
-...
-**************************************************************************/
-static unsigned char *put_conv(const char *src, size_t *length)
-{
-  gsize len;
-  gchar *out =
-    g_convert(src, -1, network_charset, "UTF-8", NULL, &len, NULL);
-
-  if (out) {
-    unsigned char *dst = fc_malloc(len + 1);
-
-    memcpy(dst, out, len);
-    g_free(out);
-    dst[len] = '\0';
-
-    *length = len;
-    return dst;
-  } else {
-    *length = 0;
-    return NULL;
-  }
-}
-
-/**************************************************************************
- Returns FALSE if the destination isn't large enough or the source was
- bad.
-**************************************************************************/
-static bool get_conv(char *dst, size_t ndst, const unsigned char *src,
-                    size_t nsrc)
-{
-  gsize len;                   /* length to copy, not including null */
-  gchar *out = g_convert(src, nsrc, "UTF-8", network_charset, NULL, &len, 
NULL);
-  bool ret = TRUE;
-
-  if (!out) {
-    dst[0] = '\0';
-    return FALSE;
-  }
-
-  if (ndst > 0 && len >= ndst) {
-    ret = FALSE;
-    len = ndst - 1;
-  }
-
-  memcpy(dst, out, len);
-  dst[len] = '\0';
-  g_free(out);
-
-  return ret;
-}
-
-/**************************************************************************
-Local log callback functions.
-**************************************************************************/
-static void fprintf_utf8(FILE *stream, const char *format, ...)
-{
-  va_list ap;
-  const gchar *charset;
-  gchar *s;
-
-  va_start(ap, format);
-  s = g_strdup_vprintf(format, ap);
-  va_end(ap);
-
-  if (!g_get_charset(&charset)) {
-    GError *error = NULL;
-    gchar  *s2;
-
-    s2 = g_convert(s, -1, charset, "UTF-8", NULL, NULL, &error);
-
-    if (error) {
-      fprintf(stream, "fprintf_utf8: %s\n", error->message);
-      g_error_free(error);
-    } else {
-      g_free(s);
-      s = s2;
-    }
-  }
-  fputs(s, stream);
-  fflush(stream);
-  g_free(s);
-}
 
 /**************************************************************************
 ...
 **************************************************************************/
 static void log_callback_utf8(int level, const char *message)
 {
-  fprintf_utf8(stderr, "%d: %s\n", level, message);
+  fc_fprintf(stderr, "%d: %s\n", level, message);
 }
 
 /**************************************************************************
@@ -267,7 +174,7 @@
 static void print_usage(const char *argv0)
 {
   /* add client-specific usage information here */
-  fprintf_utf8(stderr, _("Report bugs to <%s>.\n"), BUG_EMAIL_ADDRESS);
+  fc_fprintf(stderr, _("Report bugs to <%s>.\n"), BUG_EMAIL_ADDRESS);
 }
 
 /**************************************************************************
@@ -880,33 +787,11 @@
 void ui_init(void)
 {
   gchar *s;
-  char *net_charset;
 
-#ifdef ENABLE_NLS
-  bind_textdomain_codeset(PACKAGE, "UTF-8");
-#endif
+  init_character_encodings("UTF-8");
 
   log_set_callback(log_callback_utf8);
 
-  /* set networking string conversion callbacks */
-  if ((net_charset = getenv("FREECIV_NETWORK_ENCODING"))) {
-    network_charset = mystrdup(net_charset);
-  } else {
-    const gchar *charset;
-
-    g_get_charset(&charset);
-
-    if (!strcmp(charset, "ANSI_X3.4-1968")
-       || !strcmp(charset, "ASCII")) {
-      charset = "ISO-8859-1";
-    }
-    
-    network_charset = mystrdup(charset);
-  }
-
-  dio_set_put_conv_callback(put_conv);
-  dio_set_get_conv_callback(get_conv);
-
   /* convert inputs */
   s = g_locale_to_utf8(player_name, -1, NULL, NULL, NULL);
   sz_strlcpy(player_name, s);
Index: client/gui-win32/gui_main.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-win32/gui_main.c,v
retrieving revision 1.16.2.1
diff -u -r1.16.2.1 gui_main.c
--- client/gui-win32/gui_main.c 15 Oct 2002 16:56:19 -0000      1.16.2.1
+++ client/gui-win32/gui_main.c 17 Aug 2004 19:24:24 -0000
@@ -19,6 +19,7 @@
 #include <commctrl.h>
 #include <richedit.h>
 
+#include "fciconv.h"
 #include "fcintl.h"
 #include "game.h"
 #include "log.h"
@@ -512,6 +513,7 @@
 **************************************************************************/
 void ui_init(void)
 {
+  init_character_encodings(NULL);
 }
 
 /**************************************************************************
Index: client/gui-xaw/gui_main.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-xaw/gui_main.c,v
retrieving revision 1.71
diff -u -r1.71 gui_main.c
--- client/gui-xaw/gui_main.c   24 Aug 2002 14:37:48 -0000      1.71
+++ client/gui-xaw/gui_main.c   17 Aug 2004 19:24:24 -0000
@@ -36,6 +36,7 @@
 #include "canvas.h"
 #include "pixcomm.h"
 
+#include "fciconv.h"
 #include "fcintl.h"
 #include "game.h"
 #include "government.h"
@@ -264,6 +265,7 @@
 **************************************************************************/
 void ui_init(void)
 {
+  init_character_encodings(NULL);
 }
 
 /**************************************************************************
Index: common/Makefile.am
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/Makefile.am,v
retrieving revision 1.41
diff -u -r1.41 Makefile.am
--- common/Makefile.am  9 Oct 2002 20:54:20 -0000       1.41
+++ common/Makefile.am  17 Aug 2004 19:24:24 -0000
@@ -25,6 +25,8 @@
                diptreaty.c     \
                diptreaty.h     \
                events.h        \
+               fciconv.c       \
+               fciconv.h       \
                fcintl.c        \
                fcintl.h        \
                game.c          \
Index: common/log.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/Attic/log.c,v
retrieving revision 1.39.2.1
diff -u -r1.39.2.1 log.c
--- common/log.c        13 Nov 2002 18:47:21 -0000      1.39.2.1
+++ common/log.c        17 Aug 2004 19:24:24 -0000
@@ -18,6 +18,7 @@
 #include <stdarg.h>
 #include <string.h>
 
+#include "fciconv.h"
 #include "fcintl.h"
 #include "mem.h"
 #include "shared.h"
@@ -79,16 +80,16 @@
   }
   if (n == 0) {
     if (sscanf(level_str, "%d", &level) != 1) {
-      fprintf(stderr, _("Bad log level \"%s\".\n"), level_str);
+      fc_fprintf(stderr, _("Bad log level \"%s\".\n"), level_str);
       return -1;
     }
     if (level >= LOG_FATAL && level <= max_level) {
       return level;
     } else {
-      fprintf(stderr, _("Bad log level %d in \"%s\".\n"), level, level_str);
+      fc_fprintf(stderr, _("Bad log level %d in \"%s\".\n"), level, level_str);
       if (level == LOG_DEBUG && max_level < LOG_DEBUG) {
-       fprintf(stderr, _("Freeciv must be compiled with the DEBUG flag"
-                         " to use debug level %d.\n"), LOG_DEBUG);
+       fc_fprintf(stderr, _("Freeciv must be compiled with the DEBUG flag"
+                            " to use debug level %d.\n"), LOG_DEBUG);
       }
       return -1;
     }
@@ -98,12 +99,13 @@
   if (c[0] == ('0' + LOG_DEBUG) && c[1] == ':') {
     level = LOG_DEBUG;
     if (max_level < LOG_DEBUG) {
-      fprintf(stderr, _("Freeciv must be compiled with the DEBUG flag"
-                       " to use debug level %d.\n"), LOG_DEBUG);
+      fc_fprintf(stderr, _("Freeciv must be compiled with the DEBUG flag"
+                          " to use debug level %d.\n"), LOG_DEBUG);
       return -1;
     }
   } else {
-    fprintf(stderr, _("Badly formed log level argument \"%s\".\n"), level_str);
+    fc_fprintf(stderr, _("Badly formed log level argument \"%s\".\n"),
+              level_str);
     return -1;
   }
   logd_num_files = n;
@@ -114,7 +116,8 @@
   tok = strtok(dup, ":");
   
   if (!tok) {
-    fprintf(stderr, _("Badly formed log level argument \"%s\".\n"), level_str);
+    fc_fprintf(stderr, _("Badly formed log level argument \"%s\".\n"),
+              level_str);
     level = -1;
     goto out;
   }
@@ -131,20 +134,20 @@
       if (d && *pc != '\0' && d[1] != '\0') {
        d[0] = '\0';
        if (sscanf(pc, "%d", &logd_files[i].min) != 1) {
-         fprintf(stderr, _("Not an integer: '%s'\n"), pc);
+         fc_fprintf(stderr, _("Not an integer: '%s'\n"), pc);
          level = -1;
          goto out;
        }
        if (sscanf(d + 1, "%d", &logd_files[i].max) != 1) {
-         fprintf(stderr, _("Not an integer: '%s'\n"), d + 1);
+         fc_fprintf(stderr, _("Not an integer: '%s'\n"), d + 1);
          level = -1;
          goto out;
        }
       }
     }
     if(strlen(tok)==0) {
-      fprintf(stderr, _("Empty filename in log level argument \"%s\".\n"),
-             level_str);
+      fc_fprintf(stderr, _("Empty filename in log level argument \"%s\".\n"),
+                level_str);
       level = -1;
       goto out;
     }
@@ -154,7 +157,8 @@
   } while(tok);
 
   if (i!=logd_num_files) {
-    fprintf(stderr, _("Badly formed log level argument \"%s\".\n"), level_str);
+    fc_fprintf(stderr, _("Badly formed log level argument \"%s\".\n"),
+              level_str);
     level = -1;
     goto out;
   }
@@ -259,7 +263,7 @@
 
     if(log_filename) {
       if(!(fs=fopen(log_filename, "a"))) {
-       fprintf(stderr, _("Couldn't open logfile: %s for appending.\n"), 
+       fc_fprintf(stderr, _("Couldn't open logfile: %s for appending.\n"), 
                log_filename);
        exit(EXIT_FAILURE);
       }
Index: common/shared.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/Attic/shared.c,v
retrieving revision 1.92.2.8
diff -u -r1.92.2.8 shared.c
--- common/shared.c     6 Jan 2004 07:14:46 -0000       1.92.2.8
+++ common/shared.c     17 Aug 2004 19:24:24 -0000
@@ -28,16 +28,6 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 
-#ifdef HAVE_ICONV
-#include <iconv.h>
-#ifdef HAVE_LIBCHARSET
-#include <libcharset.h>
-#else
-#ifdef HAVE_LANGINFO_CODESET
-#include <langinfo.h>
-#endif
-#endif
-#endif
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #endif
@@ -1235,136 +1225,3 @@
   }
   return FALSE;
 }
-
-#ifdef HAVE_ICONV
-/***************************************************************************
-  Convert the text.  This assumes 'from' is an 8-bit charset.
-***************************************************************************/
-static char *convert_string_malloc(const char *text,
-                                  const char *from, const char *to)
-{
-  iconv_t cd;
-  size_t from_len = strlen(text) + 1, to_len = from_len;
-  char *result;
-
-  cd = iconv_open(to, from);
-  if (cd == (iconv_t) (-1)) {
-    freelog(LOG_ERROR,
-           _("String conversion from %s not possible.  You may\n"
-             "want to set your local encoding manually by setting\n"
-             "the environment variable $FREECIV_LOCAL_ENCODING."
-             "Proceeding anyway..."),
-           from);
-    return mystrdup(text); /* The best we can do? */
-  }
-
-  do {
-    size_t flen = from_len, tlen = to_len, res;
-    const char *mytext = text;
-    char *myresult;
-
-    if (to_len > 1000000) {
-      /* Avoid unterminated loop. */
-      /* NOTE: same as error message above. */
-      freelog(LOG_ERROR,
-             _("String conversion from %s not possible.  You may\n"
-               "want to set your local encoding manually by setting\n"
-               "the environment variable $FREECIV_LOCAL_ENCODING."
-               "Proceeding anyway..."),
-             from);
-      iconv_close(cd);
-      return mystrdup(text);
-    }
-
-    result = fc_malloc(to_len);
-
-    myresult = result;
-
-    /* Since we may do multiple translations, we may need to reset iconv
-     * in between. */
-    iconv(cd, NULL, NULL, NULL, NULL);
-
-    res = iconv(cd, (ICONV_CONST char **)&mytext, &flen, &myresult, &tlen);
-    if (res == (size_t) (-1)) {
-      if (errno != E2BIG) {
-       /* Invalid input. */
-       freelog(LOG_ERROR,
-               _("The string '%s' is not valid: %s. Ruleset files must\n"
-                 "be encoded as %s; you can change this by setting\n"
-                 "$FREECIV_DATA_ENCODING."),
-               text, strerror(errno), from);
-       free(result);
-       iconv_close(cd);
-       return mystrdup(text); /* The best we can do? */
-      }
-    } else {
-      /* Success. */
-      iconv_close(cd);
-
-      /* There may be wasted space here.  But we don't want to call
-       * mystrdup on result since it might not be in an 8-bit charset. */
-      return result;
-    }
-
-    /* Not enough space; try again. */
-    free(result);
-    to_len *= 2;
-  } while (TRUE);
-}
-#endif
-
-/***************************************************************************
-  We convert from the charset used by the rulesets into the local encoding.
-***************************************************************************/
-char *convert_data_string_malloc(const char *text)
-{
-#ifdef HAVE_ICONV
-  char *local_encoding, *data_encoding;
-  char target[128];
-
-  data_encoding = getenv("FREECIV_DATA_ENCODING");
-  if (!data_encoding) {
-    /* Currently the rulesets are in latin1 (ISO-8859-1). */
-    data_encoding = "ISO-8859-1";
-  }
-
-  local_encoding = getenv("FREECIV_LOCAL_ENCODING");
-  if (!local_encoding) {
-#ifdef HAVE_LIBCHARSET
-    local_encoding = locale_charset();
-#else
-#ifdef HAVE_LANGINFO_CODESET
-    local_encoding = nl_langinfo(CODESET);
-#else
-    local_encoding = "";
-#endif
-#endif
-    if (strcasecmp(local_encoding, "ANSI_X3.4-1968") == 0
-       || strcasecmp(local_encoding, "ASCII") == 0) {
-      /* HACK: Use latin1 instead of ascii. */
-      local_encoding = "ISO-8859-1";
-    }
-    my_snprintf(target, sizeof(target), "%s//TRANSLIT", local_encoding);
-    local_encoding = target;
-  }
-
-  return convert_string_malloc(text, data_encoding, local_encoding);
-#else
-/* Don't expect that win32 users install iconv on their own, especially
- * not from http://gnu.org/ in source form... */
-#ifndef WIN32_NATIVE
-  static bool only_give_this_damn_warning_once = FALSE;
-
-  if (!only_give_this_damn_warning_once) {
-    only_give_this_damn_warning_once = TRUE;
-
-   freelog(LOG_ERROR,
-           _("You are running Freeciv without using iconv.  Unless\n"
-           "you are using the latin1 character set, some characters\n"
-           "may not be displayed properly.  You can download iconv\n"
-           "at http://gnu.org/.";));
-   }
-#endif
-  return mystrdup(text);
-#endif
-}
Index: common/shared.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/Attic/shared.h,v
retrieving revision 1.104.2.1
diff -u -r1.104.2.1 shared.h
--- common/shared.h     4 Feb 2003 18:15:48 -0000       1.104.2.1
+++ common/shared.h     17 Aug 2004 19:24:24 -0000
@@ -178,6 +178,4 @@
 
 const char *freeciv_motto(void);
 
-char *convert_data_string_malloc(const char *text);
-
 #endif  /* FC__SHARED_H */
Index: server/ruleset.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/ruleset.c,v
retrieving revision 1.120.2.3
diff -u -r1.120.2.3 ruleset.c
--- server/ruleset.c    14 Jul 2004 18:53:13 -0000      1.120.2.3
+++ server/ruleset.c    17 Aug 2004 19:24:25 -0000
@@ -1951,7 +1951,7 @@
       } /* if (!next) */
     } /* if (name) */
     remove_leading_trailing_spaces(cities[j]);
-    city_names[j].name = convert_data_string_malloc(cities[j]);
+    city_names[j].name = mystrdup(cities[j]);
     if (check_name(city_names[j].name)) {
       /* The ruleset contains a name that is too long.  This shouldn't
         happen - if it does, the author should get immediate feedback */
@@ -2003,7 +2003,7 @@
     }
     pl->leader_count = dim;
     for(j = 0; j < dim; j++) {
-      pl->leader_name[j] = convert_data_string_malloc(leaders[j]);
+      pl->leader_name[j] = mystrdup(leaders[j]);
       if (check_name(leaders[j])) {
        pl->leader_name[j][MAX_LEN_NAME - 1] = 0;
       }
Index: server/srv_main.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/srv_main.c,v
retrieving revision 1.97.2.2
diff -u -r1.97.2.2 srv_main.c
--- server/srv_main.c   12 Oct 2003 11:04:55 -0000      1.97.2.2
+++ server/srv_main.c   17 Aug 2004 19:24:26 -0000
@@ -47,6 +47,7 @@
 #include "capstr.h"
 #include "city.h"
 #include "events.h"
+#include "fciconv.h"
 #include "fcintl.h"
 #include "game.h"
 #include "log.h"
@@ -182,6 +183,9 @@
   /* mark as initialized */
   has_been_srv_init = TRUE;
 
+  /* init character encodings. */
+  init_character_encodings(DEFAULT_DATA_ENCODING);
+
   /* done */
   return;
 }
/********************************************************************** 
 Freeciv - Copyright (C) 2003-2004 - The Freeciv Project
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2, or (at your option)
   any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
***********************************************************************/

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>

#ifdef HAVE_ICONV
#include <iconv.h>
#endif

#ifdef HAVE_LANGINFO_CODESET
#include <langinfo.h>
#endif

#include "fciconv.h"
#include "fcintl.h"
#include "log.h"
#include "mem.h"
#include "support.h"

static bool is_init = FALSE;
static char convert_buffer[4096];

#ifdef HAVE_ICONV
static char *local_encoding, *data_encoding, *internal_encoding;
#endif

/***************************************************************************
  Must be called during the initialization phase of server and client to
  initialize the character encodings to be used.
***************************************************************************/
void init_character_encodings(char *my_internal_encoding)
{
#ifdef HAVE_ICONV
  /* Set the data encoding - first check $FREECIV_DATA_ENCODING,
   * then fall back to the default. */
  data_encoding = getenv("FREECIV_DATA_ENCODING");
  if (!data_encoding) {
    /* Currently the rulesets are in latin1 (ISO-8859-1). */
    data_encoding = DEFAULT_DATA_ENCODING;
  }

  /* Set the local encoding - first check $FREECIV_LOCAL_ENCODING,
   * then ask the system. */
  local_encoding = getenv("FREECIV_LOCAL_ENCODING");
  if (!local_encoding) {
#ifdef HAVE_LIBCHARSET
    local_encoding = locale_charset();
#else
#ifdef HAVE_LANGINFO_CODESET
    local_encoding = nl_langinfo(CODESET);
#else
    local_encoding = "";
#endif
#endif
    if (strcasecmp(local_encoding, "ANSI_X3.4-1968") == 0
        || strcasecmp(local_encoding, "ASCII") == 0) {
      /* HACK: use latin1 instead of ascii in typical cases when the
       * encoding is unconfigured. */
      local_encoding = "ISO-8859-1";
    }
  }

  /* Set the internal encoding - first check $FREECIV_INTERNAL_ENCODING,
   * then check the passed-in default value, then fall back to the local
   * encoding. */
  internal_encoding = getenv("FREECIV_INTERNAL_ENCODING");
  if (!internal_encoding) {
    internal_encoding = my_internal_encoding;

    if (!internal_encoding) {
      internal_encoding = local_encoding;
    }
  }

#ifdef ENABLE_NLS
  bind_textdomain_codeset(PACKAGE, internal_encoding);
#endif

  fprintf(stderr, "Data=%s, Local=%s, Internal=%s\n",
             data_encoding, local_encoding, internal_encoding);
#else
   /* freelog may not work at this point. */
  fprintf(stderr,
             _("You are running Freeciv without using iconv.  Unless\n"
               "you are using the latin1 character set, some characters\n"
               "may not be displayed properly.  You can download iconv\n"
               "at http://gnu.org/.\n";));
#endif

  is_init = TRUE;
}

const char *get_data_encoding(void)
{
  assert(is_init);
  return data_encoding;
}

const char *get_local_encoding(void)
{
  assert(is_init);
  return local_encoding;
}

const char *get_internal_encoding(void)
{
  assert(is_init);
  return internal_encoding;
}

/***************************************************************************
  Convert the text.  Both 'from' and 'to' must be 8-bit charsets.  The
  result will be put into the buf buffer unless it is NULL, in which case it
  will be allocated on demand.
***************************************************************************/
static char *convert_string(const char *text,
                            const char *from,
                            const char *to,
                            char *buf, size_t bufsz)
{
#ifdef HAVE_ICONV
  iconv_t cd = iconv_open(to, from);
  size_t from_len = strlen(text) + 1, to_len;
  bool alloc = (buf == NULL);

  assert(is_init && from != NULL && to != NULL);
  assert(text != NULL);

  if (cd == (iconv_t) (-1)) {
    freelog(LOG_ERROR,
            _("Could not convert text from %s to %s: %s"),
            from, to, strerror(errno));
    /* The best we can do? */
    if (alloc) {
      return mystrdup(text);
    } else {
      my_snprintf(buf, bufsz, "%s", text);
      return buf;
    }
  }

  if (alloc) {
    to_len = from_len;
  } else {
    to_len = bufsz;
  }

  do {
    size_t flen = from_len, tlen = to_len, res;
    const char *mytext = text;
    char *myresult;

    if (alloc) {
      buf = fc_malloc(to_len);
    }

    myresult = buf;

    /* Since we may do multiple translations, we may need to reset iconv
     * in between. */
    iconv(cd, NULL, NULL, NULL, NULL);

    res = iconv(cd, (char**)&mytext, &flen, &myresult, &tlen);
    if (res == (size_t) (-1)) {
      if (errno != E2BIG) {
        /* Invalid input. */
        freelog(LOG_ERROR, "Invalid string conversion from %s to %s.",
                from, to);
        iconv_close(cd);
        if (alloc) {
          free(buf);
          return mystrdup(text); /* The best we can do? */
        } else {
          my_snprintf(buf, bufsz, "%s", text);
          return buf;
        }
      }
    } else {
      /* Success. */
      iconv_close(cd);

      /* There may be wasted space here, but there's nothing we can do
       * about it. */
      return buf;
    }

    if (alloc) {
      /* Not enough space; try again. */
      buf[to_len - 1] = 0;
      freelog(LOG_VERBOSE, "   Result was '%s'.", buf);

      free(buf);
      to_len *= 2;
    }
  } while (alloc);

  return buf;
#else /* HAVE_ICONV */
  if (buf) {
    strncpy(buf, text, bufsz);
    buf[bufsz - 1] = '\0';
  } else {
    return mystrdup(text);
  }
#endif /* HAVE_ICONV */
}

#define CONV_FUNC_MALLOC(src, dst)                                          \
char *src ## _to_ ## dst ## _string_malloc(const char *text)                \
{                                                                           \
  return convert_string(text, (src ## _encoding),                           \
                        (dst ## _encoding), NULL, 0);                       \
}

#define CONV_FUNC_BUFFER(src, dst)                                          \
char *src ## _to_ ## dst ## _string_buffer(const char *text,                \
                                           char *buf, size_t bufsz)         \
{                                                                           \
  return convert_string(text, (src ## _encoding),                           \
                        (dst ## _encoding), buf, bufsz);                    \
}

#define CONV_FUNC_STATIC(src, dst)                                          \
char *src ## _to_ ## dst ## _string_static(const char *text)                \
{                                                                           \
  (src ## _to_ ## dst ## _string_buffer)(text,                              \
                                        convert_buffer,                     \
                                        sizeof(convert_buffer));            \
  return convert_buffer;                                                    \
}

CONV_FUNC_MALLOC(data, internal)
CONV_FUNC_MALLOC(internal, data)

static CONV_FUNC_BUFFER(internal, local)
static CONV_FUNC_STATIC(internal, local)

/***************************************************************************
  Do a printf in the currently bound codeset.
***************************************************************************/
void fc_fprintf(FILE *stream, const char *format, ...)
{
  va_list ap;
  char string[4096];
  const char *output;

  va_start(ap, format);
  my_vsnprintf(string, sizeof(string), format, ap);
  va_end(ap);

  output = internal_to_local_string_static(string);

  fputs(output, stream);
  fflush(stream);
}
/********************************************************************** 
 Freeciv - Copyright (C) 2003-2004 - The Freeciv Project
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2, or (at your option)
   any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
***********************************************************************/
#ifndef FC__FCICONV_H
#define FC__FCICONV_H

#include "shared.h"

#define DEFAULT_DATA_ENCODING "ISO-8859-1"

void init_character_encodings(char *internal_encoding);

const char *get_data_encoding(void);
const char *get_local_encoding(void);
const char *get_internal_encoding(void);

char *data_to_internal_string_malloc(const char *text);
char *internal_to_data_string_malloc(const char *text);

void fc_fprintf(FILE *stream, const char *format, ...)
      fc__attribute((format (printf, 2, 3)));

#endif /* FC__FCICONV_H */

[Prev in Thread] Current Thread [Next in Thread]
  • [Freeciv-Dev] (PR#9722) fix charset problems in 1.14, Jason Short <=