Index: Makefile.am
===================================================================
RCS file: /cvs/gnome/glib/glib/Makefile.am,v
retrieving revision 1.89
diff -u -r1.89 Makefile.am
--- Makefile.am	2001/07/23 11:44:04	1.89
+++ Makefile.am	2001/08/03 19:20:33
@@ -1,6 +1,7 @@
 ## Process this file with automake to produce Makefile.in
 
 INCLUDES = -I$(top_srcdir) -DG_LOG_DOMAIN=g_log_domain_glib \
+	-DSYSCONFDIR=\"$(sysconfdir)\" 		\
 	@GLIB_DEBUG_FLAGS@ -DG_DISABLE_DEPRECATED -DGLIB_COMPILATION 
 
 EXTRA_DIST = 			\
Index: gconvert.c
===================================================================
RCS file: /cvs/gnome/glib/glib/gconvert.c,v
retrieving revision 1.16
diff -u -r1.16 gconvert.c
--- gconvert.c	2001/06/23 13:55:07	1.16
+++ gconvert.c	2001/08/03 19:20:34
@@ -46,6 +46,258 @@
   return quark;
 }
 
+typedef struct _GIconvModule GIconvModule;
+
+struct _GIconvModule
+{
+  gchar *codeset;
+  gsize alias_num;
+  gchar **aliases;
+};
+
+#ifdef G_OS_WIN32
+static gchar *
+get_glib_dll_name (void)
+{
+  static gchar *glib_dll = NULL;
+
+  if (!glib_dll)
+    glib_dll = g_strdup_printf ("glib-%d.%d.dll", GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION);
+
+  return glib_dll;
+}
+#endif /* G_OS_WIN32 */
+
+static gchar*
+g_iconv_get_alias_file (void)
+{
+  gchar *result = g_strdup (g_getenv ("G_ICONV_ALIAS_FILE"));
+
+  if (!result)
+#ifndef G_OS_WIN32
+    result = g_strdup (SYSCONFDIR G_DIR_SEPARATOR_S "glib-2.0" G_DIR_SEPARATOR_S "giconv.aliases");
+#else
+    result = g_strdup_printf ("%s\\giconv.aliases", g_win32_get_package_installation_directory (GETTEXT_PACKAGE, get_glib_dll_name ()));
+#endif
+
+  return result;
+}
+
+/**
+ * scan_string:
+ * @pos: in/out string position
+ * @out: a #GString into which to write the result
+ * 
+ * Scan a string into a #GString buffer. The string may either
+ * be a sequence of non-white-space characters, or a quoted
+ * string with '"'. Instead a quoted string, '\"' represents
+ * a literal quote. Leading white space outside of quotes is skipped.
+ * 
+ * Return value: %FALSE if a parse error occured.
+ **/
+gboolean
+scan_string (const char **pos, GString *out)
+{
+  const char *p = *pos;
+  
+  while (g_unichar_isspace (*p))
+    p++;
+
+  if (!*p)
+    return FALSE;
+
+  g_string_truncate (out, 0);
+
+  while (*p && !g_unichar_isspace (*p))
+    {
+      g_string_append_c (out, *p);
+      p++;
+    }
+
+  *pos = p;
+
+  return TRUE;
+}
+
+/**
+ * skip_space:
+ * @pos: in/out string position
+ * 
+ * Skips 0 or more characters of white space.
+ * 
+ * Return value: %FALSE if skipping the white space leaves
+ * the position at a '\0' character.
+ **/
+static gboolean
+skip_space (const char **pos)
+{
+  const char *p = *pos;
+  
+  while (g_unichar_isspace (*p))
+    p++;
+
+  *pos = p;
+
+  return !(*p == '\0');
+}
+
+/**
+ * trim_string:
+ * @str: a string
+ * 
+ * Trim leading and trailing whitespace from a string.
+ * 
+ * Return value: A newly allocated string that must be freed with g_free()
+ **/
+static char *
+trim_string (const char *str)
+{
+  int len;
+
+  g_return_val_if_fail (str != NULL, NULL);
+  
+  while (*str && g_unichar_isspace (*str))
+    str++;
+
+  len = strlen (str);
+  while (len > 0 && g_unichar_isspace (str[len-1]))
+    len--;
+
+  return g_strndup (str, len);
+}
+
+static void
+free_info (GIconvModule *info)
+{
+  int i;
+  g_free ((char *)info->codeset);
+  for (i = 0; i < info->alias_num; i++)
+    g_free ((char *)info->aliases[i]);
+  g_free ((char *)info->aliases);
+  g_free (info);
+}
+
+static GList*
+g_iconv_read_alias_file (void)
+{
+  GIOChannel *channel = NULL;
+  GIOStatus status;
+  GError *local_err = NULL;
+  gchar *filename;
+  GIconvModule *data;
+  GString *line_buffer;
+  GString *tmp_buffer;
+  const char *pos;
+  gchar **modules;
+  int i;
+  GList *iconv_modules = NULL;
+
+  filename = g_iconv_get_alias_file ();
+  if (!filename)
+    return NULL;
+
+  channel = g_io_channel_new_file (filename, "r", &local_err);
+  if (!channel)
+    {
+      g_warning ("'%s' : %s", filename, local_err->message);
+      g_clear_error (&local_err);
+      g_free (filename);
+      return NULL;
+    }
+
+  line_buffer = g_string_new (0);
+  tmp_buffer = g_string_new (0);
+
+  while (TRUE)
+    {
+      gchar *codeset = NULL;
+
+      do
+	status = g_io_channel_read_line_string (channel, line_buffer,
+						NULL, &local_err);
+      while (status == G_IO_STATUS_AGAIN);
+      if (status != G_IO_STATUS_NORMAL)
+	break;
+
+      pos = line_buffer->str;
+
+      if (!skip_space (&pos))
+	continue;
+
+      if (*pos == '#')		/* skip comment line */
+	continue;
+
+      if (!scan_string (&pos, tmp_buffer))
+	goto context_error;
+
+      codeset = g_strdup (tmp_buffer->str);
+
+      if (!scan_string (&pos, tmp_buffer))
+	goto context_error;
+
+      /* Remove excess whitespace and check for complete fields */
+      modules = g_strsplit (tmp_buffer->str, ",", -1);
+      for (i = 0; modules[i]; i++)
+	{
+	  char *trimmed = trim_string (modules[i]);
+	  g_free (modules[i]);
+	  modules[i] = trimmed;
+	}
+      data = g_malloc (sizeof(GIconvModule));
+      data->codeset = codeset;
+      data->alias_num = i;
+      data->aliases = modules;
+
+      iconv_modules = g_list_append (iconv_modules, data);
+
+      continue;
+
+    context_error:
+      g_warning ("Error parsing context info in '%s' at the line: %s",
+		 filename, line_buffer->str);
+    }
+  /* end of while loop */
+
+  g_string_free (line_buffer, TRUE);
+  g_string_free (tmp_buffer, TRUE);
+
+  if (local_err)
+    {
+      g_warning (local_err->message);
+      g_clear_error (&local_err);
+    }
+
+  g_io_channel_unref (channel);
+
+  g_free (filename);
+
+  return iconv_modules;
+
+}
+
+static gchar**
+g_iconv_alias (GList *iconv_modules, const gchar *codeset, gint *list_num)
+{
+  GList* it;
+  GIconvModule *data;
+
+  g_return_if_fail (iconv_modules != NULL);
+
+  for (it = iconv_modules; it; it = g_list_next(it))
+    {
+      data = (GIconvModule*)it->data;
+      if (data->codeset && !strcmp (data->codeset, codeset))
+	{
+	  *list_num = data->alias_num;
+	  return (gchar**)data->aliases;
+	}
+    }
+
+  /* not found */
+  *list_num = 0;
+  return 0;
+}
+
 #if defined(USE_LIBICONV) && !defined (_LIBICONV_H)
 #error libiconv in use but included iconv.h not from libiconv
 #endif
@@ -72,7 +324,37 @@
 	      const gchar  *from_codeset)
 {
   iconv_t cd = iconv_open (to_codeset, from_codeset);
-  
+
+  if (cd == (iconv_t)-1)
+    { /* try different names */
+      GList *iconv_modules, *tmp_list;
+
+      iconv_modules = g_iconv_read_alias_file ();
+      if (iconv_modules)
+	{
+	  gchar **to_list, **from_list, **p, **q;
+	  gint from_list_num, to_list_num;
+
+	  from_list = g_iconv_alias (iconv_modules, from_codeset, &from_list_num);
+	  to_list = g_iconv_alias (iconv_modules, to_codeset, &to_list_num);
+
+	  for (p = from_list; p < &from_list[from_list_num]; p++)
+	    for (q = to_list; q < &to_list[to_list_num]; q++)
+	      {
+		cd = iconv_open (*q, *p);
+		if (cd != (iconv_t)-1)
+		  goto found;
+	      }
+	found:
+	  tmp_list = iconv_modules;
+	  while (tmp_list)
+	    {
+	      free_info (tmp_list->data);
+	      tmp_list = tmp_list->next;
+	    }
+	  g_list_free (iconv_modules);
+	}
+    }
   return (GIConv)cd;
 }
 
