Introduce the idea of a filename encoding, which is *literally* the
authorMatthias Clasen <mclasen@redhat.com>
Wed, 27 Oct 2004 16:46:29 +0000 (16:46 +0000)
committerMatthias Clasen <matthiasc@src.gnome.org>
Wed, 27 Oct 2004 16:46:29 +0000 (16:46 +0000)
2004-10-27  Matthias Clasen  <mclasen@redhat.com>

Introduce the idea of a filename encoding, which is
*literally* the filename encoding on Unix. On windows,
use the Unicode name converted to UTF-8. (#156325,
Tor Lillqvist, Owen Taylor)

* glib/gdir.[hc]:
* glib/gconvert.[hc]:
* glib/gfileutils.[hc]:
* glib/gutils.[hc]:
* glib/giowin32.c: On Windows, keep old ABI versions
of GLib pathname api for DLL ABI stability. Use different
names for the new-style UTF-8 versions. Hide this through
a #define.

* glib/gstdio.[hc]: New files containing wrappers for
POSIX pathname api.

* glib/glib.symbols: Add new symbols.

* glib/makegalias.pl: Drop Win32 specific .def syntax,
include gstdio.h

24 files changed:
ChangeLog
ChangeLog.pre-2-10
ChangeLog.pre-2-12
ChangeLog.pre-2-6
ChangeLog.pre-2-8
docs/reference/ChangeLog
docs/reference/glib/glib-sections.txt
docs/reference/glib/tmpl/fileutils.sgml
docs/reference/glib/tmpl/macros_misc.sgml
docs/reference/glib/tmpl/main.sgml
glib/Makefile.am
glib/gconvert.c
glib/gconvert.h
glib/gdir.c
glib/gdir.h
glib/gfileutils.c
glib/gfileutils.h
glib/giowin32.c
glib/glib.symbols
glib/gstdio.c [new file with mode: 0644]
glib/gstdio.h [new file with mode: 0644]
glib/gutils.c
glib/gutils.h
glib/makegalias.pl

index 16526fd..24cb4dc 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,29 @@
 2004-10-27  Matthias Clasen  <mclasen@redhat.com>
 
+       Introduce the idea of a filename encoding, which is 
+       *literally* the filename encoding on Unix. On windows, 
+       use the Unicode name converted to UTF-8. (#156325,
+       Tor Lillqvist, Owen Taylor)
+       
+       * glib/gdir.[hc]: 
+       * glib/gconvert.[hc]: 
+       * glib/gfileutils.[hc]: 
+       * glib/gutils.[hc]: 
+       * glib/giowin32.c: On Windows, keep old ABI versions 
+       of GLib pathname api for DLL ABI stability. Use different 
+       names for the new-style UTF-8 versions. Hide this through 
+       a #define.
+
+       * glib/gstdio.[hc]: New files containing wrappers for
+       POSIX pathname api.
+
+       * glib/glib.symbols: Add new symbols.
+
+       * glib/makegalias.pl: Drop Win32 specific .def syntax,
+       include gstdio.h
+
+2004-10-27  Matthias Clasen  <mclasen@redhat.com>
+
        * glib/gkeyfile.c: Fix includes. (#156500, #156499, 
        Kazuki IWAMOTO)
 
index 16526fd..24cb4dc 100644 (file)
@@ -1,5 +1,29 @@
 2004-10-27  Matthias Clasen  <mclasen@redhat.com>
 
+       Introduce the idea of a filename encoding, which is 
+       *literally* the filename encoding on Unix. On windows, 
+       use the Unicode name converted to UTF-8. (#156325,
+       Tor Lillqvist, Owen Taylor)
+       
+       * glib/gdir.[hc]: 
+       * glib/gconvert.[hc]: 
+       * glib/gfileutils.[hc]: 
+       * glib/gutils.[hc]: 
+       * glib/giowin32.c: On Windows, keep old ABI versions 
+       of GLib pathname api for DLL ABI stability. Use different 
+       names for the new-style UTF-8 versions. Hide this through 
+       a #define.
+
+       * glib/gstdio.[hc]: New files containing wrappers for
+       POSIX pathname api.
+
+       * glib/glib.symbols: Add new symbols.
+
+       * glib/makegalias.pl: Drop Win32 specific .def syntax,
+       include gstdio.h
+
+2004-10-27  Matthias Clasen  <mclasen@redhat.com>
+
        * glib/gkeyfile.c: Fix includes. (#156500, #156499, 
        Kazuki IWAMOTO)
 
index 16526fd..24cb4dc 100644 (file)
@@ -1,5 +1,29 @@
 2004-10-27  Matthias Clasen  <mclasen@redhat.com>
 
+       Introduce the idea of a filename encoding, which is 
+       *literally* the filename encoding on Unix. On windows, 
+       use the Unicode name converted to UTF-8. (#156325,
+       Tor Lillqvist, Owen Taylor)
+       
+       * glib/gdir.[hc]: 
+       * glib/gconvert.[hc]: 
+       * glib/gfileutils.[hc]: 
+       * glib/gutils.[hc]: 
+       * glib/giowin32.c: On Windows, keep old ABI versions 
+       of GLib pathname api for DLL ABI stability. Use different 
+       names for the new-style UTF-8 versions. Hide this through 
+       a #define.
+
+       * glib/gstdio.[hc]: New files containing wrappers for
+       POSIX pathname api.
+
+       * glib/glib.symbols: Add new symbols.
+
+       * glib/makegalias.pl: Drop Win32 specific .def syntax,
+       include gstdio.h
+
+2004-10-27  Matthias Clasen  <mclasen@redhat.com>
+
        * glib/gkeyfile.c: Fix includes. (#156500, #156499, 
        Kazuki IWAMOTO)
 
index 16526fd..24cb4dc 100644 (file)
@@ -1,5 +1,29 @@
 2004-10-27  Matthias Clasen  <mclasen@redhat.com>
 
+       Introduce the idea of a filename encoding, which is 
+       *literally* the filename encoding on Unix. On windows, 
+       use the Unicode name converted to UTF-8. (#156325,
+       Tor Lillqvist, Owen Taylor)
+       
+       * glib/gdir.[hc]: 
+       * glib/gconvert.[hc]: 
+       * glib/gfileutils.[hc]: 
+       * glib/gutils.[hc]: 
+       * glib/giowin32.c: On Windows, keep old ABI versions 
+       of GLib pathname api for DLL ABI stability. Use different 
+       names for the new-style UTF-8 versions. Hide this through 
+       a #define.
+
+       * glib/gstdio.[hc]: New files containing wrappers for
+       POSIX pathname api.
+
+       * glib/glib.symbols: Add new symbols.
+
+       * glib/makegalias.pl: Drop Win32 specific .def syntax,
+       include gstdio.h
+
+2004-10-27  Matthias Clasen  <mclasen@redhat.com>
+
        * glib/gkeyfile.c: Fix includes. (#156500, #156499, 
        Kazuki IWAMOTO)
 
index 16526fd..24cb4dc 100644 (file)
@@ -1,5 +1,29 @@
 2004-10-27  Matthias Clasen  <mclasen@redhat.com>
 
+       Introduce the idea of a filename encoding, which is 
+       *literally* the filename encoding on Unix. On windows, 
+       use the Unicode name converted to UTF-8. (#156325,
+       Tor Lillqvist, Owen Taylor)
+       
+       * glib/gdir.[hc]: 
+       * glib/gconvert.[hc]: 
+       * glib/gfileutils.[hc]: 
+       * glib/gutils.[hc]: 
+       * glib/giowin32.c: On Windows, keep old ABI versions 
+       of GLib pathname api for DLL ABI stability. Use different 
+       names for the new-style UTF-8 versions. Hide this through 
+       a #define.
+
+       * glib/gstdio.[hc]: New files containing wrappers for
+       POSIX pathname api.
+
+       * glib/glib.symbols: Add new symbols.
+
+       * glib/makegalias.pl: Drop Win32 specific .def syntax,
+       include gstdio.h
+
+2004-10-27  Matthias Clasen  <mclasen@redhat.com>
+
        * glib/gkeyfile.c: Fix includes. (#156500, #156499, 
        Kazuki IWAMOTO)
 
index c2ab433..da017ed 100644 (file)
@@ -1,3 +1,7 @@
+2004-10-27  Matthias Clasen  <mclasen@redhat.com>
+
+       * glib/tmpl/fileutils.sgml: Add some intro.
+
 2004-10-26  Matthias Clasen  <mclasen@redhat.com>
 
        * gobject/gobject-docs.sgml: Add an index for 2.6 additions.
index 4593fa4..f89b484 100644 (file)
@@ -967,6 +967,7 @@ g_option_error_quark
 <SECTION>
 <TITLE>File Utilities</TITLE>
 <FILE>fileutils</FILE>
+<INCLUDE>glib.h,glib/gstdio.h</INCLUDE>
 GFileError
 G_FILE_ERROR
 GFileTest
@@ -984,6 +985,16 @@ g_dir_read_name
 g_dir_rewind
 g_dir_close
 
+<SUBSECTION>
+g_open
+g_rename
+g_mkdir
+g_stat
+g_unlink
+g_remove
+g_fopen
+g_freopen
+
 <SUBSECTION Private>
 g_file_error_quark
 </SECTION>
index 092346b..28ebe3b 100644 (file)
@@ -6,7 +6,31 @@ various file-related functions.
 
 <!-- ##### SECTION Long_Description ##### -->
 <para>
+There is a group of functions which wrap the common POSIX functions 
+dealing with filenames (g_open(), g_rename(), g_mkdir(), g_stat(), 
+g_unlink(), g_remove(), g_fopen(), g_freopen()). The point of these 
+wrappers is to make it possible to handle file names with any Unicode 
+characters in them on Windows without having to use ifdefs and the 
+wide character API in the application code.
+</para>
+<para>
+The pathname argument should be in the GLib file name encoding. On
+POSIX this is the actual on-disk encoding which might correspond to
+the locale settings of the process (or the 
+<envar>G_FILENAME_ENCODING</envar> environment variable), or not.
+</para>
+<para>
+On Windows the GLib file name encoding is UTF-8. Note that the
+Microsoft C library does not use UTF-8, but has separate APIs for
+current system code page and wide characters (UTF-16). The GLib
+wrappers call the wide character API if present (on modern Windows
+systems), otherwise convert to/from the system code page.
+</para>
 
+<para>
+Another group of functions allows to open and read directories
+in the GLib file name encoding. These are g_dir_open(), 
+g_dir_read_name(), g_dir_rewind(), g_dir_close().
 </para>
 
 <!-- ##### SECTION See_Also ##### -->
@@ -223,3 +247,83 @@ An opaque structure representing an opened directory.
 @dir: 
 
 
+<!-- ##### FUNCTION g_open ##### -->
+<para>
+
+</para>
+
+@filename: 
+@flags: 
+@mode: 
+@Returns: 
+
+
+<!-- ##### FUNCTION g_rename ##### -->
+<para>
+
+</para>
+
+@oldfilename: 
+@newfilename: 
+@Returns: 
+
+
+<!-- ##### FUNCTION g_mkdir ##### -->
+<para>
+
+</para>
+
+@filename: 
+@mode: 
+@Returns: 
+
+
+<!-- ##### FUNCTION g_stat ##### -->
+<para>
+
+</para>
+
+@filename: 
+@buf: 
+@Returns: 
+
+
+<!-- ##### FUNCTION g_unlink ##### -->
+<para>
+
+</para>
+
+@filename: 
+@Returns: 
+
+
+<!-- ##### FUNCTION g_remove ##### -->
+<para>
+
+</para>
+
+@filename: 
+@Returns: 
+
+
+<!-- ##### FUNCTION g_fopen ##### -->
+<para>
+
+</para>
+
+@filename: 
+@mode: 
+@Returns: 
+
+
+<!-- ##### FUNCTION g_freopen ##### -->
+<para>
+
+</para>
+
+@filename: 
+@mode: 
+@stream: 
+@Returns: 
+
+
index 270b258..9ea09c5 100644 (file)
@@ -260,6 +260,7 @@ attributes (currently only <command>gcc</command>).
 Since: 2.6
 
 
+
 <!-- ##### MACRO G_GNUC_INTERNAL ##### -->
 <para>
 Expands to the GNU C <literal>visibility(hidden)</literal> attribute if the 
index ff396f5..03bc48d 100644 (file)
@@ -610,7 +610,7 @@ The type of functions to be called when a child exists.
 @pid: the process id of the child process
 @status: Status information about the child process,
   see waitpid(2) for more information about this field
-@data: user data passed to g_child_watch_add() 
+@data: user data passed to g_child_watch_add()
 
 
 <!-- ##### FUNCTION g_child_watch_source_new ##### -->
index e5a77ad..77d47d6 100644 (file)
@@ -90,6 +90,7 @@ libglib_2_0_la_SOURCES =      \
        gscanner.c              \
        gshell.c                \
        gslist.c                \
+       gstdio.c                \
        gstrfuncs.c             \
        gstring.c               \
        gthread.c               \
@@ -164,6 +165,7 @@ glibsubinclude_HEADERS =   \
        gshell.h        \
        gslist.h        \
        gspawn.h        \
+       gstdio.h        \
        gstrfuncs.h     \
        gstring.h       \
        gthread.h       \
index 346d0e6..6915893 100644 (file)
@@ -1014,8 +1014,9 @@ filename_charset_cache_free (gpointer data)
  * get_filename_charset:
  * @charset: return location for the name of the filename encoding 
  *
- * Determines the character set used for filenames by consulting the 
- * environment variables G_FILENAME_ENCODING and G_BROKEN_FILENAMES. 
+ * Determines the preferred character set used for filenames by
+ * consulting the environment variables G_FILENAME_ENCODING and
+ * G_BROKEN_FILENAMES.
  *
  * G_FILENAME_ENCODING may be set to a comma-separated list of character 
  * set names. The special token "@locale" is taken to mean the character set 
@@ -1025,8 +1026,13 @@ filename_charset_cache_free (gpointer data)
  * character set of the current locale is taken as the filename encoding.
  *
  * The returned @charset belongs to GLib and must not be freed.
- * 
- * Return value: %TRUE if the charset used for filename is UTF-8.
+ *
+ * Note that on Unix, regardless of the locale character set or
+ * G_FILENAME_ENCODING value, the actual file names present on a
+ * system might be in any random encoding or just gibberish.
+ *
+ *  Return value: %TRUE
+ * if the charset used for filename is UTF-8.
  */
 static gboolean
 get_filename_charset (const gchar **filename_charset)
@@ -1089,12 +1095,33 @@ get_filename_charset (const gchar **filename_charset)
 }
 
 #else /* G_PLATFORM_WIN32 */
+
 static gboolean
 get_filename_charset (const gchar **filename_charset) 
 {
+#ifdef G_OS_WIN32
+  /* On Windows GLib pretends that the filename charset is UTF-8 */
+  if (filename_charset)
+    *filename_charset = "UTF-8";
+  return TRUE;
+#else
+  /* Cygwin works like before */
+  g_get_charset (filename_charset);
+  return FALSE;
+#endif
+}
+
+#ifdef G_OS_WIN32
+
+static gboolean
+old_get_filename_charset (const gchar **filename_charset) 
+{
   g_get_charset (filename_charset);
   return FALSE;
 }
+
+#endif
+
 #endif /* G_PLATFORM_WIN32 */
 
 /* This is called from g_thread_init(). It's used to
@@ -1146,6 +1173,30 @@ g_filename_to_utf8 (const gchar *opsysstring,
                      "UTF-8", charset, bytes_read, bytes_written, error);
 }
 
+#ifdef G_OS_WIN32
+
+#undef g_filename_to_utf8
+
+/* Binary compatibility version. Not for newly compiled code. */
+
+gchar*
+g_filename_to_utf8 (const gchar *opsysstring, 
+                   gssize       len,           
+                   gsize       *bytes_read,   
+                   gsize       *bytes_written,
+                   GError     **error)
+{
+  const gchar *charset;
+
+  if (old_get_filename_charset (&charset))
+    return strdup_len (opsysstring, len, bytes_read, bytes_written, error);
+  else
+    return g_convert (opsysstring, len, 
+                     "UTF-8", charset, bytes_read, bytes_written, error);
+}
+
+#endif
+
 /**
  * g_filename_from_utf8:
  * @utf8string:    a UTF-8 encoded string.
@@ -1184,6 +1235,30 @@ g_filename_from_utf8 (const gchar *utf8string,
                      charset, "UTF-8", bytes_read, bytes_written, error);
 }
 
+#ifdef G_OS_WIN32
+
+#undef g_filename_from_utf8
+
+/* Binary compatibility version. Not for newly compiled code. */
+
+gchar*
+g_filename_from_utf8 (const gchar *utf8string,
+                     gssize       len,            
+                     gsize       *bytes_read,    
+                     gsize       *bytes_written,
+                     GError     **error)
+{
+  const gchar *charset;
+
+  if (old_get_filename_charset (&charset))
+    return strdup_len (utf8string, len, bytes_read, bytes_written, error);
+  else
+    return g_convert (utf8string, len,
+                     charset, "UTF-8", bytes_read, bytes_written, error);
+}
+
+#endif
+
 /* Test of haystack has the needle prefix, comparing case
  * insensitive. haystack may be UTF-8, but needle must
  * contain only ascii. */
index 7b203ec..f666e28 100644 (file)
@@ -98,6 +98,11 @@ gchar* g_locale_from_utf8 (const gchar  *utf8string,
 /* Convert between the operating system (or C runtime)
  * representation of file names and UTF-8.
  */
+#ifdef G_OS_WIN32
+#define g_filename_to_utf8 g_filename_to_utf8_utf8
+#define g_filename_from_utf8 g_filename_from_utf8_utf8
+#endif
+
 gchar* g_filename_to_utf8   (const gchar  *opsysstring,
                             gssize        len,            
                             gsize        *bytes_read,     
index ba51995..8896b33 100644 (file)
@@ -4,6 +4,7 @@
  * gdir.c: Simplified wrapper around the DIRENT functions.
  *
  * Copyright 2001 Hans Breuer
+ * Copyright 2004 Tor Lillqvist
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
 
 struct _GDir
 {
-  DIR *dir;
+  union {
+    DIR *dirp;
+#ifdef G_OS_WIN32
+    _WDIR *wdirp;
+#endif
+  } u;
+#ifdef G_OS_WIN32
+  gchar utf8_buf[FILENAME_MAX*4];
+#endif
 };
 
 /**
  * g_dir_open:
- * @path: the path to the directory you are interested in
+ * @path: the path to the directory you are interested in. On Unix
+ *         in the on-disk encoding. On Windows in UTF-8
  * @flags: Currently must be set to 0. Reserved for future use.
  * @error: return location for a #GError, or %NULL.
  *         If non-%NULL, an error will be set if and only if
  *         g_dir_open_fails.
  *
- * Opens a directory for reading. The names of the files
- * in the directory can then be retrieved using
- * g_dir_read_name().
+ * Opens a directory for reading. The names of the files in the
+ * directory can then be retrieved using g_dir_read_name().
  *
  * Return value: a newly allocated #GDir on success, %NULL on failure.
  *   If non-%NULL, you must free the result with g_dir_close()
@@ -64,15 +73,62 @@ g_dir_open (const gchar  *path,
             GError      **error)
 {
   GDir *dir;
+#ifndef G_OS_WIN32
   gchar *utf8_path;
+#endif
 
   g_return_val_if_fail (path != NULL, NULL);
 
+#ifdef G_OS_WIN32
+  if (G_WIN32_HAVE_WIDECHAR_API ())
+    {
+      wchar_t *wpath = g_utf8_to_utf16 (path, -1, NULL, NULL, error);
+  
+      if (wpath == NULL)
+       return NULL;
+
+      dir = g_new (GDir, 1);
+
+      dir->u.wdirp = _wopendir (wpath);
+      g_free (wpath);
+  
+      if (dir->u.wdirp)
+       return dir;
+    }
+  else
+    {
+      gchar *cp_path = g_locale_from_utf8 (path, -1, NULL, NULL, error);
+
+      if (cp_path == NULL)
+       return NULL;
+
+      dir = g_new (GDir, 1);
+
+      dir->u.dirp = opendir (cp_path);
+
+      g_free (cp_path);
+
+      if (dir->u.dirp)
+       return dir;
+    }
+
+  /* error case */
+
+  g_set_error (error,
+              G_FILE_ERROR,
+              g_file_error_from_errno (errno),
+              _("Error opening directory '%s': %s"),
+              path, g_strerror (errno));
+  
+  g_free (dir);
+      
+  return NULL;
+#else
   dir = g_new (GDir, 1);
 
-  dir->dir = opendir (path);
+  dir->u.dirp = opendir (path);
 
-  if (dir->dir)
+  if (dir->u.dirp)
     return dir;
 
   /* error case */
@@ -88,18 +144,48 @@ g_dir_open (const gchar  *path,
   g_free (dir);
 
   return NULL;
+#endif
 }
 
+#ifdef G_OS_WIN32
+
+/* The above function actually is called g_dir_open_utf8, and it's
+ * that what applications compiled with this GLib version will
+ * use.
+ */
+
+#undef g_dir_open
+
+/* Binary compatibility version. Not for newly compiled code. */
+
+GDir *
+g_dir_open (const gchar  *path,
+            guint         flags,
+            GError      **error)
+{
+  gchar *utf8_path = g_locale_to_utf8 (path, -1, NULL, NULL, error);
+  GDir *retval;
+
+  if (utf8_path == NULL)
+    return NULL;
+
+  retval = g_dir_open_utf8 (utf8_path, flags, error);
+
+  g_free (utf8_path);
+
+  return retval;
+}
+#endif
+
 /**
  * g_dir_read_name:
  * @dir: a #GDir* created by g_dir_open()
  *
- * Retrieves the name of the next entry in the directory.
- * The '.' and '..' entries are omitted. The returned name is in 
- * the encoding used for filenames. Use g_filename_to_utf8() to 
- * convert it to UTF-8.
+ * Retrieves the name of the next entry in the directory.  The '.' and
+ * '..' entries are omitted. On Windows, the returned name is in
+ * UTF-8. On Unix, it is in the on-disk encoding.
  *
- * Return value: The entries name or %NULL if there are no 
+ * Return value: The entry's name or %NULL if there are no 
  *   more entries. The return value is owned by GLib and
  *   must not be modified or freed.
  **/
@@ -110,18 +196,107 @@ g_dir_read_name (GDir *dir)
 
   g_return_val_if_fail (dir != NULL, NULL);
 
-  entry = readdir (dir->dir);
+#ifdef G_OS_WIN32
+  if (G_WIN32_HAVE_WIDECHAR_API ())
+    {
+      gchar *utf8_name;
+      struct _wdirent *wentry;
+
+      while (1)
+       {
+         wentry = _wreaddir (dir->u.wdirp);
+         while (wentry 
+                && (0 == wcscmp (wentry->d_name, L".") ||
+                    0 == wcscmp (wentry->d_name, L"..")))
+           wentry = _wreaddir (dir->u.wdirp);
+         
+         if (wentry == NULL)
+           return NULL;
+         
+         utf8_name = g_utf16_to_utf8 (wentry->d_name, -1, NULL, NULL, NULL);
+
+         if (utf8_name == NULL)
+           continue;           /* Huh, impossible? Skip it anyway */
+         
+         strcpy (dir->utf8_buf, utf8_name);
+         g_free (utf8_name);
+         
+         return dir->utf8_buf;
+       }
+    }
+  else
+    {
+      while (1)
+       {
+         gchar *utf8_name;
+      
+         entry = readdir (dir->u.dirp);
+         while (entry 
+                && (0 == strcmp (entry->d_name, ".") ||
+                    0 == strcmp (entry->d_name, "..")))
+           entry = readdir (dir->u.dirp);
+
+         if (entry == NULL)
+           return NULL;
+
+         utf8_name = g_locale_to_utf8 (entry->d_name, -1, NULL, NULL, NULL);
+
+         if (utf8_name != NULL)
+           {
+             strcpy (dir->utf8_buf, utf8_name);
+             g_free (utf8_name);
+             
+             return dir->utf8_buf;
+           }
+       }
+    }
+#else
+  entry = readdir (dir->u.dirp);
   while (entry 
          && (0 == strcmp (entry->d_name, ".") ||
              0 == strcmp (entry->d_name, "..")))
-    entry = readdir (dir->dir);
+    entry = readdir (dir->u.dirp);
 
   if (entry)
     return entry->d_name;
   else
     return NULL;
+#endif
+}
+
+#ifdef G_OS_WIN32
+
+/* Ditto for g_dir_read_name */
+
+#undef g_dir_read_name
+
+/* Binary compatibility version. Not for newly compiled code. */
+
+G_CONST_RETURN gchar*
+g_dir_read_name (GDir *dir)
+{
+  while (1)
+    {
+      const gchar *utf8_name = g_dir_read_name_utf8 (dir);
+      gchar *retval;
+      
+      if (utf8_name == NULL)
+       return NULL;
+
+      retval = g_locale_from_utf8 (utf8_name, -1, NULL, NULL, NULL);
+
+      if (retval != NULL)
+       {
+         strcpy (dir->utf8_buf, retval);
+         g_free (retval);
+
+         return dir->utf8_buf;
+       }
+    }
 }
 
+#endif
+
 /**
  * g_dir_rewind:
  * @dir: a #GDir* created by g_dir_open()
@@ -134,7 +309,15 @@ g_dir_rewind (GDir *dir)
 {
   g_return_if_fail (dir != NULL);
   
-  rewinddir (dir->dir);
+#ifdef G_OS_WIN32
+  if (G_WIN32_HAVE_WIDECHAR_API ())
+    {
+      _wrewinddir (dir->u.wdirp);
+      return;
+    }
+#endif
+
+  rewinddir (dir->u.dirp);
 }
 
 /**
@@ -148,6 +331,15 @@ g_dir_close (GDir *dir)
 {
   g_return_if_fail (dir != NULL);
 
-  closedir (dir->dir);
+#ifdef G_OS_WIN32
+  if (G_WIN32_HAVE_WIDECHAR_API ())
+    {
+      _wclosedir (dir->u.wdirp);
+      g_free (dir);
+      return;
+    }
+#endif
+
+  closedir (dir->u.dirp);
   g_free (dir);
 }
index 0ca63b1..011174e 100644 (file)
@@ -29,12 +29,18 @@ G_BEGIN_DECLS
 
 typedef struct _GDir GDir;
 
-GDir    *               g_dir_open      (const gchar  *path,
-                                        guint         flags,
-                                        GError      **error);
-G_CONST_RETURN gchar   *g_dir_read_name (GDir         *dir);
-void                    g_dir_rewind    (GDir         *dir);
-void                    g_dir_close     (GDir         *dir);
+#ifdef G_OS_WIN32
+/* For DLL ABI stability, keep old names for old (non-UTF-8) functionality. */
+#define g_dir_open g_dir_open_utf8
+#define g_dir_read_name g_dir_read_name_utf8
+#endif
+
+GDir    *                g_dir_open           (const gchar  *path,
+                                              guint         flags,
+                                              GError      **error);
+G_CONST_RETURN gchar    *g_dir_read_name      (GDir         *dir);
+void                     g_dir_rewind         (GDir         *dir);
+void                     g_dir_close          (GDir         *dir);
 
 G_END_DECLS
 
index f0f7528..8a37968 100644 (file)
@@ -63,6 +63,7 @@
 #define O_BINARY 0
 #endif
 
+#include "gstdio.h"
 #include "glibintl.h"
 
 /**
@@ -94,7 +95,7 @@
  * <informalexample><programlisting>
  * /&ast; DON'T DO THIS &ast;/
  *  if (!g_file_test (filename, G_FILE_TEST_IS_SYMLINK)) {
- *    fd = open (filename, O_WRONLY);
+ *    fd = g_open (filename, O_WRONLY);
  *    /&ast; write to fd &ast;/
  *  }
  * </programlisting></informalexample>
@@ -112,10 +113,103 @@ gboolean
 g_file_test (const gchar *filename,
              GFileTest    test)
 {
+#ifdef G_OS_WIN32
+  if (G_WIN32_HAVE_WIDECHAR_API ())
+    {
+      wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
+
+      if (wfilename == NULL)
+       return FALSE;
+
+      if ((test & G_FILE_TEST_EXISTS) && (_waccess (wfilename, F_OK) == 0))
+       {
+         g_free (wfilename);
+         return TRUE;
+       }
+      
+      if (test & (G_FILE_TEST_IS_REGULAR |
+                 G_FILE_TEST_IS_DIR |
+                 G_FILE_TEST_IS_EXECUTABLE))
+       {
+         struct _stat s;
+         
+         if (_wstat (wfilename, &s) == 0)
+           {
+             if ((test & G_FILE_TEST_IS_REGULAR) && S_ISREG (s.st_mode))
+               {
+                 g_free (wfilename);
+                 return TRUE;
+               }
+             
+             if ((test & G_FILE_TEST_IS_DIR) && S_ISDIR (s.st_mode))
+               {
+                 g_free (wfilename);
+                 return TRUE;
+               }
+             
+             if ((test & G_FILE_TEST_IS_EXECUTABLE) &&
+                 (s.st_mode & _S_IEXEC))
+               {
+                 g_free (wfilename);
+                 return TRUE;
+               }
+           }
+       }
+
+      g_free (wfilename);
+      
+      return FALSE;
+    }
+  else
+    {
+      gchar *cp_filename = g_locale_from_utf8 (filename, -1, NULL, NULL, NULL);
+
+      if (cp_filename == NULL)
+       return FALSE;
+      
+      if ((test & G_FILE_TEST_EXISTS) && (access (cp_filename, F_OK) == 0))
+       {
+         g_free (cp_filename);
+         return TRUE;
+       }
+      
+      if (test & (G_FILE_TEST_IS_REGULAR |
+                 G_FILE_TEST_IS_DIR |
+                 G_FILE_TEST_IS_EXECUTABLE))
+       {
+         struct stat s;
+         
+         if (stat (cp_filename, &s) == 0)
+           {
+             if ((test & G_FILE_TEST_IS_REGULAR) && S_ISREG (s.st_mode))
+               {
+                 g_free (cp_filename);
+                 return TRUE;
+               }
+             
+             if ((test & G_FILE_TEST_IS_DIR) && S_ISDIR (s.st_mode))
+               {
+                 g_free (cp_filename);
+                 return TRUE;
+               }
+             
+             if ((test & G_FILE_TEST_IS_EXECUTABLE) &&
+                 (s.st_mode & _S_IEXEC))
+               {
+                 g_free (cp_filename);
+                 return TRUE;
+               }
+           }
+       }
+
+      g_free (cp_filename);
+      
+      return FALSE;
+    }
+#else
   if ((test & G_FILE_TEST_EXISTS) && (access (filename, F_OK) == 0))
     return TRUE;
   
-#ifndef G_OS_WIN32
   if ((test & G_FILE_TEST_IS_EXECUTABLE) && (access (filename, X_OK) == 0))
     {
       if (getuid () != 0)
@@ -128,18 +222,13 @@ g_file_test (const gchar *filename,
     }
   else
     test &= ~G_FILE_TEST_IS_EXECUTABLE;
-#endif 
 
   if (test & G_FILE_TEST_IS_SYMLINK)
     {
-#ifdef G_OS_WIN32
-      /* no sym links on win32, no lstat in msvcrt */
-#else
       struct stat s;
 
       if ((lstat (filename, &s) == 0) && S_ISLNK (s.st_mode))
         return TRUE;
-#endif
     }
   
   if (test & (G_FILE_TEST_IS_REGULAR |
@@ -156,26 +245,45 @@ g_file_test (const gchar *filename,
          if ((test & G_FILE_TEST_IS_DIR) && S_ISDIR (s.st_mode))
            return TRUE;
 
-#ifndef G_OS_WIN32
          /* The extra test for root when access (file, X_OK) succeeds.
-          * Probably only makes sense on Unix.
           */
          if ((test & G_FILE_TEST_IS_EXECUTABLE) &&
              ((s.st_mode & S_IXOTH) ||
               (s.st_mode & S_IXUSR) ||
               (s.st_mode & S_IXGRP)))
            return TRUE;
-#else
-         if ((test & G_FILE_TEST_IS_EXECUTABLE) &&
-             (s.st_mode & _S_IEXEC))
-           return TRUE;
-#endif
        }
     }
 
   return FALSE;
+#endif
+}
+
+#ifdef G_OS_WIN32
+
+#undef g_file_test
+
+/* Binary compatibility version. Not for newly compiled code. */
+
+gboolean
+g_file_test (const gchar *filename,
+             GFileTest    test)
+{
+  gchar *utf8_filename = g_locale_to_utf8 (filename, -1, NULL, NULL, NULL);
+  gboolean retval;
+
+  if (utf8_filename == NULL)
+    return FALSE;
+
+  retval = g_file_test_utf8 (utf8_filename, test);
+
+  g_free (utf8_filename);
+
+  return retval;
 }
 
+#endif
+
 GQuark
 g_file_error_quark (void)
 {
@@ -357,7 +465,7 @@ g_file_error_from_errno (gint err_no)
 }
 
 static gboolean
-get_contents_stdio (const gchar *filename,
+get_contents_stdio (const gchar *utf8_filename,
                     FILE        *f,
                     gchar      **contents,
                     gsize       *length, 
@@ -388,15 +496,12 @@ get_contents_stdio (const gchar *filename,
 
           if (str == NULL)
             {
-             gchar *utf8_filename = g_filename_to_utf8 (filename, -1,
-                                                        NULL, NULL, NULL);
               g_set_error (error,
                            G_FILE_ERROR,
                            G_FILE_ERROR_NOMEM,
                            _("Could not allocate %lu bytes to read file \"%s\""),
                            (gulong) total_allocated, 
                           utf8_filename ? utf8_filename : "???");
-             g_free (utf8_filename);
 
               goto error;
             }
@@ -404,15 +509,12 @@ get_contents_stdio (const gchar *filename,
       
       if (ferror (f))
         {
-         gchar *utf8_filename = g_filename_to_utf8 (filename, -1,
-                                                    NULL, NULL, NULL);
           g_set_error (error,
                        G_FILE_ERROR,
                        g_file_error_from_errno (errno),
                        _("Error reading file '%s': %s"),
                        utf8_filename ? utf8_filename : "???", 
                       g_strerror (errno));
-         g_free (utf8_filename);
 
           goto error;
         }
@@ -443,7 +545,7 @@ get_contents_stdio (const gchar *filename,
 #ifndef G_OS_WIN32
 
 static gboolean
-get_contents_regfile (const gchar *filename,
+get_contents_regfile (const gchar *utf8_filename,
                       struct stat *stat_buf,
                       gint         fd,
                       gchar      **contents,
@@ -462,15 +564,12 @@ get_contents_regfile (const gchar *filename,
 
   if (buf == NULL)
     {
-      gchar *utf8_filename = g_filename_to_utf8 (filename, -1,
-                                                NULL, NULL, NULL);
       g_set_error (error,
                    G_FILE_ERROR,
                    G_FILE_ERROR_NOMEM,
                    _("Could not allocate %lu bytes to read file \"%s\""),
                    (gulong) alloc_size, 
                   utf8_filename ? utf8_filename : "???");
-      g_free (utf8_filename);
 
       goto error;
     }
@@ -486,8 +585,6 @@ get_contents_regfile (const gchar *filename,
         {
           if (errno != EINTR) 
             {
-             gchar *utf8_filename = g_filename_to_utf8 (filename, -1,
-                                                        NULL, NULL, NULL);
               g_free (buf);
               g_set_error (error,
                            G_FILE_ERROR,
@@ -495,7 +592,6 @@ get_contents_regfile (const gchar *filename,
                            _("Failed to read from file '%s': %s"),
                            utf8_filename ? utf8_filename : "???", 
                           g_strerror (errno));
-             g_free (utf8_filename);
 
              goto error;
             }
@@ -532,14 +628,13 @@ get_contents_posix (const gchar *filename,
 {
   struct stat stat_buf;
   gint fd;
-  
+  gchar *utf8_filename = g_filename_to_utf8 (filename, -1, NULL, NULL, NULL);
+
   /* O_BINARY useful on Cygwin */
   fd = open (filename, O_RDONLY|O_BINARY);
 
   if (fd < 0)
     {
-      gchar *utf8_filename = g_filename_to_utf8 (filename, -1,
-                                                NULL, NULL, NULL);
       g_set_error (error,
                    G_FILE_ERROR,
                    g_file_error_from_errno (errno),
@@ -554,8 +649,6 @@ get_contents_posix (const gchar *filename,
   /* I don't think this will ever fail, aside from ENOMEM, but. */
   if (fstat (fd, &stat_buf) < 0)
     {
-      gchar *utf8_filename = g_filename_to_utf8 (filename, -1,
-                                                NULL, NULL, NULL);
       close (fd);
       g_set_error (error,
                    G_FILE_ERROR,
@@ -570,24 +663,25 @@ get_contents_posix (const gchar *filename,
 
   if (stat_buf.st_size > 0 && S_ISREG (stat_buf.st_mode))
     {
-      return get_contents_regfile (filename,
-                                   &stat_buf,
-                                   fd,
-                                   contents,
-                                   length,
-                                   error);
+      gboolean retval = get_contents_regfile (utf8_filename,
+                                             &stat_buf,
+                                             fd,
+                                             contents,
+                                             length,
+                                             error);
+      g_free (utf8_filename);
+
+      return retval;
     }
   else
     {
       FILE *f;
+      gboolean retval;
 
       f = fdopen (fd, "r");
       
       if (f == NULL)
         {
-         gchar *utf8_filename = g_filename_to_utf8 (filename, -1,
-                                                    NULL, NULL, NULL);
-
           g_set_error (error,
                        G_FILE_ERROR,
                        g_file_error_from_errno (errno),
@@ -599,7 +693,10 @@ get_contents_posix (const gchar *filename,
           return FALSE;
         }
   
-      return get_contents_stdio (filename, f, contents, length, error);
+      retval = get_contents_stdio (utf8_filename, f, contents, length, error);
+      g_free (utf8_filename);
+
+      return retval;
     }
 }
 
@@ -607,14 +704,16 @@ get_contents_posix (const gchar *filename,
 
 static gboolean
 get_contents_win32 (const gchar *filename,
-                    gchar      **contents,
-                    gsize       *length,
-                    GError     **error)
+                   gchar      **contents,
+                   gsize       *length,
+                   GError     **error)
 {
   FILE *f;
-
-  /* I guess you want binary mode; maybe you want text sometimes? */
-  f = fopen (filename, "rb");
+  gboolean retval;
+  wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
+  
+  f = _wfopen (wfilename, L"rb");
+  g_free (wfilename);
 
   if (f == NULL)
     {
@@ -632,14 +731,16 @@ get_contents_win32 (const gchar *filename,
       return FALSE;
     }
   
-  return get_contents_stdio (filename, f, contents, length, error);
+  retval = get_contents_stdio (filename, f, contents, length, error);
+
+  return retval;
 }
 
 #endif
 
 /**
  * g_file_get_contents:
- * @filename: a file to read contents from
+ * @filename: name of a file to read contents from, in the encoding used for filenames
  * @contents: location to store an allocated string
  * @length: location to store length in bytes of the contents
  * @error: return location for a #GError
@@ -674,6 +775,33 @@ g_file_get_contents (const gchar *filename,
 #endif
 }
 
+#ifdef G_OS_WIN32
+
+#undef g_file_get_contents
+
+/* Binary compatibility version. Not for newly compiled code. */
+
+gboolean
+g_file_get_contents (const gchar *filename,
+                     gchar      **contents,
+                     gsize       *length,
+                     GError     **error)
+{
+  gchar *utf8_filename = g_locale_to_utf8 (filename, -1, NULL, NULL, error);
+  gboolean retval;
+
+  if (utf8_filename == NULL)
+    return FALSE;
+
+  retval = g_file_get_contents (utf8_filename, contents, length, error);
+
+  g_free (utf8_filename);
+
+  return retval;
+}
+
+#endif
+
 /*
  * mkstemp() implementation is from the GNU C library.
  * Copyright (C) 1991,92,93,94,95,96,97,98,99 Free Software Foundation, Inc.
@@ -740,7 +868,8 @@ g_mkstemp (gchar *tmpl)
       v /= NLETTERS;
       XXXXXX[5] = letters[v % NLETTERS];
 
-      fd = open (tmpl, O_RDWR | O_CREAT | O_EXCL | O_BINARY, 0600);
+      /* tmpl is in UTF-8 on Windows, thus use g_open() */
+      fd = g_open (tmpl, O_RDWR | O_CREAT | O_EXCL | O_BINARY, 0600);
 
       if (fd >= 0)
        return fd;
@@ -756,6 +885,73 @@ g_mkstemp (gchar *tmpl)
 #endif
 }
 
+#ifdef G_OS_WIN32
+
+#undef g_mkstemp
+
+/* Binary compatibility version. Not for newly compiled code. */
+
+gint
+g_mkstemp (gchar *tmpl)
+{
+  int len;
+  char *XXXXXX;
+  int count, fd;
+  static const char letters[] =
+    "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+  static const int NLETTERS = sizeof (letters) - 1;
+  glong value;
+  GTimeVal tv;
+  static int counter = 0;
+
+  len = strlen (tmpl);
+  if (len < 6 || strcmp (&tmpl[len - 6], "XXXXXX"))
+    return -1;
+
+  /* This is where the Xs start.  */
+  XXXXXX = &tmpl[len - 6];
+
+  /* Get some more or less random data.  */
+  g_get_current_time (&tv);
+  value = (tv.tv_usec ^ tv.tv_sec) + counter++;
+
+  for (count = 0; count < 100; value += 7777, ++count)
+    {
+      glong v = value;
+
+      /* Fill in the random bits.  */
+      XXXXXX[0] = letters[v % NLETTERS];
+      v /= NLETTERS;
+      XXXXXX[1] = letters[v % NLETTERS];
+      v /= NLETTERS;
+      XXXXXX[2] = letters[v % NLETTERS];
+      v /= NLETTERS;
+      XXXXXX[3] = letters[v % NLETTERS];
+      v /= NLETTERS;
+      XXXXXX[4] = letters[v % NLETTERS];
+      v /= NLETTERS;
+      XXXXXX[5] = letters[v % NLETTERS];
+
+      /* This is the backward compatibility system codepage version,
+       * thus use normal open().
+       */
+      fd = open (tmpl, O_RDWR | O_CREAT | O_EXCL | O_BINARY, 0600);
+
+      if (fd >= 0)
+       return fd;
+      else if (errno != EEXIST)
+       /* Any other error will apply also to other names we might
+        *  try, and there are 2^32 or so of them, so give up now.
+        */
+       return -1;
+    }
+
+  /* We got out of the loop because we ran out of combinations to try.  */
+  return -1;
+}
+
+#endif
+
 /**
  * g_file_open_tmp:
  * @tmpl: Template for file name, as in g_mkstemp(), basename only
@@ -857,6 +1053,39 @@ g_file_open_tmp (const gchar *tmpl,
   return retval;
 }
 
+#ifdef G_OS_WIN32
+
+#undef g_file_open_tmp
+
+/* Binary compatibility version. Not for newly compiled code. */
+
+gint
+g_file_open_tmp (const gchar *tmpl,
+                gchar      **name_used,
+                GError     **error)
+{
+  gchar *utf8_tmpl = g_locale_to_utf8 (tmpl, -1, NULL, NULL, error);
+  gchar *utf8_name_used;
+  gint retval;
+
+  if (utf8_tmpl == NULL)
+    return -1;
+
+  retval = g_file_open_tmp_utf8 (utf8_tmpl, &utf8_name_used, error);
+  
+  if (retval == -1)
+    return -1;
+
+  if (name_used)
+    *name_used = g_locale_from_utf8 (utf8_name_used, -1, NULL, NULL, NULL);
+
+  g_free (utf8_name_used);
+
+  return retval;
+}
+
+#endif
+
 static gchar *
 g_build_pathv (const gchar *separator,
               const gchar *first_element,
index 939d545..cc3b494 100644 (file)
@@ -73,6 +73,13 @@ GQuark     g_file_error_quark      (void);
 /* So other code can generate a GFileError */
 GFileError g_file_error_from_errno (gint err_no);
 
+#ifdef G_OS_WIN32
+#define g_file_test g_file_test_utf8
+#define g_file_get_contents g_file_get_contents_utf8
+#define g_mkstemp g_mkstemp_utf8
+#define g_file_open_tmp g_file_open_tmp_utf8
+#endif
+
 gboolean g_file_test         (const gchar  *filename,
                               GFileTest     test);
 gboolean g_file_get_contents (const gchar  *filename,
@@ -99,5 +106,3 @@ gchar *g_build_filename (const gchar *first_element,
 G_END_DECLS
 
 #endif /* __G_FILEUTILS_H__ */
-
-
index 8fcb827..9bffc05 100644 (file)
@@ -46,6 +46,7 @@
 #include <errno.h>
 #include <sys/stat.h>
 
+#include "gstdio.h"
 #include "glibintl.h"
 
 typedef struct _GIOWin32Channel GIOWin32Channel;
@@ -1336,7 +1337,7 @@ g_io_channel_new_file (const gchar  *filename,
     }
 
   /* always open 'untranslated' */
-  fid = open (filename, flags | _O_BINARY, pmode);
+  fid = g_open (filename, flags | _O_BINARY, pmode);
 
   if (g_io_win32_get_debug_flag ())
     {
@@ -1383,6 +1384,32 @@ g_io_channel_new_file (const gchar  *filename,
   return channel;
 }
 
+#ifdef G_OS_WIN32
+
+#undef g_io_channel_new_file
+
+/* Binary compatibility version. Not for newly compiled code. */
+
+GIOChannel *
+g_io_channel_new_file (const gchar  *filename,
+                       const gchar  *mode,
+                       GError      **error)
+{
+  gchar *utf8_filename = g_locale_to_utf8 (filename, -1, NULL, NULL, error);
+  GIOChannel *retval;
+
+  if (utf8_filename == NULL)
+    return NULL;
+
+  retval = g_io_channel_new_file_utf8 (utf8_filename, mode, error);
+
+  g_free (utf8_filename);
+
+  return retval;
+}
+
+#endif
+
 static GIOStatus
 g_io_win32_set_flags (GIOChannel *channel,
                       GIOFlags    flags,
index 16392f6..fe47872 100644 (file)
@@ -148,8 +148,14 @@ g_date_valid_year
 g_dir_close
 g_direct_equal
 g_direct_hash
-g_dir_open
-g_dir_read_name
+g_dir_open PRIVATE
+#ifdef G_OS_WIN32
+g_dir_open_utf8
+#endif
+g_dir_read_name PRIVATE
+#ifdef G_OS_WIN32
+g_dir_read_name_utf8
+#endif
 g_dir_rewind
 g_error_copy
 g_error_free
@@ -158,29 +164,55 @@ g_error_new
 g_error_new_literal
 g_file_error_from_errno
 g_file_error_quark
-g_file_get_contents
+g_file_get_contents PRIVATE
+#ifdef G_OS_WIN32
+g_file_get_contents_utf8
+#endif
 g_filename_from_uri
-g_filename_from_utf8
+g_filename_from_utf8 PRIVATE
+#ifdef G_OS_WIN32
+g_filename_from_utf8_utf8
+#endif
 g_filename_to_uri
-g_filename_to_utf8
-g_file_open_tmp
+g_filename_to_utf8 PRIVATE
+#ifdef G_OS_WIN32
+g_filename_to_utf8_utf8
+#endif
+g_file_open_tmp PRIVATE
+#ifdef G_OS_WIN32
+g_file_open_tmp_utf8
+#endif
 g_file_read_link
-g_file_test
+g_file_test PRIVATE
+#ifdef G_OS_WIN32
+g_file_test_utf8
+#endif
 g_find_program_in_path
+g_fopen
 g_fprintf
 g_free
+g_freopen
 g_get_application_name
 g_get_charset
-g_get_current_dir
+g_get_current_dir PRIVATE
+#ifdef G_OS_WIN32
+g_get_current_dir_utf8
+#endif
 g_get_current_time
 g_getenv
-g_get_home_dir
+g_get_home_dir PRIVATE
+#ifdef G_OS_WIN32
+g_get_home_dir_utf8
+#endif
 g_get_language_names
 g_get_prgname
 g_get_real_name
 g_get_system_config_dirs
 g_get_system_data_dirs
-g_get_tmp_dir
+g_get_tmp_dir PRIVATE
+#ifdef G_OS_WIN32
+g_get_tmp_dir_utf8
+#endif
 g_get_user_cache_dir
 g_get_user_config_dir
 g_get_user_data_dir
@@ -245,7 +277,10 @@ g_io_channel_get_encoding
 g_io_channel_get_flags
 g_io_channel_get_line_term
 g_io_channel_init
-g_io_channel_new_file
+g_io_channel_new_file PRIVATE
+#ifdef G_OS_WIN32
+g_io_channel_new_file_utf8
+#endif
 g_io_channel_read
 g_io_channel_read_chars
 g_io_channel_read_line
@@ -410,7 +445,11 @@ g_memdup
 g_mem_is_system_malloc
 g_mem_profile
 g_mem_set_vtable
-g_mkstemp
+g_mkdir
+g_mkstemp PRIVATE
+#ifdef G_OS_WIN32
+g_mkstemp_utf8
+#endif
 g_node_child_index
 g_node_child_position
 g_node_children_foreach
@@ -443,6 +482,7 @@ g_nullify_pointer
 g_once_impl
 g_on_error_query
 g_on_error_stack_trace
+g_open
 g_option_context_add_group
 g_option_context_add_main_entries
 g_option_error_quark
@@ -559,6 +599,8 @@ g_relation_insert
 g_relation_new
 g_relation_print
 g_relation_select
+g_remove
+g_rename
 g_return_if_fail_warning
 g_scanner_cur_line
 g_scanner_cur_position
@@ -648,6 +690,7 @@ g_spawn_command_line_sync
 g_spawn_error_quark
 g_spawn_sync
 g_sprintf
+g_stat
 g_static_mutex_free
 g_static_mutex_get_mutex_impl
 g_static_mutex_init
@@ -815,6 +858,7 @@ g_unichar_validate
 g_unichar_xdigit_value
 g_unicode_canonical_decomposition
 g_unicode_canonical_ordering
+g_unlink
 g_unsetenv
 g_uri_list_extract_uris
 g_usleep
diff --git a/glib/gstdio.c b/glib/gstdio.c
new file mode 100644 (file)
index 0000000..cdd393e
--- /dev/null
@@ -0,0 +1,446 @@
+/* gstdio.c - wrappers for C library functions
+ *
+ * Copyright 2004 Tor Lillqvist
+ *
+ * GLib is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * GLib 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GLib; see the file COPYING.LIB.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef G_OS_WIN32
+#include <wchar.h>
+#include <io.h>
+#endif
+
+#include "galias.h"
+#include "glib.h"
+#include "gstdio.h"
+
+#if !defined (G_OS_UNIX) && !defined (G_OS_WIN32)
+#error Please port this to your operating system
+#endif
+
+
+/**
+ * g_open:
+ * @filename: a pathname in the GLib file name encoding
+ * @flags: as in open()
+ * @mode: as in open()
+ *
+ * A wrapper for the POSIX open() function. The open() function is used 
+ * to convert a pathname into a file descriptor.
+ *
+ * See the C library manual for more details about open().
+ *
+ * The point of these wrappers is to make it possible to handle file
+ * names with any Unicode characters in them on Windows without having
+ * to use ifdefs and the wide character API in the application code.
+ *
+ * The pathname argument should be in the GLib file name encoding. On
+ * POSIX this is the actual on-disk encoding which might correspond to
+ * the locale settings of the process (or the 
+ * <envar>G_FILENAME_ENCODING</envar> environment variable), or not.
+ *
+ * On Windows the GLib file name encoding is UTF-8. Note that the
+ * Microsoft C library does not use UTF-8, but has separate APIs for
+ * current system code page and wide characters (UTF-16). The GLib
+ * wrappers call the wide character API if present (on modern Windows
+ * systems), otherwise convert to/from the system code page.
+ * 
+ * Returns: a new file descriptor, or -1 if an error occurred
+ * 
+ * Since: 2.6
+ */
+int
+g_open (const gchar *filename,
+       int          flags,
+       int          mode)
+{
+#ifdef G_OS_WIN32
+  if (G_WIN32_HAVE_WIDECHAR_API ())
+    {
+      wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
+      int retval = _wopen (wfilename, flags, mode);
+      int save_errno = errno;
+      
+      g_free (wfilename);
+
+      errno = save_errno;
+      return retval;
+    }
+  else
+    {    
+      gchar *cp_filename = g_locale_from_utf8 (filename, -1, NULL, NULL, NULL);
+      int retval = open (cp_filename, flags, mode);
+      int save_errno = errno;
+
+      g_free (cp_filename);
+
+      errno = save_errno;
+      return retval;
+    }
+#else
+  return open (filename, flags, mode);
+#endif
+}
+
+/**
+ * g_rename:
+ * @oldfilename: a pathname in the GLib file name encoding
+ * @newfilename: a pathname in the GLib file name encoding
+ *
+ * A wrapper for the POSIX rename() function. The rename() function 
+ * renames a file, moving it between directories if required.
+ * 
+ * See the C library manual for more details about rename().
+ *
+ * Returns: 0 if the renaming succeeded, -1 if an error occurred
+ * 
+ * Since: 2.6
+ */
+int
+g_rename (const gchar *oldfilename,
+         const gchar *newfilename)
+{
+#ifdef G_OS_WIN32
+  if (G_WIN32_HAVE_WIDECHAR_API ())
+    {
+      wchar_t *woldfilename = g_utf8_to_utf16 (oldfilename, -1, NULL, NULL, NULL);
+      wchar_t *wnewfilename = g_utf8_to_utf16 (newfilename, -1, NULL, NULL, NULL);
+      int retval = _wrename (woldfilename, wnewfilename);
+      int save_errno = errno;
+      
+      g_free (woldfilename);
+      g_free (wnewfilename);
+      
+      errno = save_errno;
+      return retval;
+    }
+  else
+    {
+      gchar *cp_oldfilename = g_locale_from_utf8 (oldfilename, -1, NULL, NULL, NULL);
+      gchar *cp_newfilename = g_locale_from_utf8 (newfilename, -1, NULL, NULL, NULL);
+      int retval = rename (cp_oldfilename, cp_newfilename);
+      int save_errno = errno;
+
+      g_free (cp_oldfilename);
+      g_free (cp_newfilename);
+
+      errno = save_errno;
+      return retval;
+    }
+#else
+  return rename (oldfilename, newfilename);
+#endif
+}
+
+/**
+ * g_mkdir: 
+ * @filename: a pathname in the GLib file name encoding
+ * @mode: permissions to use for the newly created directory
+ *
+ * A wrapper for the POSIX mkdir() function. The mkdir() function 
+ * attempts to create a directory with the given name and permissions.
+ * 
+ * See the C library manual for more details about mkdir().
+ *
+ * Returns: 0 if the directory was successfully created, -1 if an error 
+ *    occurred
+ * 
+ * Since: 2.6
+ */
+int
+g_mkdir (const gchar *filename,
+        int          mode)
+{
+#ifdef G_OS_WIN32
+  if (G_WIN32_HAVE_WIDECHAR_API ())
+    {
+      wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
+      int retval = _wmkdir (wfilename);
+      int save_errno = errno;
+
+      g_free (wfilename);
+      
+      errno = save_errno;
+      return retval;
+    }
+  else
+    {
+      gchar *cp_filename = g_locale_from_utf8 (filename, -1, NULL, NULL, NULL);
+      int retval = mkdir (cp_filename);
+      int save_errno = errno;
+
+      g_free (cp_filename);
+
+      errno = save_errno;
+      return retval;
+    }
+#else
+  return mkdir (filename, mode);
+#endif
+}
+
+/**
+ * g_stat: 
+ * @filename: a pathname in the GLib file name encoding
+ * @buf: a pointer to a <structname>stat</structname> struct, which
+ *    will be filled with the file information
+ *
+ * A wrapper for the POSIX stat() function. The stat() function 
+ * returns information about a file.
+ * 
+ * See the C library manual for more details about stat().
+ *
+ * Returns: 0 if the directory was successfully created, -1 if an error 
+ *    occurred
+ * 
+ * Since: 2.6
+ */
+int
+g_stat (const gchar *filename,
+       struct stat *buf)
+{
+#ifdef G_OS_WIN32
+  if (G_WIN32_HAVE_WIDECHAR_API ())
+    {
+      wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
+      int retval = _wstat (wfilename, (struct _stat *) buf);
+      int save_errno = errno;
+
+      g_free (wfilename);
+
+      errno = save_errno;
+      return retval;
+    }
+  else
+    {
+      gchar *cp_filename = g_locale_from_utf8 (filename, -1, NULL, NULL, NULL);
+      int retval = stat (cp_filename, buf);
+      int save_errno = errno;
+
+      g_free (cp_filename);
+
+      errno = save_errno;
+      return retval;
+    }
+#else
+  return stat (filename, buf);
+#endif
+}
+
+/**
+ * g_unlink:
+ * @filename: a pathname in the GLib file name encoding
+ *
+ * A wrapper for the POSIX unlink() function. The unlink() function 
+ * deletes a name from the filesystem. If this was the last link to the 
+ * file and no processes have it opened, the diskspace occupied by the
+ * file is freed.
+ * 
+ * See the C library manual for more details about unlink().
+ *
+ * Returns: 0 if the directory was successfully created, -1 if an error 
+ *    occurred
+ * 
+ * Since: 2.6
+ */
+int
+g_unlink (const gchar *filename)
+{
+#ifdef G_OS_WIN32
+  if (G_WIN32_HAVE_WIDECHAR_API ())
+    {
+      wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
+      int retval = _wunlink (wfilename);
+      int save_errno = errno;
+
+      g_free (wfilename);
+
+      errno = save_errno;
+      return retval;
+    }
+  else
+    {
+      gchar *cp_filename = g_locale_from_utf8 (filename, -1, NULL, NULL, NULL);
+      int retval = unlink (cp_filename);
+      int save_errno = errno;
+
+      g_free (cp_filename);
+
+      errno = save_errno;
+      return retval;
+    }
+#else
+  return unlink (filename);
+#endif
+}
+
+/**
+ * g_remove:
+ * @filename: a pathname in the GLib file name encoding
+ *
+ * A wrapper for the POSIX remove() function. The remove() function 
+ * deletes a name from the filesystem. It calls unlink() for files
+ * and rmdir() for directories.
+ * 
+ * See the C library manual for more details about remove().
+ *
+ * Returns: 0 if the directory was successfully created, -1 if an error 
+ *    occurred
+ * 
+ * Since: 2.6
+ */
+int
+g_remove (const gchar *filename)
+{
+#ifdef G_OS_WIN32
+  if (G_WIN32_HAVE_WIDECHAR_API ())
+    {
+      wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
+      int retval = _wremove (wfilename);
+      int save_errno = errno;
+
+      g_free (wfilename);
+
+      errno = save_errno;
+      return retval;
+    }
+  else
+    {
+      gchar *cp_filename = g_locale_from_utf8 (filename, -1, NULL, NULL, NULL);
+      int retval = remove (cp_filename);
+      int save_errno = errno;
+
+      g_free (cp_filename);
+
+      errno = save_errno;
+      return retval;
+    }
+#else
+  return remove (filename);
+#endif
+}
+
+/**
+ * g_fopen:
+ * @filename: a pathname in the GLib file name encoding
+ * @mode: a string describing the mode in which the file should be 
+ *   opened
+ *
+ * A wrapper for the POSIX fopen() function. The fopen() function opens
+ * a file and associates a new stream with it. 
+ * 
+ * See the C library manual for more details about fopen().
+ *
+ * Returns: A <typename>FILE</typename> pointer if the file was successfully
+ *    opened, or %NULL if an error occurred
+ * 
+ * Since: 2.6
+ */
+FILE *
+g_fopen (const gchar *filename,
+        const gchar *mode)
+{
+#ifdef G_OS_WIN32
+  if (G_WIN32_HAVE_WIDECHAR_API ())
+    {
+      wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
+      wchar_t *wmode = g_utf8_to_utf16 (mode, -1, NULL, NULL, NULL);
+      FILE *retval = _wfopen (wfilename, wmode);
+      int save_errno = errno;
+
+      g_free (wfilename);
+      g_free (wmode);
+
+      errno = save_errno;
+      return retval;
+    }
+  else
+    {
+      gchar *cp_filename = g_locale_from_utf8 (filename, -1, NULL, NULL, NULL);
+      FILE *retval = fopen (cp_filename, mode);
+      int save_errno = errno;
+
+      g_free (cp_filename);
+
+      errno = save_errno;
+      return retval;
+    }
+#else
+  return fopen (filename, mode);
+#endif
+}
+
+/**
+ * g_freopen:
+ * @filename: a pathname in the GLib file name encoding
+ * @mode: a string describing the mode in which the file should be 
+ *   opened
+ * @stream: an existing stream which will be reused, or %NULL
+ *
+ * A wrapper for the POSIX freopen() function. The freopen() function
+ * opens a file and associates it with an existing stream.
+ * 
+ * See the C library manual for more details about freopen().
+ *
+ * Returns: A <typename>FILE</typename> pointer if the file was successfully
+ *    opened, or %NULL if an error occurred.
+ * 
+ * Since: 2.6
+ */
+FILE *
+g_freopen (const gchar *filename,
+          const gchar *mode,
+          FILE        *stream)
+{
+#ifdef G_OS_WIN32
+  if (G_WIN32_HAVE_WIDECHAR_API ())
+    {
+      wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
+      wchar_t *wmode = g_utf8_to_utf16 (mode, -1, NULL, NULL, NULL);
+      FILE *retval = _wfreopen (wfilename, wmode, stream);
+      int save_errno = errno;
+
+      g_free (wfilename);
+      g_free (wmode);
+
+      errno = save_errno;
+      return retval;
+    }
+  else
+    {
+      gchar *cp_filename = g_locale_from_utf8 (filename, -1, NULL, NULL, NULL);
+      FILE *retval = freopen (cp_filename, mode, stream);
+      int save_errno = errno;
+
+      g_free (cp_filename);
+
+      errno = save_errno;
+      return retval;
+    }
+#else
+  return freopen (filename, mode, stream);
+#endif
+}
diff --git a/glib/gstdio.h b/glib/gstdio.h
new file mode 100644 (file)
index 0000000..9594973
--- /dev/null
@@ -0,0 +1,61 @@
+/* gstdio.h - GFilename wrappers for C library functions
+ *
+ * Copyright 2004 Tor Lillqvist
+ *
+ * GLib is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * GLib 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GLib; see the file COPYING.LIB.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __G_STDIO_H__
+#define __G_STDIO_H__
+
+#include <glib/gprintf.h>
+
+#include <sys/stat.h>
+
+/* Wrappers for C library functions that take pathname arguments. On
+ * Unix, the pathname is a file name as it literally is in the file
+ * system. On well-maintained systems with consistent users who know
+ * what they are doing and no exchange of files with others this would
+ * be a well-defined encoding, preferrably UTF-8. On Windows, the
+ * pathname is always in UTF-8, even if that is not the on-disk
+ * encoding or the encoding used by the Win32 API.
+ */
+
+int g_open      (const gchar *filename,
+                 int          flags,
+                 int          mode);
+
+int g_rename    (const gchar *oldfilename,
+                 const gchar *newfilename);
+
+int g_mkdir     (const gchar *filename,
+                 int          mode);
+
+int g_stat      (const gchar *filename,
+                 struct stat *buf);
+
+int g_unlink    (const gchar *filename);
+
+int g_remove    (const gchar *filename);
+
+FILE *g_fopen   (const gchar *filename,
+                 const gchar *mode);
+
+FILE *g_freopen (const gchar *filename,
+                 const gchar *mode,
+                 FILE        *stream);
+
+#endif /* __G_STDIO_H__ */
index 4c619f2..0fea41e 100644 (file)
@@ -702,12 +702,33 @@ g_get_current_dir (void)
       buffer[1] = 0;
     }
 
+#ifdef G_OS_WIN32
+  dir = g_locale_to_utf8 (buffer, -1, NULL, NULL, NULL);
+#else
   dir = g_strdup (buffer);
+#endif
   g_free (buffer);
   
   return dir;
 }
 
+#ifdef G_OS_WIN32
+
+#undef g_get_current_dir
+
+/* Binary compatibility version. Not for newly compiled code. */
+
+gchar*
+g_get_current_dir (void)
+{
+  gchar *utf8_dir = g_get_current_dir_utf8 ();
+  gchar *dir = g_locale_from_utf8 (utf8_dir, -1, NULL, NULL, NULL);
+  g_free (utf8_dir);
+  return dir;
+}
+
+#endif
+
 /**
  * g_getenv:
  * @variable: the environment variable to get.
@@ -1167,6 +1188,27 @@ g_get_home_dir (void)
   return g_home_dir;
 }
 
+#ifdef G_OS_WIN32
+
+#undef g_get_home_dir
+
+G_CONST_RETURN gchar*
+g_get_home_dir (void)
+{
+  static gchar *home_dir = NULL;
+
+  G_LOCK (g_utils_global);
+  if (!g_tmp_dir)
+    g_get_any_init ();
+  if (!home_dir && g_home_dir)
+    home_dir = g_locale_from_utf8 (g_home_dir, -1, NULL, NULL, NULL);
+  G_UNLOCK (g_utils_global);
+
+  return home_dir;
+}
+
+#endif
+
 /* Return a directory to be used to store temporary files. This is the
  * value of the TMPDIR, TMP or TEMP environment variables (they are
  * checked in that order). If none of those exist, use P_tmpdir from
@@ -1185,6 +1227,30 @@ g_get_tmp_dir (void)
   return g_tmp_dir;
 }
 
+#ifdef G_OS_WIN32
+
+#undef g_get_tmp_dir
+
+G_CONST_RETURN gchar*
+g_get_tmp_dir (void)
+{
+  static gchar *tmp_dir = NULL;
+
+  G_LOCK (g_utils_global);
+  if (!g_tmp_dir)
+    g_get_any_init ();
+  if (!tmp_dir)
+    tmp_dir = g_locale_from_utf8 (g_tmp_dir, -1, NULL, NULL, NULL);
+
+  if (tmp_dir == NULL)
+    tmp_dir = "C:\\";
+  G_UNLOCK (g_utils_global);
+
+  return tmp_dir;
+}
+
+#endif
+
 G_LOCK_DEFINE_STATIC (g_prgname);
 static gchar *g_prgname = NULL;
 
index 03eaa17..e3f1418 100644 (file)
@@ -115,6 +115,10 @@ G_BEGIN_DECLS
 
 /* Retrive static string info
  */
+#ifdef G_OS_WIN32
+#define g_get_home_dir g_get_home_dir_utf8
+#define g_get_tmp_dir g_get_tmp_dir_utf8
+#endif
 G_CONST_RETURN gchar* g_get_user_name        (void);
 G_CONST_RETURN gchar* g_get_real_name        (void);
 G_CONST_RETURN gchar* g_get_home_dir         (void);
@@ -171,6 +175,10 @@ G_CONST_RETURN gchar* g_basename           (const gchar *file_name);
 
 #endif /* G_DISABLE_DEPRECATED */
 
+#ifdef G_OS_WIN32
+#define g_get_current_dir g_get_current_dir_utf8
+#endif
+
 /* The returned strings are newly allocated with g_malloc() */
 gchar*                g_get_current_dir    (void);
 gchar*                g_path_get_basename  (const gchar *file_name);
index d3d1a45..b89778d 100755 (executable)
@@ -16,7 +16,7 @@ print <<EOF;
 
 #include "glib.h"
 
-#include "gprintf.h"
+#include "gstdio.h"
 #ifdef G_OS_WIN32
 #include "gwin32.h"
 #endif
@@ -77,8 +77,9 @@ while (<>) {
       next;
   }
  
-
   my $str = $_;
+  # Drop any Win32 specific .def file syntax
+  $str = (split (/ /, $str))[0];
   chomp($str);
   my $alias = "IA__".$str;