Complete.Org: Mailing Lists: Archives: freeciv-dev: July 2004:
[Freeciv-Dev] (PR#1824) ruleset data is in incompatible charsets
Home

[Freeciv-Dev] (PR#1824) ruleset data is in incompatible charsets

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
To: Kenn.Munro@xxxxxxxxxxxxxx, jdwheeler42@xxxxxxxxx, jrg45@xxxxxxxxxxxxxxxxx, pawel@xxxxxxxxxxxxxxx, per@xxxxxxxxxxx
Cc: mrproper@xxxxxxxxxx, jlangley@xxxxxxx
Subject: [Freeciv-Dev] (PR#1824) ruleset data is in incompatible charsets
From: "Jason Short" <jdorje@xxxxxxxxxxxxxxxxxxxxx>
Date: Sun, 18 Jul 2004 19:23:18 -0700
Reply-to: rt@xxxxxxxxxxx

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

Here's an update of a patch implementing my design.

It works in all the cases I've thrown at it.  However I know there are
some corner cases out there.  is_sane_name has to be fixed, for one thing.

jason

Index: configure.ac
===================================================================
RCS file: /home/freeciv/CVS/freeciv/configure.ac,v
retrieving revision 1.67
diff -u -r1.67 configure.ac
--- configure.ac        14 Jul 2004 19:16:24 -0000      1.67
+++ configure.ac        19 Jul 2004 02:19:27 -0000
@@ -306,6 +306,11 @@
   AC_MSG_ERROR([zlib found but not zlib.h.  
 You may need to install a zlib \"development\" package.]))
 
+dnl Check for libiconv (which is usually included in glibc, but may be
+dnl distributed separately).
+AM_ICONV
+LIBS="$LIBS $LIBICONV"
+
 dnl Check and choose clients
 if test x$client != xno; then
 
Index: configure.in
===================================================================
RCS file: /home/freeciv/CVS/freeciv/configure.in,v
retrieving revision 1.243
diff -u -r1.243 configure.in
--- configure.in        14 Jul 2004 19:16:24 -0000      1.243
+++ configure.in        19 Jul 2004 02:19:27 -0000
@@ -299,6 +299,11 @@
   AC_MSG_ERROR([zlib found but not zlib.h.  
 You may need to install a zlib \"development\" package.]))
 
+dnl Check for libiconv (which is usually included in glibc, but may be
+dnl distributed separately).
+AM_ICONV
+LIBS="$LIBS $LIBICONV"
+
 dnl Check and choose clients
 if test x$client != xno; then
 
Index: client/civclient.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/civclient.c,v
retrieving revision 1.190
diff -u -r1.190 civclient.c
--- client/civclient.c  25 Jun 2004 23:35:55 -0000      1.190
+++ client/civclient.c  19 Jul 2004 02:19:27 -0000
@@ -21,7 +21,9 @@
 #include <time.h>
 
 #include "capstr.h"
+#include "dataio.h"
 #include "diptreaty.h"
+#include "fciconv.h"
 #include "fcintl.h"
 #include "game.h"
 #include "idex.h"
@@ -91,6 +93,61 @@
  */
 bool turn_done_sent = FALSE;
 
+/**************************************************************************
+  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);
+}
 
 /**************************************************************************
 ...
@@ -203,6 +260,7 @@
   conn_list_init(&game.game_connections);
 
   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.150
diff -u -r1.150 gui_main.c
--- client/gui-gtk/gui_main.c   10 Jul 2004 18:48:18 -0000      1.150
+++ client/gui-gtk/gui_main.c   19 Jul 2004 02:19:27 -0000
@@ -31,6 +31,7 @@
 #include <unistd.h>
 #endif
 
+#include "fciconv.h"
 #include "fcintl.h"
 #include "game.h"
 #include "government.h"
@@ -803,6 +804,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.37
diff -u -r1.37 connectdlg.c
--- client/gui-gtk-2.0/connectdlg.c     29 May 2004 13:41:57 -0000      1.37
+++ client/gui-gtk-2.0/connectdlg.c     19 Jul 2004 02:19:28 -0000
@@ -260,12 +260,12 @@
       GtkTreeIter it;
       int i;
 
-      row[0] = ntoh_str(pserver->name);
-      row[1] = ntoh_str(pserver->port);
-      row[2] = ntoh_str(pserver->version);
-      row[3] = g_strdup(_(pserver->status));
-      row[4] = ntoh_str(pserver->players);
-      row[5] = ntoh_str(pserver->metastring);
+      row[0] = pserver->name;
+      row[1] = pserver->port;
+      row[2] = pserver->version;
+      row[3] = _(pserver->status);
+      row[4] = pserver->players;
+      row[5] = pserver->metastring;
 
       gtk_list_store_append(storelan, &it);
       gtk_list_store_set(storelan, &it,
@@ -1128,12 +1128,12 @@
     GtkTreeIter it;
     int i;
 
-    row[0] = ntoh_str(pserver->name);
-    row[1] = ntoh_str(pserver->port);
-    row[2] = ntoh_str(pserver->version);
-    row[3] = g_strdup(_(pserver->status));
-    row[4] = ntoh_str(pserver->players);
-    row[5] = ntoh_str(pserver->metastring);
+    row[0] = pserver->name;
+    row[1] = pserver->port;
+    row[2] = pserver->version;
+    row[3] = _(pserver->status);
+    row[4] = pserver->players;
+    row[5] = pserver->metastring;
 
     gtk_list_store_append(storemeta, &it);
     gtk_list_store_set(storemeta, &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.74
diff -u -r1.74 gui_main.c
--- client/gui-gtk-2.0/gui_main.c       10 Jul 2004 18:48:18 -0000      1.74
+++ client/gui-gtk-2.0/gui_main.c       19 Jul 2004 02:19:28 -0000
@@ -33,6 +33,7 @@
 #include <gdk/gdkkeysyms.h>
 
 #include "dataio.h"
+#include "fciconv.h"
 #include "fcintl.h"
 #include "game.h"
 #include "government.h"
@@ -173,107 +174,13 @@
 static gint timer_callback(gpointer data);
 static gboolean show_conn_popup(GtkWidget *view, GdkEventButton *ev,
                                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);
 }
 
 /**************************************************************************
@@ -283,7 +190,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);
 }
 
 /**************************************************************************
@@ -1020,33 +927,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(user_name, -1, NULL, NULL, NULL);
   sz_strlcpy(user_name, s);
Index: client/gui-sdl/gui_iconv.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-sdl/gui_iconv.c,v
retrieving revision 1.8
diff -u -r1.8 gui_iconv.c
--- client/gui-sdl/gui_iconv.c  7 Aug 2003 21:54:29 -0000       1.8
+++ client/gui-sdl/gui_iconv.c  19 Jul 2004 02:19:28 -0000
@@ -66,22 +66,6 @@
 }
 
 /**************************************************************************
-  Return the local charset encoding (which will be passed to iconv).
-**************************************************************************/
-static const char *get_local_encoding(void)
-{
-#ifdef HAVE_LIBCHARSET
-  return locale_charset();
-#else
-#  ifdef HAVE_LANGINFO_CODESET
-  return nl_langinfo(CODESET);
-#  else
-  return "";
-#  endif
-#endif
-}
-
-/**************************************************************************
   Convert string from local encoding (8 bit char) to
   display encoding (16 bit unicode) and resut put in pToUniString.
   if pToUniString == NULL then resulting string will be allocate automaticaly.
@@ -94,7 +78,7 @@
 {
   /* Start Parametrs */
   const char *pTocode = get_display_encoding();
-  const char *pFromcode = get_local_encoding();
+  const char *pFromcode = INTERNAL_ENCODING;
   const char *pStart = pFromString;
   size_t length = strlen(pFromString) + 1;
 
@@ -175,7 +159,7 @@
 {
   /* Start Parametrs */
   const char *pFromcode = get_display_encoding();
-  const char *pTocode = get_local_encoding();
+  const char *pTocode = INTERNAL_ENCODING;
   const char *pStart = (char *) pFromUniString;
   size_t ulength = (unistrlen(pFromUniString) + 1) * 2;
 
Index: client/gui-sdl/gui_iconv.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-sdl/gui_iconv.h,v
retrieving revision 1.5
diff -u -r1.5 gui_iconv.h
--- client/gui-sdl/gui_iconv.h  7 Aug 2003 21:54:29 -0000       1.5
+++ client/gui-sdl/gui_iconv.h  19 Jul 2004 02:19:28 -0000
@@ -26,6 +26,10 @@
 #ifndef FC__GUI_ICONV_H
 #define FC__GUI_ICONV_H
 
+/* The encoding used internally by the client (outside of the GUI code).
+ * This must be a single-width encoding. */
+#define INTERNAL_ENCODING "UTF-8"
+
 Uint16 *convertcopy_to_utf16(Uint16 *pToUniString, size_t ulenght,
                              const char *pFromString);
 char *convertcopy_to_chars(char *pToString, size_t lenght,
Index: client/gui-sdl/gui_main.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-sdl/gui_main.c,v
retrieving revision 1.44
diff -u -r1.44 gui_main.c
--- client/gui-sdl/gui_main.c   24 Jan 2004 02:58:55 -0000      1.44
+++ client/gui-sdl/gui_main.c   19 Jul 2004 02:19:28 -0000
@@ -698,6 +698,8 @@
   SDL_Surface *pBgd, *pTmp;
   Uint32 iSDL_Flags;
 
+  init_character_encodings(INTERNAL_ENCODING);
+
   SDL_Client_Flags = 0;
   iSDL_Flags = SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE;
   
Index: client/gui-win32/gui_main.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-win32/gui_main.c,v
retrieving revision 1.26
diff -u -r1.26 gui_main.c
--- client/gui-win32/gui_main.c 17 Jun 2004 00:39:51 -0000      1.26
+++ client/gui-win32/gui_main.c 19 Jul 2004 02:19:30 -0000
@@ -21,6 +21,7 @@
 #include <commctrl.h>
 #include <richedit.h>
 
+#include "fciconv.h"
 #include "fcintl.h"
 #include "game.h"
 #include "log.h"
@@ -530,6 +531,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.92
diff -u -r1.92 gui_main.c
--- client/gui-xaw/gui_main.c   6 Jun 2004 06:00:09 -0000       1.92
+++ client/gui-xaw/gui_main.c   19 Jul 2004 02:19:30 -0000
@@ -37,6 +37,7 @@
 #include "canvas.h"
 #include "pixcomm.h"
 
+#include "fciconv.h"
 #include "fcintl.h"
 #include "game.h"
 #include "government.h"
@@ -261,6 +262,7 @@
 **************************************************************************/
 void ui_init(void)
 {
+  init_character_encodings(NULL);
 }
 
 /**************************************************************************
Index: server/srv_main.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/srv_main.c,v
retrieving revision 1.176
diff -u -r1.176 srv_main.c
--- server/srv_main.c   18 Jul 2004 05:47:22 -0000      1.176
+++ server/srv_main.c   19 Jul 2004 02:19:30 -0000
@@ -49,6 +49,7 @@
 #include "city.h"
 #include "dataio.h"
 #include "events.h"
+#include "fciconv.h"
 #include "fcintl.h"
 #include "game.h"
 #include "log.h"
@@ -178,6 +179,9 @@
   /* mark as initialized */
   has_been_srv_init = TRUE;
 
+  /* init character encodings. */
+  init_character_encodings(DEFAULT_DATA_ENCODING);
+
   /* done */
   return;
 }
Index: utility/Makefile.am
===================================================================
RCS file: /home/freeciv/CVS/freeciv/utility/Makefile.am,v
retrieving revision 1.3
diff -u -r1.3 Makefile.am
--- utility/Makefile.am 6 May 2004 22:57:36 -0000       1.3
+++ utility/Makefile.am 19 Jul 2004 02:19:31 -0000
@@ -11,6 +11,8 @@
                astring.h       \
                capability.c    \
                capability.h    \
+               fciconv.c       \
+               fciconv.h       \
                fcintl.c        \
                fcintl.h        \
                genlist.c       \
Index: utility/fciconv.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/utility/fciconv.c,v
retrieving revision 1.1
diff -u -r1.1 fciconv.c
--- utility/fciconv.c   26 Apr 2004 02:13:30 -0000      1.1
+++ utility/fciconv.c   19 Jul 2004 02:19:31 -0000
@@ -0,0 +1,272 @@
+/********************************************************************** 
+ 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);
+}
Index: utility/fciconv.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/utility/fciconv.h,v
retrieving revision 1.1
diff -u -r1.1 fciconv.h
--- utility/fciconv.h   26 Apr 2004 02:13:30 -0000      1.1
+++ utility/fciconv.h   19 Jul 2004 02:19:31 -0000
@@ -0,0 +1,32 @@
+/********************************************************************** 
+ 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 */
Index: utility/log.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/utility/log.c,v
retrieving revision 1.45
diff -u -r1.45 log.c
--- utility/log.c       10 Apr 2004 03:47:49 -0000      1.45
+++ utility/log.c       19 Jul 2004 02:19:31 -0000
@@ -19,6 +19,7 @@
 #include <stdio.h>
 #include <string.h>
 
+#include "fciconv.h"
 #include "fcintl.h"
 #include "mem.h"
 #include "shared.h"
@@ -80,16 +81,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;
     }
@@ -99,12 +100,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;
@@ -115,7 +117,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;
   }
@@ -132,20 +135,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;
     }
@@ -155,7 +158,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;
   }
@@ -236,7 +240,7 @@
     log_callback(level, message);
   }
   if (log_filename || (!log_callback)) {
-    fprintf(fs, "%d: %s\n", level, message);
+    fc_fprintf(fs, "%d: %s\n", level, message);
     fflush(fs);
   }
 }
@@ -264,7 +268,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);
       }

[Prev in Thread] Current Thread [Next in Thread]