From 8a7eecd7c62f26dfb9b6d6a8ec8e57920a0c5ac4 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Wed, 27 Oct 2004 16:46:29 +0000 Subject: [PATCH] Introduce the idea of a filename encoding, which is *literally* the 2004-10-27 Matthias Clasen 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 --- ChangeLog | 24 ++ ChangeLog.pre-2-10 | 24 ++ ChangeLog.pre-2-12 | 24 ++ ChangeLog.pre-2-6 | 24 ++ ChangeLog.pre-2-8 | 24 ++ docs/reference/ChangeLog | 4 + docs/reference/glib/glib-sections.txt | 11 + docs/reference/glib/tmpl/fileutils.sgml | 104 +++++ docs/reference/glib/tmpl/macros_misc.sgml | 1 + docs/reference/glib/tmpl/main.sgml | 2 +- glib/Makefile.am | 2 + glib/gconvert.c | 83 +++- glib/gconvert.h | 5 + glib/gdir.c | 224 ++++++++++- glib/gdir.h | 18 +- glib/gfileutils.c | 333 +++++++++++++--- glib/gfileutils.h | 9 +- glib/giowin32.c | 29 +- glib/glib.symbols | 68 +++- glib/gstdio.c | 446 ++++++++++++++++++++++ glib/gstdio.h | 61 +++ glib/gutils.c | 66 ++++ glib/gutils.h | 8 + glib/makegalias.pl | 5 +- 24 files changed, 1503 insertions(+), 96 deletions(-) create mode 100644 glib/gstdio.c create mode 100644 glib/gstdio.h diff --git a/ChangeLog b/ChangeLog index 16526fd23..24cb4dcb1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,27 @@ +2004-10-27 Matthias Clasen + + 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 * glib/gkeyfile.c: Fix includes. (#156500, #156499, diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index 16526fd23..24cb4dcb1 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,3 +1,27 @@ +2004-10-27 Matthias Clasen + + 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 * glib/gkeyfile.c: Fix includes. (#156500, #156499, diff --git a/ChangeLog.pre-2-12 b/ChangeLog.pre-2-12 index 16526fd23..24cb4dcb1 100644 --- a/ChangeLog.pre-2-12 +++ b/ChangeLog.pre-2-12 @@ -1,3 +1,27 @@ +2004-10-27 Matthias Clasen + + 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 * glib/gkeyfile.c: Fix includes. (#156500, #156499, diff --git a/ChangeLog.pre-2-6 b/ChangeLog.pre-2-6 index 16526fd23..24cb4dcb1 100644 --- a/ChangeLog.pre-2-6 +++ b/ChangeLog.pre-2-6 @@ -1,3 +1,27 @@ +2004-10-27 Matthias Clasen + + 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 * glib/gkeyfile.c: Fix includes. (#156500, #156499, diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8 index 16526fd23..24cb4dcb1 100644 --- a/ChangeLog.pre-2-8 +++ b/ChangeLog.pre-2-8 @@ -1,3 +1,27 @@ +2004-10-27 Matthias Clasen + + 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 * glib/gkeyfile.c: Fix includes. (#156500, #156499, diff --git a/docs/reference/ChangeLog b/docs/reference/ChangeLog index c2ab4339f..da017ed20 100644 --- a/docs/reference/ChangeLog +++ b/docs/reference/ChangeLog @@ -1,3 +1,7 @@ +2004-10-27 Matthias Clasen + + * glib/tmpl/fileutils.sgml: Add some intro. + 2004-10-26 Matthias Clasen * gobject/gobject-docs.sgml: Add an index for 2.6 additions. diff --git a/docs/reference/glib/glib-sections.txt b/docs/reference/glib/glib-sections.txt index 4593fa45b..f89b484e0 100644 --- a/docs/reference/glib/glib-sections.txt +++ b/docs/reference/glib/glib-sections.txt @@ -967,6 +967,7 @@ g_option_error_quark
File Utilities fileutils +glib.h,glib/gstdio.h GFileError G_FILE_ERROR GFileTest @@ -984,6 +985,16 @@ g_dir_read_name g_dir_rewind g_dir_close + +g_open +g_rename +g_mkdir +g_stat +g_unlink +g_remove +g_fopen +g_freopen + g_file_error_quark
diff --git a/docs/reference/glib/tmpl/fileutils.sgml b/docs/reference/glib/tmpl/fileutils.sgml index 092346b9e..28ebe3b2c 100644 --- a/docs/reference/glib/tmpl/fileutils.sgml +++ b/docs/reference/glib/tmpl/fileutils.sgml @@ -6,7 +6,31 @@ various file-related functions. +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. + + +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 +G_FILENAME_ENCODING 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. + + +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(). @@ -223,3 +247,83 @@ An opaque structure representing an opened directory. @dir: + + + + + +@filename: +@flags: +@mode: +@Returns: + + + + + + + +@oldfilename: +@newfilename: +@Returns: + + + + + + + +@filename: +@mode: +@Returns: + + + + + + + +@filename: +@buf: +@Returns: + + + + + + + +@filename: +@Returns: + + + + + + + +@filename: +@Returns: + + + + + + + +@filename: +@mode: +@Returns: + + + + + + + +@filename: +@mode: +@stream: +@Returns: + + diff --git a/docs/reference/glib/tmpl/macros_misc.sgml b/docs/reference/glib/tmpl/macros_misc.sgml index 270b2584b..9ea09c5e0 100644 --- a/docs/reference/glib/tmpl/macros_misc.sgml +++ b/docs/reference/glib/tmpl/macros_misc.sgml @@ -260,6 +260,7 @@ attributes (currently only gcc). Since: 2.6 + Expands to the GNU C visibility(hidden) attribute if the diff --git a/docs/reference/glib/tmpl/main.sgml b/docs/reference/glib/tmpl/main.sgml index ff396f53d..03bc48dd9 100644 --- a/docs/reference/glib/tmpl/main.sgml +++ b/docs/reference/glib/tmpl/main.sgml @@ -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() diff --git a/glib/Makefile.am b/glib/Makefile.am index e5a77ad65..77d47d6f0 100644 --- a/glib/Makefile.am +++ b/glib/Makefile.am @@ -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 \ diff --git a/glib/gconvert.c b/glib/gconvert.c index 346d0e680..6915893f0 100644 --- a/glib/gconvert.c +++ b/glib/gconvert.c @@ -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. */ diff --git a/glib/gconvert.h b/glib/gconvert.h index 7b203ec62..f666e28bd 100644 --- a/glib/gconvert.h +++ b/glib/gconvert.h @@ -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, diff --git a/glib/gdir.c b/glib/gdir.c index ba5199506..8896b3363 100644 --- a/glib/gdir.c +++ b/glib/gdir.c @@ -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 @@ -39,20 +40,28 @@ 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); } diff --git a/glib/gdir.h b/glib/gdir.h index 0ca63b1fc..011174ebd 100644 --- a/glib/gdir.h +++ b/glib/gdir.h @@ -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 diff --git a/glib/gfileutils.c b/glib/gfileutils.c index f0f7528c2..8a37968c9 100644 --- a/glib/gfileutils.c +++ b/glib/gfileutils.c @@ -63,6 +63,7 @@ #define O_BINARY 0 #endif +#include "gstdio.h" #include "glibintl.h" /** @@ -94,7 +95,7 @@ * * /* DON'T DO THIS */ * if (!g_file_test (filename, G_FILE_TEST_IS_SYMLINK)) { - * fd = open (filename, O_WRONLY); + * fd = g_open (filename, O_WRONLY); * /* write to fd */ * } * @@ -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, diff --git a/glib/gfileutils.h b/glib/gfileutils.h index 939d5459f..cc3b4941a 100644 --- a/glib/gfileutils.h +++ b/glib/gfileutils.h @@ -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__ */ - - diff --git a/glib/giowin32.c b/glib/giowin32.c index 8fcb82709..9bffc0577 100644 --- a/glib/giowin32.c +++ b/glib/giowin32.c @@ -46,6 +46,7 @@ #include #include +#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, diff --git a/glib/glib.symbols b/glib/glib.symbols index 16392f682..fe47872e8 100644 --- a/glib/glib.symbols +++ b/glib/glib.symbols @@ -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 index 000000000..cdd393e9f --- /dev/null +++ b/glib/gstdio.c @@ -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 +#include +#include + +#ifdef HAVE_UNISTD_H +#include +#endif + +#ifdef G_OS_WIN32 +#include +#include +#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 + * G_FILENAME_ENCODING 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 stat 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 FILE 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 FILE 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 index 000000000..9594973f9 --- /dev/null +++ b/glib/gstdio.h @@ -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 + +#include + +/* 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__ */ diff --git a/glib/gutils.c b/glib/gutils.c index 4c619f282..0fea41e8c 100644 --- a/glib/gutils.c +++ b/glib/gutils.c @@ -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; diff --git a/glib/gutils.h b/glib/gutils.h index 03eaa17a0..e3f141812 100644 --- a/glib/gutils.h +++ b/glib/gutils.h @@ -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); diff --git a/glib/makegalias.pl b/glib/makegalias.pl index d3d1a456b..b89778dee 100755 --- a/glib/makegalias.pl +++ b/glib/makegalias.pl @@ -16,7 +16,7 @@ print <) { next; } - my $str = $_; + # Drop any Win32 specific .def file syntax + $str = (split (/ /, $str))[0]; chomp($str); my $alias = "IA__".$str;